[
  {
    "path": ".coveragerc",
    "content": "[run]\nomit =\n    *test*\n"
  },
  {
    "path": ".github/workflows/check-python.yml",
    "content": "name: Check Python code\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: [\"3.10\"]\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v2\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install -r 00_Utilities/python/ci-requirements.txt\n    - name: Test with mypy\n      run: |\n        mypy . --exclude 79_Slalom --exclude 27_Civil_War --exclude 38_Fur_Trader --exclude 81_Splat --exclude 09_Battle --exclude 40_Gomoko --exclude 36_Flip_Flop --exclude 43_Hammurabi --exclude 04_Awari --exclude 78_Sine_Wave --exclude 77_Salvo --exclude 34_Digits --exclude 17_Bullfight --exclude 16_Bug\n    - name: Test with flake8\n      run: |\n        flake8 . --ignore E501,W503,E203,E731,B011,SIM119,SIM106\n"
  },
  {
    "path": ".github/workflows/file-size.yml",
    "content": "name: File Size Check\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: [\"3.10\"]\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v2\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Get changed files\n      id: changed-files\n      uses: tj-actions/changed-files@v18.4\n    - name: List all changed files\n      run: |\n        # MAXSIZE is 1 MB\n        MAXSIZE=1000000\n        for FILENAME in ${{ steps.changed-files.outputs.all_changed_files }}; do\n          FILESIZE=$(stat -c%s \"$FILENAME\")\n          echo \"Size of $FILENAME = $FILESIZE bytes.\"\n          if (( FILESIZE > MAXSIZE)); then\n            echo \"$FILENAME is too big. Only $MAXSIZE bytes allowed.\"\n            exit 1\n          fi\n        done\n"
  },
  {
    "path": ".github/workflows/rust.yml",
    "content": "name: Rust\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\nenv:\n  CARGO_TERM_COLOR: always\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: Build All\n      run: find */rust/Cargo.toml|xargs -I {} dirname {}|xargs -I {} bash -c 'cd {} && cargo build --verbose'\n\n    - name: Run All tests\n      run: find */rust/Cargo.toml|xargs -I {} dirname {}|xargs -I {} bash -c 'cd {} && cargo test --verbose'\n"
  },
  {
    "path": ".gitignore",
    "content": ".local/\n.vscode/\n.gradle/\nnode_modules/\nbuildJvm/bin\nbuildJvm/*/build/\n\n.classpath\n.project\n.settings\n.metadata\n*.iml\n*.ipr\n\n*.class\n*/.vs\n*.suo\n\nbin/\nobj/\n\n.idea\n*.iws\n*.iml\n*.ipr\nout/\n\n*.py[co]\n.python-version\nPipfile\nvenv/\n.coverage\n\n.DS_Store\n.vs/\n**/target/\n**/*.rs.bk\n/target\ntodo.md\n\n.fake\n.fake"
  },
  {
    "path": ".nojekyll",
    "content": ""
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "# pre-commit run --all-files\nrepos:\n-   repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v4.1.0\n    hooks:\n    -   id: check-ast\n    -   id: check-case-conflict\n    -   id: check-docstring-first\n    -   id: check-executables-have-shebangs\n    -   id: check-json\n    -   id: check-yaml\n    -   id: debug-statements\n    -   id: end-of-file-fixer\n    -   id: trailing-whitespace\n    -   id: mixed-line-ending\n    -   id: check-added-large-files\n        args: ['--maxkb=1000']\n-   repo: https://github.com/pre-commit/mirrors-isort\n    rev: v5.10.1\n    hooks:\n    -   id: isort\n-   repo: https://github.com/psf/black\n    rev: 22.1.0\n    hooks:\n    -   id: black\n-   repo: https://github.com/asottile/pyupgrade\n    rev: v2.31.1\n    hooks:\n    -   id: pyupgrade\n        args: [--py37-plus]\n-   repo: https://github.com/asottile/blacken-docs\n    rev: v1.12.1\n    hooks:\n    -   id: blacken-docs\n        additional_dependencies: [black==22.1.0]\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript aceyducey.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"aceyducey\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms",
    "content": "print \" \"*26 + \"Acey Ducey Card Game\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint\nprint\nprint \"Acey-ducey is played in the following manner.\"\nprint \"The dealer (computer) deals two cards face up.\"\nprint \"You have an option to bet or not bet depending\"\nprint \"on whether or not you feel the card will have\"\nprint \"a value between the first two.\"\nprint \"If you do not want to bet, input a 0.\"\n\ncards = range(2,10) + [\"Jack\", \"Queen\", \"King\", \"Ace\"]\n\nwhile true\n\tmoney = 100\n\t\n\twhile true\n\t\tprint \"You now have \" + money + \" dollars.\"\n\t\tprint\n\t\tprint \"Here are your next two cards:\"\n\t\twhile true\n\t\t\tA = floor(rnd * cards.len)\n\t\t\tB = floor(rnd * cards.len)\n\t\t\tif B > A then break\n\t\tend while\n\t\tprint cards[A]\n\t\tprint cards[B]\n\t\tbet = input(\"What is your bet? \").val\n\t\twhile bet > money\n\t\t\tprint \"Sorry, my friend, but you bet too much.\"\n\t\t\tprint \"You have only \" + money + \" dollars to bet.\"\n\t\t\tbet = input(\"What is your bet? \").val\n\t\tend while\n\t\tif bet == 0 then\n\t\t\tprint \"Chicken!!\"\n\t\t\tcontinue\n\t\tend if\n\t\tC = floor(rnd * cards.len)\n\t\tprint cards[C]\n\t\t\t\t\n\t\tif C <= A or C >= B\tthen\n\t\t\tprint \"Sorry, you lose.\"\n\t\t\tmoney -= bet\n\t\t\tif money <= 0 then break\n\t\telse\n\t\t\tprint \"You win!!!\"\n\t\t\tmoney += bet\n\t\tend if\n\tend while\n\t\n\tprint\n\tprint\n\tprint \"Sorry, friend, but you blew your wad.\"\n\tprint; print\n\tagain = input(\"Try again (yes or no)? \").lower\n\tif again and again[0] == \"n\" then break\nend while\n\nprint \"O.K., hope you had fun!\""
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only.\n\n#### External Links\n - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp\n - PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/aceyducey.bas",
    "content": "10 PRINT TAB(26);\"ACEY DUCEY CARD GAME\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n21 PRINT\n22 PRINT\n30 PRINT\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \"\n40 PRINT\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\"\n50 PRINT\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\"\n60 PRINT\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\"\n70 PRINT\"A VALUE BETWEEN THE FIRST TWO.\"\n80 PRINT\"IF YOU DO NOT WANT TO BET, INPUT A 0\"\n100 N=100\n110 Q=100\n120 PRINT \"YOU NOW HAVE \";Q;\" DOLLARS.\"\n130 PRINT\n140 GOTO 260\n210 Q=Q+M\n220 GOTO 120\n240 Q=Q-M\n250 GOTO 120\n260 PRINT\"HERE ARE YOUR NEXT TWO CARDS: \"\n270 A=INT(14*RND(1))+2\n280 IF A<2 THEN 270\n290 IF A>14 THEN 270\n300 B=INT(14*RND(1))+2\n310 IF B<2 THEN 300\n320 IF B>14 THEN 300\n330 IF A>=B THEN 270\n350 IF A<11 THEN 400\n360 IF A=11 THEN 420\n370 IF A=12 THEN 440\n380 IF A=13 THEN 460\n390 IF A=14 THEN 480\n400 PRINT A\n410 GOTO 500\n420 PRINT\"JACK\"\n430 GOTO 500\n440 PRINT\"QUEEN\"\n450 GOTO 500\n460 PRINT\"KING\"\n470 GOTO 500\n480 PRINT\"ACE\"\n500 IF B<11 THEN 550\n510 IF B=11 THEN 570\n520 IF B=12 THEN 590\n530 IF B=13 THEN 610\n540 IF B=14 THEN 630\n550 PRINT B\n560 GOTO 650\n570 PRINT\"JACK\"\n580 GOTO 650\n590 PRINT\"QUEEN\"\n600 GOTO 650\n610 PRINT\"KING\"\n620 GOTO 650\n630 PRINT\"ACE\"\n640 PRINT\n650 PRINT\n660 INPUT\"WHAT IS YOUR BET\";M\n670 IF M<>0 THEN 680\n675 PRINT\"CHICKEN!!\"\n676 PRINT\n677 GOTO 260\n680 IF M<=Q THEN 730\n690 PRINT\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\"\n700 PRINT\"YOU HAVE ONLY \";Q;\" DOLLARS TO BET.\"\n710 GOTO 650\n730 C=INT(14*RND(1))+2\n740 IF C<2 THEN 730\n750 IF C>14 THEN 730\n760 IF C<11 THEN 810\n770 IF C=11 THEN 830\n780 IF C=12 THEN 850\n790 IF C=13 THEN 870\n800 IF C=14 THEN 890\n810 PRINT C\n820 GOTO 910\n830 PRINT\"JACK\"\n840 GOTO 910\n850 PRINT\"QUEEN\"\n860 GOTO 910\n870 PRINT\"KING\"\n880 GOTO 910\n890 PRINT \"ACE\"\n900 PRINT\n910 IF C>A THEN 930\n920 GOTO 970\n930 IF C>=B THEN 970\n950 PRINT\"YOU WIN!!!\"\n960 GOTO 210\n970 PRINT\"SORRY, YOU LOSE\"\n980 IF M<Q THEN 240\n990 PRINT\n1000 PRINT\n1010 PRINT\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\"\n1015 PRINT:PRINT\n1020 INPUT\"TRY AGAIN (YES OR NO)\";A$\n1025 PRINT:PRINT\n1030 IF A$=\"YES\" THEN 110\n1040 PRINT\"O.K., HOPE YOU HAD FUN!\"\n1050 END\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/c++/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [C++14](https://en.wikipedia.org/wiki/C%2B%2B14)\n\nThe build folder are executables for x86 and x64 systems. Compiled and built using Visual Studio."
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp",
    "content": "#include <iostream>\n#include <time.h>\n#include \"Aceyducey.h\"\n\n\nint main()\n{\n    //Setting Seed for the Random Generator\n    srand((unsigned int)time(NULL));\n    bool isPlaying(true);\n    Money = 100;\n    WelcomeMessage();\n    while (isPlaying)\n    {\n        Play(isPlaying);\n    }\n    printf(\"O.K., HOPE YOU HAD FUN!\\n\");\n}\n\nvoid WelcomeMessage()\n{\n    for (int i = 0; i < 25; i++)\n    {\n        printf(\" \");\n    }\n    printf(\"ACEY DUCEY CARD GAME\\n\");\n    for (int i = 0; i < 14; i++)\n    {\n        printf(\" \");\n    }\n    printf(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\nACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \\n\");\n    printf(\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\\nYOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\\n\");\n    printf(\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\\nA VALUE BETWEEN THE FIRST TWO.\\n\");\n    printf(\"IF YOU DO NOT WANT TO BET, INPUT A 0\\n\");\n}\n\nvoid Play(bool& isPlaying)\n{\n    short int DealerCards[2];\n    int Bet;\n    short int CurrentCard;\n    printf(\"YOU NOW HAVE %d DOLLARS.\\n\\n\", Money);\n    printf(\"HERE ARE YOUR NEXT TWO CARDS: \\n\");\n\n    //Draw Dealers Cards\n    DrawCard(DealerCards[0]);\n    printf(\"\\n\");\n    DrawCard(DealerCards[1]);\n    printf(\"\\n\\n\\n\");\n\n    //Check if Bet is Valid\n    do {\n        printf(\"WHAT IS YOUR BET: \");\n        std::cin >> Bet;\n        if (Bet == 0)\n        {\n            printf(\"CHICKEN!!\\n\\n\");\n        }\n    } while (Bet > Money || Bet < 0);\n\n    //Draw Players Card\n    DrawCard(CurrentCard);\n    printf(\"\\n\");\n    if (CurrentCard > DealerCards[0] && CurrentCard < DealerCards[1])\n    {\n        printf(\"YOU WIN!!!\\n\");\n        Money += Bet;\n        return;\n    }\n    else\n    {\n        printf(\"SORRY, YOU LOSE\\n\");\n        Money -= Bet;\n    }\n    if (isGameOver())\n    {\n        printf(\"TRY AGAIN (YES OR NO)\\n\\n\");\n        std::string response;\n        std::cin >> response;\n        if (response != \"YES\")\n        {\n            isPlaying = false;\n        }\n        Money = 100;\n    }\n}\n\nbool isGameOver()\n{\n    if (Money <= 0)\n    {\n        printf(\"\\n\\n\");\n        printf(\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\\n\\n\");\n        return true;\n    }\n    return false;\n}\n\nvoid DrawCard(short int& Card)\n{\n    //Basically generate 2 numbers first one is between 2-11 and second one 0-3\n    short int RandomNum1 = (rand() % 10) + 2;\n    short int RandomNum2 = rand() % 4;\n    Card = RandomNum1 + RandomNum2;\n\n    switch (Card)\n    {\n    case 11:\n        printf(\"JACK\");\n        break;\n    case 12:\n        printf(\"QUEEN\");\n        break;\n    case 13:\n        printf(\"KING\");\n        break;\n    case 14:\n        printf(\"ACE\");\n        break;\n    default:\n        printf(\"%d\", Card);\n    }\n}"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h",
    "content": "#pragma once\n\nvoid WelcomeMessage();\nvoid DrawCard(short int& Card);\nvoid Play(bool& isPlaying);\nbool isGameOver();\nint Money;"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/d/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\nTwo versions are supplied that are functionally equivalent, but differ in source layout:\n\n<dl>\n  <dt><tt>aceyducey_literal.d</tt></dt>\n  <dd>A largely literal transcription of the original Basic source. All unnecessary uglyness is preserved.</dd>\n  <dt><tt>aceyducey.d</tt></dt>\n  <dd>An idiomatic D refactoring of the original, with a focus on increasing the readability and robustness.\n      Memory-safety <A href=\"https://dlang.org/spec/memory-safe-d.html\">is ensured by the language</a>, thanks to the\n      <tt>@safe</tt> annotation.</dd>\n</dl>\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -run aceyducey.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n\nNote that there are compiler switches related to memory-safety (`-preview=dip25` and `-preview=dip1000`) that are not\nused here because they are unnecessary in this case. What these do is to make the analysis more thorough, so that with\nthem some code that needed to be `@system` can then be inferred to be in fact `@safe`. [Code that compiles without\nthese switches is just as safe as when compiled with them]\n(https://forum.dlang.org/post/dftgjalswvwfjpyushgn@forum.dlang.org).\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/d/aceyducey.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\n\nvoid main()\n{\n    import std.stdio : write, writeln;\n    import std.string : center, toUpper, wrap;\n    import std.exception : ifThrown;\n\n    enum width = 80;\n    writeln(center(\"Acey Ducey Card Game\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\", width));\n    writeln(wrap(\"Acey-Ducey is played in the following manner: The dealer (computer) deals two cards face up. \" ~\n                 \"You have an option to bet or not bet depending on whether or not you feel the third card will \" ~\n                 \"have a value between the first two. If you do not want to bet, input a 0.\", width));\n\n    enum Hand {low, middle, high}\n    Card[Hand.max + 1] cards; // Three cards.\n    bool play = true;\n\n    while (play)\n    {\n        int cash = 100;\n        while (cash > 0)\n        {\n            writeln(\"\\nYou now have \", cash, \" dollars.\");\n            int bet = 0;\n            while (bet <= 0)\n            {\n                do // Draw new cards, until the first card has a smaller value than the last card.\n                {\n                    foreach (ref card; cards)\n                        card.drawNew;\n                } while (cards[Hand.low] >= cards[Hand.high]);\n                writeln(\"Here are your next two cards:\\n\", cards[Hand.low], \"\\n\", cards[Hand.high]);\n\n                int askBet() // A nested function.\n                {\n                    import std.conv : to;\n\n                    write(\"\\nWhat is your bet? \");\n                    int answer = readString.to!int.\n                            ifThrown!Exception(askBet); // Try again when answer does not convert to int.\n                    if (answer <= cash)\n                        return answer;\n                    writeln(\"Sorry, my friend, but you bet too much.\\nYou have only \", cash, \" dollars to bet.\");\n                    return askBet; // Recurse: Ask again.\n                }\n                bet = askBet;\n                if (bet <= 0) // Negative bets are interpreted as 0.\n                    writeln(\"CHICKEN!!\");\n            } // bet is now > 0.\n\n            writeln(cards[Hand.middle]);\n            if (cards[Hand.low] < cards[Hand.middle] && cards[Hand.middle] < cards[Hand.high])\n            {\n                writeln(\"YOU WIN!!!\");\n                cash += bet;\n            }\n            else\n            {\n                writeln(\"Sorry, you lose.\");\n                cash -= bet;\n                if (cash <= 0)\n                {\n                    writeln(\"\\n\\nSorry, friend, but you blew your wad.\");\n                    write(\"\\n\\nTry again (Yes or No)? \");\n                    play = readString.toUpper == \"YES\";\n                }\n            }\n        }\n    }\n    writeln(\"O.K., hope you had fun!\");\n}\n\nstruct Card\n{\n    int value = 2;\n    alias value this; // Enables Card to stand in as an int, so that cards can be compared as ints.\n\n    invariant\n    {\n        assert(2 <= value && value <= 14); // Ensure cards always have a valid value.\n    }\n\n    /// Adopt a new value.\n    void drawNew()\n    {\n        import std.random : uniform;\n\n        value = uniform!(\"[]\", int, int)(2, 14); // A random int between inclusive bounds.\n    }\n\n    /// Called for implicit conversion to string.\n    string toString() const pure\n    {\n        import std.conv : text;\n\n        switch (value)\n        {\n            case 11: return \"Jack\";\n            case 12: return \"Queen\";\n            case 13: return \"King\";\n            case 14: return \"Ace\";\n            default: return text(\" \", value); // Basic prepends a space.\n        }\n    }\n}\n\n/// Read a string from standard input, stripping newline and other enclosing whitespace.\nstring readString() nothrow\n{\n    import std.string : strip;\n\n    try\n        return trustedReadln.strip;\n    catch (Exception)   // readln throws on I/O and Unicode errors, which we handle here.\n        return \"\";\n}\n\n/** An @trusted wrapper around readln.\n *\n * This is the only function that formally requires manual review for memory-safety.\n * [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)\n * which would remove the need to have any @trusted code in this program.\n */\nstring trustedReadln() @trusted\n{\n    import std.stdio : readln;\n\n    return readln;\n}\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/d/aceyducey_literal.d",
    "content": "void main()\n{\n    import std;\n\n    L10: writef(\"%26s\", ' '); writeln(\"ACEY DUCEY CARD GAME\");\n    L20: writef(\"%15s\", ' '); writeln(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    L21: writeln;\n    L22: writeln;\n    L30: writeln(\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \");\n    L40: writeln(\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\");\n    L50: writeln(\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\");\n    L60: writeln(\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\");\n    L70: writeln(\"A VALUE BETWEEN THE FIRST TWO.\");\n    L80: writeln(\"IF YOU DO NOT WANT TO BET, INPUT A 0\");\n    L100: int N=100;\n    L110: int Q=100, M;\n    L120: writeln(\"YOU NOW HAVE \",Q,\" DOLLARS.\");\n    L130: writeln;\n    L140: goto L260;\n    L210: Q=Q+M;\n    L220: goto L120;\n    L240: Q=Q-M;\n    L250: goto L120;\n    L260: writeln(\"HERE ARE YOUR NEXT TWO CARDS: \");\n    L270: auto A=to!int(14*uniform01)+2;\n    L280: if (A<2) goto L270;\n    L290: if (A>14) goto L270;\n    L300: auto B=to!int(14*uniform01)+2;\n    L310: if (B<2) goto L300;\n    L320: if (B>14) goto L300;\n    L330: if (A>=B) goto L270;\n    L350: if (A<11) goto L400;\n    L360: if (A==11) goto L420;\n    L370: if (A==12) goto L440;\n    L380: if (A==13) goto L460;\n    L390: if (A==14) goto L480;\n    L400: writefln(\"%2d\", A);\n    L410: goto L500;\n    L420: writeln(\"JACK\");\n    L430: goto L500;\n    L440: writeln(\"QUEEN\");\n    L450: goto L500;\n    L460: writeln(\"KING\");\n    L470: goto L500;\n    L480: writeln(\"ACE\");\n    L500: if (B<11) goto L550;\n    L510: if (B==11) goto L570;\n    L520: if (B==12) goto L590;\n    L530: if (B==13) goto L610;\n    L540: if (B==14) goto L630;\n    L550: writefln(\"%2d\", B);\n    L560: goto L650;\n    L570: writeln(\"JACK\");\n    L580: goto L650;\n    L590: writeln(\"QUEEN\");\n    L600: goto L650;\n    L610: writeln(\"KING\");\n    L620: goto L650;\n    L630: writeln(\"ACE\");\n    L640: writeln;\n    L650: writeln;\n    L660: write(\"WHAT IS YOUR BET? \"); M = stdin.readln.strip.to!int;\n    L670: if (M!=0) goto L680;\n    L675: writeln(\"CHICKEN!!\");\n    L676: writeln;\n    L677: goto L260;\n    L680: if (M<=Q) goto L730;\n    L690: writeln(\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\");\n    L700: writeln(\"YOU HAVE ONLY \",Q,\" DOLLARS TO BET.\");\n    L710: goto L650;\n    L730: auto C=to!int(14*uniform01)+2;\n    L740: if (C<2) goto L730;\n    L750: if (C>14) goto L730;\n    L760: if (C<11) goto L810;\n    L770: if (C==11) goto L830;\n    L780: if (C==12) goto L850;\n    L790: if (C==13) goto L870;\n    L800: if (C==14) goto L890;\n    L810: writeln(C);\n    L820: goto L910;\n    L830: writeln(\"JACK\");\n    L840: goto L910;\n    L850: writeln(\"QUEEN\");\n    L860: goto L910;\n    L870: writeln(\"KING\");\n    L880: goto L910;\n    L890: writeln( \"ACE\");\n    L900: writeln;\n    L910: if (C>A) goto L930;\n    L920: goto L970;\n    L930: if (C>=B) goto L970;\n    L950: writeln(\"YOU WIN!!!\");\n    L960: goto L210;\n    L970: writeln(\"SORRY, YOU LOSE\");\n    L980: if (M<Q) goto L240;\n    L990: writeln;\n    L1000: writeln;\n    L1010: writeln(\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\");\n    L1015: writeln;writeln;\n    L1020: write(\"TRY AGAIN (YES OR NO)? \"); auto AS=stdin.readln;\n    L1025: writeln;writeln;\n    L1030: if (AS.strip.toUpper==\"YES\") goto L110;\n    L1040: writeln(\"O.K., HOPE YOU HAD FUN!\");\n}\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/.gitignore",
    "content": "\n# Created by https://www.toptal.com/developers/gitignore/api/macos,visualstudiocode,elm\n# Edit at https://www.toptal.com/developers/gitignore?templates=macos,visualstudiocode,elm\n\n### Elm ###\n# elm-package generated files\nelm-stuff\n# elm-repl generated files\nrepl-temp-*\n\n### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### VisualStudioCode ###\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n!.vscode/*.code-snippets\n\n# Local History for Visual Studio Code\n.history/\n\n# Built Visual Studio Code Extensions\n*.vsix\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n.ionide\n\n# Support for Project snippet scope\n\n# End of https://www.toptal.com/developers/gitignore/api/macos,visualstudiocode,elm\n\n# Created by https://www.toptal.com/developers/gitignore/api/node\n# Edit at https://www.toptal.com/developers/gitignore?templates=node\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n### Node Patch ###\n# Serverless Webpack directories\n.webpack/\n\n# Optional stylelint cache\n\n# SvelteKit build / generate output\n.svelte-kit\n\n# End of https://www.toptal.com/developers/gitignore/api/node\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/README.md",
    "content": "# Acey Ducey\n\nThis is an Elm implementation of the `Basic Compouter Games` Game Acey Ducey.\n\n## Build App\n\n- install elm\n\n```bash\nyarn\nyarn build\n```\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/docs/app.js",
    "content": "(function(scope){\n'use strict';\n\nfunction F(arity, fun, wrapper) {\n  wrapper.a = arity;\n  wrapper.f = fun;\n  return wrapper;\n}\n\nfunction F2(fun) {\n  return F(2, fun, function(a) { return function(b) { return fun(a,b); }; })\n}\nfunction F3(fun) {\n  return F(3, fun, function(a) {\n    return function(b) { return function(c) { return fun(a, b, c); }; };\n  });\n}\nfunction F4(fun) {\n  return F(4, fun, function(a) { return function(b) { return function(c) {\n    return function(d) { return fun(a, b, c, d); }; }; };\n  });\n}\nfunction F5(fun) {\n  return F(5, fun, function(a) { return function(b) { return function(c) {\n    return function(d) { return function(e) { return fun(a, b, c, d, e); }; }; }; };\n  });\n}\nfunction F6(fun) {\n  return F(6, fun, function(a) { return function(b) { return function(c) {\n    return function(d) { return function(e) { return function(f) {\n    return fun(a, b, c, d, e, f); }; }; }; }; };\n  });\n}\nfunction F7(fun) {\n  return F(7, fun, function(a) { return function(b) { return function(c) {\n    return function(d) { return function(e) { return function(f) {\n    return function(g) { return fun(a, b, c, d, e, f, g); }; }; }; }; }; };\n  });\n}\nfunction F8(fun) {\n  return F(8, fun, function(a) { return function(b) { return function(c) {\n    return function(d) { return function(e) { return function(f) {\n    return function(g) { return function(h) {\n    return fun(a, b, c, d, e, f, g, h); }; }; }; }; }; }; };\n  });\n}\nfunction F9(fun) {\n  return F(9, fun, function(a) { return function(b) { return function(c) {\n    return function(d) { return function(e) { return function(f) {\n    return function(g) { return function(h) { return function(i) {\n    return fun(a, b, c, d, e, f, g, h, i); }; }; }; }; }; }; }; };\n  });\n}\n\nfunction A2(fun, a, b) {\n  return fun.a === 2 ? fun.f(a, b) : fun(a)(b);\n}\nfunction A3(fun, a, b, c) {\n  return fun.a === 3 ? fun.f(a, b, c) : fun(a)(b)(c);\n}\nfunction A4(fun, a, b, c, d) {\n  return fun.a === 4 ? fun.f(a, b, c, d) : fun(a)(b)(c)(d);\n}\nfunction A5(fun, a, b, c, d, e) {\n  return fun.a === 5 ? fun.f(a, b, c, d, e) : fun(a)(b)(c)(d)(e);\n}\nfunction A6(fun, a, b, c, d, e, f) {\n  return fun.a === 6 ? fun.f(a, b, c, d, e, f) : fun(a)(b)(c)(d)(e)(f);\n}\nfunction A7(fun, a, b, c, d, e, f, g) {\n  return fun.a === 7 ? fun.f(a, b, c, d, e, f, g) : fun(a)(b)(c)(d)(e)(f)(g);\n}\nfunction A8(fun, a, b, c, d, e, f, g, h) {\n  return fun.a === 8 ? fun.f(a, b, c, d, e, f, g, h) : fun(a)(b)(c)(d)(e)(f)(g)(h);\n}\nfunction A9(fun, a, b, c, d, e, f, g, h, i) {\n  return fun.a === 9 ? fun.f(a, b, c, d, e, f, g, h, i) : fun(a)(b)(c)(d)(e)(f)(g)(h)(i);\n}\n\n\n\n\n// EQUALITY\n\nfunction _Utils_eq(x, y)\n{\n\tfor (\n\t\tvar pair, stack = [], isEqual = _Utils_eqHelp(x, y, 0, stack);\n\t\tisEqual && (pair = stack.pop());\n\t\tisEqual = _Utils_eqHelp(pair.a, pair.b, 0, stack)\n\t\t)\n\t{}\n\n\treturn isEqual;\n}\n\nfunction _Utils_eqHelp(x, y, depth, stack)\n{\n\tif (x === y)\n\t{\n\t\treturn true;\n\t}\n\n\tif (typeof x !== 'object' || x === null || y === null)\n\t{\n\t\ttypeof x === 'function' && _Debug_crash(5);\n\t\treturn false;\n\t}\n\n\tif (depth > 100)\n\t{\n\t\tstack.push(_Utils_Tuple2(x,y));\n\t\treturn true;\n\t}\n\n\t/**_UNUSED/\n\tif (x.$ === 'Set_elm_builtin')\n\t{\n\t\tx = $elm$core$Set$toList(x);\n\t\ty = $elm$core$Set$toList(y);\n\t}\n\tif (x.$ === 'RBNode_elm_builtin' || x.$ === 'RBEmpty_elm_builtin')\n\t{\n\t\tx = $elm$core$Dict$toList(x);\n\t\ty = $elm$core$Dict$toList(y);\n\t}\n\t//*/\n\n\t/**/\n\tif (x.$ < 0)\n\t{\n\t\tx = $elm$core$Dict$toList(x);\n\t\ty = $elm$core$Dict$toList(y);\n\t}\n\t//*/\n\n\tfor (var key in x)\n\t{\n\t\tif (!_Utils_eqHelp(x[key], y[key], depth + 1, stack))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nvar _Utils_equal = F2(_Utils_eq);\nvar _Utils_notEqual = F2(function(a, b) { return !_Utils_eq(a,b); });\n\n\n\n// COMPARISONS\n\n// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on\n// the particular integer values assigned to LT, EQ, and GT.\n\nfunction _Utils_cmp(x, y, ord)\n{\n\tif (typeof x !== 'object')\n\t{\n\t\treturn x === y ? /*EQ*/ 0 : x < y ? /*LT*/ -1 : /*GT*/ 1;\n\t}\n\n\t/**_UNUSED/\n\tif (x instanceof String)\n\t{\n\t\tvar a = x.valueOf();\n\t\tvar b = y.valueOf();\n\t\treturn a === b ? 0 : a < b ? -1 : 1;\n\t}\n\t//*/\n\n\t/**/\n\tif (typeof x.$ === 'undefined')\n\t//*/\n\t/**_UNUSED/\n\tif (x.$[0] === '#')\n\t//*/\n\t{\n\t\treturn (ord = _Utils_cmp(x.a, y.a))\n\t\t\t? ord\n\t\t\t: (ord = _Utils_cmp(x.b, y.b))\n\t\t\t\t? ord\n\t\t\t\t: _Utils_cmp(x.c, y.c);\n\t}\n\n\t// traverse conses until end of a list or a mismatch\n\tfor (; x.b && y.b && !(ord = _Utils_cmp(x.a, y.a)); x = x.b, y = y.b) {} // WHILE_CONSES\n\treturn ord || (x.b ? /*GT*/ 1 : y.b ? /*LT*/ -1 : /*EQ*/ 0);\n}\n\nvar _Utils_lt = F2(function(a, b) { return _Utils_cmp(a, b) < 0; });\nvar _Utils_le = F2(function(a, b) { return _Utils_cmp(a, b) < 1; });\nvar _Utils_gt = F2(function(a, b) { return _Utils_cmp(a, b) > 0; });\nvar _Utils_ge = F2(function(a, b) { return _Utils_cmp(a, b) >= 0; });\n\nvar _Utils_compare = F2(function(x, y)\n{\n\tvar n = _Utils_cmp(x, y);\n\treturn n < 0 ? $elm$core$Basics$LT : n ? $elm$core$Basics$GT : $elm$core$Basics$EQ;\n});\n\n\n// COMMON VALUES\n\nvar _Utils_Tuple0 = 0;\nvar _Utils_Tuple0_UNUSED = { $: '#0' };\n\nfunction _Utils_Tuple2(a, b) { return { a: a, b: b }; }\nfunction _Utils_Tuple2_UNUSED(a, b) { return { $: '#2', a: a, b: b }; }\n\nfunction _Utils_Tuple3(a, b, c) { return { a: a, b: b, c: c }; }\nfunction _Utils_Tuple3_UNUSED(a, b, c) { return { $: '#3', a: a, b: b, c: c }; }\n\nfunction _Utils_chr(c) { return c; }\nfunction _Utils_chr_UNUSED(c) { return new String(c); }\n\n\n// RECORDS\n\nfunction _Utils_update(oldRecord, updatedFields)\n{\n\tvar newRecord = {};\n\n\tfor (var key in oldRecord)\n\t{\n\t\tnewRecord[key] = oldRecord[key];\n\t}\n\n\tfor (var key in updatedFields)\n\t{\n\t\tnewRecord[key] = updatedFields[key];\n\t}\n\n\treturn newRecord;\n}\n\n\n// APPEND\n\nvar _Utils_append = F2(_Utils_ap);\n\nfunction _Utils_ap(xs, ys)\n{\n\t// append Strings\n\tif (typeof xs === 'string')\n\t{\n\t\treturn xs + ys;\n\t}\n\n\t// append Lists\n\tif (!xs.b)\n\t{\n\t\treturn ys;\n\t}\n\tvar root = _List_Cons(xs.a, ys);\n\txs = xs.b\n\tfor (var curr = root; xs.b; xs = xs.b) // WHILE_CONS\n\t{\n\t\tcurr = curr.b = _List_Cons(xs.a, ys);\n\t}\n\treturn root;\n}\n\n\n\nvar _List_Nil = { $: 0 };\nvar _List_Nil_UNUSED = { $: '[]' };\n\nfunction _List_Cons(hd, tl) { return { $: 1, a: hd, b: tl }; }\nfunction _List_Cons_UNUSED(hd, tl) { return { $: '::', a: hd, b: tl }; }\n\n\nvar _List_cons = F2(_List_Cons);\n\nfunction _List_fromArray(arr)\n{\n\tvar out = _List_Nil;\n\tfor (var i = arr.length; i--; )\n\t{\n\t\tout = _List_Cons(arr[i], out);\n\t}\n\treturn out;\n}\n\nfunction _List_toArray(xs)\n{\n\tfor (var out = []; xs.b; xs = xs.b) // WHILE_CONS\n\t{\n\t\tout.push(xs.a);\n\t}\n\treturn out;\n}\n\nvar _List_map2 = F3(function(f, xs, ys)\n{\n\tfor (var arr = []; xs.b && ys.b; xs = xs.b, ys = ys.b) // WHILE_CONSES\n\t{\n\t\tarr.push(A2(f, xs.a, ys.a));\n\t}\n\treturn _List_fromArray(arr);\n});\n\nvar _List_map3 = F4(function(f, xs, ys, zs)\n{\n\tfor (var arr = []; xs.b && ys.b && zs.b; xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES\n\t{\n\t\tarr.push(A3(f, xs.a, ys.a, zs.a));\n\t}\n\treturn _List_fromArray(arr);\n});\n\nvar _List_map4 = F5(function(f, ws, xs, ys, zs)\n{\n\tfor (var arr = []; ws.b && xs.b && ys.b && zs.b; ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES\n\t{\n\t\tarr.push(A4(f, ws.a, xs.a, ys.a, zs.a));\n\t}\n\treturn _List_fromArray(arr);\n});\n\nvar _List_map5 = F6(function(f, vs, ws, xs, ys, zs)\n{\n\tfor (var arr = []; vs.b && ws.b && xs.b && ys.b && zs.b; vs = vs.b, ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES\n\t{\n\t\tarr.push(A5(f, vs.a, ws.a, xs.a, ys.a, zs.a));\n\t}\n\treturn _List_fromArray(arr);\n});\n\nvar _List_sortBy = F2(function(f, xs)\n{\n\treturn _List_fromArray(_List_toArray(xs).sort(function(a, b) {\n\t\treturn _Utils_cmp(f(a), f(b));\n\t}));\n});\n\nvar _List_sortWith = F2(function(f, xs)\n{\n\treturn _List_fromArray(_List_toArray(xs).sort(function(a, b) {\n\t\tvar ord = A2(f, a, b);\n\t\treturn ord === $elm$core$Basics$EQ ? 0 : ord === $elm$core$Basics$LT ? -1 : 1;\n\t}));\n});\n\n\n\nvar _JsArray_empty = [];\n\nfunction _JsArray_singleton(value)\n{\n    return [value];\n}\n\nfunction _JsArray_length(array)\n{\n    return array.length;\n}\n\nvar _JsArray_initialize = F3(function(size, offset, func)\n{\n    var result = new Array(size);\n\n    for (var i = 0; i < size; i++)\n    {\n        result[i] = func(offset + i);\n    }\n\n    return result;\n});\n\nvar _JsArray_initializeFromList = F2(function (max, ls)\n{\n    var result = new Array(max);\n\n    for (var i = 0; i < max && ls.b; i++)\n    {\n        result[i] = ls.a;\n        ls = ls.b;\n    }\n\n    result.length = i;\n    return _Utils_Tuple2(result, ls);\n});\n\nvar _JsArray_unsafeGet = F2(function(index, array)\n{\n    return array[index];\n});\n\nvar _JsArray_unsafeSet = F3(function(index, value, array)\n{\n    var length = array.length;\n    var result = new Array(length);\n\n    for (var i = 0; i < length; i++)\n    {\n        result[i] = array[i];\n    }\n\n    result[index] = value;\n    return result;\n});\n\nvar _JsArray_push = F2(function(value, array)\n{\n    var length = array.length;\n    var result = new Array(length + 1);\n\n    for (var i = 0; i < length; i++)\n    {\n        result[i] = array[i];\n    }\n\n    result[length] = value;\n    return result;\n});\n\nvar _JsArray_foldl = F3(function(func, acc, array)\n{\n    var length = array.length;\n\n    for (var i = 0; i < length; i++)\n    {\n        acc = A2(func, array[i], acc);\n    }\n\n    return acc;\n});\n\nvar _JsArray_foldr = F3(function(func, acc, array)\n{\n    for (var i = array.length - 1; i >= 0; i--)\n    {\n        acc = A2(func, array[i], acc);\n    }\n\n    return acc;\n});\n\nvar _JsArray_map = F2(function(func, array)\n{\n    var length = array.length;\n    var result = new Array(length);\n\n    for (var i = 0; i < length; i++)\n    {\n        result[i] = func(array[i]);\n    }\n\n    return result;\n});\n\nvar _JsArray_indexedMap = F3(function(func, offset, array)\n{\n    var length = array.length;\n    var result = new Array(length);\n\n    for (var i = 0; i < length; i++)\n    {\n        result[i] = A2(func, offset + i, array[i]);\n    }\n\n    return result;\n});\n\nvar _JsArray_slice = F3(function(from, to, array)\n{\n    return array.slice(from, to);\n});\n\nvar _JsArray_appendN = F3(function(n, dest, source)\n{\n    var destLen = dest.length;\n    var itemsToCopy = n - destLen;\n\n    if (itemsToCopy > source.length)\n    {\n        itemsToCopy = source.length;\n    }\n\n    var size = destLen + itemsToCopy;\n    var result = new Array(size);\n\n    for (var i = 0; i < destLen; i++)\n    {\n        result[i] = dest[i];\n    }\n\n    for (var i = 0; i < itemsToCopy; i++)\n    {\n        result[i + destLen] = source[i];\n    }\n\n    return result;\n});\n\n\n\n// LOG\n\nvar _Debug_log = F2(function(tag, value)\n{\n\treturn value;\n});\n\nvar _Debug_log_UNUSED = F2(function(tag, value)\n{\n\tconsole.log(tag + ': ' + _Debug_toString(value));\n\treturn value;\n});\n\n\n// TODOS\n\nfunction _Debug_todo(moduleName, region)\n{\n\treturn function(message) {\n\t\t_Debug_crash(8, moduleName, region, message);\n\t};\n}\n\nfunction _Debug_todoCase(moduleName, region, value)\n{\n\treturn function(message) {\n\t\t_Debug_crash(9, moduleName, region, value, message);\n\t};\n}\n\n\n// TO STRING\n\nfunction _Debug_toString(value)\n{\n\treturn '<internals>';\n}\n\nfunction _Debug_toString_UNUSED(value)\n{\n\treturn _Debug_toAnsiString(false, value);\n}\n\nfunction _Debug_toAnsiString(ansi, value)\n{\n\tif (typeof value === 'function')\n\t{\n\t\treturn _Debug_internalColor(ansi, '<function>');\n\t}\n\n\tif (typeof value === 'boolean')\n\t{\n\t\treturn _Debug_ctorColor(ansi, value ? 'True' : 'False');\n\t}\n\n\tif (typeof value === 'number')\n\t{\n\t\treturn _Debug_numberColor(ansi, value + '');\n\t}\n\n\tif (value instanceof String)\n\t{\n\t\treturn _Debug_charColor(ansi, \"'\" + _Debug_addSlashes(value, true) + \"'\");\n\t}\n\n\tif (typeof value === 'string')\n\t{\n\t\treturn _Debug_stringColor(ansi, '\"' + _Debug_addSlashes(value, false) + '\"');\n\t}\n\n\tif (typeof value === 'object' && '$' in value)\n\t{\n\t\tvar tag = value.$;\n\n\t\tif (typeof tag === 'number')\n\t\t{\n\t\t\treturn _Debug_internalColor(ansi, '<internals>');\n\t\t}\n\n\t\tif (tag[0] === '#')\n\t\t{\n\t\t\tvar output = [];\n\t\t\tfor (var k in value)\n\t\t\t{\n\t\t\t\tif (k === '$') continue;\n\t\t\t\toutput.push(_Debug_toAnsiString(ansi, value[k]));\n\t\t\t}\n\t\t\treturn '(' + output.join(',') + ')';\n\t\t}\n\n\t\tif (tag === 'Set_elm_builtin')\n\t\t{\n\t\t\treturn _Debug_ctorColor(ansi, 'Set')\n\t\t\t\t+ _Debug_fadeColor(ansi, '.fromList') + ' '\n\t\t\t\t+ _Debug_toAnsiString(ansi, $elm$core$Set$toList(value));\n\t\t}\n\n\t\tif (tag === 'RBNode_elm_builtin' || tag === 'RBEmpty_elm_builtin')\n\t\t{\n\t\t\treturn _Debug_ctorColor(ansi, 'Dict')\n\t\t\t\t+ _Debug_fadeColor(ansi, '.fromList') + ' '\n\t\t\t\t+ _Debug_toAnsiString(ansi, $elm$core$Dict$toList(value));\n\t\t}\n\n\t\tif (tag === 'Array_elm_builtin')\n\t\t{\n\t\t\treturn _Debug_ctorColor(ansi, 'Array')\n\t\t\t\t+ _Debug_fadeColor(ansi, '.fromList') + ' '\n\t\t\t\t+ _Debug_toAnsiString(ansi, $elm$core$Array$toList(value));\n\t\t}\n\n\t\tif (tag === '::' || tag === '[]')\n\t\t{\n\t\t\tvar output = '[';\n\n\t\t\tvalue.b && (output += _Debug_toAnsiString(ansi, value.a), value = value.b)\n\n\t\t\tfor (; value.b; value = value.b) // WHILE_CONS\n\t\t\t{\n\t\t\t\toutput += ',' + _Debug_toAnsiString(ansi, value.a);\n\t\t\t}\n\t\t\treturn output + ']';\n\t\t}\n\n\t\tvar output = '';\n\t\tfor (var i in value)\n\t\t{\n\t\t\tif (i === '$') continue;\n\t\t\tvar str = _Debug_toAnsiString(ansi, value[i]);\n\t\t\tvar c0 = str[0];\n\t\t\tvar parenless = c0 === '{' || c0 === '(' || c0 === '[' || c0 === '<' || c0 === '\"' || str.indexOf(' ') < 0;\n\t\t\toutput += ' ' + (parenless ? str : '(' + str + ')');\n\t\t}\n\t\treturn _Debug_ctorColor(ansi, tag) + output;\n\t}\n\n\tif (typeof DataView === 'function' && value instanceof DataView)\n\t{\n\t\treturn _Debug_stringColor(ansi, '<' + value.byteLength + ' bytes>');\n\t}\n\n\tif (typeof File !== 'undefined' && value instanceof File)\n\t{\n\t\treturn _Debug_internalColor(ansi, '<' + value.name + '>');\n\t}\n\n\tif (typeof value === 'object')\n\t{\n\t\tvar output = [];\n\t\tfor (var key in value)\n\t\t{\n\t\t\tvar field = key[0] === '_' ? key.slice(1) : key;\n\t\t\toutput.push(_Debug_fadeColor(ansi, field) + ' = ' + _Debug_toAnsiString(ansi, value[key]));\n\t\t}\n\t\tif (output.length === 0)\n\t\t{\n\t\t\treturn '{}';\n\t\t}\n\t\treturn '{ ' + output.join(', ') + ' }';\n\t}\n\n\treturn _Debug_internalColor(ansi, '<internals>');\n}\n\nfunction _Debug_addSlashes(str, isChar)\n{\n\tvar s = str\n\t\t.replace(/\\\\/g, '\\\\\\\\')\n\t\t.replace(/\\n/g, '\\\\n')\n\t\t.replace(/\\t/g, '\\\\t')\n\t\t.replace(/\\r/g, '\\\\r')\n\t\t.replace(/\\v/g, '\\\\v')\n\t\t.replace(/\\0/g, '\\\\0');\n\n\tif (isChar)\n\t{\n\t\treturn s.replace(/\\'/g, '\\\\\\'');\n\t}\n\telse\n\t{\n\t\treturn s.replace(/\\\"/g, '\\\\\"');\n\t}\n}\n\nfunction _Debug_ctorColor(ansi, string)\n{\n\treturn ansi ? '\\x1b[96m' + string + '\\x1b[0m' : string;\n}\n\nfunction _Debug_numberColor(ansi, string)\n{\n\treturn ansi ? '\\x1b[95m' + string + '\\x1b[0m' : string;\n}\n\nfunction _Debug_stringColor(ansi, string)\n{\n\treturn ansi ? '\\x1b[93m' + string + '\\x1b[0m' : string;\n}\n\nfunction _Debug_charColor(ansi, string)\n{\n\treturn ansi ? '\\x1b[92m' + string + '\\x1b[0m' : string;\n}\n\nfunction _Debug_fadeColor(ansi, string)\n{\n\treturn ansi ? '\\x1b[37m' + string + '\\x1b[0m' : string;\n}\n\nfunction _Debug_internalColor(ansi, string)\n{\n\treturn ansi ? '\\x1b[36m' + string + '\\x1b[0m' : string;\n}\n\nfunction _Debug_toHexDigit(n)\n{\n\treturn String.fromCharCode(n < 10 ? 48 + n : 55 + n);\n}\n\n\n// CRASH\n\n\nfunction _Debug_crash(identifier)\n{\n\tthrow new Error('https://github.com/elm/core/blob/1.0.0/hints/' + identifier + '.md');\n}\n\n\nfunction _Debug_crash_UNUSED(identifier, fact1, fact2, fact3, fact4)\n{\n\tswitch(identifier)\n\t{\n\t\tcase 0:\n\t\t\tthrow new Error('What node should I take over? In JavaScript I need something like:\\n\\n    Elm.Main.init({\\n        node: document.getElementById(\"elm-node\")\\n    })\\n\\nYou need to do this with any Browser.sandbox or Browser.element program.');\n\n\t\tcase 1:\n\t\t\tthrow new Error('Browser.application programs cannot handle URLs like this:\\n\\n    ' + document.location.href + '\\n\\nWhat is the root? The root of your file system? Try looking at this program with `elm reactor` or some other server.');\n\n\t\tcase 2:\n\t\t\tvar jsonErrorString = fact1;\n\t\t\tthrow new Error('Problem with the flags given to your Elm program on initialization.\\n\\n' + jsonErrorString);\n\n\t\tcase 3:\n\t\t\tvar portName = fact1;\n\t\t\tthrow new Error('There can only be one port named `' + portName + '`, but your program has multiple.');\n\n\t\tcase 4:\n\t\t\tvar portName = fact1;\n\t\t\tvar problem = fact2;\n\t\t\tthrow new Error('Trying to send an unexpected type of value through port `' + portName + '`:\\n' + problem);\n\n\t\tcase 5:\n\t\t\tthrow new Error('Trying to use `(==)` on functions.\\nThere is no way to know if functions are \"the same\" in the Elm sense.\\nRead more about this at https://package.elm-lang.org/packages/elm/core/latest/Basics#== which describes why it is this way and what the better version will look like.');\n\n\t\tcase 6:\n\t\t\tvar moduleName = fact1;\n\t\t\tthrow new Error('Your page is loading multiple Elm scripts with a module named ' + moduleName + '. Maybe a duplicate script is getting loaded accidentally? If not, rename one of them so I know which is which!');\n\n\t\tcase 8:\n\t\t\tvar moduleName = fact1;\n\t\t\tvar region = fact2;\n\t\t\tvar message = fact3;\n\t\t\tthrow new Error('TODO in module `' + moduleName + '` ' + _Debug_regionToString(region) + '\\n\\n' + message);\n\n\t\tcase 9:\n\t\t\tvar moduleName = fact1;\n\t\t\tvar region = fact2;\n\t\t\tvar value = fact3;\n\t\t\tvar message = fact4;\n\t\t\tthrow new Error(\n\t\t\t\t'TODO in module `' + moduleName + '` from the `case` expression '\n\t\t\t\t+ _Debug_regionToString(region) + '\\n\\nIt received the following value:\\n\\n    '\n\t\t\t\t+ _Debug_toString(value).replace('\\n', '\\n    ')\n\t\t\t\t+ '\\n\\nBut the branch that handles it says:\\n\\n    ' + message.replace('\\n', '\\n    ')\n\t\t\t);\n\n\t\tcase 10:\n\t\t\tthrow new Error('Bug in https://github.com/elm/virtual-dom/issues');\n\n\t\tcase 11:\n\t\t\tthrow new Error('Cannot perform mod 0. Division by zero error.');\n\t}\n}\n\nfunction _Debug_regionToString(region)\n{\n\tif (region.Q.H === region.V.H)\n\t{\n\t\treturn 'on line ' + region.Q.H;\n\t}\n\treturn 'on lines ' + region.Q.H + ' through ' + region.V.H;\n}\n\n\n\n// MATH\n\nvar _Basics_add = F2(function(a, b) { return a + b; });\nvar _Basics_sub = F2(function(a, b) { return a - b; });\nvar _Basics_mul = F2(function(a, b) { return a * b; });\nvar _Basics_fdiv = F2(function(a, b) { return a / b; });\nvar _Basics_idiv = F2(function(a, b) { return (a / b) | 0; });\nvar _Basics_pow = F2(Math.pow);\n\nvar _Basics_remainderBy = F2(function(b, a) { return a % b; });\n\n// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf\nvar _Basics_modBy = F2(function(modulus, x)\n{\n\tvar answer = x % modulus;\n\treturn modulus === 0\n\t\t? _Debug_crash(11)\n\t\t:\n\t((answer > 0 && modulus < 0) || (answer < 0 && modulus > 0))\n\t\t? answer + modulus\n\t\t: answer;\n});\n\n\n// TRIGONOMETRY\n\nvar _Basics_pi = Math.PI;\nvar _Basics_e = Math.E;\nvar _Basics_cos = Math.cos;\nvar _Basics_sin = Math.sin;\nvar _Basics_tan = Math.tan;\nvar _Basics_acos = Math.acos;\nvar _Basics_asin = Math.asin;\nvar _Basics_atan = Math.atan;\nvar _Basics_atan2 = F2(Math.atan2);\n\n\n// MORE MATH\n\nfunction _Basics_toFloat(x) { return x; }\nfunction _Basics_truncate(n) { return n | 0; }\nfunction _Basics_isInfinite(n) { return n === Infinity || n === -Infinity; }\n\nvar _Basics_ceiling = Math.ceil;\nvar _Basics_floor = Math.floor;\nvar _Basics_round = Math.round;\nvar _Basics_sqrt = Math.sqrt;\nvar _Basics_log = Math.log;\nvar _Basics_isNaN = isNaN;\n\n\n// BOOLEANS\n\nfunction _Basics_not(bool) { return !bool; }\nvar _Basics_and = F2(function(a, b) { return a && b; });\nvar _Basics_or  = F2(function(a, b) { return a || b; });\nvar _Basics_xor = F2(function(a, b) { return a !== b; });\n\n\n\nvar _String_cons = F2(function(chr, str)\n{\n\treturn chr + str;\n});\n\nfunction _String_uncons(string)\n{\n\tvar word = string.charCodeAt(0);\n\treturn !isNaN(word)\n\t\t? $elm$core$Maybe$Just(\n\t\t\t0xD800 <= word && word <= 0xDBFF\n\t\t\t\t? _Utils_Tuple2(_Utils_chr(string[0] + string[1]), string.slice(2))\n\t\t\t\t: _Utils_Tuple2(_Utils_chr(string[0]), string.slice(1))\n\t\t)\n\t\t: $elm$core$Maybe$Nothing;\n}\n\nvar _String_append = F2(function(a, b)\n{\n\treturn a + b;\n});\n\nfunction _String_length(str)\n{\n\treturn str.length;\n}\n\nvar _String_map = F2(function(func, string)\n{\n\tvar len = string.length;\n\tvar array = new Array(len);\n\tvar i = 0;\n\twhile (i < len)\n\t{\n\t\tvar word = string.charCodeAt(i);\n\t\tif (0xD800 <= word && word <= 0xDBFF)\n\t\t{\n\t\t\tarray[i] = func(_Utils_chr(string[i] + string[i+1]));\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tarray[i] = func(_Utils_chr(string[i]));\n\t\ti++;\n\t}\n\treturn array.join('');\n});\n\nvar _String_filter = F2(function(isGood, str)\n{\n\tvar arr = [];\n\tvar len = str.length;\n\tvar i = 0;\n\twhile (i < len)\n\t{\n\t\tvar char = str[i];\n\t\tvar word = str.charCodeAt(i);\n\t\ti++;\n\t\tif (0xD800 <= word && word <= 0xDBFF)\n\t\t{\n\t\t\tchar += str[i];\n\t\t\ti++;\n\t\t}\n\n\t\tif (isGood(_Utils_chr(char)))\n\t\t{\n\t\t\tarr.push(char);\n\t\t}\n\t}\n\treturn arr.join('');\n});\n\nfunction _String_reverse(str)\n{\n\tvar len = str.length;\n\tvar arr = new Array(len);\n\tvar i = 0;\n\twhile (i < len)\n\t{\n\t\tvar word = str.charCodeAt(i);\n\t\tif (0xD800 <= word && word <= 0xDBFF)\n\t\t{\n\t\t\tarr[len - i] = str[i + 1];\n\t\t\ti++;\n\t\t\tarr[len - i] = str[i - 1];\n\t\t\ti++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tarr[len - i] = str[i];\n\t\t\ti++;\n\t\t}\n\t}\n\treturn arr.join('');\n}\n\nvar _String_foldl = F3(function(func, state, string)\n{\n\tvar len = string.length;\n\tvar i = 0;\n\twhile (i < len)\n\t{\n\t\tvar char = string[i];\n\t\tvar word = string.charCodeAt(i);\n\t\ti++;\n\t\tif (0xD800 <= word && word <= 0xDBFF)\n\t\t{\n\t\t\tchar += string[i];\n\t\t\ti++;\n\t\t}\n\t\tstate = A2(func, _Utils_chr(char), state);\n\t}\n\treturn state;\n});\n\nvar _String_foldr = F3(function(func, state, string)\n{\n\tvar i = string.length;\n\twhile (i--)\n\t{\n\t\tvar char = string[i];\n\t\tvar word = string.charCodeAt(i);\n\t\tif (0xDC00 <= word && word <= 0xDFFF)\n\t\t{\n\t\t\ti--;\n\t\t\tchar = string[i] + char;\n\t\t}\n\t\tstate = A2(func, _Utils_chr(char), state);\n\t}\n\treturn state;\n});\n\nvar _String_split = F2(function(sep, str)\n{\n\treturn str.split(sep);\n});\n\nvar _String_join = F2(function(sep, strs)\n{\n\treturn strs.join(sep);\n});\n\nvar _String_slice = F3(function(start, end, str) {\n\treturn str.slice(start, end);\n});\n\nfunction _String_trim(str)\n{\n\treturn str.trim();\n}\n\nfunction _String_trimLeft(str)\n{\n\treturn str.replace(/^\\s+/, '');\n}\n\nfunction _String_trimRight(str)\n{\n\treturn str.replace(/\\s+$/, '');\n}\n\nfunction _String_words(str)\n{\n\treturn _List_fromArray(str.trim().split(/\\s+/g));\n}\n\nfunction _String_lines(str)\n{\n\treturn _List_fromArray(str.split(/\\r\\n|\\r|\\n/g));\n}\n\nfunction _String_toUpper(str)\n{\n\treturn str.toUpperCase();\n}\n\nfunction _String_toLower(str)\n{\n\treturn str.toLowerCase();\n}\n\nvar _String_any = F2(function(isGood, string)\n{\n\tvar i = string.length;\n\twhile (i--)\n\t{\n\t\tvar char = string[i];\n\t\tvar word = string.charCodeAt(i);\n\t\tif (0xDC00 <= word && word <= 0xDFFF)\n\t\t{\n\t\t\ti--;\n\t\t\tchar = string[i] + char;\n\t\t}\n\t\tif (isGood(_Utils_chr(char)))\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n});\n\nvar _String_all = F2(function(isGood, string)\n{\n\tvar i = string.length;\n\twhile (i--)\n\t{\n\t\tvar char = string[i];\n\t\tvar word = string.charCodeAt(i);\n\t\tif (0xDC00 <= word && word <= 0xDFFF)\n\t\t{\n\t\t\ti--;\n\t\t\tchar = string[i] + char;\n\t\t}\n\t\tif (!isGood(_Utils_chr(char)))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n});\n\nvar _String_contains = F2(function(sub, str)\n{\n\treturn str.indexOf(sub) > -1;\n});\n\nvar _String_startsWith = F2(function(sub, str)\n{\n\treturn str.indexOf(sub) === 0;\n});\n\nvar _String_endsWith = F2(function(sub, str)\n{\n\treturn str.length >= sub.length &&\n\t\tstr.lastIndexOf(sub) === str.length - sub.length;\n});\n\nvar _String_indexes = F2(function(sub, str)\n{\n\tvar subLen = sub.length;\n\n\tif (subLen < 1)\n\t{\n\t\treturn _List_Nil;\n\t}\n\n\tvar i = 0;\n\tvar is = [];\n\n\twhile ((i = str.indexOf(sub, i)) > -1)\n\t{\n\t\tis.push(i);\n\t\ti = i + subLen;\n\t}\n\n\treturn _List_fromArray(is);\n});\n\n\n// TO STRING\n\nfunction _String_fromNumber(number)\n{\n\treturn number + '';\n}\n\n\n// INT CONVERSIONS\n\nfunction _String_toInt(str)\n{\n\tvar total = 0;\n\tvar code0 = str.charCodeAt(0);\n\tvar start = code0 == 0x2B /* + */ || code0 == 0x2D /* - */ ? 1 : 0;\n\n\tfor (var i = start; i < str.length; ++i)\n\t{\n\t\tvar code = str.charCodeAt(i);\n\t\tif (code < 0x30 || 0x39 < code)\n\t\t{\n\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t}\n\t\ttotal = 10 * total + code - 0x30;\n\t}\n\n\treturn i == start\n\t\t? $elm$core$Maybe$Nothing\n\t\t: $elm$core$Maybe$Just(code0 == 0x2D ? -total : total);\n}\n\n\n// FLOAT CONVERSIONS\n\nfunction _String_toFloat(s)\n{\n\t// check if it is a hex, octal, or binary number\n\tif (s.length === 0 || /[\\sxbo]/.test(s))\n\t{\n\t\treturn $elm$core$Maybe$Nothing;\n\t}\n\tvar n = +s;\n\t// faster isNaN check\n\treturn n === n ? $elm$core$Maybe$Just(n) : $elm$core$Maybe$Nothing;\n}\n\nfunction _String_fromList(chars)\n{\n\treturn _List_toArray(chars).join('');\n}\n\n\n\n\nfunction _Char_toCode(char)\n{\n\tvar code = char.charCodeAt(0);\n\tif (0xD800 <= code && code <= 0xDBFF)\n\t{\n\t\treturn (code - 0xD800) * 0x400 + char.charCodeAt(1) - 0xDC00 + 0x10000\n\t}\n\treturn code;\n}\n\nfunction _Char_fromCode(code)\n{\n\treturn _Utils_chr(\n\t\t(code < 0 || 0x10FFFF < code)\n\t\t\t? '\\uFFFD'\n\t\t\t:\n\t\t(code <= 0xFFFF)\n\t\t\t? String.fromCharCode(code)\n\t\t\t:\n\t\t(code -= 0x10000,\n\t\t\tString.fromCharCode(Math.floor(code / 0x400) + 0xD800, code % 0x400 + 0xDC00)\n\t\t)\n\t);\n}\n\nfunction _Char_toUpper(char)\n{\n\treturn _Utils_chr(char.toUpperCase());\n}\n\nfunction _Char_toLower(char)\n{\n\treturn _Utils_chr(char.toLowerCase());\n}\n\nfunction _Char_toLocaleUpper(char)\n{\n\treturn _Utils_chr(char.toLocaleUpperCase());\n}\n\nfunction _Char_toLocaleLower(char)\n{\n\treturn _Utils_chr(char.toLocaleLowerCase());\n}\n\n\n\n/**_UNUSED/\nfunction _Json_errorToString(error)\n{\n\treturn $elm$json$Json$Decode$errorToString(error);\n}\n//*/\n\n\n// CORE DECODERS\n\nfunction _Json_succeed(msg)\n{\n\treturn {\n\t\t$: 0,\n\t\ta: msg\n\t};\n}\n\nfunction _Json_fail(msg)\n{\n\treturn {\n\t\t$: 1,\n\t\ta: msg\n\t};\n}\n\nfunction _Json_decodePrim(decoder)\n{\n\treturn { $: 2, b: decoder };\n}\n\nvar _Json_decodeInt = _Json_decodePrim(function(value) {\n\treturn (typeof value !== 'number')\n\t\t? _Json_expecting('an INT', value)\n\t\t:\n\t(-2147483647 < value && value < 2147483647 && (value | 0) === value)\n\t\t? $elm$core$Result$Ok(value)\n\t\t:\n\t(isFinite(value) && !(value % 1))\n\t\t? $elm$core$Result$Ok(value)\n\t\t: _Json_expecting('an INT', value);\n});\n\nvar _Json_decodeBool = _Json_decodePrim(function(value) {\n\treturn (typeof value === 'boolean')\n\t\t? $elm$core$Result$Ok(value)\n\t\t: _Json_expecting('a BOOL', value);\n});\n\nvar _Json_decodeFloat = _Json_decodePrim(function(value) {\n\treturn (typeof value === 'number')\n\t\t? $elm$core$Result$Ok(value)\n\t\t: _Json_expecting('a FLOAT', value);\n});\n\nvar _Json_decodeValue = _Json_decodePrim(function(value) {\n\treturn $elm$core$Result$Ok(_Json_wrap(value));\n});\n\nvar _Json_decodeString = _Json_decodePrim(function(value) {\n\treturn (typeof value === 'string')\n\t\t? $elm$core$Result$Ok(value)\n\t\t: (value instanceof String)\n\t\t\t? $elm$core$Result$Ok(value + '')\n\t\t\t: _Json_expecting('a STRING', value);\n});\n\nfunction _Json_decodeList(decoder) { return { $: 3, b: decoder }; }\nfunction _Json_decodeArray(decoder) { return { $: 4, b: decoder }; }\n\nfunction _Json_decodeNull(value) { return { $: 5, c: value }; }\n\nvar _Json_decodeField = F2(function(field, decoder)\n{\n\treturn {\n\t\t$: 6,\n\t\td: field,\n\t\tb: decoder\n\t};\n});\n\nvar _Json_decodeIndex = F2(function(index, decoder)\n{\n\treturn {\n\t\t$: 7,\n\t\te: index,\n\t\tb: decoder\n\t};\n});\n\nfunction _Json_decodeKeyValuePairs(decoder)\n{\n\treturn {\n\t\t$: 8,\n\t\tb: decoder\n\t};\n}\n\nfunction _Json_mapMany(f, decoders)\n{\n\treturn {\n\t\t$: 9,\n\t\tf: f,\n\t\tg: decoders\n\t};\n}\n\nvar _Json_andThen = F2(function(callback, decoder)\n{\n\treturn {\n\t\t$: 10,\n\t\tb: decoder,\n\t\th: callback\n\t};\n});\n\nfunction _Json_oneOf(decoders)\n{\n\treturn {\n\t\t$: 11,\n\t\tg: decoders\n\t};\n}\n\n\n// DECODING OBJECTS\n\nvar _Json_map1 = F2(function(f, d1)\n{\n\treturn _Json_mapMany(f, [d1]);\n});\n\nvar _Json_map2 = F3(function(f, d1, d2)\n{\n\treturn _Json_mapMany(f, [d1, d2]);\n});\n\nvar _Json_map3 = F4(function(f, d1, d2, d3)\n{\n\treturn _Json_mapMany(f, [d1, d2, d3]);\n});\n\nvar _Json_map4 = F5(function(f, d1, d2, d3, d4)\n{\n\treturn _Json_mapMany(f, [d1, d2, d3, d4]);\n});\n\nvar _Json_map5 = F6(function(f, d1, d2, d3, d4, d5)\n{\n\treturn _Json_mapMany(f, [d1, d2, d3, d4, d5]);\n});\n\nvar _Json_map6 = F7(function(f, d1, d2, d3, d4, d5, d6)\n{\n\treturn _Json_mapMany(f, [d1, d2, d3, d4, d5, d6]);\n});\n\nvar _Json_map7 = F8(function(f, d1, d2, d3, d4, d5, d6, d7)\n{\n\treturn _Json_mapMany(f, [d1, d2, d3, d4, d5, d6, d7]);\n});\n\nvar _Json_map8 = F9(function(f, d1, d2, d3, d4, d5, d6, d7, d8)\n{\n\treturn _Json_mapMany(f, [d1, d2, d3, d4, d5, d6, d7, d8]);\n});\n\n\n// DECODE\n\nvar _Json_runOnString = F2(function(decoder, string)\n{\n\ttry\n\t{\n\t\tvar value = JSON.parse(string);\n\t\treturn _Json_runHelp(decoder, value);\n\t}\n\tcatch (e)\n\t{\n\t\treturn $elm$core$Result$Err(A2($elm$json$Json$Decode$Failure, 'This is not valid JSON! ' + e.message, _Json_wrap(string)));\n\t}\n});\n\nvar _Json_run = F2(function(decoder, value)\n{\n\treturn _Json_runHelp(decoder, _Json_unwrap(value));\n});\n\nfunction _Json_runHelp(decoder, value)\n{\n\tswitch (decoder.$)\n\t{\n\t\tcase 2:\n\t\t\treturn decoder.b(value);\n\n\t\tcase 5:\n\t\t\treturn (value === null)\n\t\t\t\t? $elm$core$Result$Ok(decoder.c)\n\t\t\t\t: _Json_expecting('null', value);\n\n\t\tcase 3:\n\t\t\tif (!_Json_isArray(value))\n\t\t\t{\n\t\t\t\treturn _Json_expecting('a LIST', value);\n\t\t\t}\n\t\t\treturn _Json_runArrayDecoder(decoder.b, value, _List_fromArray);\n\n\t\tcase 4:\n\t\t\tif (!_Json_isArray(value))\n\t\t\t{\n\t\t\t\treturn _Json_expecting('an ARRAY', value);\n\t\t\t}\n\t\t\treturn _Json_runArrayDecoder(decoder.b, value, _Json_toElmArray);\n\n\t\tcase 6:\n\t\t\tvar field = decoder.d;\n\t\t\tif (typeof value !== 'object' || value === null || !(field in value))\n\t\t\t{\n\t\t\t\treturn _Json_expecting('an OBJECT with a field named `' + field + '`', value);\n\t\t\t}\n\t\t\tvar result = _Json_runHelp(decoder.b, value[field]);\n\t\t\treturn ($elm$core$Result$isOk(result)) ? result : $elm$core$Result$Err(A2($elm$json$Json$Decode$Field, field, result.a));\n\n\t\tcase 7:\n\t\t\tvar index = decoder.e;\n\t\t\tif (!_Json_isArray(value))\n\t\t\t{\n\t\t\t\treturn _Json_expecting('an ARRAY', value);\n\t\t\t}\n\t\t\tif (index >= value.length)\n\t\t\t{\n\t\t\t\treturn _Json_expecting('a LONGER array. Need index ' + index + ' but only see ' + value.length + ' entries', value);\n\t\t\t}\n\t\t\tvar result = _Json_runHelp(decoder.b, value[index]);\n\t\t\treturn ($elm$core$Result$isOk(result)) ? result : $elm$core$Result$Err(A2($elm$json$Json$Decode$Index, index, result.a));\n\n\t\tcase 8:\n\t\t\tif (typeof value !== 'object' || value === null || _Json_isArray(value))\n\t\t\t{\n\t\t\t\treturn _Json_expecting('an OBJECT', value);\n\t\t\t}\n\n\t\t\tvar keyValuePairs = _List_Nil;\n\t\t\t// TODO test perf of Object.keys and switch when support is good enough\n\t\t\tfor (var key in value)\n\t\t\t{\n\t\t\t\tif (value.hasOwnProperty(key))\n\t\t\t\t{\n\t\t\t\t\tvar result = _Json_runHelp(decoder.b, value[key]);\n\t\t\t\t\tif (!$elm$core$Result$isOk(result))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn $elm$core$Result$Err(A2($elm$json$Json$Decode$Field, key, result.a));\n\t\t\t\t\t}\n\t\t\t\t\tkeyValuePairs = _List_Cons(_Utils_Tuple2(key, result.a), keyValuePairs);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $elm$core$Result$Ok($elm$core$List$reverse(keyValuePairs));\n\n\t\tcase 9:\n\t\t\tvar answer = decoder.f;\n\t\t\tvar decoders = decoder.g;\n\t\t\tfor (var i = 0; i < decoders.length; i++)\n\t\t\t{\n\t\t\t\tvar result = _Json_runHelp(decoders[i], value);\n\t\t\t\tif (!$elm$core$Result$isOk(result))\n\t\t\t\t{\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\tanswer = answer(result.a);\n\t\t\t}\n\t\t\treturn $elm$core$Result$Ok(answer);\n\n\t\tcase 10:\n\t\t\tvar result = _Json_runHelp(decoder.b, value);\n\t\t\treturn (!$elm$core$Result$isOk(result))\n\t\t\t\t? result\n\t\t\t\t: _Json_runHelp(decoder.h(result.a), value);\n\n\t\tcase 11:\n\t\t\tvar errors = _List_Nil;\n\t\t\tfor (var temp = decoder.g; temp.b; temp = temp.b) // WHILE_CONS\n\t\t\t{\n\t\t\t\tvar result = _Json_runHelp(temp.a, value);\n\t\t\t\tif ($elm$core$Result$isOk(result))\n\t\t\t\t{\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\terrors = _List_Cons(result.a, errors);\n\t\t\t}\n\t\t\treturn $elm$core$Result$Err($elm$json$Json$Decode$OneOf($elm$core$List$reverse(errors)));\n\n\t\tcase 1:\n\t\t\treturn $elm$core$Result$Err(A2($elm$json$Json$Decode$Failure, decoder.a, _Json_wrap(value)));\n\n\t\tcase 0:\n\t\t\treturn $elm$core$Result$Ok(decoder.a);\n\t}\n}\n\nfunction _Json_runArrayDecoder(decoder, value, toElmValue)\n{\n\tvar len = value.length;\n\tvar array = new Array(len);\n\tfor (var i = 0; i < len; i++)\n\t{\n\t\tvar result = _Json_runHelp(decoder, value[i]);\n\t\tif (!$elm$core$Result$isOk(result))\n\t\t{\n\t\t\treturn $elm$core$Result$Err(A2($elm$json$Json$Decode$Index, i, result.a));\n\t\t}\n\t\tarray[i] = result.a;\n\t}\n\treturn $elm$core$Result$Ok(toElmValue(array));\n}\n\nfunction _Json_isArray(value)\n{\n\treturn Array.isArray(value) || (typeof FileList !== 'undefined' && value instanceof FileList);\n}\n\nfunction _Json_toElmArray(array)\n{\n\treturn A2($elm$core$Array$initialize, array.length, function(i) { return array[i]; });\n}\n\nfunction _Json_expecting(type, value)\n{\n\treturn $elm$core$Result$Err(A2($elm$json$Json$Decode$Failure, 'Expecting ' + type, _Json_wrap(value)));\n}\n\n\n// EQUALITY\n\nfunction _Json_equality(x, y)\n{\n\tif (x === y)\n\t{\n\t\treturn true;\n\t}\n\n\tif (x.$ !== y.$)\n\t{\n\t\treturn false;\n\t}\n\n\tswitch (x.$)\n\t{\n\t\tcase 0:\n\t\tcase 1:\n\t\t\treturn x.a === y.a;\n\n\t\tcase 2:\n\t\t\treturn x.b === y.b;\n\n\t\tcase 5:\n\t\t\treturn x.c === y.c;\n\n\t\tcase 3:\n\t\tcase 4:\n\t\tcase 8:\n\t\t\treturn _Json_equality(x.b, y.b);\n\n\t\tcase 6:\n\t\t\treturn x.d === y.d && _Json_equality(x.b, y.b);\n\n\t\tcase 7:\n\t\t\treturn x.e === y.e && _Json_equality(x.b, y.b);\n\n\t\tcase 9:\n\t\t\treturn x.f === y.f && _Json_listEquality(x.g, y.g);\n\n\t\tcase 10:\n\t\t\treturn x.h === y.h && _Json_equality(x.b, y.b);\n\n\t\tcase 11:\n\t\t\treturn _Json_listEquality(x.g, y.g);\n\t}\n}\n\nfunction _Json_listEquality(aDecoders, bDecoders)\n{\n\tvar len = aDecoders.length;\n\tif (len !== bDecoders.length)\n\t{\n\t\treturn false;\n\t}\n\tfor (var i = 0; i < len; i++)\n\t{\n\t\tif (!_Json_equality(aDecoders[i], bDecoders[i]))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n\n// ENCODE\n\nvar _Json_encode = F2(function(indentLevel, value)\n{\n\treturn JSON.stringify(_Json_unwrap(value), null, indentLevel) + '';\n});\n\nfunction _Json_wrap_UNUSED(value) { return { $: 0, a: value }; }\nfunction _Json_unwrap_UNUSED(value) { return value.a; }\n\nfunction _Json_wrap(value) { return value; }\nfunction _Json_unwrap(value) { return value; }\n\nfunction _Json_emptyArray() { return []; }\nfunction _Json_emptyObject() { return {}; }\n\nvar _Json_addField = F3(function(key, value, object)\n{\n\tobject[key] = _Json_unwrap(value);\n\treturn object;\n});\n\nfunction _Json_addEntry(func)\n{\n\treturn F2(function(entry, array)\n\t{\n\t\tarray.push(_Json_unwrap(func(entry)));\n\t\treturn array;\n\t});\n}\n\nvar _Json_encodeNull = _Json_wrap(null);\n\n\n\n// TASKS\n\nfunction _Scheduler_succeed(value)\n{\n\treturn {\n\t\t$: 0,\n\t\ta: value\n\t};\n}\n\nfunction _Scheduler_fail(error)\n{\n\treturn {\n\t\t$: 1,\n\t\ta: error\n\t};\n}\n\nfunction _Scheduler_binding(callback)\n{\n\treturn {\n\t\t$: 2,\n\t\tb: callback,\n\t\tc: null\n\t};\n}\n\nvar _Scheduler_andThen = F2(function(callback, task)\n{\n\treturn {\n\t\t$: 3,\n\t\tb: callback,\n\t\td: task\n\t};\n});\n\nvar _Scheduler_onError = F2(function(callback, task)\n{\n\treturn {\n\t\t$: 4,\n\t\tb: callback,\n\t\td: task\n\t};\n});\n\nfunction _Scheduler_receive(callback)\n{\n\treturn {\n\t\t$: 5,\n\t\tb: callback\n\t};\n}\n\n\n// PROCESSES\n\nvar _Scheduler_guid = 0;\n\nfunction _Scheduler_rawSpawn(task)\n{\n\tvar proc = {\n\t\t$: 0,\n\t\te: _Scheduler_guid++,\n\t\tf: task,\n\t\tg: null,\n\t\th: []\n\t};\n\n\t_Scheduler_enqueue(proc);\n\n\treturn proc;\n}\n\nfunction _Scheduler_spawn(task)\n{\n\treturn _Scheduler_binding(function(callback) {\n\t\tcallback(_Scheduler_succeed(_Scheduler_rawSpawn(task)));\n\t});\n}\n\nfunction _Scheduler_rawSend(proc, msg)\n{\n\tproc.h.push(msg);\n\t_Scheduler_enqueue(proc);\n}\n\nvar _Scheduler_send = F2(function(proc, msg)\n{\n\treturn _Scheduler_binding(function(callback) {\n\t\t_Scheduler_rawSend(proc, msg);\n\t\tcallback(_Scheduler_succeed(_Utils_Tuple0));\n\t});\n});\n\nfunction _Scheduler_kill(proc)\n{\n\treturn _Scheduler_binding(function(callback) {\n\t\tvar task = proc.f;\n\t\tif (task.$ === 2 && task.c)\n\t\t{\n\t\t\ttask.c();\n\t\t}\n\n\t\tproc.f = null;\n\n\t\tcallback(_Scheduler_succeed(_Utils_Tuple0));\n\t});\n}\n\n\n/* STEP PROCESSES\n\ntype alias Process =\n  { $ : tag\n  , id : unique_id\n  , root : Task\n  , stack : null | { $: SUCCEED | FAIL, a: callback, b: stack }\n  , mailbox : [msg]\n  }\n\n*/\n\n\nvar _Scheduler_working = false;\nvar _Scheduler_queue = [];\n\n\nfunction _Scheduler_enqueue(proc)\n{\n\t_Scheduler_queue.push(proc);\n\tif (_Scheduler_working)\n\t{\n\t\treturn;\n\t}\n\t_Scheduler_working = true;\n\twhile (proc = _Scheduler_queue.shift())\n\t{\n\t\t_Scheduler_step(proc);\n\t}\n\t_Scheduler_working = false;\n}\n\n\nfunction _Scheduler_step(proc)\n{\n\twhile (proc.f)\n\t{\n\t\tvar rootTag = proc.f.$;\n\t\tif (rootTag === 0 || rootTag === 1)\n\t\t{\n\t\t\twhile (proc.g && proc.g.$ !== rootTag)\n\t\t\t{\n\t\t\t\tproc.g = proc.g.i;\n\t\t\t}\n\t\t\tif (!proc.g)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tproc.f = proc.g.b(proc.f.a);\n\t\t\tproc.g = proc.g.i;\n\t\t}\n\t\telse if (rootTag === 2)\n\t\t{\n\t\t\tproc.f.c = proc.f.b(function(newRoot) {\n\t\t\t\tproc.f = newRoot;\n\t\t\t\t_Scheduler_enqueue(proc);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\telse if (rootTag === 5)\n\t\t{\n\t\t\tif (proc.h.length === 0)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tproc.f = proc.f.b(proc.h.shift());\n\t\t}\n\t\telse // if (rootTag === 3 || rootTag === 4)\n\t\t{\n\t\t\tproc.g = {\n\t\t\t\t$: rootTag === 3 ? 0 : 1,\n\t\t\t\tb: proc.f.b,\n\t\t\t\ti: proc.g\n\t\t\t};\n\t\t\tproc.f = proc.f.d;\n\t\t}\n\t}\n}\n\n\n\nfunction _Process_sleep(time)\n{\n\treturn _Scheduler_binding(function(callback) {\n\t\tvar id = setTimeout(function() {\n\t\t\tcallback(_Scheduler_succeed(_Utils_Tuple0));\n\t\t}, time);\n\n\t\treturn function() { clearTimeout(id); };\n\t});\n}\n\n\n\n\n// PROGRAMS\n\n\nvar _Platform_worker = F4(function(impl, flagDecoder, debugMetadata, args)\n{\n\treturn _Platform_initialize(\n\t\tflagDecoder,\n\t\targs,\n\t\timpl.aB,\n\t\timpl.aJ,\n\t\timpl.aH,\n\t\tfunction() { return function() {} }\n\t);\n});\n\n\n\n// INITIALIZE A PROGRAM\n\n\nfunction _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder)\n{\n\tvar result = A2(_Json_run, flagDecoder, _Json_wrap(args ? args['flags'] : undefined));\n\t$elm$core$Result$isOk(result) || _Debug_crash(2 /**_UNUSED/, _Json_errorToString(result.a) /**/);\n\tvar managers = {};\n\tvar initPair = init(result.a);\n\tvar model = initPair.a;\n\tvar stepper = stepperBuilder(sendToApp, model);\n\tvar ports = _Platform_setupEffects(managers, sendToApp);\n\n\tfunction sendToApp(msg, viewMetadata)\n\t{\n\t\tvar pair = A2(update, msg, model);\n\t\tstepper(model = pair.a, viewMetadata);\n\t\t_Platform_enqueueEffects(managers, pair.b, subscriptions(model));\n\t}\n\n\t_Platform_enqueueEffects(managers, initPair.b, subscriptions(model));\n\n\treturn ports ? { ports: ports } : {};\n}\n\n\n\n// TRACK PRELOADS\n//\n// This is used by code in elm/browser and elm/http\n// to register any HTTP requests that are triggered by init.\n//\n\n\nvar _Platform_preload;\n\n\nfunction _Platform_registerPreload(url)\n{\n\t_Platform_preload.add(url);\n}\n\n\n\n// EFFECT MANAGERS\n\n\nvar _Platform_effectManagers = {};\n\n\nfunction _Platform_setupEffects(managers, sendToApp)\n{\n\tvar ports;\n\n\t// setup all necessary effect managers\n\tfor (var key in _Platform_effectManagers)\n\t{\n\t\tvar manager = _Platform_effectManagers[key];\n\n\t\tif (manager.a)\n\t\t{\n\t\t\tports = ports || {};\n\t\t\tports[key] = manager.a(key, sendToApp);\n\t\t}\n\n\t\tmanagers[key] = _Platform_instantiateManager(manager, sendToApp);\n\t}\n\n\treturn ports;\n}\n\n\nfunction _Platform_createManager(init, onEffects, onSelfMsg, cmdMap, subMap)\n{\n\treturn {\n\t\tb: init,\n\t\tc: onEffects,\n\t\td: onSelfMsg,\n\t\te: cmdMap,\n\t\tf: subMap\n\t};\n}\n\n\nfunction _Platform_instantiateManager(info, sendToApp)\n{\n\tvar router = {\n\t\tg: sendToApp,\n\t\th: undefined\n\t};\n\n\tvar onEffects = info.c;\n\tvar onSelfMsg = info.d;\n\tvar cmdMap = info.e;\n\tvar subMap = info.f;\n\n\tfunction loop(state)\n\t{\n\t\treturn A2(_Scheduler_andThen, loop, _Scheduler_receive(function(msg)\n\t\t{\n\t\t\tvar value = msg.a;\n\n\t\t\tif (msg.$ === 0)\n\t\t\t{\n\t\t\t\treturn A3(onSelfMsg, router, value, state);\n\t\t\t}\n\n\t\t\treturn cmdMap && subMap\n\t\t\t\t? A4(onEffects, router, value.i, value.j, state)\n\t\t\t\t: A3(onEffects, router, cmdMap ? value.i : value.j, state);\n\t\t}));\n\t}\n\n\treturn router.h = _Scheduler_rawSpawn(A2(_Scheduler_andThen, loop, info.b));\n}\n\n\n\n// ROUTING\n\n\nvar _Platform_sendToApp = F2(function(router, msg)\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\trouter.g(msg);\n\t\tcallback(_Scheduler_succeed(_Utils_Tuple0));\n\t});\n});\n\n\nvar _Platform_sendToSelf = F2(function(router, msg)\n{\n\treturn A2(_Scheduler_send, router.h, {\n\t\t$: 0,\n\t\ta: msg\n\t});\n});\n\n\n\n// BAGS\n\n\nfunction _Platform_leaf(home)\n{\n\treturn function(value)\n\t{\n\t\treturn {\n\t\t\t$: 1,\n\t\t\tk: home,\n\t\t\tl: value\n\t\t};\n\t};\n}\n\n\nfunction _Platform_batch(list)\n{\n\treturn {\n\t\t$: 2,\n\t\tm: list\n\t};\n}\n\n\nvar _Platform_map = F2(function(tagger, bag)\n{\n\treturn {\n\t\t$: 3,\n\t\tn: tagger,\n\t\to: bag\n\t}\n});\n\n\n\n// PIPE BAGS INTO EFFECT MANAGERS\n//\n// Effects must be queued!\n//\n// Say your init contains a synchronous command, like Time.now or Time.here\n//\n//   - This will produce a batch of effects (FX_1)\n//   - The synchronous task triggers the subsequent `update` call\n//   - This will produce a batch of effects (FX_2)\n//\n// If we just start dispatching FX_2, subscriptions from FX_2 can be processed\n// before subscriptions from FX_1. No good! Earlier versions of this code had\n// this problem, leading to these reports:\n//\n//   https://github.com/elm/core/issues/980\n//   https://github.com/elm/core/pull/981\n//   https://github.com/elm/compiler/issues/1776\n//\n// The queue is necessary to avoid ordering issues for synchronous commands.\n\n\n// Why use true/false here? Why not just check the length of the queue?\n// The goal is to detect \"are we currently dispatching effects?\" If we\n// are, we need to bail and let the ongoing while loop handle things.\n//\n// Now say the queue has 1 element. When we dequeue the final element,\n// the queue will be empty, but we are still actively dispatching effects.\n// So you could get queue jumping in a really tricky category of cases.\n//\nvar _Platform_effectsQueue = [];\nvar _Platform_effectsActive = false;\n\n\nfunction _Platform_enqueueEffects(managers, cmdBag, subBag)\n{\n\t_Platform_effectsQueue.push({ p: managers, q: cmdBag, r: subBag });\n\n\tif (_Platform_effectsActive) return;\n\n\t_Platform_effectsActive = true;\n\tfor (var fx; fx = _Platform_effectsQueue.shift(); )\n\t{\n\t\t_Platform_dispatchEffects(fx.p, fx.q, fx.r);\n\t}\n\t_Platform_effectsActive = false;\n}\n\n\nfunction _Platform_dispatchEffects(managers, cmdBag, subBag)\n{\n\tvar effectsDict = {};\n\t_Platform_gatherEffects(true, cmdBag, effectsDict, null);\n\t_Platform_gatherEffects(false, subBag, effectsDict, null);\n\n\tfor (var home in managers)\n\t{\n\t\t_Scheduler_rawSend(managers[home], {\n\t\t\t$: 'fx',\n\t\t\ta: effectsDict[home] || { i: _List_Nil, j: _List_Nil }\n\t\t});\n\t}\n}\n\n\nfunction _Platform_gatherEffects(isCmd, bag, effectsDict, taggers)\n{\n\tswitch (bag.$)\n\t{\n\t\tcase 1:\n\t\t\tvar home = bag.k;\n\t\t\tvar effect = _Platform_toEffect(isCmd, home, taggers, bag.l);\n\t\t\teffectsDict[home] = _Platform_insert(isCmd, effect, effectsDict[home]);\n\t\t\treturn;\n\n\t\tcase 2:\n\t\t\tfor (var list = bag.m; list.b; list = list.b) // WHILE_CONS\n\t\t\t{\n\t\t\t\t_Platform_gatherEffects(isCmd, list.a, effectsDict, taggers);\n\t\t\t}\n\t\t\treturn;\n\n\t\tcase 3:\n\t\t\t_Platform_gatherEffects(isCmd, bag.o, effectsDict, {\n\t\t\t\ts: bag.n,\n\t\t\t\tt: taggers\n\t\t\t});\n\t\t\treturn;\n\t}\n}\n\n\nfunction _Platform_toEffect(isCmd, home, taggers, value)\n{\n\tfunction applyTaggers(x)\n\t{\n\t\tfor (var temp = taggers; temp; temp = temp.t)\n\t\t{\n\t\t\tx = temp.s(x);\n\t\t}\n\t\treturn x;\n\t}\n\n\tvar map = isCmd\n\t\t? _Platform_effectManagers[home].e\n\t\t: _Platform_effectManagers[home].f;\n\n\treturn A2(map, applyTaggers, value)\n}\n\n\nfunction _Platform_insert(isCmd, newEffect, effects)\n{\n\teffects = effects || { i: _List_Nil, j: _List_Nil };\n\n\tisCmd\n\t\t? (effects.i = _List_Cons(newEffect, effects.i))\n\t\t: (effects.j = _List_Cons(newEffect, effects.j));\n\n\treturn effects;\n}\n\n\n\n// PORTS\n\n\nfunction _Platform_checkPortName(name)\n{\n\tif (_Platform_effectManagers[name])\n\t{\n\t\t_Debug_crash(3, name)\n\t}\n}\n\n\n\n// OUTGOING PORTS\n\n\nfunction _Platform_outgoingPort(name, converter)\n{\n\t_Platform_checkPortName(name);\n\t_Platform_effectManagers[name] = {\n\t\te: _Platform_outgoingPortMap,\n\t\tu: converter,\n\t\ta: _Platform_setupOutgoingPort\n\t};\n\treturn _Platform_leaf(name);\n}\n\n\nvar _Platform_outgoingPortMap = F2(function(tagger, value) { return value; });\n\n\nfunction _Platform_setupOutgoingPort(name)\n{\n\tvar subs = [];\n\tvar converter = _Platform_effectManagers[name].u;\n\n\t// CREATE MANAGER\n\n\tvar init = _Process_sleep(0);\n\n\t_Platform_effectManagers[name].b = init;\n\t_Platform_effectManagers[name].c = F3(function(router, cmdList, state)\n\t{\n\t\tfor ( ; cmdList.b; cmdList = cmdList.b) // WHILE_CONS\n\t\t{\n\t\t\t// grab a separate reference to subs in case unsubscribe is called\n\t\t\tvar currentSubs = subs;\n\t\t\tvar value = _Json_unwrap(converter(cmdList.a));\n\t\t\tfor (var i = 0; i < currentSubs.length; i++)\n\t\t\t{\n\t\t\t\tcurrentSubs[i](value);\n\t\t\t}\n\t\t}\n\t\treturn init;\n\t});\n\n\t// PUBLIC API\n\n\tfunction subscribe(callback)\n\t{\n\t\tsubs.push(callback);\n\t}\n\n\tfunction unsubscribe(callback)\n\t{\n\t\t// copy subs into a new array in case unsubscribe is called within a\n\t\t// subscribed callback\n\t\tsubs = subs.slice();\n\t\tvar index = subs.indexOf(callback);\n\t\tif (index >= 0)\n\t\t{\n\t\t\tsubs.splice(index, 1);\n\t\t}\n\t}\n\n\treturn {\n\t\tsubscribe: subscribe,\n\t\tunsubscribe: unsubscribe\n\t};\n}\n\n\n\n// INCOMING PORTS\n\n\nfunction _Platform_incomingPort(name, converter)\n{\n\t_Platform_checkPortName(name);\n\t_Platform_effectManagers[name] = {\n\t\tf: _Platform_incomingPortMap,\n\t\tu: converter,\n\t\ta: _Platform_setupIncomingPort\n\t};\n\treturn _Platform_leaf(name);\n}\n\n\nvar _Platform_incomingPortMap = F2(function(tagger, finalTagger)\n{\n\treturn function(value)\n\t{\n\t\treturn tagger(finalTagger(value));\n\t};\n});\n\n\nfunction _Platform_setupIncomingPort(name, sendToApp)\n{\n\tvar subs = _List_Nil;\n\tvar converter = _Platform_effectManagers[name].u;\n\n\t// CREATE MANAGER\n\n\tvar init = _Scheduler_succeed(null);\n\n\t_Platform_effectManagers[name].b = init;\n\t_Platform_effectManagers[name].c = F3(function(router, subList, state)\n\t{\n\t\tsubs = subList;\n\t\treturn init;\n\t});\n\n\t// PUBLIC API\n\n\tfunction send(incomingValue)\n\t{\n\t\tvar result = A2(_Json_run, converter, _Json_wrap(incomingValue));\n\n\t\t$elm$core$Result$isOk(result) || _Debug_crash(4, name, result.a);\n\n\t\tvar value = result.a;\n\t\tfor (var temp = subs; temp.b; temp = temp.b) // WHILE_CONS\n\t\t{\n\t\t\tsendToApp(temp.a(value));\n\t\t}\n\t}\n\n\treturn { send: send };\n}\n\n\n\n// EXPORT ELM MODULES\n//\n// Have DEBUG and PROD versions so that we can (1) give nicer errors in\n// debug mode and (2) not pay for the bits needed for that in prod mode.\n//\n\n\nfunction _Platform_export(exports)\n{\n\tscope['Elm']\n\t\t? _Platform_mergeExportsProd(scope['Elm'], exports)\n\t\t: scope['Elm'] = exports;\n}\n\n\nfunction _Platform_mergeExportsProd(obj, exports)\n{\n\tfor (var name in exports)\n\t{\n\t\t(name in obj)\n\t\t\t? (name == 'init')\n\t\t\t\t? _Debug_crash(6)\n\t\t\t\t: _Platform_mergeExportsProd(obj[name], exports[name])\n\t\t\t: (obj[name] = exports[name]);\n\t}\n}\n\n\nfunction _Platform_export_UNUSED(exports)\n{\n\tscope['Elm']\n\t\t? _Platform_mergeExportsDebug('Elm', scope['Elm'], exports)\n\t\t: scope['Elm'] = exports;\n}\n\n\nfunction _Platform_mergeExportsDebug(moduleName, obj, exports)\n{\n\tfor (var name in exports)\n\t{\n\t\t(name in obj)\n\t\t\t? (name == 'init')\n\t\t\t\t? _Debug_crash(6, moduleName)\n\t\t\t\t: _Platform_mergeExportsDebug(moduleName + '.' + name, obj[name], exports[name])\n\t\t\t: (obj[name] = exports[name]);\n\t}\n}\n\n\n\n\n// HELPERS\n\n\nvar _VirtualDom_divertHrefToApp;\n\nvar _VirtualDom_doc = typeof document !== 'undefined' ? document : {};\n\n\nfunction _VirtualDom_appendChild(parent, child)\n{\n\tparent.appendChild(child);\n}\n\nvar _VirtualDom_init = F4(function(virtualNode, flagDecoder, debugMetadata, args)\n{\n\t// NOTE: this function needs _Platform_export available to work\n\n\t/**/\n\tvar node = args['node'];\n\t//*/\n\t/**_UNUSED/\n\tvar node = args && args['node'] ? args['node'] : _Debug_crash(0);\n\t//*/\n\n\tnode.parentNode.replaceChild(\n\t\t_VirtualDom_render(virtualNode, function() {}),\n\t\tnode\n\t);\n\n\treturn {};\n});\n\n\n\n// TEXT\n\n\nfunction _VirtualDom_text(string)\n{\n\treturn {\n\t\t$: 0,\n\t\ta: string\n\t};\n}\n\n\n\n// NODE\n\n\nvar _VirtualDom_nodeNS = F2(function(namespace, tag)\n{\n\treturn F2(function(factList, kidList)\n\t{\n\t\tfor (var kids = [], descendantsCount = 0; kidList.b; kidList = kidList.b) // WHILE_CONS\n\t\t{\n\t\t\tvar kid = kidList.a;\n\t\t\tdescendantsCount += (kid.b || 0);\n\t\t\tkids.push(kid);\n\t\t}\n\t\tdescendantsCount += kids.length;\n\n\t\treturn {\n\t\t\t$: 1,\n\t\t\tc: tag,\n\t\t\td: _VirtualDom_organizeFacts(factList),\n\t\t\te: kids,\n\t\t\tf: namespace,\n\t\t\tb: descendantsCount\n\t\t};\n\t});\n});\n\n\nvar _VirtualDom_node = _VirtualDom_nodeNS(undefined);\n\n\n\n// KEYED NODE\n\n\nvar _VirtualDom_keyedNodeNS = F2(function(namespace, tag)\n{\n\treturn F2(function(factList, kidList)\n\t{\n\t\tfor (var kids = [], descendantsCount = 0; kidList.b; kidList = kidList.b) // WHILE_CONS\n\t\t{\n\t\t\tvar kid = kidList.a;\n\t\t\tdescendantsCount += (kid.b.b || 0);\n\t\t\tkids.push(kid);\n\t\t}\n\t\tdescendantsCount += kids.length;\n\n\t\treturn {\n\t\t\t$: 2,\n\t\t\tc: tag,\n\t\t\td: _VirtualDom_organizeFacts(factList),\n\t\t\te: kids,\n\t\t\tf: namespace,\n\t\t\tb: descendantsCount\n\t\t};\n\t});\n});\n\n\nvar _VirtualDom_keyedNode = _VirtualDom_keyedNodeNS(undefined);\n\n\n\n// CUSTOM\n\n\nfunction _VirtualDom_custom(factList, model, render, diff)\n{\n\treturn {\n\t\t$: 3,\n\t\td: _VirtualDom_organizeFacts(factList),\n\t\tg: model,\n\t\th: render,\n\t\ti: diff\n\t};\n}\n\n\n\n// MAP\n\n\nvar _VirtualDom_map = F2(function(tagger, node)\n{\n\treturn {\n\t\t$: 4,\n\t\tj: tagger,\n\t\tk: node,\n\t\tb: 1 + (node.b || 0)\n\t};\n});\n\n\n\n// LAZY\n\n\nfunction _VirtualDom_thunk(refs, thunk)\n{\n\treturn {\n\t\t$: 5,\n\t\tl: refs,\n\t\tm: thunk,\n\t\tk: undefined\n\t};\n}\n\nvar _VirtualDom_lazy = F2(function(func, a)\n{\n\treturn _VirtualDom_thunk([func, a], function() {\n\t\treturn func(a);\n\t});\n});\n\nvar _VirtualDom_lazy2 = F3(function(func, a, b)\n{\n\treturn _VirtualDom_thunk([func, a, b], function() {\n\t\treturn A2(func, a, b);\n\t});\n});\n\nvar _VirtualDom_lazy3 = F4(function(func, a, b, c)\n{\n\treturn _VirtualDom_thunk([func, a, b, c], function() {\n\t\treturn A3(func, a, b, c);\n\t});\n});\n\nvar _VirtualDom_lazy4 = F5(function(func, a, b, c, d)\n{\n\treturn _VirtualDom_thunk([func, a, b, c, d], function() {\n\t\treturn A4(func, a, b, c, d);\n\t});\n});\n\nvar _VirtualDom_lazy5 = F6(function(func, a, b, c, d, e)\n{\n\treturn _VirtualDom_thunk([func, a, b, c, d, e], function() {\n\t\treturn A5(func, a, b, c, d, e);\n\t});\n});\n\nvar _VirtualDom_lazy6 = F7(function(func, a, b, c, d, e, f)\n{\n\treturn _VirtualDom_thunk([func, a, b, c, d, e, f], function() {\n\t\treturn A6(func, a, b, c, d, e, f);\n\t});\n});\n\nvar _VirtualDom_lazy7 = F8(function(func, a, b, c, d, e, f, g)\n{\n\treturn _VirtualDom_thunk([func, a, b, c, d, e, f, g], function() {\n\t\treturn A7(func, a, b, c, d, e, f, g);\n\t});\n});\n\nvar _VirtualDom_lazy8 = F9(function(func, a, b, c, d, e, f, g, h)\n{\n\treturn _VirtualDom_thunk([func, a, b, c, d, e, f, g, h], function() {\n\t\treturn A8(func, a, b, c, d, e, f, g, h);\n\t});\n});\n\n\n\n// FACTS\n\n\nvar _VirtualDom_on = F2(function(key, handler)\n{\n\treturn {\n\t\t$: 'a0',\n\t\tn: key,\n\t\to: handler\n\t};\n});\nvar _VirtualDom_style = F2(function(key, value)\n{\n\treturn {\n\t\t$: 'a1',\n\t\tn: key,\n\t\to: value\n\t};\n});\nvar _VirtualDom_property = F2(function(key, value)\n{\n\treturn {\n\t\t$: 'a2',\n\t\tn: key,\n\t\to: value\n\t};\n});\nvar _VirtualDom_attribute = F2(function(key, value)\n{\n\treturn {\n\t\t$: 'a3',\n\t\tn: key,\n\t\to: value\n\t};\n});\nvar _VirtualDom_attributeNS = F3(function(namespace, key, value)\n{\n\treturn {\n\t\t$: 'a4',\n\t\tn: key,\n\t\to: { f: namespace, o: value }\n\t};\n});\n\n\n\n// XSS ATTACK VECTOR CHECKS\n\n\nfunction _VirtualDom_noScript(tag)\n{\n\treturn tag == 'script' ? 'p' : tag;\n}\n\nfunction _VirtualDom_noOnOrFormAction(key)\n{\n\treturn /^(on|formAction$)/i.test(key) ? 'data-' + key : key;\n}\n\nfunction _VirtualDom_noInnerHtmlOrFormAction(key)\n{\n\treturn key == 'innerHTML' || key == 'formAction' ? 'data-' + key : key;\n}\n\nfunction _VirtualDom_noJavaScriptUri(value)\n{\n\treturn /^javascript:/i.test(value.replace(/\\s/g,'')) ? '' : value;\n}\n\nfunction _VirtualDom_noJavaScriptUri_UNUSED(value)\n{\n\treturn /^javascript:/i.test(value.replace(/\\s/g,''))\n\t\t? 'javascript:alert(\"This is an XSS vector. Please use ports or web components instead.\")'\n\t\t: value;\n}\n\nfunction _VirtualDom_noJavaScriptOrHtmlUri(value)\n{\n\treturn /^\\s*(javascript:|data:text\\/html)/i.test(value) ? '' : value;\n}\n\nfunction _VirtualDom_noJavaScriptOrHtmlUri_UNUSED(value)\n{\n\treturn /^\\s*(javascript:|data:text\\/html)/i.test(value)\n\t\t? 'javascript:alert(\"This is an XSS vector. Please use ports or web components instead.\")'\n\t\t: value;\n}\n\n\n\n// MAP FACTS\n\n\nvar _VirtualDom_mapAttribute = F2(function(func, attr)\n{\n\treturn (attr.$ === 'a0')\n\t\t? A2(_VirtualDom_on, attr.n, _VirtualDom_mapHandler(func, attr.o))\n\t\t: attr;\n});\n\nfunction _VirtualDom_mapHandler(func, handler)\n{\n\tvar tag = $elm$virtual_dom$VirtualDom$toHandlerInt(handler);\n\n\t// 0 = Normal\n\t// 1 = MayStopPropagation\n\t// 2 = MayPreventDefault\n\t// 3 = Custom\n\n\treturn {\n\t\t$: handler.$,\n\t\ta:\n\t\t\t!tag\n\t\t\t\t? A2($elm$json$Json$Decode$map, func, handler.a)\n\t\t\t\t:\n\t\t\tA3($elm$json$Json$Decode$map2,\n\t\t\t\ttag < 3\n\t\t\t\t\t? _VirtualDom_mapEventTuple\n\t\t\t\t\t: _VirtualDom_mapEventRecord,\n\t\t\t\t$elm$json$Json$Decode$succeed(func),\n\t\t\t\thandler.a\n\t\t\t)\n\t};\n}\n\nvar _VirtualDom_mapEventTuple = F2(function(func, tuple)\n{\n\treturn _Utils_Tuple2(func(tuple.a), tuple.b);\n});\n\nvar _VirtualDom_mapEventRecord = F2(function(func, record)\n{\n\treturn {\n\t\tt: func(record.t),\n\t\tR: record.R,\n\t\tO: record.O\n\t}\n});\n\n\n\n// ORGANIZE FACTS\n\n\nfunction _VirtualDom_organizeFacts(factList)\n{\n\tfor (var facts = {}; factList.b; factList = factList.b) // WHILE_CONS\n\t{\n\t\tvar entry = factList.a;\n\n\t\tvar tag = entry.$;\n\t\tvar key = entry.n;\n\t\tvar value = entry.o;\n\n\t\tif (tag === 'a2')\n\t\t{\n\t\t\t(key === 'className')\n\t\t\t\t? _VirtualDom_addClass(facts, key, _Json_unwrap(value))\n\t\t\t\t: facts[key] = _Json_unwrap(value);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tvar subFacts = facts[tag] || (facts[tag] = {});\n\t\t(tag === 'a3' && key === 'class')\n\t\t\t? _VirtualDom_addClass(subFacts, key, value)\n\t\t\t: subFacts[key] = value;\n\t}\n\n\treturn facts;\n}\n\nfunction _VirtualDom_addClass(object, key, newClass)\n{\n\tvar classes = object[key];\n\tobject[key] = classes ? classes + ' ' + newClass : newClass;\n}\n\n\n\n// RENDER\n\n\nfunction _VirtualDom_render(vNode, eventNode)\n{\n\tvar tag = vNode.$;\n\n\tif (tag === 5)\n\t{\n\t\treturn _VirtualDom_render(vNode.k || (vNode.k = vNode.m()), eventNode);\n\t}\n\n\tif (tag === 0)\n\t{\n\t\treturn _VirtualDom_doc.createTextNode(vNode.a);\n\t}\n\n\tif (tag === 4)\n\t{\n\t\tvar subNode = vNode.k;\n\t\tvar tagger = vNode.j;\n\n\t\twhile (subNode.$ === 4)\n\t\t{\n\t\t\ttypeof tagger !== 'object'\n\t\t\t\t? tagger = [tagger, subNode.j]\n\t\t\t\t: tagger.push(subNode.j);\n\n\t\t\tsubNode = subNode.k;\n\t\t}\n\n\t\tvar subEventRoot = { j: tagger, p: eventNode };\n\t\tvar domNode = _VirtualDom_render(subNode, subEventRoot);\n\t\tdomNode.elm_event_node_ref = subEventRoot;\n\t\treturn domNode;\n\t}\n\n\tif (tag === 3)\n\t{\n\t\tvar domNode = vNode.h(vNode.g);\n\t\t_VirtualDom_applyFacts(domNode, eventNode, vNode.d);\n\t\treturn domNode;\n\t}\n\n\t// at this point `tag` must be 1 or 2\n\n\tvar domNode = vNode.f\n\t\t? _VirtualDom_doc.createElementNS(vNode.f, vNode.c)\n\t\t: _VirtualDom_doc.createElement(vNode.c);\n\n\tif (_VirtualDom_divertHrefToApp && vNode.c == 'a')\n\t{\n\t\tdomNode.addEventListener('click', _VirtualDom_divertHrefToApp(domNode));\n\t}\n\n\t_VirtualDom_applyFacts(domNode, eventNode, vNode.d);\n\n\tfor (var kids = vNode.e, i = 0; i < kids.length; i++)\n\t{\n\t\t_VirtualDom_appendChild(domNode, _VirtualDom_render(tag === 1 ? kids[i] : kids[i].b, eventNode));\n\t}\n\n\treturn domNode;\n}\n\n\n\n// APPLY FACTS\n\n\nfunction _VirtualDom_applyFacts(domNode, eventNode, facts)\n{\n\tfor (var key in facts)\n\t{\n\t\tvar value = facts[key];\n\n\t\tkey === 'a1'\n\t\t\t? _VirtualDom_applyStyles(domNode, value)\n\t\t\t:\n\t\tkey === 'a0'\n\t\t\t? _VirtualDom_applyEvents(domNode, eventNode, value)\n\t\t\t:\n\t\tkey === 'a3'\n\t\t\t? _VirtualDom_applyAttrs(domNode, value)\n\t\t\t:\n\t\tkey === 'a4'\n\t\t\t? _VirtualDom_applyAttrsNS(domNode, value)\n\t\t\t:\n\t\t((key !== 'value' && key !== 'checked') || domNode[key] !== value) && (domNode[key] = value);\n\t}\n}\n\n\n\n// APPLY STYLES\n\n\nfunction _VirtualDom_applyStyles(domNode, styles)\n{\n\tvar domNodeStyle = domNode.style;\n\n\tfor (var key in styles)\n\t{\n\t\tdomNodeStyle[key] = styles[key];\n\t}\n}\n\n\n\n// APPLY ATTRS\n\n\nfunction _VirtualDom_applyAttrs(domNode, attrs)\n{\n\tfor (var key in attrs)\n\t{\n\t\tvar value = attrs[key];\n\t\ttypeof value !== 'undefined'\n\t\t\t? domNode.setAttribute(key, value)\n\t\t\t: domNode.removeAttribute(key);\n\t}\n}\n\n\n\n// APPLY NAMESPACED ATTRS\n\n\nfunction _VirtualDom_applyAttrsNS(domNode, nsAttrs)\n{\n\tfor (var key in nsAttrs)\n\t{\n\t\tvar pair = nsAttrs[key];\n\t\tvar namespace = pair.f;\n\t\tvar value = pair.o;\n\n\t\ttypeof value !== 'undefined'\n\t\t\t? domNode.setAttributeNS(namespace, key, value)\n\t\t\t: domNode.removeAttributeNS(namespace, key);\n\t}\n}\n\n\n\n// APPLY EVENTS\n\n\nfunction _VirtualDom_applyEvents(domNode, eventNode, events)\n{\n\tvar allCallbacks = domNode.elmFs || (domNode.elmFs = {});\n\n\tfor (var key in events)\n\t{\n\t\tvar newHandler = events[key];\n\t\tvar oldCallback = allCallbacks[key];\n\n\t\tif (!newHandler)\n\t\t{\n\t\t\tdomNode.removeEventListener(key, oldCallback);\n\t\t\tallCallbacks[key] = undefined;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (oldCallback)\n\t\t{\n\t\t\tvar oldHandler = oldCallback.q;\n\t\t\tif (oldHandler.$ === newHandler.$)\n\t\t\t{\n\t\t\t\toldCallback.q = newHandler;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tdomNode.removeEventListener(key, oldCallback);\n\t\t}\n\n\t\toldCallback = _VirtualDom_makeCallback(eventNode, newHandler);\n\t\tdomNode.addEventListener(key, oldCallback,\n\t\t\t_VirtualDom_passiveSupported\n\t\t\t&& { passive: $elm$virtual_dom$VirtualDom$toHandlerInt(newHandler) < 2 }\n\t\t);\n\t\tallCallbacks[key] = oldCallback;\n\t}\n}\n\n\n\n// PASSIVE EVENTS\n\n\nvar _VirtualDom_passiveSupported;\n\ntry\n{\n\twindow.addEventListener('t', null, Object.defineProperty({}, 'passive', {\n\t\tget: function() { _VirtualDom_passiveSupported = true; }\n\t}));\n}\ncatch(e) {}\n\n\n\n// EVENT HANDLERS\n\n\nfunction _VirtualDom_makeCallback(eventNode, initialHandler)\n{\n\tfunction callback(event)\n\t{\n\t\tvar handler = callback.q;\n\t\tvar result = _Json_runHelp(handler.a, event);\n\n\t\tif (!$elm$core$Result$isOk(result))\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tvar tag = $elm$virtual_dom$VirtualDom$toHandlerInt(handler);\n\n\t\t// 0 = Normal\n\t\t// 1 = MayStopPropagation\n\t\t// 2 = MayPreventDefault\n\t\t// 3 = Custom\n\n\t\tvar value = result.a;\n\t\tvar message = !tag ? value : tag < 3 ? value.a : value.t;\n\t\tvar stopPropagation = tag == 1 ? value.b : tag == 3 && value.R;\n\t\tvar currentEventNode = (\n\t\t\tstopPropagation && event.stopPropagation(),\n\t\t\t(tag == 2 ? value.b : tag == 3 && value.O) && event.preventDefault(),\n\t\t\teventNode\n\t\t);\n\t\tvar tagger;\n\t\tvar i;\n\t\twhile (tagger = currentEventNode.j)\n\t\t{\n\t\t\tif (typeof tagger == 'function')\n\t\t\t{\n\t\t\t\tmessage = tagger(message);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor (var i = tagger.length; i--; )\n\t\t\t\t{\n\t\t\t\t\tmessage = tagger[i](message);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcurrentEventNode = currentEventNode.p;\n\t\t}\n\t\tcurrentEventNode(message, stopPropagation); // stopPropagation implies isSync\n\t}\n\n\tcallback.q = initialHandler;\n\n\treturn callback;\n}\n\nfunction _VirtualDom_equalEvents(x, y)\n{\n\treturn x.$ == y.$ && _Json_equality(x.a, y.a);\n}\n\n\n\n// DIFF\n\n\n// TODO: Should we do patches like in iOS?\n//\n// type Patch\n//   = At Int Patch\n//   | Batch (List Patch)\n//   | Change ...\n//\n// How could it not be better?\n//\nfunction _VirtualDom_diff(x, y)\n{\n\tvar patches = [];\n\t_VirtualDom_diffHelp(x, y, patches, 0);\n\treturn patches;\n}\n\n\nfunction _VirtualDom_pushPatch(patches, type, index, data)\n{\n\tvar patch = {\n\t\t$: type,\n\t\tr: index,\n\t\ts: data,\n\t\tt: undefined,\n\t\tu: undefined\n\t};\n\tpatches.push(patch);\n\treturn patch;\n}\n\n\nfunction _VirtualDom_diffHelp(x, y, patches, index)\n{\n\tif (x === y)\n\t{\n\t\treturn;\n\t}\n\n\tvar xType = x.$;\n\tvar yType = y.$;\n\n\t// Bail if you run into different types of nodes. Implies that the\n\t// structure has changed significantly and it's not worth a diff.\n\tif (xType !== yType)\n\t{\n\t\tif (xType === 1 && yType === 2)\n\t\t{\n\t\t\ty = _VirtualDom_dekey(y);\n\t\t\tyType = 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_VirtualDom_pushPatch(patches, 0, index, y);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Now we know that both nodes are the same $.\n\tswitch (yType)\n\t{\n\t\tcase 5:\n\t\t\tvar xRefs = x.l;\n\t\t\tvar yRefs = y.l;\n\t\t\tvar i = xRefs.length;\n\t\t\tvar same = i === yRefs.length;\n\t\t\twhile (same && i--)\n\t\t\t{\n\t\t\t\tsame = xRefs[i] === yRefs[i];\n\t\t\t}\n\t\t\tif (same)\n\t\t\t{\n\t\t\t\ty.k = x.k;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ty.k = y.m();\n\t\t\tvar subPatches = [];\n\t\t\t_VirtualDom_diffHelp(x.k, y.k, subPatches, 0);\n\t\t\tsubPatches.length > 0 && _VirtualDom_pushPatch(patches, 1, index, subPatches);\n\t\t\treturn;\n\n\t\tcase 4:\n\t\t\t// gather nested taggers\n\t\t\tvar xTaggers = x.j;\n\t\t\tvar yTaggers = y.j;\n\t\t\tvar nesting = false;\n\n\t\t\tvar xSubNode = x.k;\n\t\t\twhile (xSubNode.$ === 4)\n\t\t\t{\n\t\t\t\tnesting = true;\n\n\t\t\t\ttypeof xTaggers !== 'object'\n\t\t\t\t\t? xTaggers = [xTaggers, xSubNode.j]\n\t\t\t\t\t: xTaggers.push(xSubNode.j);\n\n\t\t\t\txSubNode = xSubNode.k;\n\t\t\t}\n\n\t\t\tvar ySubNode = y.k;\n\t\t\twhile (ySubNode.$ === 4)\n\t\t\t{\n\t\t\t\tnesting = true;\n\n\t\t\t\ttypeof yTaggers !== 'object'\n\t\t\t\t\t? yTaggers = [yTaggers, ySubNode.j]\n\t\t\t\t\t: yTaggers.push(ySubNode.j);\n\n\t\t\t\tySubNode = ySubNode.k;\n\t\t\t}\n\n\t\t\t// Just bail if different numbers of taggers. This implies the\n\t\t\t// structure of the virtual DOM has changed.\n\t\t\tif (nesting && xTaggers.length !== yTaggers.length)\n\t\t\t{\n\t\t\t\t_VirtualDom_pushPatch(patches, 0, index, y);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// check if taggers are \"the same\"\n\t\t\tif (nesting ? !_VirtualDom_pairwiseRefEqual(xTaggers, yTaggers) : xTaggers !== yTaggers)\n\t\t\t{\n\t\t\t\t_VirtualDom_pushPatch(patches, 2, index, yTaggers);\n\t\t\t}\n\n\t\t\t// diff everything below the taggers\n\t\t\t_VirtualDom_diffHelp(xSubNode, ySubNode, patches, index + 1);\n\t\t\treturn;\n\n\t\tcase 0:\n\t\t\tif (x.a !== y.a)\n\t\t\t{\n\t\t\t\t_VirtualDom_pushPatch(patches, 3, index, y.a);\n\t\t\t}\n\t\t\treturn;\n\n\t\tcase 1:\n\t\t\t_VirtualDom_diffNodes(x, y, patches, index, _VirtualDom_diffKids);\n\t\t\treturn;\n\n\t\tcase 2:\n\t\t\t_VirtualDom_diffNodes(x, y, patches, index, _VirtualDom_diffKeyedKids);\n\t\t\treturn;\n\n\t\tcase 3:\n\t\t\tif (x.h !== y.h)\n\t\t\t{\n\t\t\t\t_VirtualDom_pushPatch(patches, 0, index, y);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar factsDiff = _VirtualDom_diffFacts(x.d, y.d);\n\t\t\tfactsDiff && _VirtualDom_pushPatch(patches, 4, index, factsDiff);\n\n\t\t\tvar patch = y.i(x.g, y.g);\n\t\t\tpatch && _VirtualDom_pushPatch(patches, 5, index, patch);\n\n\t\t\treturn;\n\t}\n}\n\n// assumes the incoming arrays are the same length\nfunction _VirtualDom_pairwiseRefEqual(as, bs)\n{\n\tfor (var i = 0; i < as.length; i++)\n\t{\n\t\tif (as[i] !== bs[i])\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction _VirtualDom_diffNodes(x, y, patches, index, diffKids)\n{\n\t// Bail if obvious indicators have changed. Implies more serious\n\t// structural changes such that it's not worth it to diff.\n\tif (x.c !== y.c || x.f !== y.f)\n\t{\n\t\t_VirtualDom_pushPatch(patches, 0, index, y);\n\t\treturn;\n\t}\n\n\tvar factsDiff = _VirtualDom_diffFacts(x.d, y.d);\n\tfactsDiff && _VirtualDom_pushPatch(patches, 4, index, factsDiff);\n\n\tdiffKids(x, y, patches, index);\n}\n\n\n\n// DIFF FACTS\n\n\n// TODO Instead of creating a new diff object, it's possible to just test if\n// there *is* a diff. During the actual patch, do the diff again and make the\n// modifications directly. This way, there's no new allocations. Worth it?\nfunction _VirtualDom_diffFacts(x, y, category)\n{\n\tvar diff;\n\n\t// look for changes and removals\n\tfor (var xKey in x)\n\t{\n\t\tif (xKey === 'a1' || xKey === 'a0' || xKey === 'a3' || xKey === 'a4')\n\t\t{\n\t\t\tvar subDiff = _VirtualDom_diffFacts(x[xKey], y[xKey] || {}, xKey);\n\t\t\tif (subDiff)\n\t\t\t{\n\t\t\t\tdiff = diff || {};\n\t\t\t\tdiff[xKey] = subDiff;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// remove if not in the new facts\n\t\tif (!(xKey in y))\n\t\t{\n\t\t\tdiff = diff || {};\n\t\t\tdiff[xKey] =\n\t\t\t\t!category\n\t\t\t\t\t? (typeof x[xKey] === 'string' ? '' : null)\n\t\t\t\t\t:\n\t\t\t\t(category === 'a1')\n\t\t\t\t\t? ''\n\t\t\t\t\t:\n\t\t\t\t(category === 'a0' || category === 'a3')\n\t\t\t\t\t? undefined\n\t\t\t\t\t:\n\t\t\t\t{ f: x[xKey].f, o: undefined };\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tvar xValue = x[xKey];\n\t\tvar yValue = y[xKey];\n\n\t\t// reference equal, so don't worry about it\n\t\tif (xValue === yValue && xKey !== 'value' && xKey !== 'checked'\n\t\t\t|| category === 'a0' && _VirtualDom_equalEvents(xValue, yValue))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tdiff = diff || {};\n\t\tdiff[xKey] = yValue;\n\t}\n\n\t// add new stuff\n\tfor (var yKey in y)\n\t{\n\t\tif (!(yKey in x))\n\t\t{\n\t\t\tdiff = diff || {};\n\t\t\tdiff[yKey] = y[yKey];\n\t\t}\n\t}\n\n\treturn diff;\n}\n\n\n\n// DIFF KIDS\n\n\nfunction _VirtualDom_diffKids(xParent, yParent, patches, index)\n{\n\tvar xKids = xParent.e;\n\tvar yKids = yParent.e;\n\n\tvar xLen = xKids.length;\n\tvar yLen = yKids.length;\n\n\t// FIGURE OUT IF THERE ARE INSERTS OR REMOVALS\n\n\tif (xLen > yLen)\n\t{\n\t\t_VirtualDom_pushPatch(patches, 6, index, {\n\t\t\tv: yLen,\n\t\t\ti: xLen - yLen\n\t\t});\n\t}\n\telse if (xLen < yLen)\n\t{\n\t\t_VirtualDom_pushPatch(patches, 7, index, {\n\t\t\tv: xLen,\n\t\t\te: yKids\n\t\t});\n\t}\n\n\t// PAIRWISE DIFF EVERYTHING ELSE\n\n\tfor (var minLen = xLen < yLen ? xLen : yLen, i = 0; i < minLen; i++)\n\t{\n\t\tvar xKid = xKids[i];\n\t\t_VirtualDom_diffHelp(xKid, yKids[i], patches, ++index);\n\t\tindex += xKid.b || 0;\n\t}\n}\n\n\n\n// KEYED DIFF\n\n\nfunction _VirtualDom_diffKeyedKids(xParent, yParent, patches, rootIndex)\n{\n\tvar localPatches = [];\n\n\tvar changes = {}; // Dict String Entry\n\tvar inserts = []; // Array { index : Int, entry : Entry }\n\t// type Entry = { tag : String, vnode : VNode, index : Int, data : _ }\n\n\tvar xKids = xParent.e;\n\tvar yKids = yParent.e;\n\tvar xLen = xKids.length;\n\tvar yLen = yKids.length;\n\tvar xIndex = 0;\n\tvar yIndex = 0;\n\n\tvar index = rootIndex;\n\n\twhile (xIndex < xLen && yIndex < yLen)\n\t{\n\t\tvar x = xKids[xIndex];\n\t\tvar y = yKids[yIndex];\n\n\t\tvar xKey = x.a;\n\t\tvar yKey = y.a;\n\t\tvar xNode = x.b;\n\t\tvar yNode = y.b;\n\n\t\tvar newMatch = undefined;\n\t\tvar oldMatch = undefined;\n\n\t\t// check if keys match\n\n\t\tif (xKey === yKey)\n\t\t{\n\t\t\tindex++;\n\t\t\t_VirtualDom_diffHelp(xNode, yNode, localPatches, index);\n\t\t\tindex += xNode.b || 0;\n\n\t\t\txIndex++;\n\t\t\tyIndex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// look ahead 1 to detect insertions and removals.\n\n\t\tvar xNext = xKids[xIndex + 1];\n\t\tvar yNext = yKids[yIndex + 1];\n\n\t\tif (xNext)\n\t\t{\n\t\t\tvar xNextKey = xNext.a;\n\t\t\tvar xNextNode = xNext.b;\n\t\t\toldMatch = yKey === xNextKey;\n\t\t}\n\n\t\tif (yNext)\n\t\t{\n\t\t\tvar yNextKey = yNext.a;\n\t\t\tvar yNextNode = yNext.b;\n\t\t\tnewMatch = xKey === yNextKey;\n\t\t}\n\n\n\t\t// swap x and y\n\t\tif (newMatch && oldMatch)\n\t\t{\n\t\t\tindex++;\n\t\t\t_VirtualDom_diffHelp(xNode, yNextNode, localPatches, index);\n\t\t\t_VirtualDom_insertNode(changes, localPatches, xKey, yNode, yIndex, inserts);\n\t\t\tindex += xNode.b || 0;\n\n\t\t\tindex++;\n\t\t\t_VirtualDom_removeNode(changes, localPatches, xKey, xNextNode, index);\n\t\t\tindex += xNextNode.b || 0;\n\n\t\t\txIndex += 2;\n\t\t\tyIndex += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// insert y\n\t\tif (newMatch)\n\t\t{\n\t\t\tindex++;\n\t\t\t_VirtualDom_insertNode(changes, localPatches, yKey, yNode, yIndex, inserts);\n\t\t\t_VirtualDom_diffHelp(xNode, yNextNode, localPatches, index);\n\t\t\tindex += xNode.b || 0;\n\n\t\t\txIndex += 1;\n\t\t\tyIndex += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// remove x\n\t\tif (oldMatch)\n\t\t{\n\t\t\tindex++;\n\t\t\t_VirtualDom_removeNode(changes, localPatches, xKey, xNode, index);\n\t\t\tindex += xNode.b || 0;\n\n\t\t\tindex++;\n\t\t\t_VirtualDom_diffHelp(xNextNode, yNode, localPatches, index);\n\t\t\tindex += xNextNode.b || 0;\n\n\t\t\txIndex += 2;\n\t\t\tyIndex += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// remove x, insert y\n\t\tif (xNext && xNextKey === yNextKey)\n\t\t{\n\t\t\tindex++;\n\t\t\t_VirtualDom_removeNode(changes, localPatches, xKey, xNode, index);\n\t\t\t_VirtualDom_insertNode(changes, localPatches, yKey, yNode, yIndex, inserts);\n\t\t\tindex += xNode.b || 0;\n\n\t\t\tindex++;\n\t\t\t_VirtualDom_diffHelp(xNextNode, yNextNode, localPatches, index);\n\t\t\tindex += xNextNode.b || 0;\n\n\t\t\txIndex += 2;\n\t\t\tyIndex += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\tbreak;\n\t}\n\n\t// eat up any remaining nodes with removeNode and insertNode\n\n\twhile (xIndex < xLen)\n\t{\n\t\tindex++;\n\t\tvar x = xKids[xIndex];\n\t\tvar xNode = x.b;\n\t\t_VirtualDom_removeNode(changes, localPatches, x.a, xNode, index);\n\t\tindex += xNode.b || 0;\n\t\txIndex++;\n\t}\n\n\twhile (yIndex < yLen)\n\t{\n\t\tvar endInserts = endInserts || [];\n\t\tvar y = yKids[yIndex];\n\t\t_VirtualDom_insertNode(changes, localPatches, y.a, y.b, undefined, endInserts);\n\t\tyIndex++;\n\t}\n\n\tif (localPatches.length > 0 || inserts.length > 0 || endInserts)\n\t{\n\t\t_VirtualDom_pushPatch(patches, 8, rootIndex, {\n\t\t\tw: localPatches,\n\t\t\tx: inserts,\n\t\t\ty: endInserts\n\t\t});\n\t}\n}\n\n\n\n// CHANGES FROM KEYED DIFF\n\n\nvar _VirtualDom_POSTFIX = '_elmW6BL';\n\n\nfunction _VirtualDom_insertNode(changes, localPatches, key, vnode, yIndex, inserts)\n{\n\tvar entry = changes[key];\n\n\t// never seen this key before\n\tif (!entry)\n\t{\n\t\tentry = {\n\t\t\tc: 0,\n\t\t\tz: vnode,\n\t\t\tr: yIndex,\n\t\t\ts: undefined\n\t\t};\n\n\t\tinserts.push({ r: yIndex, A: entry });\n\t\tchanges[key] = entry;\n\n\t\treturn;\n\t}\n\n\t// this key was removed earlier, a match!\n\tif (entry.c === 1)\n\t{\n\t\tinserts.push({ r: yIndex, A: entry });\n\n\t\tentry.c = 2;\n\t\tvar subPatches = [];\n\t\t_VirtualDom_diffHelp(entry.z, vnode, subPatches, entry.r);\n\t\tentry.r = yIndex;\n\t\tentry.s.s = {\n\t\t\tw: subPatches,\n\t\t\tA: entry\n\t\t};\n\n\t\treturn;\n\t}\n\n\t// this key has already been inserted or moved, a duplicate!\n\t_VirtualDom_insertNode(changes, localPatches, key + _VirtualDom_POSTFIX, vnode, yIndex, inserts);\n}\n\n\nfunction _VirtualDom_removeNode(changes, localPatches, key, vnode, index)\n{\n\tvar entry = changes[key];\n\n\t// never seen this key before\n\tif (!entry)\n\t{\n\t\tvar patch = _VirtualDom_pushPatch(localPatches, 9, index, undefined);\n\n\t\tchanges[key] = {\n\t\t\tc: 1,\n\t\t\tz: vnode,\n\t\t\tr: index,\n\t\t\ts: patch\n\t\t};\n\n\t\treturn;\n\t}\n\n\t// this key was inserted earlier, a match!\n\tif (entry.c === 0)\n\t{\n\t\tentry.c = 2;\n\t\tvar subPatches = [];\n\t\t_VirtualDom_diffHelp(vnode, entry.z, subPatches, index);\n\n\t\t_VirtualDom_pushPatch(localPatches, 9, index, {\n\t\t\tw: subPatches,\n\t\t\tA: entry\n\t\t});\n\n\t\treturn;\n\t}\n\n\t// this key has already been removed or moved, a duplicate!\n\t_VirtualDom_removeNode(changes, localPatches, key + _VirtualDom_POSTFIX, vnode, index);\n}\n\n\n\n// ADD DOM NODES\n//\n// Each DOM node has an \"index\" assigned in order of traversal. It is important\n// to minimize our crawl over the actual DOM, so these indexes (along with the\n// descendantsCount of virtual nodes) let us skip touching entire subtrees of\n// the DOM if we know there are no patches there.\n\n\nfunction _VirtualDom_addDomNodes(domNode, vNode, patches, eventNode)\n{\n\t_VirtualDom_addDomNodesHelp(domNode, vNode, patches, 0, 0, vNode.b, eventNode);\n}\n\n\n// assumes `patches` is non-empty and indexes increase monotonically.\nfunction _VirtualDom_addDomNodesHelp(domNode, vNode, patches, i, low, high, eventNode)\n{\n\tvar patch = patches[i];\n\tvar index = patch.r;\n\n\twhile (index === low)\n\t{\n\t\tvar patchType = patch.$;\n\n\t\tif (patchType === 1)\n\t\t{\n\t\t\t_VirtualDom_addDomNodes(domNode, vNode.k, patch.s, eventNode);\n\t\t}\n\t\telse if (patchType === 8)\n\t\t{\n\t\t\tpatch.t = domNode;\n\t\t\tpatch.u = eventNode;\n\n\t\t\tvar subPatches = patch.s.w;\n\t\t\tif (subPatches.length > 0)\n\t\t\t{\n\t\t\t\t_VirtualDom_addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode);\n\t\t\t}\n\t\t}\n\t\telse if (patchType === 9)\n\t\t{\n\t\t\tpatch.t = domNode;\n\t\t\tpatch.u = eventNode;\n\n\t\t\tvar data = patch.s;\n\t\t\tif (data)\n\t\t\t{\n\t\t\t\tdata.A.s = domNode;\n\t\t\t\tvar subPatches = data.w;\n\t\t\t\tif (subPatches.length > 0)\n\t\t\t\t{\n\t\t\t\t\t_VirtualDom_addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpatch.t = domNode;\n\t\t\tpatch.u = eventNode;\n\t\t}\n\n\t\ti++;\n\n\t\tif (!(patch = patches[i]) || (index = patch.r) > high)\n\t\t{\n\t\t\treturn i;\n\t\t}\n\t}\n\n\tvar tag = vNode.$;\n\n\tif (tag === 4)\n\t{\n\t\tvar subNode = vNode.k;\n\n\t\twhile (subNode.$ === 4)\n\t\t{\n\t\t\tsubNode = subNode.k;\n\t\t}\n\n\t\treturn _VirtualDom_addDomNodesHelp(domNode, subNode, patches, i, low + 1, high, domNode.elm_event_node_ref);\n\t}\n\n\t// tag must be 1 or 2 at this point\n\n\tvar vKids = vNode.e;\n\tvar childNodes = domNode.childNodes;\n\tfor (var j = 0; j < vKids.length; j++)\n\t{\n\t\tlow++;\n\t\tvar vKid = tag === 1 ? vKids[j] : vKids[j].b;\n\t\tvar nextLow = low + (vKid.b || 0);\n\t\tif (low <= index && index <= nextLow)\n\t\t{\n\t\t\ti = _VirtualDom_addDomNodesHelp(childNodes[j], vKid, patches, i, low, nextLow, eventNode);\n\t\t\tif (!(patch = patches[i]) || (index = patch.r) > high)\n\t\t\t{\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\tlow = nextLow;\n\t}\n\treturn i;\n}\n\n\n\n// APPLY PATCHES\n\n\nfunction _VirtualDom_applyPatches(rootDomNode, oldVirtualNode, patches, eventNode)\n{\n\tif (patches.length === 0)\n\t{\n\t\treturn rootDomNode;\n\t}\n\n\t_VirtualDom_addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode);\n\treturn _VirtualDom_applyPatchesHelp(rootDomNode, patches);\n}\n\nfunction _VirtualDom_applyPatchesHelp(rootDomNode, patches)\n{\n\tfor (var i = 0; i < patches.length; i++)\n\t{\n\t\tvar patch = patches[i];\n\t\tvar localDomNode = patch.t\n\t\tvar newNode = _VirtualDom_applyPatch(localDomNode, patch);\n\t\tif (localDomNode === rootDomNode)\n\t\t{\n\t\t\trootDomNode = newNode;\n\t\t}\n\t}\n\treturn rootDomNode;\n}\n\nfunction _VirtualDom_applyPatch(domNode, patch)\n{\n\tswitch (patch.$)\n\t{\n\t\tcase 0:\n\t\t\treturn _VirtualDom_applyPatchRedraw(domNode, patch.s, patch.u);\n\n\t\tcase 4:\n\t\t\t_VirtualDom_applyFacts(domNode, patch.u, patch.s);\n\t\t\treturn domNode;\n\n\t\tcase 3:\n\t\t\tdomNode.replaceData(0, domNode.length, patch.s);\n\t\t\treturn domNode;\n\n\t\tcase 1:\n\t\t\treturn _VirtualDom_applyPatchesHelp(domNode, patch.s);\n\n\t\tcase 2:\n\t\t\tif (domNode.elm_event_node_ref)\n\t\t\t{\n\t\t\t\tdomNode.elm_event_node_ref.j = patch.s;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdomNode.elm_event_node_ref = { j: patch.s, p: patch.u };\n\t\t\t}\n\t\t\treturn domNode;\n\n\t\tcase 6:\n\t\t\tvar data = patch.s;\n\t\t\tfor (var i = 0; i < data.i; i++)\n\t\t\t{\n\t\t\t\tdomNode.removeChild(domNode.childNodes[data.v]);\n\t\t\t}\n\t\t\treturn domNode;\n\n\t\tcase 7:\n\t\t\tvar data = patch.s;\n\t\t\tvar kids = data.e;\n\t\t\tvar i = data.v;\n\t\t\tvar theEnd = domNode.childNodes[i];\n\t\t\tfor (; i < kids.length; i++)\n\t\t\t{\n\t\t\t\tdomNode.insertBefore(_VirtualDom_render(kids[i], patch.u), theEnd);\n\t\t\t}\n\t\t\treturn domNode;\n\n\t\tcase 9:\n\t\t\tvar data = patch.s;\n\t\t\tif (!data)\n\t\t\t{\n\t\t\t\tdomNode.parentNode.removeChild(domNode);\n\t\t\t\treturn domNode;\n\t\t\t}\n\t\t\tvar entry = data.A;\n\t\t\tif (typeof entry.r !== 'undefined')\n\t\t\t{\n\t\t\t\tdomNode.parentNode.removeChild(domNode);\n\t\t\t}\n\t\t\tentry.s = _VirtualDom_applyPatchesHelp(domNode, data.w);\n\t\t\treturn domNode;\n\n\t\tcase 8:\n\t\t\treturn _VirtualDom_applyPatchReorder(domNode, patch);\n\n\t\tcase 5:\n\t\t\treturn patch.s(domNode);\n\n\t\tdefault:\n\t\t\t_Debug_crash(10); // 'Ran into an unknown patch!'\n\t}\n}\n\n\nfunction _VirtualDom_applyPatchRedraw(domNode, vNode, eventNode)\n{\n\tvar parentNode = domNode.parentNode;\n\tvar newNode = _VirtualDom_render(vNode, eventNode);\n\n\tif (!newNode.elm_event_node_ref)\n\t{\n\t\tnewNode.elm_event_node_ref = domNode.elm_event_node_ref;\n\t}\n\n\tif (parentNode && newNode !== domNode)\n\t{\n\t\tparentNode.replaceChild(newNode, domNode);\n\t}\n\treturn newNode;\n}\n\n\nfunction _VirtualDom_applyPatchReorder(domNode, patch)\n{\n\tvar data = patch.s;\n\n\t// remove end inserts\n\tvar frag = _VirtualDom_applyPatchReorderEndInsertsHelp(data.y, patch);\n\n\t// removals\n\tdomNode = _VirtualDom_applyPatchesHelp(domNode, data.w);\n\n\t// inserts\n\tvar inserts = data.x;\n\tfor (var i = 0; i < inserts.length; i++)\n\t{\n\t\tvar insert = inserts[i];\n\t\tvar entry = insert.A;\n\t\tvar node = entry.c === 2\n\t\t\t? entry.s\n\t\t\t: _VirtualDom_render(entry.z, patch.u);\n\t\tdomNode.insertBefore(node, domNode.childNodes[insert.r]);\n\t}\n\n\t// add end inserts\n\tif (frag)\n\t{\n\t\t_VirtualDom_appendChild(domNode, frag);\n\t}\n\n\treturn domNode;\n}\n\n\nfunction _VirtualDom_applyPatchReorderEndInsertsHelp(endInserts, patch)\n{\n\tif (!endInserts)\n\t{\n\t\treturn;\n\t}\n\n\tvar frag = _VirtualDom_doc.createDocumentFragment();\n\tfor (var i = 0; i < endInserts.length; i++)\n\t{\n\t\tvar insert = endInserts[i];\n\t\tvar entry = insert.A;\n\t\t_VirtualDom_appendChild(frag, entry.c === 2\n\t\t\t? entry.s\n\t\t\t: _VirtualDom_render(entry.z, patch.u)\n\t\t);\n\t}\n\treturn frag;\n}\n\n\nfunction _VirtualDom_virtualize(node)\n{\n\t// TEXT NODES\n\n\tif (node.nodeType === 3)\n\t{\n\t\treturn _VirtualDom_text(node.textContent);\n\t}\n\n\n\t// WEIRD NODES\n\n\tif (node.nodeType !== 1)\n\t{\n\t\treturn _VirtualDom_text('');\n\t}\n\n\n\t// ELEMENT NODES\n\n\tvar attrList = _List_Nil;\n\tvar attrs = node.attributes;\n\tfor (var i = attrs.length; i--; )\n\t{\n\t\tvar attr = attrs[i];\n\t\tvar name = attr.name;\n\t\tvar value = attr.value;\n\t\tattrList = _List_Cons( A2(_VirtualDom_attribute, name, value), attrList );\n\t}\n\n\tvar tag = node.tagName.toLowerCase();\n\tvar kidList = _List_Nil;\n\tvar kids = node.childNodes;\n\n\tfor (var i = kids.length; i--; )\n\t{\n\t\tkidList = _List_Cons(_VirtualDom_virtualize(kids[i]), kidList);\n\t}\n\treturn A3(_VirtualDom_node, tag, attrList, kidList);\n}\n\nfunction _VirtualDom_dekey(keyedNode)\n{\n\tvar keyedKids = keyedNode.e;\n\tvar len = keyedKids.length;\n\tvar kids = new Array(len);\n\tfor (var i = 0; i < len; i++)\n\t{\n\t\tkids[i] = keyedKids[i].b;\n\t}\n\n\treturn {\n\t\t$: 1,\n\t\tc: keyedNode.c,\n\t\td: keyedNode.d,\n\t\te: kids,\n\t\tf: keyedNode.f,\n\t\tb: keyedNode.b\n\t};\n}\n\n\n\n\n// ELEMENT\n\n\nvar _Debugger_element;\n\nvar _Browser_element = _Debugger_element || F4(function(impl, flagDecoder, debugMetadata, args)\n{\n\treturn _Platform_initialize(\n\t\tflagDecoder,\n\t\targs,\n\t\timpl.aB,\n\t\timpl.aJ,\n\t\timpl.aH,\n\t\tfunction(sendToApp, initialModel) {\n\t\t\tvar view = impl.aK;\n\t\t\t/**/\n\t\t\tvar domNode = args['node'];\n\t\t\t//*/\n\t\t\t/**_UNUSED/\n\t\t\tvar domNode = args && args['node'] ? args['node'] : _Debug_crash(0);\n\t\t\t//*/\n\t\t\tvar currNode = _VirtualDom_virtualize(domNode);\n\n\t\t\treturn _Browser_makeAnimator(initialModel, function(model)\n\t\t\t{\n\t\t\t\tvar nextNode = view(model);\n\t\t\t\tvar patches = _VirtualDom_diff(currNode, nextNode);\n\t\t\t\tdomNode = _VirtualDom_applyPatches(domNode, currNode, patches, sendToApp);\n\t\t\t\tcurrNode = nextNode;\n\t\t\t});\n\t\t}\n\t);\n});\n\n\n\n// DOCUMENT\n\n\nvar _Debugger_document;\n\nvar _Browser_document = _Debugger_document || F4(function(impl, flagDecoder, debugMetadata, args)\n{\n\treturn _Platform_initialize(\n\t\tflagDecoder,\n\t\targs,\n\t\timpl.aB,\n\t\timpl.aJ,\n\t\timpl.aH,\n\t\tfunction(sendToApp, initialModel) {\n\t\t\tvar divertHrefToApp = impl.P && impl.P(sendToApp)\n\t\t\tvar view = impl.aK;\n\t\t\tvar title = _VirtualDom_doc.title;\n\t\t\tvar bodyNode = _VirtualDom_doc.body;\n\t\t\tvar currNode = _VirtualDom_virtualize(bodyNode);\n\t\t\treturn _Browser_makeAnimator(initialModel, function(model)\n\t\t\t{\n\t\t\t\t_VirtualDom_divertHrefToApp = divertHrefToApp;\n\t\t\t\tvar doc = view(model);\n\t\t\t\tvar nextNode = _VirtualDom_node('body')(_List_Nil)(doc.au);\n\t\t\t\tvar patches = _VirtualDom_diff(currNode, nextNode);\n\t\t\t\tbodyNode = _VirtualDom_applyPatches(bodyNode, currNode, patches, sendToApp);\n\t\t\t\tcurrNode = nextNode;\n\t\t\t\t_VirtualDom_divertHrefToApp = 0;\n\t\t\t\t(title !== doc.aI) && (_VirtualDom_doc.title = title = doc.aI);\n\t\t\t});\n\t\t}\n\t);\n});\n\n\n\n// ANIMATION\n\n\nvar _Browser_cancelAnimationFrame =\n\ttypeof cancelAnimationFrame !== 'undefined'\n\t\t? cancelAnimationFrame\n\t\t: function(id) { clearTimeout(id); };\n\nvar _Browser_requestAnimationFrame =\n\ttypeof requestAnimationFrame !== 'undefined'\n\t\t? requestAnimationFrame\n\t\t: function(callback) { return setTimeout(callback, 1000 / 60); };\n\n\nfunction _Browser_makeAnimator(model, draw)\n{\n\tdraw(model);\n\n\tvar state = 0;\n\n\tfunction updateIfNeeded()\n\t{\n\t\tstate = state === 1\n\t\t\t? 0\n\t\t\t: ( _Browser_requestAnimationFrame(updateIfNeeded), draw(model), 1 );\n\t}\n\n\treturn function(nextModel, isSync)\n\t{\n\t\tmodel = nextModel;\n\n\t\tisSync\n\t\t\t? ( draw(model),\n\t\t\t\tstate === 2 && (state = 1)\n\t\t\t\t)\n\t\t\t: ( state === 0 && _Browser_requestAnimationFrame(updateIfNeeded),\n\t\t\t\tstate = 2\n\t\t\t\t);\n\t};\n}\n\n\n\n// APPLICATION\n\n\nfunction _Browser_application(impl)\n{\n\tvar onUrlChange = impl.aD;\n\tvar onUrlRequest = impl.aE;\n\tvar key = function() { key.a(onUrlChange(_Browser_getUrl())); };\n\n\treturn _Browser_document({\n\t\tP: function(sendToApp)\n\t\t{\n\t\t\tkey.a = sendToApp;\n\t\t\t_Browser_window.addEventListener('popstate', key);\n\t\t\t_Browser_window.navigator.userAgent.indexOf('Trident') < 0 || _Browser_window.addEventListener('hashchange', key);\n\n\t\t\treturn F2(function(domNode, event)\n\t\t\t{\n\t\t\t\tif (!event.ctrlKey && !event.metaKey && !event.shiftKey && event.button < 1 && !domNode.target && !domNode.hasAttribute('download'))\n\t\t\t\t{\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tvar href = domNode.href;\n\t\t\t\t\tvar curr = _Browser_getUrl();\n\t\t\t\t\tvar next = $elm$url$Url$fromString(href).a;\n\t\t\t\t\tsendToApp(onUrlRequest(\n\t\t\t\t\t\t(next\n\t\t\t\t\t\t\t&& curr.ah === next.ah\n\t\t\t\t\t\t\t&& curr.Z === next.Z\n\t\t\t\t\t\t\t&& curr.ae.a === next.ae.a\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\t? $elm$browser$Browser$Internal(next)\n\t\t\t\t\t\t\t: $elm$browser$Browser$External(href)\n\t\t\t\t\t));\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\taB: function(flags)\n\t\t{\n\t\t\treturn A3(impl.aB, flags, _Browser_getUrl(), key);\n\t\t},\n\t\taK: impl.aK,\n\t\taJ: impl.aJ,\n\t\taH: impl.aH\n\t});\n}\n\nfunction _Browser_getUrl()\n{\n\treturn $elm$url$Url$fromString(_VirtualDom_doc.location.href).a || _Debug_crash(1);\n}\n\nvar _Browser_go = F2(function(key, n)\n{\n\treturn A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function() {\n\t\tn && history.go(n);\n\t\tkey();\n\t}));\n});\n\nvar _Browser_pushUrl = F2(function(key, url)\n{\n\treturn A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function() {\n\t\thistory.pushState({}, '', url);\n\t\tkey();\n\t}));\n});\n\nvar _Browser_replaceUrl = F2(function(key, url)\n{\n\treturn A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function() {\n\t\thistory.replaceState({}, '', url);\n\t\tkey();\n\t}));\n});\n\n\n\n// GLOBAL EVENTS\n\n\nvar _Browser_fakeNode = { addEventListener: function() {}, removeEventListener: function() {} };\nvar _Browser_doc = typeof document !== 'undefined' ? document : _Browser_fakeNode;\nvar _Browser_window = typeof window !== 'undefined' ? window : _Browser_fakeNode;\n\nvar _Browser_on = F3(function(node, eventName, sendToSelf)\n{\n\treturn _Scheduler_spawn(_Scheduler_binding(function(callback)\n\t{\n\t\tfunction handler(event)\t{ _Scheduler_rawSpawn(sendToSelf(event)); }\n\t\tnode.addEventListener(eventName, handler, _VirtualDom_passiveSupported && { passive: true });\n\t\treturn function() { node.removeEventListener(eventName, handler); };\n\t}));\n});\n\nvar _Browser_decodeEvent = F2(function(decoder, event)\n{\n\tvar result = _Json_runHelp(decoder, event);\n\treturn $elm$core$Result$isOk(result) ? $elm$core$Maybe$Just(result.a) : $elm$core$Maybe$Nothing;\n});\n\n\n\n// PAGE VISIBILITY\n\n\nfunction _Browser_visibilityInfo()\n{\n\treturn (typeof _VirtualDom_doc.hidden !== 'undefined')\n\t\t? { az: 'hidden', av: 'visibilitychange' }\n\t\t:\n\t(typeof _VirtualDom_doc.mozHidden !== 'undefined')\n\t\t? { az: 'mozHidden', av: 'mozvisibilitychange' }\n\t\t:\n\t(typeof _VirtualDom_doc.msHidden !== 'undefined')\n\t\t? { az: 'msHidden', av: 'msvisibilitychange' }\n\t\t:\n\t(typeof _VirtualDom_doc.webkitHidden !== 'undefined')\n\t\t? { az: 'webkitHidden', av: 'webkitvisibilitychange' }\n\t\t: { az: 'hidden', av: 'visibilitychange' };\n}\n\n\n\n// ANIMATION FRAMES\n\n\nfunction _Browser_rAF()\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\tvar id = _Browser_requestAnimationFrame(function() {\n\t\t\tcallback(_Scheduler_succeed(Date.now()));\n\t\t});\n\n\t\treturn function() {\n\t\t\t_Browser_cancelAnimationFrame(id);\n\t\t};\n\t});\n}\n\n\nfunction _Browser_now()\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\tcallback(_Scheduler_succeed(Date.now()));\n\t});\n}\n\n\n\n// DOM STUFF\n\n\nfunction _Browser_withNode(id, doStuff)\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\t_Browser_requestAnimationFrame(function() {\n\t\t\tvar node = document.getElementById(id);\n\t\t\tcallback(node\n\t\t\t\t? _Scheduler_succeed(doStuff(node))\n\t\t\t\t: _Scheduler_fail($elm$browser$Browser$Dom$NotFound(id))\n\t\t\t);\n\t\t});\n\t});\n}\n\n\nfunction _Browser_withWindow(doStuff)\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\t_Browser_requestAnimationFrame(function() {\n\t\t\tcallback(_Scheduler_succeed(doStuff()));\n\t\t});\n\t});\n}\n\n\n// FOCUS and BLUR\n\n\nvar _Browser_call = F2(function(functionName, id)\n{\n\treturn _Browser_withNode(id, function(node) {\n\t\tnode[functionName]();\n\t\treturn _Utils_Tuple0;\n\t});\n});\n\n\n\n// WINDOW VIEWPORT\n\n\nfunction _Browser_getViewport()\n{\n\treturn {\n\t\tal: _Browser_getScene(),\n\t\tao: {\n\t\t\taq: _Browser_window.pageXOffset,\n\t\t\tar: _Browser_window.pageYOffset,\n\t\t\tap: _Browser_doc.documentElement.clientWidth,\n\t\t\tY: _Browser_doc.documentElement.clientHeight\n\t\t}\n\t};\n}\n\nfunction _Browser_getScene()\n{\n\tvar body = _Browser_doc.body;\n\tvar elem = _Browser_doc.documentElement;\n\treturn {\n\t\tap: Math.max(body.scrollWidth, body.offsetWidth, elem.scrollWidth, elem.offsetWidth, elem.clientWidth),\n\t\tY: Math.max(body.scrollHeight, body.offsetHeight, elem.scrollHeight, elem.offsetHeight, elem.clientHeight)\n\t};\n}\n\nvar _Browser_setViewport = F2(function(x, y)\n{\n\treturn _Browser_withWindow(function()\n\t{\n\t\t_Browser_window.scroll(x, y);\n\t\treturn _Utils_Tuple0;\n\t});\n});\n\n\n\n// ELEMENT VIEWPORT\n\n\nfunction _Browser_getViewportOf(id)\n{\n\treturn _Browser_withNode(id, function(node)\n\t{\n\t\treturn {\n\t\t\tal: {\n\t\t\t\tap: node.scrollWidth,\n\t\t\t\tY: node.scrollHeight\n\t\t\t},\n\t\t\tao: {\n\t\t\t\taq: node.scrollLeft,\n\t\t\t\tar: node.scrollTop,\n\t\t\t\tap: node.clientWidth,\n\t\t\t\tY: node.clientHeight\n\t\t\t}\n\t\t};\n\t});\n}\n\n\nvar _Browser_setViewportOf = F3(function(id, x, y)\n{\n\treturn _Browser_withNode(id, function(node)\n\t{\n\t\tnode.scrollLeft = x;\n\t\tnode.scrollTop = y;\n\t\treturn _Utils_Tuple0;\n\t});\n});\n\n\n\n// ELEMENT\n\n\nfunction _Browser_getElement(id)\n{\n\treturn _Browser_withNode(id, function(node)\n\t{\n\t\tvar rect = node.getBoundingClientRect();\n\t\tvar x = _Browser_window.pageXOffset;\n\t\tvar y = _Browser_window.pageYOffset;\n\t\treturn {\n\t\t\tal: _Browser_getScene(),\n\t\t\tao: {\n\t\t\t\taq: x,\n\t\t\t\tar: y,\n\t\t\t\tap: _Browser_doc.documentElement.clientWidth,\n\t\t\t\tY: _Browser_doc.documentElement.clientHeight\n\t\t\t},\n\t\t\tax: {\n\t\t\t\taq: x + rect.left,\n\t\t\t\tar: y + rect.top,\n\t\t\t\tap: rect.width,\n\t\t\t\tY: rect.height\n\t\t\t}\n\t\t};\n\t});\n}\n\n\n\n// LOAD and RELOAD\n\n\nfunction _Browser_reload(skipCache)\n{\n\treturn A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function(callback)\n\t{\n\t\t_VirtualDom_doc.location.reload(skipCache);\n\t}));\n}\n\nfunction _Browser_load(url)\n{\n\treturn A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function(callback)\n\t{\n\t\ttry\n\t\t{\n\t\t\t_Browser_window.location = url;\n\t\t}\n\t\tcatch(err)\n\t\t{\n\t\t\t// Only Firefox can throw a NS_ERROR_MALFORMED_URI exception here.\n\t\t\t// Other browsers reload the page, so let's be consistent about that.\n\t\t\t_VirtualDom_doc.location.reload(false);\n\t\t}\n\t}));\n}\n\n\n\nvar _Bitwise_and = F2(function(a, b)\n{\n\treturn a & b;\n});\n\nvar _Bitwise_or = F2(function(a, b)\n{\n\treturn a | b;\n});\n\nvar _Bitwise_xor = F2(function(a, b)\n{\n\treturn a ^ b;\n});\n\nfunction _Bitwise_complement(a)\n{\n\treturn ~a;\n};\n\nvar _Bitwise_shiftLeftBy = F2(function(offset, a)\n{\n\treturn a << offset;\n});\n\nvar _Bitwise_shiftRightBy = F2(function(offset, a)\n{\n\treturn a >> offset;\n});\n\nvar _Bitwise_shiftRightZfBy = F2(function(offset, a)\n{\n\treturn a >>> offset;\n});\n\n\n\nfunction _Time_now(millisToPosix)\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\tcallback(_Scheduler_succeed(millisToPosix(Date.now())));\n\t});\n}\n\nvar _Time_setInterval = F2(function(interval, task)\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\tvar id = setInterval(function() { _Scheduler_rawSpawn(task); }, interval);\n\t\treturn function() { clearInterval(id); };\n\t});\n});\n\nfunction _Time_here()\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\tcallback(_Scheduler_succeed(\n\t\t\tA2($elm$time$Time$customZone, -(new Date().getTimezoneOffset()), _List_Nil)\n\t\t));\n\t});\n}\n\n\nfunction _Time_getZoneName()\n{\n\treturn _Scheduler_binding(function(callback)\n\t{\n\t\ttry\n\t\t{\n\t\t\tvar name = $elm$time$Time$Name(Intl.DateTimeFormat().resolvedOptions().timeZone);\n\t\t}\n\t\tcatch (e)\n\t\t{\n\t\t\tvar name = $elm$time$Time$Offset(new Date().getTimezoneOffset());\n\t\t}\n\t\tcallback(_Scheduler_succeed(name));\n\t});\n}\nvar $elm$core$Basics$EQ = 1;\nvar $elm$core$Basics$GT = 2;\nvar $elm$core$Basics$LT = 0;\nvar $elm$core$List$cons = _List_cons;\nvar $elm$core$Dict$foldr = F3(\n\tfunction (func, acc, t) {\n\t\tfoldr:\n\t\twhile (true) {\n\t\t\tif (t.$ === -2) {\n\t\t\t\treturn acc;\n\t\t\t} else {\n\t\t\t\tvar key = t.b;\n\t\t\t\tvar value = t.c;\n\t\t\t\tvar left = t.d;\n\t\t\t\tvar right = t.e;\n\t\t\t\tvar $temp$func = func,\n\t\t\t\t\t$temp$acc = A3(\n\t\t\t\t\tfunc,\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue,\n\t\t\t\t\tA3($elm$core$Dict$foldr, func, acc, right)),\n\t\t\t\t\t$temp$t = left;\n\t\t\t\tfunc = $temp$func;\n\t\t\t\tacc = $temp$acc;\n\t\t\t\tt = $temp$t;\n\t\t\t\tcontinue foldr;\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$Dict$toList = function (dict) {\n\treturn A3(\n\t\t$elm$core$Dict$foldr,\n\t\tF3(\n\t\t\tfunction (key, value, list) {\n\t\t\t\treturn A2(\n\t\t\t\t\t$elm$core$List$cons,\n\t\t\t\t\t_Utils_Tuple2(key, value),\n\t\t\t\t\tlist);\n\t\t\t}),\n\t\t_List_Nil,\n\t\tdict);\n};\nvar $elm$core$Dict$keys = function (dict) {\n\treturn A3(\n\t\t$elm$core$Dict$foldr,\n\t\tF3(\n\t\t\tfunction (key, value, keyList) {\n\t\t\t\treturn A2($elm$core$List$cons, key, keyList);\n\t\t\t}),\n\t\t_List_Nil,\n\t\tdict);\n};\nvar $elm$core$Set$toList = function (_v0) {\n\tvar dict = _v0;\n\treturn $elm$core$Dict$keys(dict);\n};\nvar $elm$core$Elm$JsArray$foldr = _JsArray_foldr;\nvar $elm$core$Array$foldr = F3(\n\tfunction (func, baseCase, _v0) {\n\t\tvar tree = _v0.c;\n\t\tvar tail = _v0.d;\n\t\tvar helper = F2(\n\t\t\tfunction (node, acc) {\n\t\t\t\tif (!node.$) {\n\t\t\t\t\tvar subTree = node.a;\n\t\t\t\t\treturn A3($elm$core$Elm$JsArray$foldr, helper, acc, subTree);\n\t\t\t\t} else {\n\t\t\t\t\tvar values = node.a;\n\t\t\t\t\treturn A3($elm$core$Elm$JsArray$foldr, func, acc, values);\n\t\t\t\t}\n\t\t\t});\n\t\treturn A3(\n\t\t\t$elm$core$Elm$JsArray$foldr,\n\t\t\thelper,\n\t\t\tA3($elm$core$Elm$JsArray$foldr, func, baseCase, tail),\n\t\t\ttree);\n\t});\nvar $elm$core$Array$toList = function (array) {\n\treturn A3($elm$core$Array$foldr, $elm$core$List$cons, _List_Nil, array);\n};\nvar $elm$core$Result$Err = function (a) {\n\treturn {$: 1, a: a};\n};\nvar $elm$json$Json$Decode$Failure = F2(\n\tfunction (a, b) {\n\t\treturn {$: 3, a: a, b: b};\n\t});\nvar $elm$json$Json$Decode$Field = F2(\n\tfunction (a, b) {\n\t\treturn {$: 0, a: a, b: b};\n\t});\nvar $elm$json$Json$Decode$Index = F2(\n\tfunction (a, b) {\n\t\treturn {$: 1, a: a, b: b};\n\t});\nvar $elm$core$Result$Ok = function (a) {\n\treturn {$: 0, a: a};\n};\nvar $elm$json$Json$Decode$OneOf = function (a) {\n\treturn {$: 2, a: a};\n};\nvar $elm$core$Basics$False = 1;\nvar $elm$core$Basics$add = _Basics_add;\nvar $elm$core$Maybe$Just = function (a) {\n\treturn {$: 0, a: a};\n};\nvar $elm$core$Maybe$Nothing = {$: 1};\nvar $elm$core$String$all = _String_all;\nvar $elm$core$Basics$and = _Basics_and;\nvar $elm$core$Basics$append = _Utils_append;\nvar $elm$json$Json$Encode$encode = _Json_encode;\nvar $elm$core$String$fromInt = _String_fromNumber;\nvar $elm$core$String$join = F2(\n\tfunction (sep, chunks) {\n\t\treturn A2(\n\t\t\t_String_join,\n\t\t\tsep,\n\t\t\t_List_toArray(chunks));\n\t});\nvar $elm$core$String$split = F2(\n\tfunction (sep, string) {\n\t\treturn _List_fromArray(\n\t\t\tA2(_String_split, sep, string));\n\t});\nvar $elm$json$Json$Decode$indent = function (str) {\n\treturn A2(\n\t\t$elm$core$String$join,\n\t\t'\\n    ',\n\t\tA2($elm$core$String$split, '\\n', str));\n};\nvar $elm$core$List$foldl = F3(\n\tfunction (func, acc, list) {\n\t\tfoldl:\n\t\twhile (true) {\n\t\t\tif (!list.b) {\n\t\t\t\treturn acc;\n\t\t\t} else {\n\t\t\t\tvar x = list.a;\n\t\t\t\tvar xs = list.b;\n\t\t\t\tvar $temp$func = func,\n\t\t\t\t\t$temp$acc = A2(func, x, acc),\n\t\t\t\t\t$temp$list = xs;\n\t\t\t\tfunc = $temp$func;\n\t\t\t\tacc = $temp$acc;\n\t\t\t\tlist = $temp$list;\n\t\t\t\tcontinue foldl;\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$List$length = function (xs) {\n\treturn A3(\n\t\t$elm$core$List$foldl,\n\t\tF2(\n\t\t\tfunction (_v0, i) {\n\t\t\t\treturn i + 1;\n\t\t\t}),\n\t\t0,\n\t\txs);\n};\nvar $elm$core$List$map2 = _List_map2;\nvar $elm$core$Basics$le = _Utils_le;\nvar $elm$core$Basics$sub = _Basics_sub;\nvar $elm$core$List$rangeHelp = F3(\n\tfunction (lo, hi, list) {\n\t\trangeHelp:\n\t\twhile (true) {\n\t\t\tif (_Utils_cmp(lo, hi) < 1) {\n\t\t\t\tvar $temp$lo = lo,\n\t\t\t\t\t$temp$hi = hi - 1,\n\t\t\t\t\t$temp$list = A2($elm$core$List$cons, hi, list);\n\t\t\t\tlo = $temp$lo;\n\t\t\t\thi = $temp$hi;\n\t\t\t\tlist = $temp$list;\n\t\t\t\tcontinue rangeHelp;\n\t\t\t} else {\n\t\t\t\treturn list;\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$List$range = F2(\n\tfunction (lo, hi) {\n\t\treturn A3($elm$core$List$rangeHelp, lo, hi, _List_Nil);\n\t});\nvar $elm$core$List$indexedMap = F2(\n\tfunction (f, xs) {\n\t\treturn A3(\n\t\t\t$elm$core$List$map2,\n\t\t\tf,\n\t\t\tA2(\n\t\t\t\t$elm$core$List$range,\n\t\t\t\t0,\n\t\t\t\t$elm$core$List$length(xs) - 1),\n\t\t\txs);\n\t});\nvar $elm$core$Char$toCode = _Char_toCode;\nvar $elm$core$Char$isLower = function (_char) {\n\tvar code = $elm$core$Char$toCode(_char);\n\treturn (97 <= code) && (code <= 122);\n};\nvar $elm$core$Char$isUpper = function (_char) {\n\tvar code = $elm$core$Char$toCode(_char);\n\treturn (code <= 90) && (65 <= code);\n};\nvar $elm$core$Basics$or = _Basics_or;\nvar $elm$core$Char$isAlpha = function (_char) {\n\treturn $elm$core$Char$isLower(_char) || $elm$core$Char$isUpper(_char);\n};\nvar $elm$core$Char$isDigit = function (_char) {\n\tvar code = $elm$core$Char$toCode(_char);\n\treturn (code <= 57) && (48 <= code);\n};\nvar $elm$core$Char$isAlphaNum = function (_char) {\n\treturn $elm$core$Char$isLower(_char) || ($elm$core$Char$isUpper(_char) || $elm$core$Char$isDigit(_char));\n};\nvar $elm$core$List$reverse = function (list) {\n\treturn A3($elm$core$List$foldl, $elm$core$List$cons, _List_Nil, list);\n};\nvar $elm$core$String$uncons = _String_uncons;\nvar $elm$json$Json$Decode$errorOneOf = F2(\n\tfunction (i, error) {\n\t\treturn '\\n\\n(' + ($elm$core$String$fromInt(i + 1) + (') ' + $elm$json$Json$Decode$indent(\n\t\t\t$elm$json$Json$Decode$errorToString(error))));\n\t});\nvar $elm$json$Json$Decode$errorToString = function (error) {\n\treturn A2($elm$json$Json$Decode$errorToStringHelp, error, _List_Nil);\n};\nvar $elm$json$Json$Decode$errorToStringHelp = F2(\n\tfunction (error, context) {\n\t\terrorToStringHelp:\n\t\twhile (true) {\n\t\t\tswitch (error.$) {\n\t\t\t\tcase 0:\n\t\t\t\t\tvar f = error.a;\n\t\t\t\t\tvar err = error.b;\n\t\t\t\t\tvar isSimple = function () {\n\t\t\t\t\t\tvar _v1 = $elm$core$String$uncons(f);\n\t\t\t\t\t\tif (_v1.$ === 1) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar _v2 = _v1.a;\n\t\t\t\t\t\t\tvar _char = _v2.a;\n\t\t\t\t\t\t\tvar rest = _v2.b;\n\t\t\t\t\t\t\treturn $elm$core$Char$isAlpha(_char) && A2($elm$core$String$all, $elm$core$Char$isAlphaNum, rest);\n\t\t\t\t\t\t}\n\t\t\t\t\t}();\n\t\t\t\t\tvar fieldName = isSimple ? ('.' + f) : ('[\\'' + (f + '\\']'));\n\t\t\t\t\tvar $temp$error = err,\n\t\t\t\t\t\t$temp$context = A2($elm$core$List$cons, fieldName, context);\n\t\t\t\t\terror = $temp$error;\n\t\t\t\t\tcontext = $temp$context;\n\t\t\t\t\tcontinue errorToStringHelp;\n\t\t\t\tcase 1:\n\t\t\t\t\tvar i = error.a;\n\t\t\t\t\tvar err = error.b;\n\t\t\t\t\tvar indexName = '[' + ($elm$core$String$fromInt(i) + ']');\n\t\t\t\t\tvar $temp$error = err,\n\t\t\t\t\t\t$temp$context = A2($elm$core$List$cons, indexName, context);\n\t\t\t\t\terror = $temp$error;\n\t\t\t\t\tcontext = $temp$context;\n\t\t\t\t\tcontinue errorToStringHelp;\n\t\t\t\tcase 2:\n\t\t\t\t\tvar errors = error.a;\n\t\t\t\t\tif (!errors.b) {\n\t\t\t\t\t\treturn 'Ran into a Json.Decode.oneOf with no possibilities' + function () {\n\t\t\t\t\t\t\tif (!context.b) {\n\t\t\t\t\t\t\t\treturn '!';\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn ' at json' + A2(\n\t\t\t\t\t\t\t\t\t$elm$core$String$join,\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t$elm$core$List$reverse(context));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (!errors.b.b) {\n\t\t\t\t\t\t\tvar err = errors.a;\n\t\t\t\t\t\t\tvar $temp$error = err,\n\t\t\t\t\t\t\t\t$temp$context = context;\n\t\t\t\t\t\t\terror = $temp$error;\n\t\t\t\t\t\t\tcontext = $temp$context;\n\t\t\t\t\t\t\tcontinue errorToStringHelp;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvar starter = function () {\n\t\t\t\t\t\t\t\tif (!context.b) {\n\t\t\t\t\t\t\t\t\treturn 'Json.Decode.oneOf';\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\treturn 'The Json.Decode.oneOf at json' + A2(\n\t\t\t\t\t\t\t\t\t\t$elm$core$String$join,\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t$elm$core$List$reverse(context));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}();\n\t\t\t\t\t\t\tvar introduction = starter + (' failed in the following ' + ($elm$core$String$fromInt(\n\t\t\t\t\t\t\t\t$elm$core$List$length(errors)) + ' ways:'));\n\t\t\t\t\t\t\treturn A2(\n\t\t\t\t\t\t\t\t$elm$core$String$join,\n\t\t\t\t\t\t\t\t'\\n\\n',\n\t\t\t\t\t\t\t\tA2(\n\t\t\t\t\t\t\t\t\t$elm$core$List$cons,\n\t\t\t\t\t\t\t\t\tintroduction,\n\t\t\t\t\t\t\t\t\tA2($elm$core$List$indexedMap, $elm$json$Json$Decode$errorOneOf, errors)));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tvar msg = error.a;\n\t\t\t\t\tvar json = error.b;\n\t\t\t\t\tvar introduction = function () {\n\t\t\t\t\t\tif (!context.b) {\n\t\t\t\t\t\t\treturn 'Problem with the given value:\\n\\n';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn 'Problem with the value at json' + (A2(\n\t\t\t\t\t\t\t\t$elm$core$String$join,\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t$elm$core$List$reverse(context)) + ':\\n\\n    ');\n\t\t\t\t\t\t}\n\t\t\t\t\t}();\n\t\t\t\t\treturn introduction + ($elm$json$Json$Decode$indent(\n\t\t\t\t\t\tA2($elm$json$Json$Encode$encode, 4, json)) + ('\\n\\n' + msg));\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$Array$branchFactor = 32;\nvar $elm$core$Array$Array_elm_builtin = F4(\n\tfunction (a, b, c, d) {\n\t\treturn {$: 0, a: a, b: b, c: c, d: d};\n\t});\nvar $elm$core$Elm$JsArray$empty = _JsArray_empty;\nvar $elm$core$Basics$ceiling = _Basics_ceiling;\nvar $elm$core$Basics$fdiv = _Basics_fdiv;\nvar $elm$core$Basics$logBase = F2(\n\tfunction (base, number) {\n\t\treturn _Basics_log(number) / _Basics_log(base);\n\t});\nvar $elm$core$Basics$toFloat = _Basics_toFloat;\nvar $elm$core$Array$shiftStep = $elm$core$Basics$ceiling(\n\tA2($elm$core$Basics$logBase, 2, $elm$core$Array$branchFactor));\nvar $elm$core$Array$empty = A4($elm$core$Array$Array_elm_builtin, 0, $elm$core$Array$shiftStep, $elm$core$Elm$JsArray$empty, $elm$core$Elm$JsArray$empty);\nvar $elm$core$Elm$JsArray$initialize = _JsArray_initialize;\nvar $elm$core$Array$Leaf = function (a) {\n\treturn {$: 1, a: a};\n};\nvar $elm$core$Basics$apL = F2(\n\tfunction (f, x) {\n\t\treturn f(x);\n\t});\nvar $elm$core$Basics$apR = F2(\n\tfunction (x, f) {\n\t\treturn f(x);\n\t});\nvar $elm$core$Basics$eq = _Utils_equal;\nvar $elm$core$Basics$floor = _Basics_floor;\nvar $elm$core$Elm$JsArray$length = _JsArray_length;\nvar $elm$core$Basics$gt = _Utils_gt;\nvar $elm$core$Basics$max = F2(\n\tfunction (x, y) {\n\t\treturn (_Utils_cmp(x, y) > 0) ? x : y;\n\t});\nvar $elm$core$Basics$mul = _Basics_mul;\nvar $elm$core$Array$SubTree = function (a) {\n\treturn {$: 0, a: a};\n};\nvar $elm$core$Elm$JsArray$initializeFromList = _JsArray_initializeFromList;\nvar $elm$core$Array$compressNodes = F2(\n\tfunction (nodes, acc) {\n\t\tcompressNodes:\n\t\twhile (true) {\n\t\t\tvar _v0 = A2($elm$core$Elm$JsArray$initializeFromList, $elm$core$Array$branchFactor, nodes);\n\t\t\tvar node = _v0.a;\n\t\t\tvar remainingNodes = _v0.b;\n\t\t\tvar newAcc = A2(\n\t\t\t\t$elm$core$List$cons,\n\t\t\t\t$elm$core$Array$SubTree(node),\n\t\t\t\tacc);\n\t\t\tif (!remainingNodes.b) {\n\t\t\t\treturn $elm$core$List$reverse(newAcc);\n\t\t\t} else {\n\t\t\t\tvar $temp$nodes = remainingNodes,\n\t\t\t\t\t$temp$acc = newAcc;\n\t\t\t\tnodes = $temp$nodes;\n\t\t\t\tacc = $temp$acc;\n\t\t\t\tcontinue compressNodes;\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$Tuple$first = function (_v0) {\n\tvar x = _v0.a;\n\treturn x;\n};\nvar $elm$core$Array$treeFromBuilder = F2(\n\tfunction (nodeList, nodeListSize) {\n\t\ttreeFromBuilder:\n\t\twhile (true) {\n\t\t\tvar newNodeSize = $elm$core$Basics$ceiling(nodeListSize / $elm$core$Array$branchFactor);\n\t\t\tif (newNodeSize === 1) {\n\t\t\t\treturn A2($elm$core$Elm$JsArray$initializeFromList, $elm$core$Array$branchFactor, nodeList).a;\n\t\t\t} else {\n\t\t\t\tvar $temp$nodeList = A2($elm$core$Array$compressNodes, nodeList, _List_Nil),\n\t\t\t\t\t$temp$nodeListSize = newNodeSize;\n\t\t\t\tnodeList = $temp$nodeList;\n\t\t\t\tnodeListSize = $temp$nodeListSize;\n\t\t\t\tcontinue treeFromBuilder;\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$Array$builderToArray = F2(\n\tfunction (reverseNodeList, builder) {\n\t\tif (!builder.b) {\n\t\t\treturn A4(\n\t\t\t\t$elm$core$Array$Array_elm_builtin,\n\t\t\t\t$elm$core$Elm$JsArray$length(builder.e),\n\t\t\t\t$elm$core$Array$shiftStep,\n\t\t\t\t$elm$core$Elm$JsArray$empty,\n\t\t\t\tbuilder.e);\n\t\t} else {\n\t\t\tvar treeLen = builder.b * $elm$core$Array$branchFactor;\n\t\t\tvar depth = $elm$core$Basics$floor(\n\t\t\t\tA2($elm$core$Basics$logBase, $elm$core$Array$branchFactor, treeLen - 1));\n\t\t\tvar correctNodeList = reverseNodeList ? $elm$core$List$reverse(builder.f) : builder.f;\n\t\t\tvar tree = A2($elm$core$Array$treeFromBuilder, correctNodeList, builder.b);\n\t\t\treturn A4(\n\t\t\t\t$elm$core$Array$Array_elm_builtin,\n\t\t\t\t$elm$core$Elm$JsArray$length(builder.e) + treeLen,\n\t\t\t\tA2($elm$core$Basics$max, 5, depth * $elm$core$Array$shiftStep),\n\t\t\t\ttree,\n\t\t\t\tbuilder.e);\n\t\t}\n\t});\nvar $elm$core$Basics$idiv = _Basics_idiv;\nvar $elm$core$Basics$lt = _Utils_lt;\nvar $elm$core$Array$initializeHelp = F5(\n\tfunction (fn, fromIndex, len, nodeList, tail) {\n\t\tinitializeHelp:\n\t\twhile (true) {\n\t\t\tif (fromIndex < 0) {\n\t\t\t\treturn A2(\n\t\t\t\t\t$elm$core$Array$builderToArray,\n\t\t\t\t\tfalse,\n\t\t\t\t\t{f: nodeList, b: (len / $elm$core$Array$branchFactor) | 0, e: tail});\n\t\t\t} else {\n\t\t\t\tvar leaf = $elm$core$Array$Leaf(\n\t\t\t\t\tA3($elm$core$Elm$JsArray$initialize, $elm$core$Array$branchFactor, fromIndex, fn));\n\t\t\t\tvar $temp$fn = fn,\n\t\t\t\t\t$temp$fromIndex = fromIndex - $elm$core$Array$branchFactor,\n\t\t\t\t\t$temp$len = len,\n\t\t\t\t\t$temp$nodeList = A2($elm$core$List$cons, leaf, nodeList),\n\t\t\t\t\t$temp$tail = tail;\n\t\t\t\tfn = $temp$fn;\n\t\t\t\tfromIndex = $temp$fromIndex;\n\t\t\t\tlen = $temp$len;\n\t\t\t\tnodeList = $temp$nodeList;\n\t\t\t\ttail = $temp$tail;\n\t\t\t\tcontinue initializeHelp;\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$Basics$remainderBy = _Basics_remainderBy;\nvar $elm$core$Array$initialize = F2(\n\tfunction (len, fn) {\n\t\tif (len <= 0) {\n\t\t\treturn $elm$core$Array$empty;\n\t\t} else {\n\t\t\tvar tailLen = len % $elm$core$Array$branchFactor;\n\t\t\tvar tail = A3($elm$core$Elm$JsArray$initialize, tailLen, len - tailLen, fn);\n\t\t\tvar initialFromIndex = (len - tailLen) - $elm$core$Array$branchFactor;\n\t\t\treturn A5($elm$core$Array$initializeHelp, fn, initialFromIndex, len, _List_Nil, tail);\n\t\t}\n\t});\nvar $elm$core$Basics$True = 0;\nvar $elm$core$Result$isOk = function (result) {\n\tif (!result.$) {\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n};\nvar $elm$json$Json$Decode$map = _Json_map1;\nvar $elm$json$Json$Decode$map2 = _Json_map2;\nvar $elm$json$Json$Decode$succeed = _Json_succeed;\nvar $elm$virtual_dom$VirtualDom$toHandlerInt = function (handler) {\n\tswitch (handler.$) {\n\t\tcase 0:\n\t\t\treturn 0;\n\t\tcase 1:\n\t\t\treturn 1;\n\t\tcase 2:\n\t\t\treturn 2;\n\t\tdefault:\n\t\t\treturn 3;\n\t}\n};\nvar $elm$browser$Browser$External = function (a) {\n\treturn {$: 1, a: a};\n};\nvar $elm$browser$Browser$Internal = function (a) {\n\treturn {$: 0, a: a};\n};\nvar $elm$core$Basics$identity = function (x) {\n\treturn x;\n};\nvar $elm$browser$Browser$Dom$NotFound = $elm$core$Basics$identity;\nvar $elm$url$Url$Http = 0;\nvar $elm$url$Url$Https = 1;\nvar $elm$url$Url$Url = F6(\n\tfunction (protocol, host, port_, path, query, fragment) {\n\t\treturn {X: fragment, Z: host, ac: path, ae: port_, ah: protocol, ai: query};\n\t});\nvar $elm$core$String$contains = _String_contains;\nvar $elm$core$String$length = _String_length;\nvar $elm$core$String$slice = _String_slice;\nvar $elm$core$String$dropLeft = F2(\n\tfunction (n, string) {\n\t\treturn (n < 1) ? string : A3(\n\t\t\t$elm$core$String$slice,\n\t\t\tn,\n\t\t\t$elm$core$String$length(string),\n\t\t\tstring);\n\t});\nvar $elm$core$String$indexes = _String_indexes;\nvar $elm$core$String$isEmpty = function (string) {\n\treturn string === '';\n};\nvar $elm$core$String$left = F2(\n\tfunction (n, string) {\n\t\treturn (n < 1) ? '' : A3($elm$core$String$slice, 0, n, string);\n\t});\nvar $elm$core$String$toInt = _String_toInt;\nvar $elm$url$Url$chompBeforePath = F5(\n\tfunction (protocol, path, params, frag, str) {\n\t\tif ($elm$core$String$isEmpty(str) || A2($elm$core$String$contains, '@', str)) {\n\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t} else {\n\t\t\tvar _v0 = A2($elm$core$String$indexes, ':', str);\n\t\t\tif (!_v0.b) {\n\t\t\t\treturn $elm$core$Maybe$Just(\n\t\t\t\t\tA6($elm$url$Url$Url, protocol, str, $elm$core$Maybe$Nothing, path, params, frag));\n\t\t\t} else {\n\t\t\t\tif (!_v0.b.b) {\n\t\t\t\t\tvar i = _v0.a;\n\t\t\t\t\tvar _v1 = $elm$core$String$toInt(\n\t\t\t\t\t\tA2($elm$core$String$dropLeft, i + 1, str));\n\t\t\t\t\tif (_v1.$ === 1) {\n\t\t\t\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar port_ = _v1;\n\t\t\t\t\t\treturn $elm$core$Maybe$Just(\n\t\t\t\t\t\t\tA6(\n\t\t\t\t\t\t\t\t$elm$url$Url$Url,\n\t\t\t\t\t\t\t\tprotocol,\n\t\t\t\t\t\t\t\tA2($elm$core$String$left, i, str),\n\t\t\t\t\t\t\t\tport_,\n\t\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t\t\tfrag));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\nvar $elm$url$Url$chompBeforeQuery = F4(\n\tfunction (protocol, params, frag, str) {\n\t\tif ($elm$core$String$isEmpty(str)) {\n\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t} else {\n\t\t\tvar _v0 = A2($elm$core$String$indexes, '/', str);\n\t\t\tif (!_v0.b) {\n\t\t\t\treturn A5($elm$url$Url$chompBeforePath, protocol, '/', params, frag, str);\n\t\t\t} else {\n\t\t\t\tvar i = _v0.a;\n\t\t\t\treturn A5(\n\t\t\t\t\t$elm$url$Url$chompBeforePath,\n\t\t\t\t\tprotocol,\n\t\t\t\t\tA2($elm$core$String$dropLeft, i, str),\n\t\t\t\t\tparams,\n\t\t\t\t\tfrag,\n\t\t\t\t\tA2($elm$core$String$left, i, str));\n\t\t\t}\n\t\t}\n\t});\nvar $elm$url$Url$chompBeforeFragment = F3(\n\tfunction (protocol, frag, str) {\n\t\tif ($elm$core$String$isEmpty(str)) {\n\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t} else {\n\t\t\tvar _v0 = A2($elm$core$String$indexes, '?', str);\n\t\t\tif (!_v0.b) {\n\t\t\t\treturn A4($elm$url$Url$chompBeforeQuery, protocol, $elm$core$Maybe$Nothing, frag, str);\n\t\t\t} else {\n\t\t\t\tvar i = _v0.a;\n\t\t\t\treturn A4(\n\t\t\t\t\t$elm$url$Url$chompBeforeQuery,\n\t\t\t\t\tprotocol,\n\t\t\t\t\t$elm$core$Maybe$Just(\n\t\t\t\t\t\tA2($elm$core$String$dropLeft, i + 1, str)),\n\t\t\t\t\tfrag,\n\t\t\t\t\tA2($elm$core$String$left, i, str));\n\t\t\t}\n\t\t}\n\t});\nvar $elm$url$Url$chompAfterProtocol = F2(\n\tfunction (protocol, str) {\n\t\tif ($elm$core$String$isEmpty(str)) {\n\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t} else {\n\t\t\tvar _v0 = A2($elm$core$String$indexes, '#', str);\n\t\t\tif (!_v0.b) {\n\t\t\t\treturn A3($elm$url$Url$chompBeforeFragment, protocol, $elm$core$Maybe$Nothing, str);\n\t\t\t} else {\n\t\t\t\tvar i = _v0.a;\n\t\t\t\treturn A3(\n\t\t\t\t\t$elm$url$Url$chompBeforeFragment,\n\t\t\t\t\tprotocol,\n\t\t\t\t\t$elm$core$Maybe$Just(\n\t\t\t\t\t\tA2($elm$core$String$dropLeft, i + 1, str)),\n\t\t\t\t\tA2($elm$core$String$left, i, str));\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$String$startsWith = _String_startsWith;\nvar $elm$url$Url$fromString = function (str) {\n\treturn A2($elm$core$String$startsWith, 'http://', str) ? A2(\n\t\t$elm$url$Url$chompAfterProtocol,\n\t\t0,\n\t\tA2($elm$core$String$dropLeft, 7, str)) : (A2($elm$core$String$startsWith, 'https://', str) ? A2(\n\t\t$elm$url$Url$chompAfterProtocol,\n\t\t1,\n\t\tA2($elm$core$String$dropLeft, 8, str)) : $elm$core$Maybe$Nothing);\n};\nvar $elm$core$Basics$never = function (_v0) {\n\tnever:\n\twhile (true) {\n\t\tvar nvr = _v0;\n\t\tvar $temp$_v0 = nvr;\n\t\t_v0 = $temp$_v0;\n\t\tcontinue never;\n\t}\n};\nvar $elm$core$Task$Perform = $elm$core$Basics$identity;\nvar $elm$core$Task$succeed = _Scheduler_succeed;\nvar $elm$core$Task$init = $elm$core$Task$succeed(0);\nvar $elm$core$List$foldrHelper = F4(\n\tfunction (fn, acc, ctr, ls) {\n\t\tif (!ls.b) {\n\t\t\treturn acc;\n\t\t} else {\n\t\t\tvar a = ls.a;\n\t\t\tvar r1 = ls.b;\n\t\t\tif (!r1.b) {\n\t\t\t\treturn A2(fn, a, acc);\n\t\t\t} else {\n\t\t\t\tvar b = r1.a;\n\t\t\t\tvar r2 = r1.b;\n\t\t\t\tif (!r2.b) {\n\t\t\t\t\treturn A2(\n\t\t\t\t\t\tfn,\n\t\t\t\t\t\ta,\n\t\t\t\t\t\tA2(fn, b, acc));\n\t\t\t\t} else {\n\t\t\t\t\tvar c = r2.a;\n\t\t\t\t\tvar r3 = r2.b;\n\t\t\t\t\tif (!r3.b) {\n\t\t\t\t\t\treturn A2(\n\t\t\t\t\t\t\tfn,\n\t\t\t\t\t\t\ta,\n\t\t\t\t\t\t\tA2(\n\t\t\t\t\t\t\t\tfn,\n\t\t\t\t\t\t\t\tb,\n\t\t\t\t\t\t\t\tA2(fn, c, acc)));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar d = r3.a;\n\t\t\t\t\t\tvar r4 = r3.b;\n\t\t\t\t\t\tvar res = (ctr > 500) ? A3(\n\t\t\t\t\t\t\t$elm$core$List$foldl,\n\t\t\t\t\t\t\tfn,\n\t\t\t\t\t\t\tacc,\n\t\t\t\t\t\t\t$elm$core$List$reverse(r4)) : A4($elm$core$List$foldrHelper, fn, acc, ctr + 1, r4);\n\t\t\t\t\t\treturn A2(\n\t\t\t\t\t\t\tfn,\n\t\t\t\t\t\t\ta,\n\t\t\t\t\t\t\tA2(\n\t\t\t\t\t\t\t\tfn,\n\t\t\t\t\t\t\t\tb,\n\t\t\t\t\t\t\t\tA2(\n\t\t\t\t\t\t\t\t\tfn,\n\t\t\t\t\t\t\t\t\tc,\n\t\t\t\t\t\t\t\t\tA2(fn, d, res))));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$List$foldr = F3(\n\tfunction (fn, acc, ls) {\n\t\treturn A4($elm$core$List$foldrHelper, fn, acc, 0, ls);\n\t});\nvar $elm$core$List$map = F2(\n\tfunction (f, xs) {\n\t\treturn A3(\n\t\t\t$elm$core$List$foldr,\n\t\t\tF2(\n\t\t\t\tfunction (x, acc) {\n\t\t\t\t\treturn A2(\n\t\t\t\t\t\t$elm$core$List$cons,\n\t\t\t\t\t\tf(x),\n\t\t\t\t\t\tacc);\n\t\t\t\t}),\n\t\t\t_List_Nil,\n\t\t\txs);\n\t});\nvar $elm$core$Task$andThen = _Scheduler_andThen;\nvar $elm$core$Task$map = F2(\n\tfunction (func, taskA) {\n\t\treturn A2(\n\t\t\t$elm$core$Task$andThen,\n\t\t\tfunction (a) {\n\t\t\t\treturn $elm$core$Task$succeed(\n\t\t\t\t\tfunc(a));\n\t\t\t},\n\t\t\ttaskA);\n\t});\nvar $elm$core$Task$map2 = F3(\n\tfunction (func, taskA, taskB) {\n\t\treturn A2(\n\t\t\t$elm$core$Task$andThen,\n\t\t\tfunction (a) {\n\t\t\t\treturn A2(\n\t\t\t\t\t$elm$core$Task$andThen,\n\t\t\t\t\tfunction (b) {\n\t\t\t\t\t\treturn $elm$core$Task$succeed(\n\t\t\t\t\t\t\tA2(func, a, b));\n\t\t\t\t\t},\n\t\t\t\t\ttaskB);\n\t\t\t},\n\t\t\ttaskA);\n\t});\nvar $elm$core$Task$sequence = function (tasks) {\n\treturn A3(\n\t\t$elm$core$List$foldr,\n\t\t$elm$core$Task$map2($elm$core$List$cons),\n\t\t$elm$core$Task$succeed(_List_Nil),\n\t\ttasks);\n};\nvar $elm$core$Platform$sendToApp = _Platform_sendToApp;\nvar $elm$core$Task$spawnCmd = F2(\n\tfunction (router, _v0) {\n\t\tvar task = _v0;\n\t\treturn _Scheduler_spawn(\n\t\t\tA2(\n\t\t\t\t$elm$core$Task$andThen,\n\t\t\t\t$elm$core$Platform$sendToApp(router),\n\t\t\t\ttask));\n\t});\nvar $elm$core$Task$onEffects = F3(\n\tfunction (router, commands, state) {\n\t\treturn A2(\n\t\t\t$elm$core$Task$map,\n\t\t\tfunction (_v0) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\t$elm$core$Task$sequence(\n\t\t\t\tA2(\n\t\t\t\t\t$elm$core$List$map,\n\t\t\t\t\t$elm$core$Task$spawnCmd(router),\n\t\t\t\t\tcommands)));\n\t});\nvar $elm$core$Task$onSelfMsg = F3(\n\tfunction (_v0, _v1, _v2) {\n\t\treturn $elm$core$Task$succeed(0);\n\t});\nvar $elm$core$Task$cmdMap = F2(\n\tfunction (tagger, _v0) {\n\t\tvar task = _v0;\n\t\treturn A2($elm$core$Task$map, tagger, task);\n\t});\n_Platform_effectManagers['Task'] = _Platform_createManager($elm$core$Task$init, $elm$core$Task$onEffects, $elm$core$Task$onSelfMsg, $elm$core$Task$cmdMap);\nvar $elm$core$Task$command = _Platform_leaf('Task');\nvar $elm$core$Task$perform = F2(\n\tfunction (toMessage, task) {\n\t\treturn $elm$core$Task$command(\n\t\t\tA2($elm$core$Task$map, toMessage, task));\n\t});\nvar $elm$browser$Browser$element = _Browser_element;\nvar $author$project$Main$NewCard = function (a) {\n\treturn {$: 2, a: a};\n};\nvar $elm$random$Random$Generate = $elm$core$Basics$identity;\nvar $elm$random$Random$Seed = F2(\n\tfunction (a, b) {\n\t\treturn {$: 0, a: a, b: b};\n\t});\nvar $elm$core$Bitwise$shiftRightZfBy = _Bitwise_shiftRightZfBy;\nvar $elm$random$Random$next = function (_v0) {\n\tvar state0 = _v0.a;\n\tvar incr = _v0.b;\n\treturn A2($elm$random$Random$Seed, ((state0 * 1664525) + incr) >>> 0, incr);\n};\nvar $elm$random$Random$initialSeed = function (x) {\n\tvar _v0 = $elm$random$Random$next(\n\t\tA2($elm$random$Random$Seed, 0, 1013904223));\n\tvar state1 = _v0.a;\n\tvar incr = _v0.b;\n\tvar state2 = (state1 + x) >>> 0;\n\treturn $elm$random$Random$next(\n\t\tA2($elm$random$Random$Seed, state2, incr));\n};\nvar $elm$time$Time$Name = function (a) {\n\treturn {$: 0, a: a};\n};\nvar $elm$time$Time$Offset = function (a) {\n\treturn {$: 1, a: a};\n};\nvar $elm$time$Time$Zone = F2(\n\tfunction (a, b) {\n\t\treturn {$: 0, a: a, b: b};\n\t});\nvar $elm$time$Time$customZone = $elm$time$Time$Zone;\nvar $elm$time$Time$Posix = $elm$core$Basics$identity;\nvar $elm$time$Time$millisToPosix = $elm$core$Basics$identity;\nvar $elm$time$Time$now = _Time_now($elm$time$Time$millisToPosix);\nvar $elm$time$Time$posixToMillis = function (_v0) {\n\tvar millis = _v0;\n\treturn millis;\n};\nvar $elm$random$Random$init = A2(\n\t$elm$core$Task$andThen,\n\tfunction (time) {\n\t\treturn $elm$core$Task$succeed(\n\t\t\t$elm$random$Random$initialSeed(\n\t\t\t\t$elm$time$Time$posixToMillis(time)));\n\t},\n\t$elm$time$Time$now);\nvar $elm$random$Random$step = F2(\n\tfunction (_v0, seed) {\n\t\tvar generator = _v0;\n\t\treturn generator(seed);\n\t});\nvar $elm$random$Random$onEffects = F3(\n\tfunction (router, commands, seed) {\n\t\tif (!commands.b) {\n\t\t\treturn $elm$core$Task$succeed(seed);\n\t\t} else {\n\t\t\tvar generator = commands.a;\n\t\t\tvar rest = commands.b;\n\t\t\tvar _v1 = A2($elm$random$Random$step, generator, seed);\n\t\t\tvar value = _v1.a;\n\t\t\tvar newSeed = _v1.b;\n\t\t\treturn A2(\n\t\t\t\t$elm$core$Task$andThen,\n\t\t\t\tfunction (_v2) {\n\t\t\t\t\treturn A3($elm$random$Random$onEffects, router, rest, newSeed);\n\t\t\t\t},\n\t\t\t\tA2($elm$core$Platform$sendToApp, router, value));\n\t\t}\n\t});\nvar $elm$random$Random$onSelfMsg = F3(\n\tfunction (_v0, _v1, seed) {\n\t\treturn $elm$core$Task$succeed(seed);\n\t});\nvar $elm$random$Random$Generator = $elm$core$Basics$identity;\nvar $elm$random$Random$map = F2(\n\tfunction (func, _v0) {\n\t\tvar genA = _v0;\n\t\treturn function (seed0) {\n\t\t\tvar _v1 = genA(seed0);\n\t\t\tvar a = _v1.a;\n\t\t\tvar seed1 = _v1.b;\n\t\t\treturn _Utils_Tuple2(\n\t\t\t\tfunc(a),\n\t\t\t\tseed1);\n\t\t};\n\t});\nvar $elm$random$Random$cmdMap = F2(\n\tfunction (func, _v0) {\n\t\tvar generator = _v0;\n\t\treturn A2($elm$random$Random$map, func, generator);\n\t});\n_Platform_effectManagers['Random'] = _Platform_createManager($elm$random$Random$init, $elm$random$Random$onEffects, $elm$random$Random$onSelfMsg, $elm$random$Random$cmdMap);\nvar $elm$random$Random$command = _Platform_leaf('Random');\nvar $elm$random$Random$generate = F2(\n\tfunction (tagger, generator) {\n\t\treturn $elm$random$Random$command(\n\t\t\tA2($elm$random$Random$map, tagger, generator));\n\t});\nvar $elm$core$Bitwise$and = _Bitwise_and;\nvar $elm$core$Basics$negate = function (n) {\n\treturn -n;\n};\nvar $elm$core$Bitwise$xor = _Bitwise_xor;\nvar $elm$random$Random$peel = function (_v0) {\n\tvar state = _v0.a;\n\tvar word = (state ^ (state >>> ((state >>> 28) + 4))) * 277803737;\n\treturn ((word >>> 22) ^ word) >>> 0;\n};\nvar $elm$random$Random$int = F2(\n\tfunction (a, b) {\n\t\treturn function (seed0) {\n\t\t\tvar _v0 = (_Utils_cmp(a, b) < 0) ? _Utils_Tuple2(a, b) : _Utils_Tuple2(b, a);\n\t\t\tvar lo = _v0.a;\n\t\t\tvar hi = _v0.b;\n\t\t\tvar range = (hi - lo) + 1;\n\t\t\tif (!((range - 1) & range)) {\n\t\t\t\treturn _Utils_Tuple2(\n\t\t\t\t\t(((range - 1) & $elm$random$Random$peel(seed0)) >>> 0) + lo,\n\t\t\t\t\t$elm$random$Random$next(seed0));\n\t\t\t} else {\n\t\t\t\tvar threshhold = (((-range) >>> 0) % range) >>> 0;\n\t\t\t\tvar accountForBias = function (seed) {\n\t\t\t\t\taccountForBias:\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tvar x = $elm$random$Random$peel(seed);\n\t\t\t\t\t\tvar seedN = $elm$random$Random$next(seed);\n\t\t\t\t\t\tif (_Utils_cmp(x, threshhold) < 0) {\n\t\t\t\t\t\t\tvar $temp$seed = seedN;\n\t\t\t\t\t\t\tseed = $temp$seed;\n\t\t\t\t\t\t\tcontinue accountForBias;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn _Utils_Tuple2((x % range) + lo, seedN);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\treturn accountForBias(seed0);\n\t\t\t}\n\t\t};\n\t});\nvar $author$project$Main$newCard = A2($elm$random$Random$int, 2, 14);\nvar $author$project$Main$init = function (_v0) {\n\treturn _Utils_Tuple2(\n\t\t{\n\t\t\ta: {d: $elm$core$Maybe$Nothing, g: $elm$core$Maybe$Nothing, w: $elm$core$Maybe$Nothing},\n\t\t\tC: $elm$core$Maybe$Nothing,\n\t\t\tD: $elm$core$Maybe$Nothing,\n\t\t\ti: 100,\n\t\t\tj: 0\n\t\t},\n\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard));\n};\nvar $elm$core$Platform$Sub$batch = _Platform_batch;\nvar $elm$core$Platform$Sub$none = $elm$core$Platform$Sub$batch(_List_Nil);\nvar $author$project$Main$subscriptions = function (_v0) {\n\treturn $elm$core$Platform$Sub$none;\n};\nvar $author$project$Main$NewCardC = function (a) {\n\treturn {$: 3, a: a};\n};\nvar $elm$core$Platform$Cmd$batch = _Platform_batch;\nvar $elm$core$Platform$Cmd$none = $elm$core$Platform$Cmd$batch(_List_Nil);\nvar $author$project$Main$calculateNewState = F2(\n\tfunction (cardC, model) {\n\t\tvar _v0 = model.a.d;\n\t\tif (!_v0.$) {\n\t\t\tvar cardA = _v0.a;\n\t\t\tvar _v1 = model.a.g;\n\t\t\tif (!_v1.$) {\n\t\t\t\tvar cardB = _v1.a;\n\t\t\t\tvar currentGame = model.a;\n\t\t\t\treturn (_Utils_eq(cardC, cardA) || _Utils_eq(cardC, cardB)) ? _Utils_Tuple2(\n\t\t\t\t\tmodel,\n\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCardC, $author$project$Main$newCard)) : (((_Utils_cmp(cardA, cardC) < 0) && (_Utils_cmp(cardC, cardB) < 0)) ? _Utils_Tuple2(\n\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ta: _Utils_update(\n\t\t\t\t\t\t\t\tcurrentGame,\n\t\t\t\t\t\t\t\t{d: $elm$core$Maybe$Nothing, g: $elm$core$Maybe$Nothing}),\n\t\t\t\t\t\t\tD: $elm$core$Maybe$Just(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\td: model.a.d,\n\t\t\t\t\t\t\t\t\tg: model.a.g,\n\t\t\t\t\t\t\t\t\tw: $elm$core$Maybe$Just(cardC)\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ti: model.i + model.j\n\t\t\t\t\t\t}),\n\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard)) : ((_Utils_cmp(model.j, model.i - model.j) > 0) ? _Utils_Tuple2(\n\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ta: _Utils_update(\n\t\t\t\t\t\t\t\tcurrentGame,\n\t\t\t\t\t\t\t\t{d: $elm$core$Maybe$Nothing, g: $elm$core$Maybe$Nothing}),\n\t\t\t\t\t\t\tD: $elm$core$Maybe$Just(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\td: model.a.d,\n\t\t\t\t\t\t\t\t\tg: model.a.g,\n\t\t\t\t\t\t\t\t\tw: $elm$core$Maybe$Just(cardC)\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ti: model.i - model.j,\n\t\t\t\t\t\t\tj: model.i - model.j\n\t\t\t\t\t\t}),\n\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard)) : _Utils_Tuple2(\n\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ta: _Utils_update(\n\t\t\t\t\t\t\t\tcurrentGame,\n\t\t\t\t\t\t\t\t{d: $elm$core$Maybe$Nothing, g: $elm$core$Maybe$Nothing}),\n\t\t\t\t\t\t\tD: $elm$core$Maybe$Just(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\td: model.a.d,\n\t\t\t\t\t\t\t\t\tg: model.a.g,\n\t\t\t\t\t\t\t\t\tw: $elm$core$Maybe$Just(cardC)\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ti: model.i - model.j\n\t\t\t\t\t\t}),\n\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard))));\n\t\t\t} else {\n\t\t\t\treturn _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);\n\t\t\t}\n\t\t} else {\n\t\t\treturn _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);\n\t\t}\n\t});\nvar $author$project$Main$update = F2(\n\tfunction (msg, model) {\n\t\tswitch (msg.$) {\n\t\t\tcase 0:\n\t\t\t\tvar bet = msg.a;\n\t\t\t\treturn _Utils_Tuple2(\n\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t{j: bet}),\n\t\t\t\t\t$elm$core$Platform$Cmd$none);\n\t\t\tcase 1:\n\t\t\t\tvar value = msg.a;\n\t\t\t\tvar _v1 = $elm$core$String$toInt(value);\n\t\t\t\tif (!_v1.$) {\n\t\t\t\t\tvar newValue = _v1.a;\n\t\t\t\t\treturn (_Utils_cmp(newValue, model.i) > 0) ? _Utils_Tuple2(\n\t\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tC: $elm$core$Maybe$Just('You cannot bet more than you have'),\n\t\t\t\t\t\t\t\tj: model.i\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t$elm$core$Platform$Cmd$none) : _Utils_Tuple2(\n\t\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t{C: $elm$core$Maybe$Nothing, j: newValue}),\n\t\t\t\t\t\t$elm$core$Platform$Cmd$none);\n\t\t\t\t} else {\n\t\t\t\t\treturn _Utils_Tuple2(\n\t\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tC: $elm$core$Maybe$Just('Wrong input for bet')\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t$elm$core$Platform$Cmd$none);\n\t\t\t\t}\n\t\t\tcase 2:\n\t\t\t\tvar card = msg.a;\n\t\t\t\tvar _v2 = model.a.d;\n\t\t\t\tif (_v2.$ === 1) {\n\t\t\t\t\tvar currentGame = model.a;\n\t\t\t\t\treturn (card > 13) ? _Utils_Tuple2(\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard)) : _Utils_Tuple2(\n\t\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ta: _Utils_update(\n\t\t\t\t\t\t\t\t\tcurrentGame,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\td: $elm$core$Maybe$Just(card)\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard));\n\t\t\t\t} else {\n\t\t\t\t\tvar cardA = _v2.a;\n\t\t\t\t\tvar currentGame = model.a;\n\t\t\t\t\treturn (_Utils_cmp(card, cardA) < 1) ? _Utils_Tuple2(\n\t\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ta: _Utils_update(\n\t\t\t\t\t\t\t\t\tcurrentGame,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\td: $elm$core$Maybe$Just(card)\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCard, $author$project$Main$newCard)) : _Utils_Tuple2(\n\t\t\t\t\t\t_Utils_update(\n\t\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ta: _Utils_update(\n\t\t\t\t\t\t\t\t\tcurrentGame,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tg: $elm$core$Maybe$Just(card)\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t$elm$core$Platform$Cmd$none);\n\t\t\t\t}\n\t\t\tcase 4:\n\t\t\t\treturn _Utils_Tuple2(\n\t\t\t\t\tmodel,\n\t\t\t\t\tA2($elm$random$Random$generate, $author$project$Main$NewCardC, $author$project$Main$newCard));\n\t\t\tcase 3:\n\t\t\t\tvar card = msg.a;\n\t\t\t\treturn A2($author$project$Main$calculateNewState, card, model);\n\t\t\tdefault:\n\t\t\t\treturn $author$project$Main$init(0);\n\t\t}\n\t});\nvar $elm$virtual_dom$VirtualDom$style = _VirtualDom_style;\nvar $elm$html$Html$Attributes$style = $elm$virtual_dom$VirtualDom$style;\nvar $author$project$Main$centerHeadlineStyle = _List_fromArray(\n\t[\n\t\tA2($elm$html$Html$Attributes$style, 'display', 'grid'),\n\t\tA2($elm$html$Html$Attributes$style, 'place-items', 'center'),\n\t\tA2($elm$html$Html$Attributes$style, 'margin', '2rem')\n\t]);\nvar $elm$html$Html$div = _VirtualDom_node('div');\nvar $author$project$Main$NewGame = {$: 5};\nvar $author$project$Main$Play = {$: 4};\nvar $author$project$Main$UpdateBetValue = function (a) {\n\treturn {$: 1, a: a};\n};\nvar $elm$html$Html$article = _VirtualDom_node('article');\nvar $elm$html$Html$button = _VirtualDom_node('button');\nvar $author$project$Main$cardContentPStyle = _List_fromArray(\n\t[\n\t\tA2($elm$html$Html$Attributes$style, 'font-size', '2rem')\n\t]);\nvar $author$project$Main$cardToString = function (card) {\n\tif (!card.$) {\n\t\tvar value = card.a;\n\t\tif (value < 11) {\n\t\t\treturn $elm$core$String$fromInt(value);\n\t\t} else {\n\t\t\tswitch (value) {\n\t\t\t\tcase 11:\n\t\t\t\t\treturn 'Jack';\n\t\t\t\tcase 12:\n\t\t\t\t\treturn 'Queen';\n\t\t\t\tcase 13:\n\t\t\t\t\treturn 'King';\n\t\t\t\tcase 14:\n\t\t\t\t\treturn 'Ace';\n\t\t\t\tdefault:\n\t\t\t\t\treturn 'impossible value';\n\t\t\t}\n\t\t}\n\t} else {\n\t\treturn '-';\n\t}\n};\nvar $author$project$Main$gameStyle = _List_fromArray(\n\t[\n\t\tA2($elm$html$Html$Attributes$style, 'width', '100%'),\n\t\tA2($elm$html$Html$Attributes$style, 'max-width', '70rem')\n\t]);\nvar $elm$html$Html$input = _VirtualDom_node('input');\nvar $elm$json$Json$Encode$string = _Json_wrap;\nvar $elm$html$Html$Attributes$stringProperty = F2(\n\tfunction (key, string) {\n\t\treturn A2(\n\t\t\t_VirtualDom_property,\n\t\t\tkey,\n\t\t\t$elm$json$Json$Encode$string(string));\n\t});\nvar $elm$html$Html$Attributes$max = $elm$html$Html$Attributes$stringProperty('max');\nvar $elm$html$Html$Attributes$min = $elm$html$Html$Attributes$stringProperty('min');\nvar $elm$virtual_dom$VirtualDom$Normal = function (a) {\n\treturn {$: 0, a: a};\n};\nvar $elm$virtual_dom$VirtualDom$on = _VirtualDom_on;\nvar $elm$html$Html$Events$on = F2(\n\tfunction (event, decoder) {\n\t\treturn A2(\n\t\t\t$elm$virtual_dom$VirtualDom$on,\n\t\t\tevent,\n\t\t\t$elm$virtual_dom$VirtualDom$Normal(decoder));\n\t});\nvar $elm$html$Html$Events$onClick = function (msg) {\n\treturn A2(\n\t\t$elm$html$Html$Events$on,\n\t\t'click',\n\t\t$elm$json$Json$Decode$succeed(msg));\n};\nvar $elm$html$Html$Events$alwaysStop = function (x) {\n\treturn _Utils_Tuple2(x, true);\n};\nvar $elm$virtual_dom$VirtualDom$MayStopPropagation = function (a) {\n\treturn {$: 1, a: a};\n};\nvar $elm$html$Html$Events$stopPropagationOn = F2(\n\tfunction (event, decoder) {\n\t\treturn A2(\n\t\t\t$elm$virtual_dom$VirtualDom$on,\n\t\t\tevent,\n\t\t\t$elm$virtual_dom$VirtualDom$MayStopPropagation(decoder));\n\t});\nvar $elm$json$Json$Decode$field = _Json_decodeField;\nvar $elm$json$Json$Decode$at = F2(\n\tfunction (fields, decoder) {\n\t\treturn A3($elm$core$List$foldr, $elm$json$Json$Decode$field, decoder, fields);\n\t});\nvar $elm$json$Json$Decode$string = _Json_decodeString;\nvar $elm$html$Html$Events$targetValue = A2(\n\t$elm$json$Json$Decode$at,\n\t_List_fromArray(\n\t\t['target', 'value']),\n\t$elm$json$Json$Decode$string);\nvar $elm$html$Html$Events$onInput = function (tagger) {\n\treturn A2(\n\t\t$elm$html$Html$Events$stopPropagationOn,\n\t\t'input',\n\t\tA2(\n\t\t\t$elm$json$Json$Decode$map,\n\t\t\t$elm$html$Html$Events$alwaysStop,\n\t\t\tA2($elm$json$Json$Decode$map, tagger, $elm$html$Html$Events$targetValue)));\n};\nvar $elm$html$Html$p = _VirtualDom_node('p');\nvar $author$project$Main$standardFontSize = A2($elm$html$Html$Attributes$style, 'font-size', '2rem');\nvar $elm$virtual_dom$VirtualDom$text = _VirtualDom_text;\nvar $elm$html$Html$text = $elm$virtual_dom$VirtualDom$text;\nvar $author$project$Main$showError = function (value) {\n\tif (!value.$) {\n\t\tvar string = value.a;\n\t\treturn A2(\n\t\t\t$elm$html$Html$p,\n\t\t\t_List_fromArray(\n\t\t\t\t[$author$project$Main$standardFontSize]),\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text(string)\n\t\t\t\t]));\n\t} else {\n\t\treturn A2($elm$html$Html$div, _List_Nil, _List_Nil);\n\t}\n};\nvar $author$project$Main$getGameStateMessage = F3(\n\tfunction (cardA, cardB, cardC) {\n\t\treturn ((_Utils_cmp(cardA, cardC) < 0) && (_Utils_cmp(cardB, cardC) > 0)) ? A2(\n\t\t\t$elm$html$Html$div,\n\t\t\t_List_fromArray(\n\t\t\t\t[$author$project$Main$standardFontSize]),\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text('You won :)')\n\t\t\t\t])) : A2(\n\t\t\t$elm$html$Html$div,\n\t\t\t_List_fromArray(\n\t\t\t\t[$author$project$Main$standardFontSize]),\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text('You loose :(')\n\t\t\t\t]));\n\t});\nvar $elm$core$Maybe$map3 = F4(\n\tfunction (func, ma, mb, mc) {\n\t\tif (ma.$ === 1) {\n\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t} else {\n\t\t\tvar a = ma.a;\n\t\t\tif (mb.$ === 1) {\n\t\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t\t} else {\n\t\t\t\tvar b = mb.a;\n\t\t\t\tif (mc.$ === 1) {\n\t\t\t\t\treturn $elm$core$Maybe$Nothing;\n\t\t\t\t} else {\n\t\t\t\t\tvar c = mc.a;\n\t\t\t\t\treturn $elm$core$Maybe$Just(\n\t\t\t\t\t\tA3(func, a, b, c));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\nvar $elm$core$Maybe$withDefault = F2(\n\tfunction (_default, maybe) {\n\t\tif (!maybe.$) {\n\t\t\tvar value = maybe.a;\n\t\t\treturn value;\n\t\t} else {\n\t\t\treturn _default;\n\t\t}\n\t});\nvar $author$project$Main$showLastWinLose = function (game) {\n\treturn A2(\n\t\t$elm$core$Maybe$withDefault,\n\t\t$elm$html$Html$text('something is wrong'),\n\t\tA4($elm$core$Maybe$map3, $author$project$Main$getGameStateMessage, game.d, game.g, game.w));\n};\nvar $author$project$Main$showLastGame = function (game) {\n\tif (game.$ === 1) {\n\t\treturn A2(\n\t\t\t$elm$html$Html$div,\n\t\t\t_List_fromArray(\n\t\t\t\t[$author$project$Main$standardFontSize]),\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text('This is your first game')\n\t\t\t\t]));\n\t} else {\n\t\tvar value = game.a;\n\t\treturn A2(\n\t\t\t$elm$html$Html$div,\n\t\t\t_List_Nil,\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$author$project$Main$showLastWinLose(value),\n\t\t\t\t\tA2(\n\t\t\t\t\t$elm$html$Html$p,\n\t\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t\t_List_fromArray(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t\t'Card 1: ' + $author$project$Main$cardToString(value.d))\n\t\t\t\t\t\t])),\n\t\t\t\t\tA2(\n\t\t\t\t\t$elm$html$Html$p,\n\t\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t\t_List_fromArray(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t\t'Card 2: ' + $author$project$Main$cardToString(value.g))\n\t\t\t\t\t\t])),\n\t\t\t\t\tA2(\n\t\t\t\t\t$elm$html$Html$p,\n\t\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t\t_List_fromArray(\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t\t'Drawn Card: ' + $author$project$Main$cardToString(value.w))\n\t\t\t\t\t\t]))\n\t\t\t\t]));\n\t}\n};\nvar $elm$html$Html$Attributes$type_ = $elm$html$Html$Attributes$stringProperty('type');\nvar $elm$html$Html$Attributes$value = $elm$html$Html$Attributes$stringProperty('value');\nvar $author$project$Main$showGame = function (model) {\n\treturn (model.i <= 0) ? A2(\n\t\t$elm$html$Html$article,\n\t\t$author$project$Main$gameStyle,\n\t\t_List_fromArray(\n\t\t\t[\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$p,\n\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text('You lose all you money')\n\t\t\t\t\t])),\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$button,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$Events$onClick($author$project$Main$NewGame),\n\t\t\t\t\t\t$author$project$Main$standardFontSize\n\t\t\t\t\t]),\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text('Again')\n\t\t\t\t\t]))\n\t\t\t])) : A2(\n\t\t$elm$html$Html$article,\n\t\t$author$project$Main$gameStyle,\n\t\t_List_fromArray(\n\t\t\t[\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$p,\n\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t'Currently you have ' + ($elm$core$String$fromInt(model.i) + ' in your pocket.'))\n\t\t\t\t\t])),\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$p,\n\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t'Card 1: ' + $author$project$Main$cardToString(model.a.d))\n\t\t\t\t\t])),\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$p,\n\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t'Card 2: ' + $author$project$Main$cardToString(model.a.g))\n\t\t\t\t\t])),\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$p,\n\t\t\t\t$author$project$Main$cardContentPStyle,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text(\n\t\t\t\t\t\t'Your current bet is ' + $elm$core$String$fromInt(model.j))\n\t\t\t\t\t])),\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$input,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$Attributes$type_('range'),\n\t\t\t\t\t\t$elm$html$Html$Attributes$max(\n\t\t\t\t\t\t$elm$core$String$fromInt(model.i)),\n\t\t\t\t\t\t$elm$html$Html$Attributes$min('0'),\n\t\t\t\t\t\t$elm$html$Html$Attributes$value(\n\t\t\t\t\t\t$elm$core$String$fromInt(model.j)),\n\t\t\t\t\t\t$elm$html$Html$Events$onInput($author$project$Main$UpdateBetValue)\n\t\t\t\t\t]),\n\t\t\t\t_List_Nil),\n\t\t\t\tA2(\n\t\t\t\t$elm$html$Html$button,\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$Events$onClick($author$project$Main$Play),\n\t\t\t\t\t\t$author$project$Main$standardFontSize\n\t\t\t\t\t]),\n\t\t\t\t_List_fromArray(\n\t\t\t\t\t[\n\t\t\t\t\t\t$elm$html$Html$text('Play')\n\t\t\t\t\t])),\n\t\t\t\t$author$project$Main$showLastGame(model.D),\n\t\t\t\t$author$project$Main$showError(model.C)\n\t\t\t]));\n};\nvar $elm$html$Html$h1 = _VirtualDom_node('h1');\nvar $author$project$Main$headerStyle = _List_fromArray(\n\t[\n\t\tA2($elm$html$Html$Attributes$style, 'font-size', '2rem'),\n\t\tA2($elm$html$Html$Attributes$style, 'text-align', 'center')\n\t]);\nvar $author$project$Main$showHeader = A2(\n\t$elm$html$Html$div,\n\t$author$project$Main$headerStyle,\n\t_List_fromArray(\n\t\t[\n\t\t\tA2(\n\t\t\t$elm$html$Html$h1,\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\tA2($elm$html$Html$Attributes$style, 'font-size', '4rem')\n\t\t\t\t]),\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text('ACEY DUCEY CARD GAME')\n\t\t\t\t])),\n\t\t\tA2(\n\t\t\t$elm$html$Html$div,\n\t\t\t_List_Nil,\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text('Creative Computing Morristown, New Jersey')\n\t\t\t\t])),\n\t\t\tA2(\n\t\t\t$elm$html$Html$div,\n\t\t\t_List_Nil,\n\t\t\t_List_fromArray(\n\t\t\t\t[\n\t\t\t\t\t$elm$html$Html$text('\\n        Acey-Ducey is played in the following manner. The Dealer (Computer) deals two cards face up. \\n        You have an option to bet or not bet depending on whether or not you feel the card will have a value between the first two.\\n        If you do not want to bet, bet 0.\\n        ')\n\t\t\t\t]))\n\t\t]));\nvar $author$project$Main$view = function (model) {\n\treturn A2(\n\t\t$elm$html$Html$div,\n\t\t$author$project$Main$centerHeadlineStyle,\n\t\t_List_fromArray(\n\t\t\t[\n\t\t\t\t$author$project$Main$showHeader,\n\t\t\t\t$author$project$Main$showGame(model)\n\t\t\t]));\n};\nvar $author$project$Main$main = $elm$browser$Browser$element(\n\t{aB: $author$project$Main$init, aH: $author$project$Main$subscriptions, aJ: $author$project$Main$update, aK: $author$project$Main$view});\n_Platform_export({'Main':{'init':$author$project$Main$main(\n\t$elm$json$Json$Decode$succeed(0))(0)}});}(this));"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/docs/index.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head>\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/@picocss/pico@latest/css/pico.min.css\">\n</head>\n\n<body>\n    <div id=\"elm-app-is-loaded-here\"></div>\n    <script src=\"app.min.js\"></script>\n    <script>\n        var app = Elm.Main.init({\n            node: document.getElementById(\"elm-app-is-loaded-here\"),\n            flags: {}\n        });\n    </script>\n</body>\n\n</html>"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/elm.json",
    "content": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.1\",\n    \"dependencies\": {\n        \"direct\": {\n            \"elm/browser\": \"1.0.2\",\n            \"elm/core\": \"1.0.5\",\n            \"elm/html\": \"1.0.0\",\n            \"elm/random\": \"1.0.0\"\n        },\n        \"indirect\": {\n            \"elm/json\": \"1.1.3\",\n            \"elm/time\": \"1.0.0\",\n            \"elm/url\": \"1.0.0\",\n            \"elm/virtual-dom\": \"1.0.2\"\n        }\n    },\n    \"test-dependencies\": {\n        \"direct\": {},\n        \"indirect\": {}\n    }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/package.json",
    "content": "{\n  \"name\": \"01_Acey_Ducey\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"repository\": \"https://github.com/auryn31/01_Acey_Ducey.git\",\n  \"author\": \"Auryn Engel <auryn.engel@sap.com>\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"live\": \"elm-live src/Main.elm --proxy-prefix=/api --proxy-host=http://localhost:8080/api --open --start-page=resources/index.html -- --output=app.js\",\n    \"build\": \"elm make src/Main.elm --optimize --output docs/app.js && cp -R resources/ docs/\"\n  },\n  \"devDependencies\": {\n    \"elm-live\": \"^4.0.2\",\n    \"uglify-js\": \"^3.15.3\"\n  }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/resources/index.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head>\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/@picocss/pico@latest/css/pico.min.css\">\n</head>\n\n<body>\n    <div id=\"elm-app-is-loaded-here\"></div>\n    <script src=\"app.js\"></script>\n    <script>\n        var app = Elm.Main.init({\n            node: document.getElementById(\"elm-app-is-loaded-here\"),\n            flags: {}\n        });\n    </script>\n</body>\n\n</html>"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/elm/src/Main.elm",
    "content": "module Main exposing (..)\n\nimport Browser\nimport Html exposing (..)\nimport Html.Attributes exposing (style, type_, value)\nimport Html.Events exposing (onInput)\nimport Random\n\n\nmain : Program () Model Msg\nmain =\n    Browser.element\n        { init = init\n        , view = view\n        , update = update\n        , subscriptions = subscriptions\n        }\n\n\n\n-- Models\n\n\ntype alias Model =\n    { money : Int\n    , currentGame : Game\n    , lastGame : Maybe Game\n    , moneyBet : Int\n    , error : Maybe String\n    }\n\n\ntype alias Game =\n    { cardA : Maybe Int\n    , cardB : Maybe Int\n    , cardC : Maybe Int\n    }\n\n\n\n-- Init\n\n\ninit : () -> ( Model, Cmd Msg )\ninit _ =\n    ( { money = 100, currentGame = { cardA = Nothing, cardB = Nothing, cardC = Nothing }, lastGame = Nothing, moneyBet = 0, error = Nothing }, Random.generate NewCard newCard )\n\n\n\n-- Messages\n\n\ntype Msg\n    = BetMoney Int\n    | UpdateBetValue String\n    | NewCard Int\n    | NewCardC Int\n    | Play\n    | NewGame\n\n\n\n-- Update\n\n\nupdate : Msg -> Model -> ( Model, Cmd Msg )\nupdate msg model =\n    case msg of\n        BetMoney bet ->\n            ( { model | moneyBet = bet }, Cmd.none )\n\n        UpdateBetValue value ->\n            case String.toInt value of\n                Just newValue ->\n                    if newValue > model.money then\n                        ( { model | error = Just \"You cannot bet more than you have\", moneyBet = model.money }, Cmd.none )\n\n                    else\n                        ( { model | moneyBet = newValue, error = Nothing }, Cmd.none )\n\n                Nothing ->\n                    ( { model | error = Just \"Wrong input for bet\" }, Cmd.none )\n\n        NewCard card ->\n            case model.currentGame.cardA of\n                Nothing ->\n                    let\n                        currentGame =\n                            model.currentGame\n                    in\n                    if card > 13 then\n                        ( model, Random.generate NewCard newCard )\n\n                    else\n                        ( { model | currentGame = { currentGame | cardA = Just card } }, Random.generate NewCard newCard )\n\n                Just cardA ->\n                    let\n                        currentGame =\n                            model.currentGame\n                    in\n                    if card <= cardA then\n                        ( { model | currentGame = { currentGame | cardA = Just card } }, Random.generate NewCard newCard )\n\n                    else\n                        ( { model | currentGame = { currentGame | cardB = Just card } }, Cmd.none )\n\n        Play ->\n            ( model, Random.generate NewCardC newCard )\n\n        NewCardC card ->\n            calculateNewState card model\n\n        NewGame ->\n            init ()\n\n\ncalculateNewState : Int -> Model -> ( Model, Cmd Msg )\ncalculateNewState cardC model =\n    case model.currentGame.cardA of\n        Just cardA ->\n            case model.currentGame.cardB of\n                Just cardB ->\n                    let\n                        currentGame =\n                            model.currentGame\n                    in\n                    if cardC == cardA || cardC == cardB then\n                        ( model, Random.generate NewCardC newCard )\n\n                    else if cardA < cardC && cardC < cardB then\n                        ( { model | money = model.money + model.moneyBet, currentGame = { currentGame | cardA = Nothing, cardB = Nothing }, lastGame = Just { cardA = model.currentGame.cardA, cardB = model.currentGame.cardB, cardC = Just cardC } }, Random.generate NewCard newCard )\n\n                    else if model.moneyBet > model.money - model.moneyBet then\n                        ( { model | money = model.money - model.moneyBet, moneyBet = model.money - model.moneyBet, currentGame = { currentGame | cardA = Nothing, cardB = Nothing }, lastGame = Just { cardA = model.currentGame.cardA, cardB = model.currentGame.cardB, cardC = Just cardC } }, Random.generate NewCard newCard )\n\n                    else\n                        ( { model | money = model.money - model.moneyBet, currentGame = { currentGame | cardA = Nothing, cardB = Nothing }, lastGame = Just { cardA = model.currentGame.cardA, cardB = model.currentGame.cardB, cardC = Just cardC } }, Random.generate NewCard newCard )\n\n                Nothing ->\n                    ( model, Cmd.none )\n\n        Nothing ->\n            ( model, Cmd.none )\n\n\nsubscriptions : Model -> Sub Msg\nsubscriptions _ =\n    Sub.none\n\n\n\n-- Views\n\n\nview : Model -> Html Msg\nview model =\n    div centerHeadlineStyle\n        [ showHeader\n        , showGame model\n        ]\n\n\nshowHeader : Html msg\nshowHeader =\n    div headerStyle\n        [ h1 [ style \"font-size\" \"4rem\" ] [ text \"ACEY DUCEY CARD GAME\" ]\n        , div [] [ text \"Creative Computing Morristown, New Jersey\" ]\n        , div []\n            [ text \"\"\"\n        Acey-Ducey is played in the following manner. The Dealer (Computer) deals two cards face up. \n        You have an option to bet or not bet depending on whether or not you feel the card will have a value between the first two.\n        If you do not want to bet, bet 0.\n        \"\"\"\n            ]\n        ]\n\n\nshowGame : Model -> Html Msg\nshowGame model =\n    if model.money <= 0 then\n        article gameStyle\n            [ p cardContentPStyle [ text \"You lose all you money\" ]\n            , button [ Html.Events.onClick NewGame, standardFontSize ] [ text \"Again\" ]\n            ]\n\n    else\n        article gameStyle\n            [ p cardContentPStyle [ text (\"Currently you have \" ++ String.fromInt model.money ++ \" in your pocket.\") ]\n            , p cardContentPStyle [ text (\"Card 1: \" ++ cardToString model.currentGame.cardA) ]\n            , p cardContentPStyle [ text (\"Card 2: \" ++ cardToString model.currentGame.cardB) ]\n            , p cardContentPStyle [ text (\"Your current bet is \" ++ String.fromInt model.moneyBet) ]\n            , input [ type_ \"range\", Html.Attributes.max (String.fromInt model.money), Html.Attributes.min \"0\", Html.Attributes.value (String.fromInt model.moneyBet), onInput UpdateBetValue ] []\n            , button [ Html.Events.onClick Play, standardFontSize ] [ text \"Play\" ]\n            , showLastGame model.lastGame\n            , showError model.error\n            ]\n\n\nshowLastGame : Maybe Game -> Html Msg\nshowLastGame game =\n    case game of\n        Nothing ->\n            div [ standardFontSize ] [ text \"This is your first game\" ]\n\n        Just value ->\n            div []\n                [ showLastWinLose value\n                , p cardContentPStyle [ text (\"Card 1: \" ++ cardToString value.cardA) ]\n                , p cardContentPStyle [ text (\"Card 2: \" ++ cardToString value.cardB) ]\n                , p cardContentPStyle [ text (\"Drawn Card: \" ++ cardToString value.cardC) ]\n                ]\n\n\nshowLastWinLose : Game -> Html Msg\nshowLastWinLose game =\n    Maybe.map3 getGameStateMessage game.cardA game.cardB game.cardC |> Maybe.withDefault (text \"something is wrong\")\n\n\ngetGameStateMessage : Int -> Int -> Int -> Html Msg\ngetGameStateMessage cardA cardB cardC =\n    if cardA < cardC && cardB > cardC then\n        div [ standardFontSize ] [ text \"You won :)\" ]\n\n    else\n        div [ standardFontSize ] [ text \"You loose :(\" ]\n\n\nshowError : Maybe String -> Html Msg\nshowError value =\n    case value of\n        Just string ->\n            p [ standardFontSize ] [ text string ]\n\n        Nothing ->\n            div [] []\n\n\n\n-- Helper\n\n\ncardToString : Maybe Int -> String\ncardToString card =\n    case card of\n        Just value ->\n            if value < 11 then\n                String.fromInt value\n\n            else\n                case value of\n                    11 ->\n                        \"Jack\"\n\n                    12 ->\n                        \"Queen\"\n\n                    13 ->\n                        \"King\"\n\n                    14 ->\n                        \"Ace\"\n\n                    _ ->\n                        \"impossible value\"\n\n        Nothing ->\n            \"-\"\n\n\nnewCard : Random.Generator Int\nnewCard =\n    Random.int 2 14\n\n\n\n-- Styles\n\n\nheaderStyle : List (Attribute msg)\nheaderStyle =\n    [ style \"font-size\" \"2rem\", style \"text-align\" \"center\" ]\n\n\ncardContentPStyle : List (Attribute msg)\ncardContentPStyle =\n    [ style \"font-size\" \"2rem\"\n    ]\n\n\ngameStyle : List (Attribute msg)\ngameStyle =\n    [ style \"width\" \"100%\"\n    , style \"max-width\" \"70rem\"\n    ]\n\n\ncenterHeadlineStyle : List (Attribute msg)\ncenterHeadlineStyle =\n    [ style \"display\" \"grid\"\n    , style \"place-items\" \"center\"\n    , style \"margin\" \"2rem\"\n    ]\n\n\nstandardFontSize : Attribute msg\nstandardFontSize =\n    style \"font-size\" \"2rem\"\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"sort\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nvar welcome = `\r\nAcey-Ducey is played in the following manner\r\nThe dealer (computer) deals two cards face up\r\nYou have an option to bet or not bet depending\r\non whether or not you feel the card will have\r\na value between the first two.\r\nIf you do not want to bet, input a 0\r\n  `\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfmt.Println(welcome)\r\n\r\n\tfor {\r\n\t\tplay(100)\r\n\t\tfmt.Println(\"TRY AGAIN (YES OR NO)\")\r\n\t\tscanner.Scan()\r\n\t\tresponse := scanner.Text()\r\n\t\tif strings.ToUpper(response) != \"YES\" {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\r\n\tfmt.Println(\"O.K., HOPE YOU HAD FUN!\")\r\n}\r\n\r\nfunc play(money int) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tvar bet int\r\n\r\n\tfor {\r\n\t\t// Shuffle the cards\r\n\t\tcards := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}\r\n\t\trand.Shuffle(len(cards), func(i, j int) { cards[i], cards[j] = cards[j], cards[i] })\r\n\r\n\t\t// Take the first two for the dealer and sort\r\n\t\tdealerCards := cards[0:2]\r\n\t\tsort.Ints(dealerCards)\r\n\r\n\t\tfmt.Printf(\"YOU NOW HAVE %d DOLLARS.\\n\\n\", money)\r\n\t\tfmt.Printf(\"HERE ARE YOUR NEXT TWO CARDS:\\n%s\\n%s\", getCardName(dealerCards[0]), getCardName(dealerCards[1]))\r\n\t\tfmt.Printf(\"\\n\\n\")\r\n\r\n\t\t//Check if Bet is Valid\r\n\t\tfor {\r\n\t\t\tfmt.Println(\"WHAT IS YOUR BET:\")\r\n\t\t\tscanner.Scan()\r\n\t\t\tb, err := strconv.Atoi(scanner.Text())\r\n\t\t\tif err != nil {\r\n\t\t\t\tfmt.Println(\"PLEASE ENTER A POSITIVE NUMBER\")\r\n\t\t\t\tcontinue\r\n\t\t\t}\r\n\t\t\tbet = b\r\n\r\n\t\t\tif bet == 0 {\r\n\t\t\t\tfmt.Printf(\"CHICKEN!\\n\\n\")\r\n\t\t\t\tgoto there\r\n\t\t\t}\r\n\r\n\t\t\tif (bet > 0) && (bet <= money) {\r\n\t\t\t\tbreak\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Draw Players Card\r\n\t\tfmt.Printf(\"YOUR CARD: %s\\n\", getCardName(cards[2]))\r\n\t\tif (cards[2] > dealerCards[0]) && (cards[2] < dealerCards[1]) {\r\n\t\t\tfmt.Println(\"YOU WIN!!!\")\r\n\t\t\tmoney = money + bet\r\n\t\t} else {\r\n\t\t\tfmt.Println(\"SORRY, YOU LOSE\")\r\n\t\t\tmoney = money - bet\r\n\t\t}\r\n\t\tfmt.Println()\r\n\r\n\t\tif money <= 0 {\r\n\t\t\tfmt.Printf(\"%s\\n\", \"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\")\r\n\t\t\treturn\r\n\t\t}\r\n\tthere:\r\n\t}\r\n}\r\n\r\nfunc getCardName(c int) string {\r\n\tswitch c {\r\n\tcase 11:\r\n\t\treturn \"JACK\"\r\n\tcase 12:\r\n\t\treturn \"QUEEN\"\r\n\tcase 13:\r\n\t\treturn \"KING\"\r\n\tcase 14:\r\n\t\treturn \"ACE\"\r\n\tdefault:\r\n\t\treturn strconv.Itoa(c)\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim",
    "content": "import std/[random,strutils]\n\nvar\n  bet, cardA, cardB, cardC, stash: int\n  retry: bool = true\n\nrandomize() # Seed the random number generator\n\nproc printGreeting() =\n  echo spaces(26),\"ACEY DUCEY CARD GAME\"\n  echo spaces(15),\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n  echo \"\"\"\n\nACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\nTHE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\nYOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\nON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\nA VALUE BETWEEN THE FIRST TWO.\nIF YOU DO NOT WANT TO BET, INPUT A 0\n\n\"\"\"\n\nproc printBalance() =\n  echo \"YOU NOW HAVE \", stash,\" DOLLARS.\"\n  echo \"\"\n\nproc printCard(aCard: int) =\n  case aCard:\n  of 11: echo \"=== JACK ===\"\n  of 12: echo \"=== QUEEN ===\"\n  of 13: echo \"=== KING ===\"\n  of 14: echo \"=== ACE ===\"\n  else: echo \"=== \", aCard, \" ===\"\n\nproc drawDealerCards() =\n  echo \"HERE ARE YOUR NEXT TWO CARDS: \"\n  cardA = rand 2..14\n  cardB = cardA # Copy cardA, so we can test cardB to be different\n  while cardB == cardA:\n    cardB = rand 2..14\n  if cardA > cardB: # Make sure cardA is the smaller card\n    swap cardA, cardB\n  echo \"\"\n  printCard cardA\n  echo \"\"\n  printCard cardB\n  echo \"\"\n\nproc drawPlayerCard() =\n  cardC = rand 2..14\n  printCard cardC\n  echo \"\"\n\nproc getBet(): int =\n  result = stash + 1 #ensure we enter the loop\n  while (result < 0) or (result > stash):\n    echo \"WHAT IS YOUR BET: \"\n    result = readLine(stdin).parseInt()\n    if result > stash:\n      echo \"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\"\n      echo \"YOU HAVE ONLY \", stash, \" DOLLARS TO BET.\"\n    if result == 0:\n      echo \"CHICKEN!!\"\n\nproc tryAgain(): bool =\n  echo \"TRY AGAIN (YES OR NO)\"\n  var answer = readLine(stdin).normalize()\n  result = (answer == \"y\") or (answer == \"yes\")\n\nprintGreeting()\nwhile retry:\n  stash = 100\n  while stash > 0:\n    printBalance()\n    drawDealerCards()\n    bet = getBet()\n    echo \"\"\n    drawPlayerCard()\n    if (cardC >= cardA) and (cardC <= cardB):\n      echo \"YOU WIN!!!\"\n      stash += bet\n    else:\n      if bet > 0:\n        echo \"SORRY, YOU LOSE\"\n        stash -= bet\n  echo \"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\"\n  echo \"\"\n  retry = tryAgain()\necho \"O.K., HOPE YOU HAD FUN!\"\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/.gitattributes",
    "content": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text=auto\n\n# Explicitly declare text files you want to always be normalized and converted\n# to native line endings on checkout.\n*.inc  text\n*.pas  text\n*.pp   text\n*.lpk  text\n*.lpi  text\n*.lps  text\n*.lpr  text\n*.def  text\n*.css  text\n*.html text\n*.xml  text\n*.sql  text\n\n# Declare files that will always have CRLF line endings on checkout.\n*.dpk   text eol=crlf\n*.dproj text eol=crlf\n\n# Declare files that will always have LF line endings on checkout.\n\n\n# Denote all files that are truly binary and should not be modified.\n*.png binary\n*.jpg binary\n*.exe binary\n*.res binary\n*.ico binary\n*.dll binary\n\n# Keep these files from archive/exports, mainly from production.\n.gitignore      export-ignore\n.gitattributes  export-ignore\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/.gitignore",
    "content": "# Basic Computer Programs project specific\naceyducey\naceyducey.exe\n\n# Compiled l10n files: .mo should be ignored\n*.mo\n\n# Ghostwriter backups\n*.backup\n\n# nano editor backup files\n*.swp\n\n# Uncomment these types if you want even more clean repository. But be careful.\n# It can make harm to an existing project source. Read explanations below.\n#\n# Resource files are binaries containing manifest, project icon and version info.\n# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.\n*.res\n\n# Delphi/Lazarus compiler-generated binaries (safe to delete)\n*.exe\n*.dll\n*.bpl\n*.bpi\n*.dcp\n*.so\n*.apk\n*.drc\n*.map\n*.dres\n*.rsm\n*.tds\n*.dcu\n*.lib\n*.[ao]\n*.or\n*.ppu\n*.dbg\n*.compiled\n\n# Delphi autogenerated files (duplicated info)\n*.cfg\n*Resource.rc\n\n# Delphi local files (user-specific info)\n*.local\n*.identcache\n*.projdata\n*.tvsconfig\n*.dsk\n\n# Delphi history and backups\n__history/\n*.~*\n\n# Lazarus history, backups and session\nbackup/\n*.bak\n*.lps\n\n# Castalia statistics file\n*.stat\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) by Gustavo Carreno [gcarreno@github](https://github.com/gcarreno)\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/object-pascal/aceyducey.lpi",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"11\"/>\n    <General>\n      <Flags>\n        <MainUnitHasCreateFormStatements Value=\"False\"/>\n        <MainUnitHasTitleStatement Value=\"False\"/>\n        <MainUnitHasScaledStatement Value=\"False\"/>\n      </Flags>\n      <SessionStorage Value=\"InProjectDir\"/>\n      <MainUnit Value=\"0\"/>\n      <Title Value=\"aceyducey\"/>\n      <UseAppBundle Value=\"False\"/>\n      <ResourceType Value=\"res\"/>\n    </General>\n    <BuildModes Count=\"1\">\n      <Item1 Name=\"Default\" Default=\"True\"/>\n    </BuildModes>\n    <PublishOptions>\n      <Version Value=\"2\"/>\n      <UseFileFilters Value=\"True\"/>\n    </PublishOptions>\n    <RunParams>\n      <FormatVersion Value=\"2\"/>\n      <Modes Count=\"0\"/>\n    </RunParams>\n    <Units Count=\"3\">\n      <Unit0>\n        <Filename Value=\"aceyducey.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n      </Unit0>\n      <Unit1>\n        <Filename Value=\"game.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n        <UnitName Value=\"Game\"/>\n      </Unit1>\n      <Unit2>\n        <Filename Value=\"deck.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n        <UnitName Value=\"Deck\"/>\n      </Unit2>\n    </Units>\n  </ProjectOptions>\n  <CompilerOptions>\n    <Version Value=\"11\"/>\n    <Target>\n      <Filename Value=\"aceyducey\"/>\n    </Target>\n    <SearchPaths>\n      <IncludeFiles Value=\"$(ProjOutDir)\"/>\n      <UnitOutputDirectory Value=\"lib/$(TargetCPU)-$(TargetOS)\"/>\n    </SearchPaths>\n  </CompilerOptions>\n  <Debugging>\n    <Exceptions Count=\"3\">\n      <Item1>\n        <Name Value=\"EAbort\"/>\n      </Item1>\n      <Item2>\n        <Name Value=\"ECodetoolError\"/>\n      </Item2>\n      <Item3>\n        <Name Value=\"EFOpenError\"/>\n      </Item3>\n    </Exceptions>\n  </Debugging>\n</CONFIG>\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/object-pascal/aceyducey.pas",
    "content": "program aceyducey;\n\n{$IFDEF FPC}\n{$mode objfpc}{$H+}\n{$ENDIF}\n\nuses\n  Game\n, Deck\n;\n\nvar\n  Acey_Ducey: TGame;\n\nbegin\n  Acey_Ducey:= TGame.Create;\n  Acey_Ducey.Run;\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/object-pascal/deck.pas",
    "content": "unit Deck;\n\n{$IFDEF FPC}\n{$mode objfpc}{$H+}\n{$ENDIF}\n\ninterface\n\nuses\n  Classes\n, SysUtils\n;\n\ntype\n{ TDeck }\n  TDeck = class\n  private\n    FDealerLow: Integer;\n    FDealerHigh: Integer;\n    FPlayer: Integer;\n\n    procedure PrintCard(const ACard: Integer);\n  protected\n  public\n    property DealerLow: Integer\n      read FDealerLow;\n    property DealerHigh: Integer\n      read FDealerHigh;\n    property Player: Integer\n      read FPlayer;\n\n    procedure DrawCards;\n    procedure ShowDealerCards;\n    procedure ShowPlayerCard;\n    function PlayerWins: Boolean;\n  published\n  end;\n\nimplementation\n\n{ TDeck }\n\nprocedure TDeck.PrintCard(const ACard: Integer);\nbegin\n  if ACard < 11 then\n  begin\n    Write(ACard);\n  end;\n  if ACard = 11 then\n  begin\n    Write('JACK');\n  end;\n  if ACard = 12 then\n  begin\n    Write('QUEEN');\n  end;\n  if ACard = 13 then\n  begin\n    Write('KING');\n  end;\n  if ACard = 14 then\n  begin\n    Write('ACE');\n  end;\nend;\n\nprocedure TDeck.DrawCards;\nvar\n  tmp: Integer;\nbegin\n  repeat\n    FDealerLow:= Random(14) + 2;\n  until (FDealerLow >= 2) and (FDealerLow <= 14);\n  repeat\n    FDealerHigh:= Random(14) + 2;\n  until (FDealerHigh >= 2) and (FDealerHigh <= 14) and (FDealerLow <> FDealerHigh);\n  if FDealerLow > FDealerHigh then\n  begin\n    tmp:= FDealerHigh;\n    FDealerHigh:= FDealerLow;\n    FDealerLow:= tmp;\n  end;\n  repeat\n    FPlayer:= Random(14) + 2;\n  until (FPlayer >= 2) and (FPlayer <= 14);\nend;\n\nprocedure TDeck.ShowDealerCards;\nbegin\n  Write('HERE ARE YOUR NEXT TWO CARDS: ');\n  PrintCard(FDealerLow);\n  Write(' ');\n  PrintCard(FDealerHigh);\n  WriteLN;\n  WriteLN;\nend;\n\nprocedure TDeck.ShowPlayerCard;\nbegin\n  PrintCard(FPlayer);\n  WriteLN;\n  WriteLN;\nend;\n\nfunction TDeck.PlayerWins: Boolean;\nbegin\n  Result:= (FPlayer > FDealerLow) and (FPlayer < FDealerHigh);\nend;\n\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/object-pascal/game.pas",
    "content": "unit Game;\n\n{$IFDEF FPC}\n{$mode objfpc}{$H+}\n{$ENDIF}\n\ninterface\n\nuses\n  Classes\n, SysUtils\n, Crt\n, Deck\n;\n\ntype\n{ TGame }\n  TGame = class\n  private\n    FStash: Integer;\n    FBet: Integer;\n    FDeck: TDeck;\n\n    procedure PrintGreeting;\n    procedure PrintBalance;\n    function GetBet: Integer;\n    function TryAgain: Boolean;\n  protected\n  public\n    constructor Create;\n    destructor Destroy; override;\n\n    procedure Run;\n  published\n  end;\n\nimplementation\n\n{ TGame }\n\nprocedure TGame.PrintGreeting;\nbegin\n  WriteLN(' ':26, 'ACEY DUCEY CARD GAME');\n  WriteLN(' ':15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY');\n  WriteLN;\n  WriteLN;\n  WriteLN('ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER ');\n  WriteLN('THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP');\n  WriteLN('YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING');\n  WriteLN('ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE');\n  WriteLN('A VALUE BETWEEN THE FIRST TWO.');\n  WriteLN('IF YOU DO NOT WANT TO BET, INPUT A 0');\n  WriteLN;\nend;\n\nprocedure TGame.PrintBalance;\nbegin\n  WriteLN('YOU NOW HAVE ', FStash,' DOLLARS.');\n  WriteLN;\nend;\n\nfunction TGame.GetBet: Integer;\nbegin\n  Result:= 0;\n  repeat\n    Write('WHAT IS YOUR BET: ');\n    ReadLN(Result);\n    if Result > FStash then\n    begin\n      WriteLn('SORRY, MY FRIEND, BUT YOU BET TOO MUCH.');\n      WriteLn('YOU HAVE ONLY ', FStash,' DOLLARS TO BET.');\n    end;\n  until (Result >=0) and (Result <= FStash);\nend;\n\nfunction TGame.TryAgain: Boolean;\nvar\n  answer: String;\nbegin\n  Result:= False;\n  Write('TRY AGAIN (YES OR NO)');\n  ReadLn(answer);\n  Result:= (LowerCase(answer)='yes') or (LowerCase(answer)='y');\nend;\n\nconstructor TGame.Create;\nbegin\n  Randomize;\n  FDeck:= TDeck.Create;\nend;\n\ndestructor TGame.Destroy;\nbegin\n  FDeck.Free;\n  inherited Destroy;\nend;\n\nprocedure TGame.Run;\nbegin\n  ClrScr;\n  PrintGreeting;\n  repeat\n    FStash:= 100;\n    repeat\n      PrintBalance;\n      FDeck.DrawCards;\n      //DrawDealerCards;\n      FDeck.ShowDealerCards;\n      FBet:= GetBet;\n      if FBet = 0 then\n      begin\n        WriteLN('CHICKEN!!');\n        continue;\n      end;\n      //DrawPlayerCard;\n      FDeck.ShowPlayerCard;\n      //if (FCardC > FCardA) and (FCardC < FCardB) then\n      if FDeck.PlayerWins then\n      begin\n        WriteLN('YOU WIN!!!');\n        Inc(FStash, FBet)\n      end\n      else\n      begin\n        WriteLN('SORRY, YOU LOSE');\n        Dec(FStash, FBet)\n      end;\n    until FStash = 0;\n    WriteLN('SORRY, FRIEND, BUT YOU BLEW YOUR WAD.');\n    WriteLN;\n  until not TryAgain;\n  WriteLN('O.K., HOPE YOU HAD FUN!');\nend;\n\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/simple/aceyducey.lpi",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"11\"/>\n    <General>\n      <Flags>\n        <MainUnitHasCreateFormStatements Value=\"False\"/>\n        <MainUnitHasTitleStatement Value=\"False\"/>\n        <MainUnitHasScaledStatement Value=\"False\"/>\n      </Flags>\n      <SessionStorage Value=\"InProjectDir\"/>\n      <MainUnit Value=\"0\"/>\n      <Title Value=\"aceyducey\"/>\n      <UseAppBundle Value=\"False\"/>\n      <ResourceType Value=\"res\"/>\n    </General>\n    <BuildModes Count=\"1\">\n      <Item1 Name=\"Default\" Default=\"True\"/>\n    </BuildModes>\n    <PublishOptions>\n      <Version Value=\"2\"/>\n      <UseFileFilters Value=\"True\"/>\n    </PublishOptions>\n    <RunParams>\n      <FormatVersion Value=\"2\"/>\n      <Modes Count=\"0\"/>\n    </RunParams>\n    <Units Count=\"1\">\n      <Unit0>\n        <Filename Value=\"aceyducey.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n      </Unit0>\n    </Units>\n  </ProjectOptions>\n  <CompilerOptions>\n    <Version Value=\"11\"/>\n    <Target>\n      <Filename Value=\"aceyducey\"/>\n    </Target>\n    <SearchPaths>\n      <IncludeFiles Value=\"$(ProjOutDir)\"/>\n      <UnitOutputDirectory Value=\"lib/$(TargetCPU)-$(TargetOS)\"/>\n    </SearchPaths>\n  </CompilerOptions>\n  <Debugging>\n    <Exceptions Count=\"3\">\n      <Item1>\n        <Name Value=\"EAbort\"/>\n      </Item1>\n      <Item2>\n        <Name Value=\"ECodetoolError\"/>\n      </Item2>\n      <Item3>\n        <Name Value=\"EFOpenError\"/>\n      </Item3>\n    </Exceptions>\n  </Debugging>\n</CONFIG>\n"
  },
  {
    "path": "00_Alternate_Languages/01_Acey_Ducey/pascal/simple/aceyducey.pas",
    "content": "program aceyducey;\n\n{$IFDEF FPC}\n{$mode objfpc}{$H+}\n{$ENDIF}\n\nuses\n Crt;\n\nvar\n  Stash: Integer;\n  CardA: Integer;\n  CardB: Integer;\n  CardC: Integer;\n  Bet: Integer;\n\nprocedure PrintGreeting;\nbegin\n  WriteLN(' ':26, 'ACEY DUCEY CARD GAME');\n  WriteLN(' ':15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY');\n  WriteLN;\n  WriteLN;\n  WriteLN('ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER ');\n  WriteLN('THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP');\n  WriteLN('YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING');\n  WriteLN('ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE');\n  WriteLN('A VALUE BETWEEN THE FIRST TWO.');\n  WriteLN('IF YOU DO NOT WANT TO BET, INPUT A 0');\n  WriteLN;\nend;\n\nprocedure PrintBalance;\nbegin\n  WriteLN('YOU NOW HAVE ', Stash,' DOLLARS.');\n  WriteLN;\nend;\n\nprocedure PrintCard(const ACard: Integer);\nbegin\n  if ACard < 11 then\n  begin\n    Write(ACard);\n  end;\n  if ACard = 11 then\n  begin\n    Write('JACK');\n  end;\n  if ACard = 12 then\n  begin\n    Write('QUEEN');\n  end;\n  if ACard = 13 then\n  begin\n    Write('KING');\n  end;\n  if ACard = 14 then\n  begin\n    Write('ACE');\n  end;\nend;\n\nprocedure DrawDealerCards;\nvar\n  tmp: Integer;\nbegin\n  Write('HERE ARE YOUR NEXT TWO CARDS: ');\n  repeat\n    CardA:= Random(14) + 2;\n  until (CardA >= 2) and (CardA <= 14);\n  repeat\n    CardB:= Random(14) + 2;\n  until (CardB >= 2) and (CardB <= 14) and (CardA <> CardB);\n  if CardA > CardB then\n  begin\n    tmp:= CardB;\n    CardB:= CardA;\n    CardA:= tmp;\n  end;\n  PrintCard(CardA);\n  Write(' ');\n  PrintCard(CardB);\n  WriteLN;\n  WriteLN;\nend;\n\nprocedure DrawPlayerCard;\nbegin\n  repeat\n    CardC:= Random(14) + 2;\n  until (CardC >= 2) and (CardC <= 14);\n  PrintCard(CardC);\n  WriteLN;\n  WriteLN;\nend;\n\nfunction GetBet: Integer;\nbegin\n  Result:= 0;\n  repeat\n    Write('WHAT IS YOUR BET: ');\n    ReadLN(Result);\n    if Result > Stash then\n    begin\n      WriteLn('SORRY, MY FRIEND, BUT YOU BET TOO MUCH.');\n      WriteLn('YOU HAVE ONLY ', Stash,' DOLLARS TO BET.');\n    end;\n  until (Result >=0) and (Result <= Stash);\nend;\n\nfunction TryAgain: Boolean;\nvar\n  answer: String;\nbegin\n  Result:= False;\n  Write('TRY AGAIN (YES OR NO)');\n  ReadLn(answer);\n  Result:= (LowerCase(answer)='yes') or (LowerCase(answer)='y');\nend;\n\nbegin\n  Randomize;\n  ClrScr;\n  PrintGreeting;\n  repeat\n    Stash:= 100;\n    repeat\n      PrintBalance;\n      DrawDealerCards;\n      Bet:= GetBet;\n      if Bet = 0 then\n      begin\n        WriteLN('CHICKEN!!');\n        continue;\n      end;\n      DrawPlayerCard;\n      if (CardC > CardA) and (CardC < CardB) then\n      begin\n        WriteLN('YOU WIN!!!');\n        Inc(Stash, Bet)\n      end\n      else\n      begin\n        WriteLN('SORRY, YOU LOSE');\n        Dec(Stash, Bet)\n      end;\n    until Stash = 0;\n    WriteLN('SORRY, FRIEND, BUT YOU BLEW YOUR WAD.');\n    WriteLN;\n  until not TryAgain;\n  WriteLN('O.K., HOPE YOU HAD FUN!');\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript amazing.ms\n```\nNote that because this program imports \"listUtil\", you will need to have a the standard MiniScript libraries somewhere in your import path.\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"amazing\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms",
    "content": "import \"listUtil\"\nprint \" \"*28 + \"Amazing Program\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print; print\nwhile true\n\tinp = input(\"What and your width and length? \")\n\tinp = inp.replace(\",\", \" \")\n\tfields = inp.split\n\th = fields[0].val; v = fields[-1].val\n\tif h > 1 and v > 1 then break\n\tprint \"Meaningless dimensions.  Try again.\"\nend while\n\n// order: keeps track of the order in which each cell was\n// visited as we built the maze.  0 means not explored yet.  Indexed in [column][row] order.\n// (This is W in the original BASIC program.)\norder = list.init2d(h,v, 0)\n\n// walls: keeps track of the walls below and to the right of each cell:\n//\t\t0: walls below and to the right\n//\t\t1: wall to the right\n//\t\t2: wall below\n//\t\t3: neither wall\n// (This is V in the original BASIC program.)\n// Note that a wall to the right can be removed from a\n// valid entry by adding 2; a wall below can be removed\n// by adding 1.\nwalls = list.init2d(h,v, 0)\nprint\nprint\nprint\nprint\n\n// pick an exit at the top of the maze,\n// and print the maze top\nx = floor(rnd * h)\nfor i in range(0, h-1)\n\tif i == x then print \".  \",\"\" else print \".--\",\"\"\nend for\nprint \".\"\n\n// walk from our starting position (by the exit) around\n// the maze, clearing a wall on each step\nc = 1\t\t// current step number\norder[x][0] = c; c += 1\nr = x; s = 0\t\t// [r][s] is our current position in the maze\nwhile true\n\t// collect the set of directions we can move in\n\tdirs = []\n\tif r > 0 and order[r-1][s] == 0 then dirs.push \"left\"\n\tif s > 0 and order[r][s-1] == 0 then dirs.push \"up\"\n\tif r+1 < h and order[r+1][s] == 0 then dirs.push \"right\"\n\tif s+1 < v and order[r][s+1] == 0 then dirs.push \"down\"\n\tif not dirs then\n\t\t//print \"Uh-oh, I'm stuck at \" + r + \",\" + s\n\t\t// couldn't find any directions for this cell; \n\t\t// find the next already-explored cell\n\t\twhile true\n\t\t\tr += 1\n\t\t\tif r >= h then\n\t\t\t\tr = 0\n\t\t\t\ts += 1\t\t\t\n\t\t\t\tif s >= v then s = 0\n\t\t\tend if\n\t\t\tif order[r][s] != 0 then break\n\t\tend while\n\t\tcontinue\n\tend if\n\t\n\t// pick a random available direction; move there,\n\t// clearing the wall in between and updating order\n\td = dirs.any\n\tif d == \"left\" then\n\t\twalls[r-1][s] += 2\n\t\tr = r-1\n\telse if d == \"up\" then\n\t\twalls[r][s-1] += 1\n\t\ts = s-1\n\telse if d == \"right\" then\n\t\twalls[r][s] += 2\n\t\tr = r+1\n\telse if d == \"down\" then\n\t\twalls[r][s] += 1\n\t\ts = s+1\n\tend if\n\t\n\t//print \"At step \" + c + \", at \" + r + \",\" + s\n\torder[r][s] = c\n\tc += 1\n\tif c > h*v then break\nend while\n\n// pick an exit at the bottom of the maze\nx = floor(rnd * h)\nwalls[x][v-1] += 1\n\n// print the (rest of the) maze\nfor j in range(0, v-1)\n\tprint \"I\", \"\"\n\tfor i in range(0, h-1)\n\tif walls[i][j] < 2 then print \"  I\", \"\" else print \"   \", \"\"\n\tend for\n\tprint\n\tfor i in range(0, h-1)\n\t\tif walls[i][j] % 2 == 0 then print \":--\", \"\" else print \":  \", \"\"\n\tend for\n\tprint \".\"\nend for\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/amazing.bas",
    "content": "10 PRINT TAB(28);\"AMAZING PROGRAM\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT:PRINT\n100 INPUT \"WHAT ARE YOUR WIDTH AND LENGTH\";H,V\n102 IF H<>1 AND V<>1 THEN 110\n104 PRINT \"MEANINGLESS DIMENSIONS.  TRY AGAIN.\":GOTO 100\n110 DIM W(H,V),V(H,V)\n120 PRINT\n130 PRINT\n140 PRINT\n150 PRINT\n160 Q=0:Z=0:X=INT(RND(1)*H+1)\n165 FOR I=1 TO H\n170 IF I=X THEN 173\n171 PRINT \".--\";:GOTO 180\n173 PRINT \".  \";\n180 NEXT I\n190 PRINT \".\"\n195 C=1:W(X,1)=C:C=C+1\n200 R=X:S=1:GOTO 260\n210 IF R<>H THEN 240\n215 IF S<>V THEN 230\n220 R=1:S=1:GOTO 250\n230 R=1:S=S+1:GOTO 250\n240 R=R+1\n250 IF W(R,S)=0 THEN 210\n260 IF R-1=0 THEN 530\n265 IF W(R-1,S)<>0 THEN 530\n270 IF S-1=0 THEN 390\n280 IF W(R,S-1)<>0 THEN 390\n290 IF R=H THEN 330\n300 IF W(R+1,S)<>0 THEN 330\n310 X=INT(RND(1)*3+1)\n320 ON X GOTO 790,820,860\n330 IF S<>V THEN 340\n334 IF Z=1 THEN 370\n338 Q=1:GOTO 350\n340 IF W(R,S+1)<>0 THEN 370\n350 X=INT(RND(1)*3+1)\n360 ON X GOTO 790,820,910\n370 X=INT(RND(1)*2+1)\n380 ON X GOTO 790,820\n390 IF R=H THEN 470\n400 IF W(R+1,S)<>0 THEN 470\n405 IF S<>V THEN 420\n410 IF Z=1 THEN 450\n415 Q=1:GOTO 430\n420 IF W(R,S+1)<>0 THEN 450\n430 X=INT(RND(1)*3+1)\n440 ON X GOTO 790,860,910\n450 X=INT(RND(1)*2+1)\n460 ON X GOTO 790,860\n470 IF S<>V THEN 490\n480 IF Z=1 THEN 520\n485 Q=1:GOTO 500\n490 IF W(R,S+1)<>0 THEN 520\n500 X=INT(RND(1)*2+1)\n510 ON X GOTO 790,910\n520 GOTO 790\n530 IF S-1=0 THEN 670\n540 IF W(R,S-1)<>0 THEN 670\n545 IF R=H THEN 610\n547 IF W(R+1,S)<>0 THEN 610\n550 IF S<>V THEN 560\n552 IF Z=1 THEN 590\n554 Q=1:GOTO 570\n560 IF W(R,S+1)<>0 THEN 590\n570 X=INT(RND(1)*3+1)\n580 ON X GOTO 820,860,910\n590 X=INT(RND(1)*2+1)\n600 ON X GOTO 820,860\n610 IF S<>V THEN 630\n620 IF Z=1 THEN 660\n625 Q=1:GOTO 640\n630 IF W(R,S+1)<>0 THEN 660\n640 X=INT(RND(1)*2+1)\n650 ON X GOTO 820,910\n660 GOTO 820\n670 IF R=H THEN 740\n680 IF W(R+1,S)<>0 THEN 740\n685 IF S<>V THEN 700\n690 IF Z=1 THEN 730\n695 Q=1:GOTO 710\n700 IF W(R,S+1)<>0 THEN 730\n710 X=INT(RND(1)*2+1)\n720 ON X GOTO 860,910\n730 GOTO 860\n740 IF S<>V THEN 760\n750 IF Z=1 THEN 780\n755 Q=1:GOTO 770\n760 IF W(R,S+1)<>0 THEN 780\n770 GOTO 910\n780 GOTO 1000\n790 W(R-1,S)=C\n800 C=C+1:V(R-1,S)=2:R=R-1\n810 IF C=H*V+1 THEN 1010\n815 Q=0:GOTO 260\n820 W(R,S-1)=C\n830 C=C+1\n840 V(R,S-1)=1:S=S-1:IF C=H*V+1 THEN 1010\n850 Q=0:GOTO 260\n860 W(R+1,S)=C\n870 C=C+1:IF V(R,S)=0 THEN 880\n875 V(R,S)=3:GOTO 890\n880 V(R,S)=2\n890 R=R+1\n900 IF C=H*V+1 THEN 1010\n905 GOTO 530\n910 IF Q=1 THEN 960\n920 W(R,S+1)=C:C=C+1:IF V(R,S)=0 THEN 940\n930 V(R,S)=3:GOTO 950\n940 V(R,S)=1\n950 S=S+1:IF C=H*V+1 THEN 1010\n955 GOTO 260\n960 Z=1\n970 IF V(R,S)=0 THEN 980\n975 V(R,S)=3:Q=0:GOTO 1000\n980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250\n1000 GOTO 210\n1010 IF Z=1 THEN 1015\n1011 X=INT(RND(1)*H+1)\n1012 IF V(X,V)=0 THEN 1014\n1013 V(X,V)=3: GOTO 1015\n1014 V(X,V)=1\n1015 FOR J=1 TO V\n1016 PRINT \"I\";\n1017 FOR I=1 TO H\n1018 IF V(I,J)<2 THEN 1030\n1020 PRINT \"   \";\n1021 GOTO 1040\n1030 PRINT \"  I\";\n1040 NEXT I\n1041 PRINT\n1043 FOR I=1 TO H\n1045 IF V(I,J)=0 THEN 1060\n1050 IF V(I,J)=2 THEN 1060\n1051 PRINT \":  \";\n1052 GOTO 1070\n1060 PRINT \":--\";\n1070 NEXT I\n1071 PRINT \".\"\n1072 NEXT J\n1073 END\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"log\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"time\"\r\n)\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\r\n\tprintWelcome()\r\n\r\n\th, w := getDimensions()\r\n\tm := NewMaze(h, w)\r\n\tm.draw()\r\n}\r\n\r\ntype direction int64\r\n\r\nconst (\r\n\tLEFT direction = iota\r\n\tUP\r\n\tRIGHT\r\n\tDOWN\r\n)\r\n\r\nconst (\r\n\tEXIT_DOWN  = 1\r\n\tEXIT_RIGHT = 2\r\n)\r\n\r\ntype maze struct {\r\n\twidth    int\r\n\tlength   int\r\n\tused     [][]int\r\n\twalls    [][]int\r\n\tenterCol int\r\n}\r\n\r\nfunc NewMaze(w, l int) maze {\r\n\tif (w < 2) || (l < 2) {\r\n\t\tlog.Fatal(\"invalid dimensions supplied\")\r\n\t}\r\n\r\n\tm := maze{width: w, length: l}\r\n\r\n\tm.used = make([][]int, l)\r\n\tfor i := range m.used {\r\n\t\tm.used[i] = make([]int, w)\r\n\t}\r\n\r\n\tm.walls = make([][]int, l)\r\n\tfor i := range m.walls {\r\n\t\tm.walls[i] = make([]int, w)\r\n\t}\r\n\r\n\t// randomly determine the entry column\r\n\tm.enterCol = rand.Intn(w)\r\n\r\n\t// determine layout of walls\r\n\tm.build()\r\n\r\n\t// add an exit\r\n\tcol := rand.Intn(m.width - 1)\r\n\trow := m.length - 1\r\n\tm.walls[row][col] = m.walls[row][col] + 1\r\n\r\n\treturn m\r\n}\r\n\r\nfunc (m *maze) build() {\r\n\trow := 0\r\n\tcol := 0\r\n\tcount := 2\r\n\r\n\tfor {\r\n\t\tpossibleDirs := m.getPossibleDirections(row, col)\r\n\r\n\t\tif len(possibleDirs) != 0 {\r\n\t\t\trow, col, count = m.makeOpening(possibleDirs, row, col, count)\r\n\t\t} else {\r\n\t\t\tfor {\r\n\t\t\t\tif col != m.width-1 {\r\n\t\t\t\t\tcol = col + 1\r\n\t\t\t\t} else if row != m.length-1 {\r\n\t\t\t\t\trow = row + 1\r\n\t\t\t\t\tcol = 0\r\n\t\t\t\t} else {\r\n\t\t\t\t\trow = 0\r\n\t\t\t\t\tcol = 0\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif m.used[row][col] != 0 {\r\n\t\t\t\t\tbreak\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif count == (m.width*m.length)+1 {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\r\n}\r\n\r\nfunc (m *maze) getPossibleDirections(row, col int) []direction {\r\n\tpossible_dirs := make(map[direction]bool, 4)\r\n\tpossible_dirs[LEFT] = true\r\n\tpossible_dirs[UP] = true\r\n\tpossible_dirs[RIGHT] = true\r\n\tpossible_dirs[DOWN] = true\r\n\r\n\tif (col == 0) || (m.used[row][col-1] != 0) {\r\n\t\tpossible_dirs[LEFT] = false\r\n\t}\r\n\tif (row == 0) || (m.used[row-1][col] != 0) {\r\n\t\tpossible_dirs[UP] = false\r\n\t}\r\n\tif (col == m.width-1) || (m.used[row][col+1] != 0) {\r\n\t\tpossible_dirs[RIGHT] = false\r\n\t}\r\n\tif (row == m.length-1) || (m.used[row+1][col] != 0) {\r\n\t\tpossible_dirs[DOWN] = false\r\n\t}\r\n\r\n\tret := make([]direction, 0)\r\n\tfor d, v := range possible_dirs {\r\n\t\tif v {\r\n\t\t\tret = append(ret, d)\r\n\t\t}\r\n\t}\r\n\treturn ret\r\n}\r\n\r\nfunc (m *maze) makeOpening(dirs []direction, row, col, count int) (int, int, int) {\r\n\tdir := rand.Intn(len(dirs))\r\n\r\n\tif dirs[dir] == LEFT {\r\n\t\tcol = col - 1\r\n\t\tm.walls[row][col] = int(EXIT_RIGHT)\r\n\t} else if dirs[dir] == UP {\r\n\t\trow = row - 1\r\n\t\tm.walls[row][col] = int(EXIT_DOWN)\r\n\t} else if dirs[dir] == RIGHT {\r\n\t\tm.walls[row][col] = m.walls[row][col] + EXIT_RIGHT\r\n\t\tcol = col + 1\r\n\t} else if dirs[dir] == DOWN {\r\n\t\tm.walls[row][col] = m.walls[row][col] + EXIT_DOWN\r\n\t\trow = row + 1\r\n\t}\r\n\r\n\tm.used[row][col] = count\r\n\tcount = count + 1\r\n\treturn row, col, count\r\n}\r\n\r\n// draw the maze\r\nfunc (m *maze) draw() {\r\n\tfor col := 0; col < m.width; col++ {\r\n\t\tif col == m.enterCol {\r\n\t\t\tfmt.Print(\".  \")\r\n\t\t} else {\r\n\t\t\tfmt.Print(\".--\")\r\n\t\t}\r\n\t}\r\n\tfmt.Println(\".\")\r\n\r\n\tfor row := 0; row < m.length; row++ {\r\n\t\tfmt.Print(\"|\")\r\n\t\tfor col := 0; col < m.width; col++ {\r\n\t\t\tif m.walls[row][col] < 2 {\r\n\t\t\t\tfmt.Print(\"  |\")\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Print(\"   \")\r\n\t\t\t}\r\n\t\t}\r\n\t\tfmt.Println()\r\n\t\tfor col := 0; col < m.width; col++ {\r\n\t\t\tif (m.walls[row][col] == 0) || (m.walls[row][col] == 2) {\r\n\t\t\t\tfmt.Print(\":--\")\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Print(\":  \")\r\n\t\t\t}\r\n\t\t}\r\n\t\tfmt.Println(\".\")\r\n\t}\r\n}\r\n\r\nfunc printWelcome() {\r\n\tfmt.Println(\"                            AMAZING PROGRAM\")\r\n\tfmt.Print(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\r\n}\r\n\r\nfunc getDimensions() (int, int) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfmt.Println(\"Enter a width ( > 1 ):\")\r\n\tscanner.Scan()\r\n\tw, err := strconv.Atoi(scanner.Text())\r\n\tif err != nil {\r\n\t\tlog.Fatal(\"invalid dimension\")\r\n\t}\r\n\r\n\tfmt.Println(\"Enter a height ( > 1 ):\")\r\n\tscanner.Scan()\r\n\th, err := strconv.Atoi(scanner.Text())\r\n\tif err != nil {\r\n\t\tlog.Fatal(\"invalid dimension\")\r\n\t}\r\n\r\n\treturn w, h\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/.gitattributes",
    "content": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text=auto\n\n# Explicitly declare text files you want to always be normalized and converted\n# to native line endings on checkout.\n*.inc  text\n*.pas  text\n*.pp   text\n*.lpk  text\n*.lpi  text\n*.lps  text\n*.lpr  text\n*.def  text\n*.css  text\n*.html text\n*.xml  text\n*.sql  text\n\n# Declare files that will always have CRLF line endings on checkout.\n*.dpk   text eol=crlf\n*.dproj text eol=crlf\n\n# Declare files that will always have LF line endings on checkout.\n\n\n# Denote all files that are truly binary and should not be modified.\n*.png binary\n*.jpg binary\n*.exe binary\n*.res binary\n*.ico binary\n*.dll binary\n\n# Keep these files from archive/exports, mainly from production.\n.gitignore      export-ignore\n.gitattributes  export-ignore\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/.gitignore",
    "content": "# Basic Computer Programs project specific\namazing\namazing.exe\n\n# Compiled l10n files: .mo should be ignored\n*.mo\n\n# Ghostwriter backups\n*.backup\n\n# nano editor backup files\n*.swp\n\n# Uncomment these types if you want even more clean repository. But be careful.\n# It can make harm to an existing project source. Read explanations below.\n#\n# Resource files are binaries containing manifest, project icon and version info.\n# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.\n*.res\n\n# Delphi/Lazarus compiler-generated binaries (safe to delete)\n*.exe\n*.dll\n*.bpl\n*.bpi\n*.dcp\n*.so\n*.apk\n*.drc\n*.map\n*.dres\n*.rsm\n*.tds\n*.dcu\n*.lib\n*.[ao]\n*.or\n*.ppu\n*.dbg\n*.compiled\n\n# Delphi autogenerated files (duplicated info)\n*.cfg\n*Resource.rc\n\n# Delphi local files (user-specific info)\n*.local\n*.identcache\n*.projdata\n*.tvsconfig\n*.dsk\n\n# Delphi history and backups\n__history/\n*.~*\n\n# Lazarus history, backups and session\nbackup/\n*.bak\n*.lps\n\n# Castalia statistics file\n*.stat\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) by Gustavo Carreno [gcarreno@github](https://github.com/gcarreno)\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazing.lpi",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"12\"/>\n    <General>\n      <Flags>\n        <MainUnitHasCreateFormStatements Value=\"False\"/>\n        <MainUnitHasTitleStatement Value=\"False\"/>\n        <MainUnitHasScaledStatement Value=\"False\"/>\n      </Flags>\n      <SessionStorage Value=\"InProjectDir\"/>\n      <Title Value=\"amazing\"/>\n      <UseAppBundle Value=\"False\"/>\n      <ResourceType Value=\"res\"/>\n    </General>\n    <BuildModes Count=\"1\">\n      <Item1 Name=\"Default\" Default=\"True\"/>\n    </BuildModes>\n    <PublishOptions>\n      <Version Value=\"2\"/>\n      <UseFileFilters Value=\"True\"/>\n    </PublishOptions>\n    <RunParams>\n      <FormatVersion Value=\"2\"/>\n    </RunParams>\n    <Units Count=\"4\">\n      <Unit0>\n        <Filename Value=\"amazing.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n      </Unit0>\n      <Unit1>\n        <Filename Value=\"amazingapplication.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n        <UnitName Value=\"AmazingApplication\"/>\n      </Unit1>\n      <Unit2>\n        <Filename Value=\"maze.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n        <UnitName Value=\"Maze\"/>\n      </Unit2>\n      <Unit3>\n        <Filename Value=\"room.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n        <UnitName Value=\"Room\"/>\n      </Unit3>\n    </Units>\n  </ProjectOptions>\n  <CompilerOptions>\n    <Version Value=\"11\"/>\n    <Target>\n      <Filename Value=\"amazing\"/>\n    </Target>\n    <SearchPaths>\n      <IncludeFiles Value=\"$(ProjOutDir)\"/>\n      <UnitOutputDirectory Value=\"lib/$(TargetCPU)-$(TargetOS)\"/>\n    </SearchPaths>\n  </CompilerOptions>\n  <Debugging>\n    <Exceptions Count=\"3\">\n      <Item1>\n        <Name Value=\"EAbort\"/>\n      </Item1>\n      <Item2>\n        <Name Value=\"ECodetoolError\"/>\n      </Item2>\n      <Item3>\n        <Name Value=\"EFOpenError\"/>\n      </Item3>\n    </Exceptions>\n  </Debugging>\n</CONFIG>\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazing.pas",
    "content": "program amazing;\n\n{$IFDEF FPC}\n{$mode ObjFPC}{$H+}\n{$ENDIF}\n\nuses\n  AmazingApplication, maze, Room;\n\nvar\n  AmazingApp: TAmazingApplication;\n\nbegin\n  AmazingApp:= TAmazingApplication.Create;\n  AmazingApp.Run;\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazingapplication.pas",
    "content": "unit AmazingApplication;\n\n{$IFDEF FPC}\n{$mode ObjFPC}{$H+}\n{$ENDIF}\n\ninterface\n\nuses\n  Classes\n, SysUtils\n, Crt\n, Maze\n;\n\ntype\n{ TAmazingApplication }\n  TAmazingApplication = class(TObject)\n  private\n    FMaze: TMaze;\n\n    procedure PrintGreeting;\n    procedure GetDimensions;\n    procedure BuildMaze;\n    procedure PrintMaze;\n  protected\n  public\n    constructor Create;\n    destructor Destroy; override;\n\n    procedure Run;\n  published\n  end;\n\nimplementation\n\n{ TAmazingApplication }\n\nprocedure TAmazingApplication.PrintGreeting;\nbegin\n  WriteLN(' ':28, 'AMAZING PROGRAM');\n  WriteLN(' ':15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY');\n  WriteLN;\n  WriteLN;\n  WriteLN;\n  WriteLN;\nend;\n\nprocedure TAmazingApplication.GetDimensions;\nvar\n  width: Integer;\n  length: Integer;\nbegin\n  repeat\n    Write('WHAT ARE YOUR WIDTH AND LENGTH (SPACE IN BETWEEN): ');\n    ReadLN(width, length);\n    if (width = 1) or (length = 1) then\n    begin\n      WriteLN('MEANINGLESS DIMENSIONS.  TRY AGAIN.');\n    end;\n  until (width > 1) and (length > 1);\n  FMaze:= TMaze.Create(width, length);\n  WriteLN;\n  WriteLN;\n  WriteLN;\n  WriteLN;\nend;\n\nprocedure TAmazingApplication.BuildMaze;\nbegin\n  FMaze.Build;\nend;\n\nprocedure TAmazingApplication.PrintMaze;\nbegin\n  FMaze.Print;\n  WriteLN;\nend;\n\nconstructor TAmazingApplication.Create;\nbegin\n  //\nend;\n\ndestructor TAmazingApplication.Destroy;\nbegin\n  if Assigned(FMaze) then\n  begin\n    FMaze.Free;\n  end;\n  inherited Destroy;\nend;\n\nprocedure TAmazingApplication.Run;\nbegin\n  //ClrScr;\n  PrintGreeting;\n  GetDimensions;\n  BuildMaze;\n  PrintMaze;\nend;\n\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/object-pascal/maze.pas",
    "content": "unit Maze;\n\n{$IFDEF FPC}\n{$mode ObjFPC}{$H+}\n{$ENDIF}\n\ninterface\n\nuses\n  Classes\n, SysUtils\n, Room\n;\n\ntype\n  TDirection = (dUp, dRight, dDown, dLeft);\n  TDirections = set of TDirection;\n{ TMaze }\n  TMaze = class(TObject)\n  private\n    FWidth: Integer;\n    FLength: Integer;\n    FEntry: Integer;\n    FLabyrinth: Array of Array of TRoom;\n\n    function GetRandomDirection(const ADirections: TDirections): TDirection;\n\n    procedure DebugVisited;\n    procedure DebugWalls;\n  protected\n  public\n    constructor Create(const AWidth, ALength: Integer);\n    destructor Destroy; override;\n\n    procedure Build;\n    procedure Print;\n  published\n  end;\n\nimplementation\n\nconst\n  EXIT_DOWN  = 1;\n  EXIT_RIGHT = 2;\n\n{ TMaze }\n\nfunction TMaze.GetRandomDirection(const ADirections: TDirections): TDirection;\nvar\n  count: Integer;\n  position: Integer;\n  directions: array [0..3] of TDirection;\nbegin\n  count:= 0;\n  position:= 0;\n  if dUp in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dUp;\n    Inc(position);\n  end;\n  if dRight in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dRight;\n    Inc(position);\n  end;\n  if dDown in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dDown;\n    Inc(position);\n  end;\n  if dLeft in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dLeft;\n    Inc(position);\n  end;\n  Result:= directions[Random(count)];\nend;\n\nprocedure TMaze.DebugVisited;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  WriteLN('Visited');\n  for indexL:= 0 to Pred(FLength) do\n  begin\n    for indexW:= 0 to Pred(FWidth) do\n    begin\n      Write(FLabyrinth[indexW][indexL].Visited:3,' ');\n    end;\n    WriteLN;\n  end;\n  WriteLN;\nend;\n\nprocedure TMaze.DebugWalls;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  WriteLN('Walls');\n  for indexL:= 0 to Pred(FLength) do\n  begin\n    for indexW:= 0 to Pred(FWidth) do\n    begin\n      Write(FLabyrinth[indexW][indexL].Walls:3,' ');\n    end;\n    WriteLN;\n  end;\n  WriteLN;\nend;\n\nconstructor TMaze.Create(const AWidth, ALength: Integer);\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  Randomize;\n  FWidth:= AWidth;\n  FLength:= ALength;\n  FEntry:= Random(FWidth);\n  SetLength(FLabyrinth, FWidth, FLength);\n  for indexW:= 0 to Pred(FWidth) do\n  begin\n    for indexL:= 0 to Pred(FLength) do\n    begin\n      FLabyrinth[indexW][indexL]:= TRoom.Create;\n    end;\n  end;\nend;\n\ndestructor TMaze.Destroy;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  for indexW:= 0 to Pred(FWidth) do\n  begin\n    for indexL:= 0 to Pred(FLength) do\n    begin\n      if Assigned(FLabyrinth[indexW][indexL]) then\n      begin\n        FLabyrinth[indexW][indexL].Free;\n      end;\n    end;\n  end;\n  inherited Destroy;\nend;\n\nprocedure TMaze.Build;\nvar\n  indexW: Integer;\n  indexL: Integer;\n  direction: TDirection;\n  directions: TDirections;\n  count: Integer;\nbegin\n  FEntry:= Random(FWidth);\n  indexW:= FEntry;\n  indexL:= 0;\n  count:= 1;\n  FLabyrinth[indexW][indexL].Visited:= count;\n  Inc(count);\n  repeat\n    directions:= [dUp, dRight, dDown, dLeft];\n    if (indexW = 0) or (FLabyrinth[Pred(indexW)][indexL].Visited <> 0) then\n    begin\n      Exclude(directions, dLeft);\n    end;\n    if (indexL = 0) or (FLabyrinth[indexW][Pred(indexL)].Visited <> 0) then\n    begin\n      Exclude(directions, dUp);\n    end;\n    if (indexW = Pred(FWidth)) or (FLabyrinth[Succ(indexW)][indexL].Visited <> 0) then\n    begin\n      Exclude(directions, dRight);\n    end;\n    if (indexL = Pred(FLength)) or (FLabyrinth[indexW][Succ(indexL)].Visited <> 0) then\n    begin\n      Exclude(directions, dDown);\n    end;\n\n    if directions <> [] then\n    begin\n      direction:= GetRandomDirection(directions);\n      case direction of\n        dLeft:begin\n          Dec(indexW);\n          FLabyrinth[indexW][indexL].Walls:= EXIT_RIGHT;\n        end;\n        dUp:begin\n          Dec(indexL);\n          FLabyrinth[indexW][indexL].Walls:= EXIT_DOWN;\n        end;\n        dRight:begin\n          FLabyrinth[indexW][indexL].Walls:= FLabyrinth[indexW][indexL].Walls + EXIT_RIGHT;\n          Inc(indexW);\n        end;\n        dDown:begin\n          FLabyrinth[indexW][indexL].Walls:= FLabyrinth[indexW][indexL].Walls + EXIT_DOWN;\n          Inc(indexL);\n        end;\n      end;\n      FLabyrinth[indexW][indexL].Visited:= count;\n      Inc(count);\n    end\n    else\n    begin\n      while True do\n      begin\n        if indexW <> Pred(FWidth) then\n        begin\n          Inc(indexW);\n        end\n        else if indexL <> Pred(FLength) then\n        begin\n          Inc(indexL);\n          indexW:= 0;\n        end\n        else\n        begin\n          indexW:= 0;\n          indexL:= 0;\n        end;\n        if FLabyrinth[indexW][indexL].Visited <> 0 then\n        begin\n          break;\n        end;\n      end;\n    end;\n  until count = (FWidth * FLength) + 1;\n  indexW:= Random(FWidth);\n  indexL:= Pred(FLength);\n  FLabyrinth[indexW][indexL].Walls:= FLabyrinth[indexW][indexL].Walls + 1;\nend;\n\nprocedure TMaze.Print;\nvar\n  indexW:Integer;\n  indexL: Integer;\nbegin\n\n  //DebugVisited;\n  //DebugWalls;\n\n  for indexW:= 0 to Pred(FWidth) do\n  begin\n    if indexW = FEntry then\n    begin\n      Write('.  ');\n    end\n    else\n    begin\n      Write('.--');\n    end;\n  end;\n  WriteLN('.');\n\n  for indexL:= 0 to Pred(FLength) do\n  begin\n    Write('I');\n    for indexW:= 0 to Pred(FWidth) do\n    begin\n      FLabyrinth[indexW][indexL].PrintRoom;\n    end;\n    WriteLN;\n    for indexW:= 0 to Pred(FWidth) do\n    begin\n      FLabyrinth[indexW][indexL].PrintWall;\n    end;\n    WriteLN('.');\n  end;\nend;\n\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/object-pascal/room.pas",
    "content": "unit Room;\n\n{$IFDEF FPC}\n{$mode ObjFPC}{$H+}\n{$ENDIF}\n\ninterface\n\nuses\n  Classes\n, SysUtils\n;\n\ntype\n{ TRoom }\n  TRoom = class(TObject)\n  private\n    FVisited: Integer;\n    FWalls: Integer;\n  protected\n  public\n    constructor Create;\n\n    procedure PrintRoom;\n    procedure PrintWall;\n\n    property Visited: Integer\n      read FVisited\n      write FVisited;\n    property Walls: Integer\n      read FWalls\n      write FWalls;\n  published\n  end;\n\nimplementation\n\n{ TRoom }\n\nconstructor TRoom.Create;\nbegin\n  FVisited:= 0;\n  FWalls:= 0;\nend;\n\nprocedure TRoom.PrintRoom;\nbegin\n  if FWalls < 2 then\n  begin\n    Write('  I');\n  end\n  else\n  begin\n    Write('   ');\n  end;\nend;\n\nprocedure TRoom.PrintWall;\nbegin\n  if (FWalls = 0) or (FWalls = 2) then\n  begin\n    Write(':--');\n  end\n  else\n  begin\n    Write(':  ');\n  end;\nend;\n\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/simple/amazing.lpi",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CONFIG>\n  <ProjectOptions>\n    <Version Value=\"12\"/>\n    <General>\n      <Flags>\n        <MainUnitHasCreateFormStatements Value=\"False\"/>\n        <MainUnitHasTitleStatement Value=\"False\"/>\n        <MainUnitHasScaledStatement Value=\"False\"/>\n        <CompatibilityMode Value=\"True\"/>\n      </Flags>\n      <SessionStorage Value=\"InProjectDir\"/>\n      <Title Value=\"amazing\"/>\n      <UseAppBundle Value=\"False\"/>\n      <ResourceType Value=\"res\"/>\n    </General>\n    <BuildModes Count=\"1\">\n      <Item1 Name=\"Default\" Default=\"True\"/>\n    </BuildModes>\n    <PublishOptions>\n      <Version Value=\"2\"/>\n      <UseFileFilters Value=\"True\"/>\n    </PublishOptions>\n    <RunParams>\n      <FormatVersion Value=\"2\"/>\n    </RunParams>\n    <Units Count=\"1\">\n      <Unit0>\n        <Filename Value=\"amazing.pas\"/>\n        <IsPartOfProject Value=\"True\"/>\n        <UnitName Value=\"Amazing\"/>\n      </Unit0>\n    </Units>\n  </ProjectOptions>\n  <CompilerOptions>\n    <Version Value=\"11\"/>\n    <Target>\n      <Filename Value=\"amazing\"/>\n    </Target>\n    <SearchPaths>\n      <IncludeFiles Value=\"$(ProjOutDir)\"/>\n      <UnitOutputDirectory Value=\"lib/$(TargetCPU)-$(TargetOS)\"/>\n    </SearchPaths>\n  </CompilerOptions>\n  <Debugging>\n    <Exceptions Count=\"3\">\n      <Item1>\n        <Name Value=\"EAbort\"/>\n      </Item1>\n      <Item2>\n        <Name Value=\"ECodetoolError\"/>\n      </Item2>\n      <Item3>\n        <Name Value=\"EFOpenError\"/>\n      </Item3>\n    </Exceptions>\n  </Debugging>\n</CONFIG>\n"
  },
  {
    "path": "00_Alternate_Languages/02_Amazing/pascal/simple/amazing.pas",
    "content": "program Amazing;\n\n{$IFDEF FPC}\n{$mode objfpc}{$H+}\n{$ENDIF}\n\nuses\n  Crt;\n\ntype\n  TDirection = (dUp, dRight, dDown, dLeft);\n  TDirections = set of TDirection;\n\nvar\n  Width: Integer;   // H\n  Length: Integer;  // V\n  Entry: Integer;\n  MatrixWalls: Array of Array of Integer;\n  MatrixVisited: Array of Array of Integer;\n\nconst\n  EXIT_DOWN  = 1;\n  EXIT_RIGHT = 2;\n\nprocedure PrintGreeting;\nbegin\n  WriteLN(' ':28, 'AMAZING PROGRAM');\n  WriteLN(' ':15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY');\n  WriteLN;\n  WriteLN;\n  WriteLN;\n  WriteLN;\nend;\n\nprocedure GetDimensions;\nbegin\n  repeat\n    Write('WHAT ARE YOUR WIDTH AND LENGTH (SPACE IN BETWEEN): ');\n    ReadLN(Width, Length);\n    if (Width = 1) or (Length = 1) then\n    begin\n      WriteLN('MEANINGLESS DIMENSIONS.  TRY AGAIN.');\n    end;\n  until (Width > 1) and (Length > 1);\n  WriteLN;\n  WriteLN;\n  WriteLN;\n  WriteLN;\nend;\n\nprocedure ClearMatrices;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  SetLength(MatrixWalls, Width, Length);\n  SetLength(MatrixVisited, Width, Length);\n  for indexW:= 0 to Pred(Width) do\n  begin\n    for indexL:= 0 to Pred(Length) do\n    begin\n      MatrixWalls[indexW][indexL]:= 0;\n      MatrixVisited[indexW][indexL]:= 0;\n    end;\n  end;\nend;\n\nfunction GetRandomDirection(const ADirections: TDirections): TDirection;\nvar\n  count: Integer;\n  position: Integer;\n  directions: array [0..3] of TDirection;\nbegin\n  count:= 0;\n  position:= 0;\n  if dUp in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dUp;\n    Inc(position);\n  end;\n  if dRight in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dRight;\n    Inc(position);\n  end;\n  if dDown in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dDown;\n    Inc(position);\n  end;\n  if dLeft in ADirections then\n  begin\n    Inc(count);\n    directions[position]:= dLeft;\n    Inc(position);\n  end;\n  Result:= directions[Random(count)];\nend;\n\nprocedure BuildMaze;\nvar\n  indexW: Integer;\n  indexL: Integer;\n  direction: TDirection;\n  directions: TDirections;\n  count: Integer;\nbegin\n  Entry:= Random(Width);\n  indexW:= Entry;\n  indexL:= 0;\n  count:= 1;\n  MatrixVisited[indexW][indexL]:= count;\n  Inc(count);\n  repeat\n    directions:= [dUp, dRight, dDown, dLeft];\n    if (indexW = 0) or (MatrixVisited[Pred(indexW)][indexL] <> 0) then\n    begin\n      Exclude(directions, dLeft);\n    end;\n    if (indexL = 0) or (MatrixVisited[indexW][Pred(indexL)] <> 0) then\n    begin\n      Exclude(directions, dUp);\n    end;\n    if (indexW = Pred(Width)) or (MatrixVisited[Succ(indexW)][indexL] <> 0) then\n    begin\n      Exclude(directions, dRight);\n    end;\n    if (indexL = Pred(Length)) or (MatrixVisited[indexW][Succ(indexL)] <> 0) then\n    begin\n      Exclude(directions, dDown);\n    end;\n\n    if directions <> [] then\n    begin\n      direction:= GetRandomDirection(directions);\n      case direction of\n        dLeft:begin\n          Dec(indexW);\n          MatrixWalls[indexW][indexL]:= EXIT_RIGHT;\n        end;\n        dUp:begin\n          Dec(indexL);\n          MatrixWalls[indexW][indexL]:= EXIT_DOWN;\n        end;\n        dRight:begin\n          Inc(MatrixWalls[indexW][indexL], EXIT_RIGHT);\n          Inc(indexW);\n        end;\n        dDown:begin\n          Inc(MatrixWalls[indexW][indexL], EXIT_DOWN);\n          Inc(indexL);\n        end;\n      end;\n      MatrixVisited[indexW][indexL]:= count;\n      Inc(count);\n    end\n    else\n    begin\n      while True do\n      begin\n        if indexW <> Pred(Width) then\n        begin\n          Inc(indexW);\n        end\n        else if indexL <> Pred(Length) then\n        begin\n          Inc(indexL);\n          indexW:= 0;\n        end\n        else\n        begin\n          indexW:= 0;\n          indexL:= 0;\n        end;\n        if MatrixVisited[indexW][indexL] <> 0 then\n        begin\n          break;\n        end;\n      end;\n    end;\n  until count = (Width * Length) + 1;\n  indexW:= Random(Width);\n  indexL:= Pred(Length);\n  Inc(MatrixWalls[indexW][indexL]);\nend;\n\nprocedure DegubVisited;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  WriteLN('Visited');\n  for indexL:= 0 to Pred(Length) do\n  begin\n    for indexW:= 0 to Pred(Width) do\n    begin\n      Write(MatrixVisited[indexW][indexL]:2,' ');\n    end;\n    WriteLN;\n  end;\n  WriteLN;\nend;\n\nprocedure DebugWalls;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n  WriteLN('Walls');\n  for indexL:= 0 to Pred(Length) do\n  begin\n    for indexW:= 0 to Pred(Width) do\n    begin\n      Write(MatrixWalls[indexW, indexL]:2, ' ');\n    end;\n    WriteLN;\n  end;\n  WriteLN;\nend;\n\nprocedure PrintMaze;\nvar\n  indexW: Integer;\n  indexL: Integer;\nbegin\n\n  for indexW:= 0 to Pred(Width) do\n  begin\n    if indexW = Entry then\n    begin\n      Write('.  ');\n    end\n    else\n    begin\n      Write('.--');\n    end;\n  end;\n  WriteLN('.');\n  for indexL:= 0 to Pred(Length) do\n  begin\n    Write('I');\n    for indexW:= 0 to Pred(Width) do\n    begin\n      if MatrixWalls[indexW, indexL] < 2 then\n      begin\n        Write('  I');\n      end\n      else\n      begin\n        Write('   ');\n      end;\n    end;\n    WriteLN;\n    for indexW:= 0 to Pred(Width) do\n    begin\n      if (MatrixWalls[indexW, indexL] = 0) or (MatrixWalls[indexW, indexL] = 2) then\n      begin\n        Write(':--');\n      end\n      else\n      begin\n        Write(':  ');\n      end;\n    end;\n    WriteLN('.');\n  end;\n  WriteLN;\nend;\n\nbegin\n  Randomize;\n  ClrScr;\n  PrintGreeting;\n  GetDimensions;\n  ClearMatrices;\n  BuildMaze;\n  //DegubVisited;\n  //DebugWalls;\n  PrintMaze;\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/03_Animal/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript animal.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"animal\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/03_Animal/MiniScript/animal.ms",
    "content": "print \" \"*32 + \"Animal\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Play 'Guess the Animal'\"\nprint\nprint \"Think of an animal and the computer will try to guess it.\"\nprint\n\n// Ask a yes/no question, and return \"Y\" or \"N\".\ngetYesNo = function(prompt)\n\twhile true\n\t\tinp = input(prompt + \"? \").upper\n\t\tif inp and (inp[0] == \"Y\" or inp[0] == \"N\") then return inp[0]\n\t\tprint \"Please answer Yes or No.\"\n\tend while\nend function\t\n\n// Our data is stored as a list of little maps.\n// Answers have only an \"answer\" key.\n// Questions have a \"question\" key, plus \"ifYes\" and \"ifNo\"\n//\tkeys which map to the index of the next question or answer.\ndata = [\n\t{\"question\":\"Does it swim\", \"ifYes\":1, \"ifNo\":2},\n\t{\"answer\":\"fish\"},\n\t{\"answer\":\"bird\"}]\n\n// List all known animals.\nlistKnown = function\n\tprint; print \"Animals I already know are:\"\n\tfor item in data\n\t\tif item.hasIndex(\"answer\") then print (item.answer + \" \"*17)[:17], \"\"\n\tend for\n\tprint; print\nend function\n\n// Ask the question at curIndex, and handle the user's response.\ndoQuestion = function\n\tq = data[curIndex]\n\tif getYesNo(q.question) == \"Y\" then\n\t\tglobals.curIndex = q.ifYes\n\telse\n\t\tglobals.curIndex = q.ifNo\n\tend if\nend function\n\n// Check the answer at curIndex.  If incorrect, get a new question\n// to put at that point in our data.\ncheckAnswer = function\n\tnode = data[curIndex]\n\tinp = getYesNo(\"Is it a \" + node.answer)\n\tif inp == \"Y\" then \n\t\tprint \"Why not try another animal?\"\n\telse\n\t\tactual = input(\"The animal you were thinking of was a? \").lower\n\t\tprint \"Please type in a question that would distinguish a\"\n\t\tprint actual + \" from a \" + node.answer\n\t\tq = {}\n\t\tq.question = input\n\t\tq.question = q.question[0].upper + q.question[1:] - \"?\"\n\t\tdata[curIndex] = q\n\t\tk = data.len\n\t\tdata.push node               // old answer at index k\n\t\tdata.push {\"answer\":actual}  // new answer at index k+1\n\t\tif getYesNo(\"For a \" + actual + \" the answer would be\") == \"Y\" then\n\t\t\tdata[curIndex].ifYes = k+1\n\t\t\tdata[curIndex].ifNo = k\n\t\telse\n\t\t\tdata[curIndex].ifNo = k+1\n\t\t\tdata[curIndex].ifYes = k\n\t\tend if\n\tend if\nend function\n\n// Main loop.  (Press Control-C to break.)\nwhile true\n\twhile true\n\t\tinp = input(\"Are you thinking of an animal? \").upper\n\t\tif inp == \"LIST\" then listKnown\n\t\tif inp and inp[0] == \"Y\" then break\n\tend while\n\tcurIndex = 0\n\twhile true\n\t\tif data[curIndex].hasIndex(\"question\") then\n\t\t\tdoQuestion\n\t\telse\n\t\t\tcheckAnswer\n\t\t\tbreak\n\t\tend if\n\tend while\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/03_Animal/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/03_Animal/animal.bas",
    "content": "10 PRINT TAB(32);\"ANIMAL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n40 PRINT \"PLAY 'GUESS THE ANIMAL'\"\n45 PRINT\n50 PRINT \"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\"\n60 PRINT\n70 DIM A$(200)\n80 FOR I=0 TO 3\n90 READ A$(I)\n100 NEXT I\n110 N=VAL(A$(0))\n120 REM          MAIN CONTROL SECTION\n130 INPUT \"ARE YOU THINKING OF AN ANIMAL\";A$\n140 IF A$=\"LIST\" THEN 600\n150 IF LEFT$(A$,1)<>\"Y\" THEN 120\n160 K=1\n170 GOSUB 390\n180 IF LEN(A$(K))=0 THEN 999\n190 IF LEFT$(A$(K),2)=\"\\Q\" THEN 170\n200 PRINT \"IS IT A \";RIGHT$(A$(K),LEN(A$(K))-2);\n210 INPUT A$\n220 A$=LEFT$(A$,1)\n230 IF LEFT$(A$,1)=\"Y\" THEN PRINT \"WHY NOT TRY ANOTHER ANIMAL?\": GOTO 120\n240 INPUT \"THE ANIMAL YOU WERE THINKING OF WAS A \";V$\n250 PRINT \"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\"\n260 PRINT V$;\" FROM A \";RIGHT$(A$(K),LEN(A$(K))-2)\n270 INPUT X$\n280 PRINT \"FOR A \";V$;\" THE ANSWER WOULD BE \";\n290 INPUT A$\n300 A$=LEFT$(A$,1): IF A$<>\"Y\" AND A$<>\"N\" THEN 280\n310 IF A$=\"Y\" THEN B$=\"N\"\n320 IF A$=\"N\" THEN B$=\"Y\"\n330 Z1=VAL(A$(0))\n340 A$(0)=STR$(Z1+2)\n350 A$(Z1)=A$(K)\n360 A$(Z1+1)=\"\\A\"+V$\n370 A$(K)=\"\\Q\"+X$+\"\\\"+A$+STR$(Z1+1)+\"\\\"+B$+STR$(Z1)+\"\\\"\n380 GOTO 120\n390 REM     SUBROUTINE TO PRINT QUESTIONS\n400 Q$=A$(K)\n410 FOR Z=3 TO LEN(Q$)\n415 IF MID$(Q$,Z,1)<>\"\\\" THEN PRINT MID$(Q$,Z,1);: NEXT Z\n420 INPUT C$\n430 C$=LEFT$(C$,1)\n440 IF C$<>\"Y\" AND C$<>\"N\" THEN 410\n450 T$=\"\\\"+C$\n455 FOR X=3 TO LEN(Q$)-1\n460 IF MID$(Q$,X,2)=T$ THEN 480\n470 NEXT X\n475 STOP\n480 FOR Y=X+1 TO LEN(Q$)\n490 IF MID$(Q$,Y,1)=\"\\\" THEN 510\n500 NEXT Y\n505 STOP\n510 K=VAL(MID$(Q$,X+2,Y-X-2))\n520 RETURN\n530 DATA \"4\",\"\\QDOES IT SWIM\\Y2\\N3\\\",\"\\AFISH\",\"\\ABIRD\"\n600 PRINT:PRINT \"ANIMALS I ALREADY KNOW ARE:\"\n605 X=0\n610 FOR I=1 TO 200\n620 IF LEFT$(A$(I),2)<>\"\\A\" THEN 650\n624 PRINT TAB(15*X);\n630 FOR Z=3 TO LEN(A$(I))\n640 IF MID$(A$(I),Z,1)<>\"\\\" THEN PRINT MID$(A$(I),Z,1);: NEXT Z\n645 X=X+1: IF X=4 THEN X=0: PRINT\n650 NEXT I\n660 PRINT\n670 PRINT\n680 GOTO 120\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/03_Animal/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"log\"\r\n\t\"os\"\r\n\t\"strings\"\r\n)\r\n\r\ntype node struct {\r\n\ttext    string\r\n\tyesNode *node\r\n\tnoNode  *node\r\n}\r\n\r\nfunc newNode(text string, yes_node, no_node *node) *node {\r\n\tn := node{text: text}\r\n\tif yes_node != nil {\r\n\t\tn.yesNode = yes_node\r\n\t}\r\n\tif no_node != nil {\r\n\t\tn.noNode = no_node\r\n\t}\r\n\treturn &n\r\n}\r\n\r\nfunc (n *node) update(newQuestion, newAnswer, newAnimal string) {\r\n\toldAnimal := n.text\r\n\r\n\tn.text = newQuestion\r\n\r\n\tif newAnswer == \"y\" {\r\n\t\tn.yesNode = newNode(newAnimal, nil, nil)\r\n\t\tn.noNode = newNode(oldAnimal, nil, nil)\r\n\t} else {\r\n\t\tn.yesNode = newNode(oldAnimal, nil, nil)\r\n\t\tn.noNode = newNode(newAnimal, nil, nil)\r\n\t}\r\n}\r\n\r\nfunc (n *node) isLeaf() bool {\r\n\treturn (n.yesNode == nil) && (n.noNode == nil)\r\n}\r\n\r\nfunc listKnownAnimals(root *node) {\r\n\tif root == nil {\r\n\t\treturn\r\n\t}\r\n\r\n\tif root.isLeaf() {\r\n\t\tfmt.Printf(\"%s           \", root.text)\r\n\t\treturn\r\n\t}\r\n\r\n\tif root.yesNode != nil {\r\n\t\tlistKnownAnimals(root.yesNode)\r\n\t}\r\n\r\n\tif root.noNode != nil {\r\n\t\tlistKnownAnimals(root.noNode)\r\n\t}\r\n}\r\n\r\nfunc parseInput(message string, checkList bool, rootNode *node) string {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\ttoken := \"\"\r\n\r\n\tfor {\r\n\t\tfmt.Println(message)\r\n\t\tscanner.Scan()\r\n\t\tinp := strings.ToLower(scanner.Text())\r\n\r\n\t\tif checkList && inp == \"list\" {\r\n\t\t\tfmt.Println(\"Animals I already know are:\")\r\n\t\t\tlistKnownAnimals(rootNode)\r\n\t\t\tfmt.Println()\r\n\t\t}\r\n\r\n\t\tif len(inp) > 0 {\r\n\t\t\ttoken = inp\r\n\t\t} else {\r\n\t\t\ttoken = \"\"\r\n\t\t}\r\n\r\n\t\tif token == \"y\" || token == \"n\" {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\treturn token\r\n}\r\n\r\nfunc avoidVoidInput(message string) string {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tanswer := \"\"\r\n\tfor {\r\n\t\tfmt.Println(message)\r\n\t\tscanner.Scan()\r\n\t\tanswer = scanner.Text()\r\n\r\n\t\tif answer != \"\" {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\treturn answer\r\n}\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"                                Animal\")\r\n\tfmt.Println(\"               Creative Computing Morristown, New Jersey\")\r\n\tfmt.Println(\"\\nPlay 'Guess the Animal'\")\r\n\tfmt.Println(\"Think of an animal and the computer will try to guess it\")\r\n}\r\n\r\nfunc main() {\r\n\tyesChild := newNode(\"Fish\", nil, nil)\r\n\tnoChild := newNode(\"Bird\", nil, nil)\r\n\trootNode := newNode(\"Does it swim?\", yesChild, noChild)\r\n\r\n\tprintIntro()\r\n\r\n\tkeepPlaying := (parseInput(\"Are you thinking of an animal?\", true, rootNode) == \"y\")\r\n\r\n\tfor keepPlaying {\r\n\t\tkeepAsking := true\r\n\r\n\t\tactualNode := rootNode\r\n\r\n\t\tfor keepAsking {\r\n\t\t\tif !actualNode.isLeaf() {\r\n\t\t\t\tanswer := parseInput(actualNode.text, false, nil)\r\n\r\n\t\t\t\tif answer == \"y\" {\r\n\t\t\t\t\tif actualNode.yesNode == nil {\r\n\t\t\t\t\t\tlog.Fatal(\"invalid node\")\r\n\t\t\t\t\t}\r\n\t\t\t\t\tactualNode = actualNode.yesNode\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif actualNode.noNode == nil {\r\n\t\t\t\t\t\tlog.Fatal(\"invalid node\")\r\n\t\t\t\t\t}\r\n\t\t\t\t\tactualNode = actualNode.noNode\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tanswer := parseInput(fmt.Sprintf(\"Is it a %s?\", actualNode.text), false, nil)\r\n\t\t\t\tif answer == \"n\" {\r\n\t\t\t\t\tnewAnimal := avoidVoidInput(\"The animal you were thinking of was a ?\")\r\n\t\t\t\t\tnewQuestion := avoidVoidInput(fmt.Sprintf(\"Please type in a question that would distinguish a '%s' from a '%s':\", newAnimal, actualNode.text))\r\n\t\t\t\t\tnewAnswer := parseInput(fmt.Sprintf(\"For a '%s' the answer would be\", newAnimal), false, nil)\r\n\t\t\t\t\tactualNode.update(newQuestion+\"?\", newAnswer, newAnimal)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tfmt.Println(\"Why not try another animal?\")\r\n\t\t\t\t}\r\n\t\t\t\tkeepAsking = false\r\n\t\t\t}\r\n\t\t}\r\n\t\tkeepPlaying = (parseInput(\"Are you thinking of an animal?\", true, rootNode) == \"y\")\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript awari.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"awari\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/MiniScript/awari.ms",
    "content": "print \" \"*34 + \"Awari\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\n\n// Keep a list of the opening moves (up to 8) of previously lost or drawn games.\n// These will be used to penalize repeating the same moves again.\nbadGames = []\n\nprintQty = function(qty)\n\tprint (\" \" + qty)[-2:], \" \"\nend function\n\nprintBoard = function\n\tprint; print \"   \", \"\"\n\tfor i in range(12, 7); printQty board[i]; end for\n\tprint; printQty board[13]\n\tprint \"   \" * 6, \"\"; printQty board[6]\n\tprint; print \"   \", \"\"\n\tfor i in range(0, 5); printQty board[i]; end for\n\tprint; print\nend function\n\n// Redistribute the stones starting at position.\n// If the last one ends by itself, opposite some nonzero\n// stones on the other side, then capture them into homePos.\n// Return true if the last stone ended at homePos, false otherwise.\nmoveStones = function(board, position, homePos)\n\tp = board[position]; board[position] = 0\n\twhile p\n\t\tposition = (position + 1) % 14\n\t\tboard[position] += 1\n\t\tp -= 1\n\tend while\n\tif board[position] == 1 and position != 6 and position != 13 and board[12-position] then\n\t\tboard[homePos] += board[12-position] + 1\n\t\tboard[position] = 0\n\t\tboard[12-position] = 0\n\tend if\n\tglobals.gameOver = board[0:6].sum == 0 or board[7:13].sum == 0\n\treturn position == homePos\nend function\n\n// Get the player move.  Note that the player inputs their move as a number\n// from 1-6, but we return it as an actual board position index 0-6.\ngetPlayerMove = function(prompt=\"Your move\")\n\twhile true\n\t\tpos = input(prompt + \"? \").val\n\t\tif 0 < pos < 7 and board[pos-1] then return pos - 1\n\t\tprint \"Illegal move.\"\n\tend while\nend function\n\ngetComputerMove = function\n\t// Copy the board for safekeeping\n\tboardCopy = board[:]\n\tbestScore = -99; bestMove = 0\n\tfor j in range(7, 12)\n\t\tif board[j] == 0 then continue\t// can't move from an empty spot\n\t\t// suppose we move at position j...\n\t\tmoveStones board, j, 13\n\t\t// consider each possible response the player could make\n\t\tbestPlayerScore = 0\n\t\tfor i in range(0, 5)\n\t\t\tif board[i] == 0 then continue\n\t\t\tlandPos = board[i] + i\t// figure the landing position\n\t\t\tscore = floor(landPos / 14); landPos %= 14\n\t\t\tif board[landPos] == 0 and landPos != 6 and landPos != 13 then\n\t\t\t\tscore += board[12 - landPos]\t// points for capturing stones\n\t\t\tend if\n\t\t\tif score > bestPlayerScore then bestPlayerScore = score\n\t\tend for\n\t\t// figure our own score as our points, minus player points, minus best player score\n\t\tourScore = board[13] - board[6] - bestPlayerScore\n\t\tif gameMoves.len < 8 then\n\t\t\t// subtract 2 points if current series of moves is in our bad-games list\n\t\t\tproposed = gameMoves + [j]\n\t\t\tfor badGame in badGames\n\t\t\t\tif badGame[:proposed.len] == proposed then ourScore -= 2\n\t\t\tend for\n\t\tend if\n\t\tif ourScore > bestScore then\n\t\t\tbestScore = ourScore\n\t\t\tbestMove = j\n\t\tend if\n\t\t// restore the board\n\t\tglobals.board = boardCopy[:]\n\tend for\n\tprint char(42+bestMove)\t// (labels computer spots as 1-6 from right to left)\n\treturn bestMove\nend function\n\n// The game is over when either side has 0 stones left.\nisGameOver = function\n\treturn board[0:6].sum == 0 or board[7:13].sum == 0\nend function\n\n// Play one game to completion.\nplayOneGame = function\n\t// The board is represented as a list of 13 numbers.\n\t// Position 6 is the player's home; 13 is the computer's home.\n\tglobals.board = [3]*14; board[13] = 0; board[6] = 0\n\t// Also keep a list of the moves in the current game\n\tglobals.gameMoves = []\n\tprint; print\n\twhile true\n\t\t// Player's turn\n\t\tprintBoard\n\t\tpos = getPlayerMove\n\t\tgameMoves.push pos\n\t\tif moveStones(board, pos, 6) then\n\t\t\tif gameOver then break\n\t\t\tprintBoard\n\t\t\tpos = getPlayerMove(\"Again\")\n\t\t\tgameMoves.push pos\n\t\t\tmoveStones board, pos, 6\n\t\tend if\n\t\tif gameOver then break\n\t\t// Computer's turn\n\t\tprintBoard; print \"My move is \", \"\"\n\t\tpos = getComputerMove\n\t\tgameMoves.push pos\n\t\tif moveStones(board, pos, 13) then\n\t\t\tif gameOver then break\n\t\t\tprintBoard; print \"...followed by \", \"\"\n\t\t\tpos = getComputerMove\n\t\t\tgameMoves.push pos\n\t\t\tmoveStones board, pos, 13\n\t\tend if\n\t\tif gameOver then break\n\tend while\n\tprintBoard\n\tprint; print \"GAME OVER\"\n\tdelta = board[6] - board[13]\n\tif delta < 0 then\n\t\tprint \"I win by \" + (-delta) + \" points\"\n\t\treturn\n\tend if\n\tif delta == 0 then print \"Drawn game\" else print \"You win by \" + delta + \" points\"\n\tif gameMoves.len > 8 then gameMoves = gameMoves[:8]\n\tif badGames.indexOf(gameMoves) == null then badGames.push gameMoves\t\nend function\n\n// Main loop\nwhile true\n\tplayOneGame\n\tprint; print\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/04_Awari/awari.bas",
    "content": "5 PRINT TAB(34);\"AWARI\"\n7 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n10 DATA 0\n15 DIM B(13),G(13),F(50):READ N\n20 PRINT:PRINT:E=0\n25 FOR I=0 TO 12:B(I)=3:NEXT I\n30 C=0:F(N)=0:B(13)=0:B(6)=0\n35 GOSUB 500\n40 PRINT \"YOUR MOVE\";:GOSUB 110\n45 IF E=0 THEN 80\n50 IF M=H THEN GOSUB 100\n55 IF E=0 THEN 80\n60 PRINT \"MY MOVE IS \";:GOSUB 800\n65 IF E=0 THEN 80\n70 IF M=H THEN PRINT \",\";:GOSUB 800\n75 IF E>0 THEN 35\n80 PRINT:PRINT\"GAME OVER\"\n85 D=B(6)-B(13):IF D<0 THEN PRINT \"I WIN BY\";-D;\"POINTS\":GOTO 20\n90 N=N+1:IF D=0 THEN PRINT \"DRAWN GAME\":GOTO 20\n95 PRINT \"YOU WIN BY\";D;\"POINTS\":GOTO 20\n100 PRINT \"AGAIN\";\n110 INPUT M:IF M<7 THEN IF M>0 THEN M=M-1:GOTO 130\n120 PRINT \"ILLEGAL MOVE\":GOTO 100\n130 IF B(M)=0 THEN 120\n140 H=6:GOSUB 200\n150 GOTO 500\n200 K=M:GOSUB 600\n205 E=0:IF K>6 THEN K=K-7\n210 C=C+1:IF C<9 THEN F(N)=F(N)*6+K\n215 FOR I=0 TO 5:IF B(I)<>0 THEN 230\n220 NEXT I\n225 RETURN\n230 FOR I=7 TO 12:IF B(I)<>0 THEN E=1:RETURN\n235 GOTO 220\n500 PRINT:PRINT\"   \";\n505 FOR I=12 TO 7 STEP -1:GOSUB 580\n510 NEXT I\n515 PRINT:I=13:GOSUB 580\n520 PRINT \"                       \";:PRINT B(6):PRINT \"   \";\n525 FOR I=0 TO 5:GOSUB 580\n530 NEXT I\n535 PRINT:PRINT:RETURN\n580 IF B(I)<10 THEN PRINT \" \";\n585 PRINT B(I);:RETURN\n600 P=B(M):B(M)=0\n605 FOR P=P TO 1 STEP -1:M=M+1:IF M>13 THEN M=M-14\n610 B(M)=B(M)+1:NEXT P\n615 IF B(M)=1 THEN IF M<>6 THEN IF M<>13 THEN IF B(12-M)<>0 THEN 625\n620 RETURN\n625 B(H)=B(H)+B(12-M)+1:B(M)=0:B(12-M)=0:RETURN\n800 D=-99:H=13\n805 FOR I=0 TO 13:G(I)=B(I):NEXT I\n810 FOR J=7 TO 12:IF B(J)=0 THEN 885\n815 Q=0:M=J:GOSUB 600\n820 FOR I=0 TO 5:IF B(I)=0 THEN 845\n825 L=B(I)+I:R=0\n830 IF L>13 THEN L=L-14:R=1:GOTO 830\n835 IF B(L)=0 THEN IF L<>6 THEN IF L<>13 THEN R=B(12-L)+R\n840 IF R>Q THEN Q=R\n845 NEXT I\n850 Q=B(13)-B(6)-Q:IF C>8 THEN 875\n855 K=J:IF K>6 THEN K=K-7\n860 FOR I=0 TO N-1:IF F(N)*6+K=INT(F(I)/6^(7-C)+.1) THEN Q=Q-2\n870 NEXT I\n875 FOR I=0 TO 13:B(I)=G(I):NEXT I\n880 IF Q>=D THEN A=J:D=Q\n885 NEXT J\n890 M=A:PRINT CHR$(42+M);:GOTO 200\n900 FOR I=0 TO N-1:PRINT B(I):NEXT I\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/.gitignore",
    "content": "\n# Created by https://www.toptal.com/developers/gitignore/api/macos,visualstudiocode,elm\n# Edit at https://www.toptal.com/developers/gitignore?templates=macos,visualstudiocode,elm\n\n### Elm ###\n# elm-package generated files\nelm-stuff\n# elm-repl generated files\nrepl-temp-*\n\n### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### VisualStudioCode ###\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n!.vscode/*.code-snippets\n\n# Local History for Visual Studio Code\n.history/\n\n# Built Visual Studio Code Extensions\n*.vsix\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n.ionide\n\n# Support for Project snippet scope\n\n# End of https://www.toptal.com/developers/gitignore/api/macos,visualstudiocode,elm\n\n# Created by https://www.toptal.com/developers/gitignore/api/node\n# Edit at https://www.toptal.com/developers/gitignore?templates=node\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n### Node Patch ###\n# Serverless Webpack directories\n.webpack/\n\n# Optional stylelint cache\n\n# SvelteKit build / generate output\n.svelte-kit\n\n# End of https://www.toptal.com/developers/gitignore/api/node\n\napp.js\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/README.md",
    "content": "# Awari\n\nThis is an Elm implementation of the `Basic Compouter Games` Game Awari.\n\n## Build App\n\n- install elm\n\n```bash\nyarn\nyarn build\n```\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/docs/index.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head>\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/@picocss/pico@latest/css/pico.min.css\">\n</head>\n\n<body>\n    <div id=\"elm-app-is-loaded-here\" />\n    <script src=\"app.js\"></script>\n    <script>\n        var app = Elm.Main.init({\n            node: document.getElementById(\"elm-app-is-loaded-here\"),\n            flags: {}\n        });\n    </script>\n</body>\n\n</html>"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/elm.json",
    "content": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.1\",\n    \"dependencies\": {\n        \"direct\": {\n            \"elm/browser\": \"1.0.2\",\n            \"elm/core\": \"1.0.5\",\n            \"elm/html\": \"1.0.0\"\n        },\n        \"indirect\": {\n            \"elm/json\": \"1.1.3\",\n            \"elm/time\": \"1.0.0\",\n            \"elm/url\": \"1.0.0\",\n            \"elm/virtual-dom\": \"1.0.2\"\n        }\n    },\n    \"test-dependencies\": {\n        \"direct\": {},\n        \"indirect\": {}\n    }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/package.json",
    "content": "{\n  \"name\": \"04_Awari\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"live\": \"elm-live src/Main.elm --proxy-prefix=/api --proxy-host=http://localhost:8080/api --open --start-page=resources/index.html -- --output=app.js --debug\",\n    \"build\": \"elm make src/Main.elm --optimize --output docs/app.js && cp -R resources/ docs/\"\n  },\n  \"devDependencies\": {\n    \"elm-live\": \"^4.0.2\"\n  }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/resources/index.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head>\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/@picocss/pico@latest/css/pico.min.css\">\n</head>\n\n<body>\n    <div id=\"elm-app-is-loaded-here\" />\n    <script src=\"app.js\"></script>\n    <script>\n        var app = Elm.Main.init({\n            node: document.getElementById(\"elm-app-is-loaded-here\"),\n            flags: {}\n        });\n    </script>\n</body>\n\n</html>"
  },
  {
    "path": "00_Alternate_Languages/04_Awari/elm/src/Main.elm",
    "content": "module Main exposing (main)\n\nimport Array exposing (Array, repeat)\nimport Browser\nimport Html exposing (..)\nimport Html.Attributes exposing (style)\nimport Html.Events exposing (onClick)\n\n\n\n-- Main\n\n\nmain : Program () Model Msg\nmain =\n    Browser.element\n        { init = init\n        , view = view\n        , update = update\n        , subscriptions = \\_ -> Sub.none\n        }\n\n\n\n-- Model\n\n\ntype alias Model =\n    { board : Array Int\n    , playerOnesTurn : Bool\n    , gameFinished : Bool\n    }\n\n\ninit : () -> ( Model, Cmd Msg )\ninit _ =\n    ( { board = initArray 0 36 (repeat boardLength 0), playerOnesTurn = False, gameFinished = False }, Cmd.none )\n\n\n\n-- Messages\n\n\ntype Msg\n    = BoardClicked Int\n    | Reset\n\n\n\n-- Update\n\n\nupdate : Msg -> Model -> ( Model, Cmd Msg )\nupdate msg model =\n    case msg of\n        BoardClicked index ->\n            if indexIsOnPit index || index < rightPitIndex && model.playerOnesTurn || index > rightPitIndex && not model.playerOnesTurn then\n                ( model, Cmd.none )\n\n            else\n                let\n                    lastStoneInPitIndex =\n                        lastStonePitPosition index model.board\n\n                    boardAfterStonesSet =\n                        changesOnBoardAfterStonesSet model.playerOnesTurn lastStoneInPitIndex (boardClicked index model.board)\n\n                    nextPlayer =\n                        determineNextPlayer lastStoneInPitIndex model.playerOnesTurn boardAfterStonesSet\n                in\n                ( { model | board = boardAfterStonesSet, playerOnesTurn = nextPlayer, gameFinished = calculateGameFinished boardAfterStonesSet }, Cmd.none )\n\n        Reset ->\n            init ()\n\n\n\n-- Constants\n\n\nboardLength : Int\nboardLength =\n    14\n\n\nleftPitIndex : Int\nleftPitIndex =\n    0\n\n\nrightPitIndex : Int\nrightPitIndex =\n    7\n\n\n\n-- View\n\n\nview : Model -> Html Msg\nview model =\n    div [ style \"margin\" \"4rem\" ]\n        [ h1 [] [ text \"Awari\" ]\n        , viewDescription\n        , getPlayerTurnText False model.playerOnesTurn\n        , viewBoard model\n        , viewWinnerIfGameFinished model\n        , getPlayerTurnText True model.playerOnesTurn\n        , div\n            [ style \"display\" \"flex\"\n            , style \"justify-content\" \"center\"\n            ]\n            [ button [ onClick Reset, style \"max-width\" \"10rem\", style \"margin\" \"0\", style \"display\" \"inline-block\" ] [ text \"Restart\" ] ]\n        ]\n\n\ngetPlayerTurnText : Bool -> Bool -> Html msg\ngetPlayerTurnText playerOne playerOnesTurn =\n    if playerOne && playerOnesTurn || not playerOnesTurn && not playerOne then\n        div [ style \"height\" \"2rem\", style \"margin\" \"1rem 0\", style \"font-size\" \"1.5rem\" ]\n            [ text\n                (\"It's your turn Player \"\n                    ++ (if playerOnesTurn then\n                            \" 2 \"\n\n                        else\n                            \" 1 \"\n                       )\n                )\n            ]\n\n    else\n        div [ style \"height\" \"2rem\", style \"margin\" \"1rem\", style \"font-size\" \"1.5rem\" ] []\n\n\nviewWinnerIfGameFinished : Model -> Html msg\nviewWinnerIfGameFinished model =\n    if not model.gameFinished then\n        div [] []\n\n    else\n        div [] [ text (\"Winner is\" ++ winnerPlayer model) ]\n\n\nwinnerPlayer : Model -> String\nwinnerPlayer model =\n    if getLeftPitValue model.board > getRightPitValue model.board then\n        \"Player 1\"\n\n    else if getLeftPitValue model.board < getRightPitValue model.board then\n        \"Player 2\"\n\n    else\n        \"None\"\n\n\nviewBoard : Model -> Html Msg\nviewBoard model =\n    let\n        boardGenerator =\n            boardCard model.playerOnesTurn\n    in\n    div boardSyle\n        (Array.toList <|\n            Array.indexedMap boardGenerator model.board\n        )\n\n\nboardSyle : List (Attribute msg)\nboardSyle =\n    [ style \"display\" \"flex\"\n    , style \"gap\" \"1rem\"\n    , style \"display\" \"grid\"\n    , style \"grid-template-columns\" \"repeat(8, 1fr)\"\n    , style \"align-items\" \"center\"\n    , style \"grid-template-areas\" \"\"\"\n    'a b c d e f g h'\n    'a n m l k j i h'\n    \"\"\"\n    ]\n\n\nboardCard : Bool -> Int -> Int -> Html Msg\nboardCard playerOnesTurn index element =\n    div (boardCardStyle playerOnesTurn index) [ text (String.fromInt element) ]\n\n\nboardCardStyle : Bool -> Int -> List (Attribute Msg)\nboardCardStyle playerOnesTurn index =\n    if not playerOnesTurn && index < rightPitIndex || playerOnesTurn && index >= rightPitIndex then\n        [ onClick (BoardClicked index)\n        , style \"grid-area\" (areaFromIndex index)\n        , style \"cursor\" \"pointer\"\n        , style \"background\" \"#36454F\"\n        , style \"border-radius\" \"6px\"\n        , style \"text-align\" \"center\"\n        , style \"padding\" \"0.5rem\"\n        ]\n\n    else\n        [ style \"grid-area\" (areaFromIndex index)\n        , style \"background\" \"black\"\n        , style \"border-radius\" \"6px\"\n        , style \"text-align\" \"center\"\n        , style \"padding\" \"0.5rem\"\n        ]\n\n\nviewDescription : Html msg\nviewDescription =\n    details []\n        [ summary [] [ text \"How the game works\" ]\n        , p [] [ text \"\"\"\n        Awari is an ancient African game played with seven sticks and thirty-six stones or beans laid out as shown above. The board is divided into six compartments or pits on each side. In addition, there are two special home pits at the ends.\n\n        A move is made by taking all the beans from any (non-empty) pit on your own side. Starting from the pit to the right of this one, these beans are ‘sown’ one in each pit working around the board anticlockwise.\n\n        A turn consists of one or two moves. If the last bean of your move is sown in your own home you may take a second move.\n\n        If the last bean sown in a move lands in an empty pit, provided that the opposite pit is not empty, all the beans in the opposite pit, together with the last bean sown are ‘captured’ and moved to the player’s home.\n\n        When either side is empty, the game is finished. The player with the most beans in his home has won.\n        \"\"\" ]\n        ]\n\n\n\n-- Functions\n\n\ncheckIfPlayerCanNotDoMove : Bool -> Array Int -> Bool\ncheckIfPlayerCanNotDoMove playerOnesTurn board =\n    if playerOnesTurn then\n        Array.foldr (+) 0 (Array.slice (rightPitIndex + 1) boardLength board) == 0\n\n    else\n        Array.foldr (+) 0 (Array.slice (leftPitIndex + 1) rightPitIndex board) == 0\n\n\ndetermineNextPlayer : Int -> Bool -> Array Int -> Bool\ndetermineNextPlayer index playerOnesTurn board =\n    if checkIfPlayerCanNotDoMove (not playerOnesTurn) board then\n        playerOnesTurn\n\n    else if indexIsOnPit index then\n        playerOnesTurn\n\n    else\n        not playerOnesTurn\n\n\nindexIsOnPit : Int -> Bool\nindexIsOnPit index =\n    index == leftPitIndex || index == rightPitIndex\n\n\ncalculateGameFinished : Array Int -> Bool\ncalculateGameFinished board =\n    Array.foldr (+) 0 board - getLeftPitValue board - getRightPitValue board == 0\n\n\ngetLeftPitValue : Array Int -> Int\ngetLeftPitValue board =\n    getPitValue leftPitIndex board\n\n\ngetRightPitValue : Array Int -> Int\ngetRightPitValue board =\n    getPitValue rightPitIndex board\n\n\ngetPitValue : Int -> Array Int -> Int\ngetPitValue index board =\n    Maybe.withDefault 0 (Array.get index board)\n\n\nlastStonePitPosition : Int -> Array Int -> Int\nlastStonePitPosition index board =\n    calcLastStonePosition index board (Maybe.withDefault 0 (Array.get index board))\n\n\ncalcLastStonePosition : Int -> Array Int -> Int -> Int\ncalcLastStonePosition index board stones =\n    if stones == 0 then\n        index\n\n    else\n        calcLastStonePosition (incrementRotatingIndex index board) board (stones - 1)\n\n\nchangesOnBoardAfterStonesSet : Bool -> Int -> Array Int -> Array Int\nchangesOnBoardAfterStonesSet playerOne lastStonesIndex board =\n    if Maybe.withDefault 0 (Array.get lastStonesIndex board) == 1 then\n        if indexIsOnPit lastStonesIndex then\n            board\n\n        else\n            let\n                sumStones =\n                    Maybe.withDefault 0 (Array.get (boardLength - lastStonesIndex) board) + 1\n\n                currentPit =\n                    if playerOne then\n                        getRightPitValue board\n\n                    else\n                        getLeftPitValue board\n\n                baordWithIndexZero =\n                    Array.set lastStonesIndex 0 board\n\n                baordWithOppositeZero =\n                    Array.set (boardLength - lastStonesIndex) 0 baordWithIndexZero\n\n                boardWithPitSum =\n                    if playerOne then\n                        Array.set rightPitIndex (sumStones + currentPit) baordWithOppositeZero\n\n                    else\n                        Array.set leftPitIndex (sumStones + currentPit) baordWithOppositeZero\n            in\n            boardWithPitSum\n\n    else\n        board\n\n\ninitArray : Int -> Int -> Array Int -> Array Int\ninitArray index stones array =\n    if stones == 0 then\n        array\n\n    else if indexIsOnPit index then\n        initArray (index + 1) stones array\n\n    else\n        initArray (index + 1) (stones - 3) (Array.set index 3 array)\n\n\nboardClicked : Int -> Array Int -> Array Int\nboardClicked index board =\n    if indexIsOnPit index then\n        board\n\n    else\n        let\n            stonesLeft =\n                Maybe.withDefault 0 (Array.get index board)\n\n            startBoard =\n                Array.set index 0 board\n        in\n        placeStones (incrementRotatingIndex index startBoard) stonesLeft startBoard\n\n\nincrementRotatingIndex : Int -> Array Int -> Int\nincrementRotatingIndex currentIndex board =\n    if 0 == currentIndex then\n        Array.length board - 1\n\n    else\n        currentIndex - 1\n\n\nplaceStones : Int -> Int -> Array Int -> Array Int\nplaceStones index stonesLeft board =\n    if stonesLeft == 0 then\n        board\n\n    else\n        let\n            oldStones =\n                Maybe.withDefault 0 (Array.get index board)\n        in\n        placeStones (incrementRotatingIndex index board) (stonesLeft - 1) (Array.set index (oldStones + 1) board)\n\n\nareaFromIndex : Int -> String\nareaFromIndex index =\n    case index of\n        0 ->\n            \"a\"\n\n        1 ->\n            \"b\"\n\n        2 ->\n            \"c\"\n\n        3 ->\n            \"d\"\n\n        4 ->\n            \"e\"\n\n        5 ->\n            \"f\"\n\n        6 ->\n            \"g\"\n\n        7 ->\n            \"h\"\n\n        8 ->\n            \"i\"\n\n        9 ->\n            \"j\"\n\n        10 ->\n            \"k\"\n\n        11 ->\n            \"l\"\n\n        12 ->\n            \"m\"\n\n        13 ->\n            \"n\"\n\n        i ->\n            String.fromInt i\n"
  },
  {
    "path": "00_Alternate_Languages/05_Bagels/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bagels.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bagels\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms",
    "content": "print \" \"*33 + \"BAGELS\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"; print; print\n// *** BAGELS Number Guessing Game\n// *** Original source unknown but suspected to be\n// *** Lawrence Hall of Science, U.C. Berkely\n\nprint; print; print\ninp = input(\"Would you like the rules (yes or no)? \")\nif not inp or inp[0].lower != \"n\" then\n\tprint; print \"I am thinking of a three-digit number.  Try to guess\"\n\tprint \"my number and I will give you clues as follows:\"\n\tprint \"   PICO   - one digit correct but in the wrong position\"\n\tprint \"   FERMI  - one digit correct and in the right position\"\n\tprint \"   BAGELS - no digits correct\"\nend if\n\npickNumber = function\n\t// pick three unique random digits\n\twhile true\n\t\tactual = [floor(10*rnd), floor(10*rnd), floor(10*rnd)]\n\t\tif actual[0] != actual[1] and actual[0] != actual[2] and actual[1] != actual[2] then break\n\tend while\n\t//print \"DEBUG: actual=\" + actual\n\tprint; print \"O.K.  I have a number in mind.\"\n\treturn actual\nend function\n\ngetGuess = function(guessNum)\n\tisNotDigit = function(c); return c < \"0\" or c > \"9\"; end function\n\twhile true\n\t\tinp = input(\"Guess #\" + guessNum + \"? \")\n\t\tif inp.len != 3 then\n\t\t\tprint \"Try guessing a three-digit number.\"\n\t\telse if inp[0] == inp[1] or inp[0] == inp[2] or inp[1] == inp[2] then\n\t\t\tprint \"Oh, I forgot to tell you that the number I have in mind\"\n\t\t\tprint \"has no two digits the same.\"\n\t\telse if isNotDigit(inp[0]) or isNotDigit(inp[1]) or isNotDigit(inp[2]) then\n\t\t\tprint \"What?\"\n\t\telse\n\t\t\treturn [inp[0].val, inp[1].val, inp[2].val]\n\t\tend if\n\tend while\nend function\n\ndoOneGame = function\n\tactual = pickNumber\n\tfor guessNum in range(1, 20)\n\t\tguess = getGuess(guessNum)\n\t\tpicos = 0; fermis = 0\n\t\tfor i in [0,1,2]\n\t\t\tif guess[i] == actual[i] then\n\t\t\t\tfermis += 1\n\t\t\telse if actual.indexOf(guess[i]) != null then\n\t\t\t\tpicos += 1\n\t\t\tend if\n\t\tend for\n\t\tif fermis == 3 then\n\t\t\tprint \"YOU GOT IT!!!\"\n\t\t\tglobals.score += 1\n\t\t\treturn\n\t\telse if picos or fermis then\n\t\t\tprint \"PICO \" * picos + \"FERMI \" * fermis\n\t\telse\n\t\t\tprint \"BAGELS\"\n\t\tend if\n\tend for\n\tprint \"Oh well.\"\n\tprint \"That's twenty guesses.  My number was \" + actual.join(\"\")\nend function\n\n// main loop\nscore = 0\nwhile true\n\tdoOneGame\n\tprint\n\tinp = input(\"Play again (yes or no)? \")\n\tif not inp or inp[0].upper != \"Y\" then break\nend while\nif score then\n\tprint; print \"A \" + score + \" point BAGELS buff!!\"\nend if\nprint \"Hope you had fun.  Bye.\"\n\n"
  },
  {
    "path": "00_Alternate_Languages/05_Bagels/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/05_Bagels/bagels.bas",
    "content": "5 PRINT TAB(33);\"BAGELS\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\":PRINT:PRINT\n15 REM *** BAGLES NUMBER GUESSING GAME\n20 REM *** ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE\n25 REM *** LAWRENCE HALL OF SCIENCE, U.C. BERKELY\n30 DIM A1(3),A(3),B(3)\n40 Y=0:T=255\n50 PRINT:PRINT:PRINT\n70 INPUT \"WOULD YOU LIKE THE RULES (YES OR NO)\";A$\n90 IF LEFT$(A$,1)=\"N\" THEN 150\n100 PRINT:PRINT \"I AM THINKING OF A THREE-DIGIT NUMBER.  TRY TO GUESS\"\n110 PRINT \"MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:\"\n120 PRINT \"   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION\"\n130 PRINT \"   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION\"\n140 PRINT \"   BAGELS - NO DIGITS CORRECT\"\n150 FOR I=1 TO 3\n160 A(I)=INT(10*RND(1))\n165 IF I-1=0 THEN 200\n170 FOR J=1 TO I-1\n180 IF A(I)=A(J) THEN 160\n190 NEXT J\n200 NEXT I\n210 PRINT:PRINT \"O.K.  I HAVE A NUMBER IN MIND.\"\n220 FOR I=1 TO 20\n230 PRINT \"GUESS #\";I,\n240 INPUT A$\n245 IF LEN(A$)<>3 THEN 630\n250 FOR Z=1 TO 3:A1(Z)=ASC(MID$(A$,Z,1)):NEXT Z\n260 FOR J=1 TO 3\n270 IF A1(J)<48 THEN 300\n280 IF A1(J)>57 THEN 300\n285 B(J)=A1(J)-48\n290 NEXT J\n295 GOTO 320\n300 PRINT \"WHAT?\"\n310 GOTO 230\n320 IF B(1)=B(2) THEN 650\n330 IF B(2)=B(3) THEN 650\n340 IF B(3)=B(1) THEN 650\n350 C=0:D=0\n360 FOR J=1 TO 2\n370 IF A(J)<>B(J+1) THEN 390\n380 C=C+1\n390 IF A(J+1)<>B(J) THEN 410\n400 C=C+1\n410 NEXT J\n420 IF A(1)<>B(3) THEN 440\n430 C=C+1\n440 IF A(3)<>B(1) THEN 460\n450 C=C+1\n460 FOR J=1 TO 3\n470 IF A(J)<>B(J) THEN 490\n480 D=D+1\n490 NEXT J\n500 IF D=3 THEN 680\n505 IF C=0 THEN 545\n520 FOR J=1 TO C\n530 PRINT \"PICO \";\n540 NEXT J\n545 IF D=0 THEN 580\n550 FOR J=1 TO D\n560 PRINT \"FERMI \";\n570 NEXT J\n580 IF C+D<>0 THEN 600\n590 PRINT \"BAGELS\";\n600 PRINT\n605 NEXT I\n610 PRINT \"OH WELL.\"\n615 PRINT \"THAT'S TWENTY GUESSES.  MY NUMBER WAS\";100*A(1)+10*A(2)+A(3)\n620 GOTO 700\n630 PRINT \"TRY GUESSING A THREE-DIGIT NUMBER.\":GOTO 230\n650 PRINT \"OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND\"\n660 PRINT \"HAS NO TWO DIGITS THE SAME.\":GOTO 230\n680 PRINT \"YOU GOT IT!!!\":PRINT\n690 Y=Y+1\n700 INPUT \"PLAY AGAIN (YES OR NO)\";A$\n720 IF LEFT$(A$,1)=\"Y\" THEN 150\n730 IF Y=0 THEN 750\n740 PRINT:PRINT \"A\";Y;\"POINT BAGELS BUFF!!\"\n750 PRINT \"HOPE YOU HAD FUN.  BYE.\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/05_Bagels/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nconst MAXGUESSES int = 20\r\n\r\nfunc printWelcome() {\r\n\tfmt.Println(\"\\n                Bagels\")\r\n\tfmt.Println(\"Creative Computing  Morristown, New Jersey\")\r\n\tfmt.Println()\r\n}\r\nfunc printRules() {\r\n\tfmt.Println()\r\n\tfmt.Println(\"I am thinking of a three-digit number.  Try to guess\")\r\n\tfmt.Println(\"my number and I will give you clues as follows:\")\r\n\tfmt.Println(\"   PICO   - One digit correct but in the wrong position\")\r\n\tfmt.Println(\"   FERMI  - One digit correct and in the right position\")\r\n\tfmt.Println(\"   BAGELS - No digits correct\")\r\n}\r\n\r\nfunc getNumber() []string {\r\n\tnumbers := []string{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"}\r\n\trand.Shuffle(len(numbers), func(i, j int) { numbers[i], numbers[j] = numbers[j], numbers[i] })\r\n\r\n\treturn numbers[:3]\r\n}\r\n\r\nfunc getValidGuess(guessNumber int) string {\r\n\tvar guess string\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tvalid := false\r\n\tfor !valid {\r\n\t\tfmt.Printf(\"Guess # %d?\\n\", guessNumber)\r\n\t\tscanner.Scan()\r\n\t\tguess = strings.TrimSpace(scanner.Text())\r\n\r\n\t\t// guess must be 3 characters\r\n\t\tif len(guess) == 3 {\r\n\t\t\t// and should be numeric\r\n\t\t\t_, err := strconv.Atoi(guess)\r\n\t\t\tif err != nil {\r\n\t\t\t\tfmt.Println(\"What?\")\r\n\t\t\t} else {\r\n\t\t\t\t// and the numbers should be unique\r\n\t\t\t\tif (guess[0:1] != guess[1:2]) && (guess[0:1] != guess[2:3]) && (guess[1:2] != guess[2:3]) {\r\n\t\t\t\t\tvalid = true\r\n\t\t\t\t} else {\r\n\t\t\t\t\tfmt.Println(\"Oh, I forgot to tell you that the number I have in mind\")\r\n\t\t\t\t\tfmt.Println(\"has no two digits the same.\")\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tfmt.Println(\"Try guessing a three-digit number.\")\r\n\t\t}\r\n\t}\r\n\r\n\treturn guess\r\n}\r\n\r\nfunc buildResultString(num []string, guess string) string {\r\n\tresult := \"\"\r\n\r\n\t// correct digits in wrong place\r\n\tfor i := 0; i < 2; i++ {\r\n\t\tif num[i] == guess[i+1:i+2] {\r\n\t\t\tresult += \"PICO \"\r\n\t\t}\r\n\t\tif num[i+1] == guess[i:i+1] {\r\n\t\t\tresult += \"PICO \"\r\n\t\t}\r\n\t}\r\n\tif num[0] == guess[2:3] {\r\n\t\tresult += \"PICO \"\r\n\t}\r\n\tif num[2] == guess[0:1] {\r\n\t\tresult += \"PICO \"\r\n\t}\r\n\r\n\t// correct digits in right place\r\n\tfor i := 0; i < 3; i++ {\r\n\t\tif num[i] == guess[i:i+1] {\r\n\t\t\tresult += \"FERMI \"\r\n\t\t}\r\n\t}\r\n\r\n\t// nothing right?\r\n\tif result == \"\" {\r\n\t\tresult = \"BAGELS\"\r\n\t}\r\n\r\n\treturn result\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tprintWelcome()\r\n\r\n\tfmt.Println(\"Would you like the rules (Yes or No)? \")\r\n\tscanner.Scan()\r\n\tresponse := scanner.Text()\r\n\tif len(response) > 0 {\r\n\t\tif strings.ToUpper(response[0:1]) != \"N\" {\r\n\t\t\tprintRules()\r\n\t\t}\r\n\t} else {\r\n\t\tprintRules()\r\n\t}\r\n\r\n\tgamesWon := 0\r\n\tstillRunning := true\r\n\r\n\tfor stillRunning {\r\n\t\tnum := getNumber()\r\n\t\tnumStr := strings.Join(num, \"\")\r\n\t\tguesses := 1\r\n\r\n\t\tfmt.Println(\"\\nO.K.  I have a number in mind.\")\r\n\t\tguessing := true\r\n\t\tfor guessing {\r\n\t\t\tguess := getValidGuess(guesses)\r\n\r\n\t\t\tif guess == numStr {\r\n\t\t\t\tfmt.Println(\"You got it!!\")\r\n\t\t\t\tgamesWon++\r\n\t\t\t\tguessing = false\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Println(buildResultString(num, guess))\r\n\t\t\t\tguesses++\r\n\t\t\t\tif guesses > MAXGUESSES {\r\n\t\t\t\t\tfmt.Println(\"Oh well\")\r\n\t\t\t\t\tfmt.Printf(\"That's %d guesses. My number was %s\\n\", MAXGUESSES, numStr)\r\n\t\t\t\t\tguessing = false\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvalidRespone := false\r\n\t\tfor !validRespone {\r\n\t\t\tfmt.Println(\"Play again (Yes or No)?\")\r\n\t\t\tscanner.Scan()\r\n\t\t\tresponse := scanner.Text()\r\n\t\t\tif len(response) > 0 {\r\n\t\t\t\tvalidRespone = true\r\n\t\t\t\tif strings.ToUpper(response[0:1]) != \"Y\" {\r\n\t\t\t\t\tstillRunning = false\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif gamesWon > 0 {\r\n\t\tfmt.Printf(\"\\nA %d point Bagels buff!!\\n\", gamesWon)\r\n\t}\r\n\r\n\tfmt.Println(\"Hope you had fun.  Bye\")\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/05_Bagels/nim/bagels.nim",
    "content": "import std/[random,strutils]\n\n# BAGLES NUMBER GUESSING GAME\n# ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE\n# LAWRENCE HALL OF SCIENCE, U.C. BERKELY\n\nvar\n  a, b: array[1..3, int]\n  wincount: int = 0\n  prompt: string\n  stillplaying: bool = true\n\nrandomize() # Seed the random number generator\n\n# Seed 3 unique random numbers; indicate if they're all unique\nproc genSeed(): bool =\n  for i in 1..3:\n    a[i] = rand(0..9)\n  if (a[1] == a[2]) or (a[2] == a[3]) or (a[3] == a[1]):\n    return false\n  return true\n\n# Primary game logic\nproc playGame() =\n  var youwin, unique: bool = false\n  # We want 3 unique random numbers: loop until we get them!\n  while unique == false:\n    unique = genSeed()\n  echo \"O.K.  I HAVE A NUMBER IN MIND.\"\n  for i in 1..20:\n    var c, d: int = 0\n    echo \"GUESS #\", i\n    prompt = readLine(stdin).normalize()\n    if (prompt.len() != 3):\n      echo \"TRY GUESSING A THREE-DIGIT NUMBER.\"\n      continue\n    for z in 1..3:\n      b[z] = prompt.substr(z-1, z-1).parseInt() # Convert string digits to array ints\n    if (b[1] == b[2]) or (b[2] == b[3]) or (b[3] == b[1]):\n      echo \"OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND\"\n      echo \"HAS NO TWO DIGITS THE SAME.\"\n    # Figure out the PICOs\n    if (a[1] == b[2]): c += 1\n    if (a[1] == b[3]): c += 1\n    if (a[2] == b[1]): c += 1\n    if (a[2] == b[3]): c += 1\n    if (a[3] == b[1]): c += 1\n    if (a[3] == b[2]): c += 1\n    # Determine FERMIs\n    for j in 1..3:\n      if (a[j] == b[j]): d += 1\n    # Reveal clues\n    if (d != 3):\n      if (c != 0):\n        for j in 1..c:\n          echo \"PICO\"\n      if (d != 0):\n        for j in 1..d:\n          echo \"FERMI\"\n      if (c == 0) and (d == 0):\n        echo \"BAGELS\"\n    # If we have 3 FERMIs, we win!\n    else:\n      echo \"YOU GOT IT!!!\"\n      echo \"\"\n      wincount += 1\n      youwin = true\n      break\n  # Only invoke if we've tried 20 guesses without winning\n  if not youwin:\n    echo \"OH WELL.\"\n    echo \"THAT'S TWENTY GUESSES.  MY NUMBER WAS \", a[1], a[2], a[3]\n\n# main program\necho spaces(33), \"BAGELS\"\necho spaces(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\necho \"\\n\\n\"\necho \"WOULD YOU LIKE THE RULES (YES OR NO)\"\nprompt = readLine(stdin).normalize()\nif prompt.substr(0, 0) == \"y\":\n  echo \"I AM THINKING OF A THREE-DIGIT NUMBER.  TRY TO GUESS\"\n  echo \"MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:\"\n  echo \"   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION\"\n  echo \"   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION\"\n  echo \"   BAGELS - NO DIGITS CORRECT\"\n  echo \"\"\nwhile(stillplaying == true):\n  playGame()\n  echo \"PLAY AGAIN (YES OR NO)\"\n  prompt = readLine(stdin).normalize()\n  if prompt.substr(0, 0) != \"y\":\n    stillplaying = false\nif wincount > 0:\n  echo \"\"\n  echo \"A \", wincount, \" POINT BAGELS BUFF!!\"\necho \"\"\necho \"HOPE YOU HAD FUN.  BYE.\"\n"
  },
  {
    "path": "00_Alternate_Languages/06_Banner/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript banner.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"banner\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/06_Banner/MiniScript/banner.ms",
    "content": "blockWidth = input(\"Horizontal? \").val\nif blockWidth <= 1 then blockWidth = 3\n\nblockHeight = input(\"Vertical? \").val\nif blockHeight <= 1 then blockHeight = 5\n\ninp = input(\"Centered? \").upper\ncentered = inp and inp[0] > \"P\"\n\nprintChar = input(\"Character (type 'all' if you want character being printed)? \")\n\nstatement = input(\"Statement: \").upper\n\n//input(\"Set page\")\t  // <-- opportunity to set your pin-feed printer before proceeding!\n\n// Define the character data.  For each character, we have 7 numbers\n// which are the 9-bit binary representation of each row, plus one.\ndata = {}\ndata[\" \"] = [0,0,0,0,0,0,0]\ndata[\"!\"] = [1,1,1,384,1,1,1]\ndata[\"?\"] = [5,3,2,354,18,11,5]\ndata[\".\"] = [1,1,129,449,129,1,1]\ndata[\"*\"] = [69,41,17,512,17,41,69]\ndata[\"=\"] = [41,41,41,41,41,41,41]\ndata[\"0\"] = [57,69,131,258,131,69,57]\ndata[\"1\"] = [0,0,261,259,512,257,257]\ndata[\"2\"] = [261,387,322,290,274,267,261]\ndata[\"3\"] = [66,130,258,274,266,150,100]\ndata[\"4\"] = [33,49,41,37,35,512,33]\ndata[\"5\"] = [160,274,274,274,274,274,226]\ndata[\"6\"] = [194,291,293,297,305,289,193]\ndata[\"7\"] = [258,130,66,34,18,10,8]\ndata[\"8\"] = [69,171,274,274,274,171,69]\ndata[\"9\"] = [263,138,74,42,26,10,7]\ndata[\"A\"] = [505,37,35,34,35,37,505]\ndata[\"B\"] = [512,274,274,274,274,274,239]\ndata[\"C\"] = [125,131,258,258,258,131,69]\ndata[\"D\"] = [512,258,258,258,258,131,125]\ndata[\"E\"] = [512,274,274,274,274,258,258]\ndata[\"F\"] = [512,18,18,18,18,2,2]\ndata[\"G\"] = [125,131,258,258,290,163,101]\ndata[\"H\"] = [512,17,17,17,17,17,512]\ndata[\"I\"] = [258,258,258,512,258,258,258]\ndata[\"J\"] = [65,129,257,257,257,129,128]\ndata[\"K\"] = [512,17,17,41,69,131,258]\ndata[\"L\"] = [512,257,257,257,257,257,257]\ndata[\"M\"] = [512,7,13,25,13,7,512]\ndata[\"N\"] = [512,7,9,17,33,193,512]\ndata[\"O\"] = [125,131,258,258,258,131,125]\ndata[\"P\"] = [512,18,18,18,18,18,15]\ndata[\"Q\"] = [125,131,258,258,322,131,381]\ndata[\"R\"] = [512,18,18,50,82,146,271]\ndata[\"S\"] = [69,139,274,274,274,163,69]\ndata[\"T\"] = [2,2,2,512,2,2,2]\ndata[\"U\"] = [128,129,257,257,257,129,128]\ndata[\"V\"] = [64,65,129,257,129,65,64]\ndata[\"W\"] = [256,257,129,65,129,257,256]\ndata[\"X\"] = [388,69,41,17,41,69,388]\ndata[\"Y\"] = [8,9,17,481,17,9,8]\ndata[\"Z\"] = [386,322,290,274,266,262,260]\n\nfor c in statement\n\tif not data.hasIndex(c) then continue\n\t\n\t// Print character c in giant sideways banner-style!\n\tfor datum in data[c]\n\t\tif datum then datum -= 1\t// remove spurious +1\n\t\tif printChar.upper != \"ALL\" then c = printChar\n\t\t\n\t\tfor lineRepeat in range(blockWidth-1)\n\t\t\tif centered then print \" \" * (34 - 4.5*blockHeight), \"\"\n\n\t\t\tfor bitPos in range(9,0)\n\t\t\t\tif bitAnd(datum, 2^bitPos) then charToPrint=c else charToPrint=\" \"\n\t\t\t\tprint charToPrint * blockHeight, \"\"\n\t\t\tend for\t// next bitPos\n\n\t\t\tprint\n\t\t\twait 0.01  // put in a small pause so it's not too fast to see!\n\t\tend for  // next lineRepeat (repeating line according to entered Y value)\n\n\tend for  // next datum (row of this character)\n\t\n\t// Add a little space after each character\n\tfor i in range(1, 2 * blockWidth)\n\t\tprint\n\t\twait 0.01\n\tend for\nend for  // next character in the message\n"
  },
  {
    "path": "00_Alternate_Languages/06_Banner/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/06_Banner/banner.bas",
    "content": "10 INPUT \"HORIZONTAL\";X\n20 INPUT \"VERTICAL\";Y\n21 INPUT \"CENTERED\";L$\n22 G1=0:IF L$>\"P\" THEN G1=1\n23 INPUT \"CHARACTER (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED)\";M$\n29 PRINT \"STATEMENT\";\n30 INPUT A$\n35 INPUT \"SET PAGE\";O$\n40 A=ASC(LEFT$(A$,1))\n50 REM\n60 REM\n70 FOR T=1 TO LEN(A$)\n80 P$=MID$(A$,T,1)\n90 FOR O=1 TO 50\n95 READ S$,S(1),S(2),S(3),S(4),S(5),S(6),S(7)\n96 IF P$=\" \" THEN 812\n100 IF P$=S$ THEN 200\n120 NEXT O\n200 RESTORE\n201 X$=M$\n202 IF M$=\"ALL\" THEN X$=S$\n205 FOR U=1 TO 7\n210 FOR K=8 TO 0 STEP -1\n230 IF 2^K<S(U) THEN 270\n240 J(9-K)=0\n250 GOTO 280\n270 J(9-K)=1: S(U)=S(U)-2^K\n272 IF S(U)=1 THEN 815\n280 NEXT K\n445 FOR T1=1 TO X\n447 PRINT TAB((63-4.5*Y)*G1/(LEN(X$))+1);\n450 FOR B=1 TO F(U)\n460 IF J(B)=0 THEN 500\n465 FOR I=1 TO Y: PRINT X$;: NEXT I\n470 GOTO 600\n500 FOR I=1 TO Y\n510 FOR I1=1 TO LEN(X$)\n520 PRINT \" \";: NEXT I1\n530 NEXT I\n600 NEXT B\n620 PRINT\n630 NEXT T1\n700 NEXT U\n750 FOR H=1 TO 2*X: PRINT: NEXT H\n800 NEXT T\n806 FOR H=1 TO 75: PRINT: NEXT H\n810 END\n812 FOR H=1 TO 7*X: PRINT: NEXT H\n813 GOTO 800\n815 F(U)=9-K: GOTO 445\n899 DATA \" \",0,0,0,0,0,0,0\n900 DATA \"A\",505,37,35,34,35,37,505\n901 DATA \"G\",125,131,258,258,290,163,101\n902 DATA \"E\",512,274,274,274,274,258,258\n903 DATA \"T\",2,2,2,512,2,2,2\n904 DATA \"W\",256,257,129,65,129,257,256\n905 DATA \"L\",512,257,257,257,257,257,257\n906 DATA \"S\",69,139,274,274,274,163,69\n907 DATA \"O\",125,131,258,258,258,131,125\n908 DATA \"N\",512,7,9,17,33,193,512\n909 DATA \"F\",512,18,18,18,18,2,2\n910 DATA \"K\",512,17,17,41,69,131,258\n911 DATA \"B\",512,274,274,274,274,274,239\n912 DATA \"D\",512,258,258,258,258,131,125\n913 DATA \"H\",512,17,17,17,17,17,512\n914 DATA \"M\",512,7,13,25,13,7,512\n915 DATA \"?\",5,3,2,354,18,11,5\n916 DATA \"U\",128,129,257,257,257,129,128\n917 DATA \"R\",512,18,18,50,82,146,271\n918 DATA \"P\",512,18,18,18,18,18,15\n919 DATA \"Q\",125,131,258,258,322,131,381\n920 DATA \"Y\",8,9,17,481,17,9,8\n921 DATA \"V\",64,65,129,257,129,65,64\n922 DATA \"X\",388,69,41,17,41,69,388\n923 DATA \"Z\",386,322,290,274,266,262,260\n924 DATA \"I\",258,258,258,512,258,258,258\n925 DATA \"C\",125,131,258,258,258,131,69\n926 DATA \"J\",65,129,257,257,257,129,128\n927 DATA \"1\",0,0,261,259,512,257,257\n928 DATA \"2\",261,387,322,290,274,267,261\n929 DATA \"*\",69,41,17,512,17,41,69\n930 DATA \"3\",66,130,258,274,266,150,100\n931 DATA \"4\",33,49,41,37,35,512,33\n932 DATA \"5\",160,274,274,274,274,274,226\n933 DATA \"6\",194,291,293,297,305,289,193\n934 DATA \"7\",258,130,66,34,18,10,8\n935 DATA \"8\",69,171,274,274,274,171,69\n936 DATA \"9\",263,138,74,42,26,10,7\n937 DATA \"=\",41,41,41,41,41,41,41\n938 DATA \"!\",1,1,1,384,1,1,1\n939 DATA \"0\",57,69,131,258,131,69,57\n940 DATA \".\",1,1,129,449,129,1,1\n1000 STOP\n1002 END\n"
  },
  {
    "path": "00_Alternate_Languages/07_Basketball/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript basketball.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"basketball\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms",
    "content": "print \" \"*31 + \"Basketball\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"This is Dartmouth College basketball.  You will be Dartmouth\"\nprint \" captain and playmaker.  Call shots as follows:  1. Long\"\nprint \" (30 ft.) jump shot; 2. Short (15 ft.) jump shot; 3. Lay\"\nprint \" up; 4. Set shot.\"\nprint \"Both teams will use the same defense.  Call defense as\"\nprint \"follows:  6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None.\"\nprint \"To change defense, just type 0 as your next shot.\"\n\ninputDefense = function(prompt)\n\twhile true\n\t\tglobals.defense = input(prompt).val\n\t\tif defense >= 6 then break\n\tend while\nend function\n\n// Do the center jump; return US or THEM who gets the ball.\ncenterJump = function\n\tprint \"Center Jump\"\n\tif rnd < 0.6 then\n\t\tprint opponent + \" controls the tap.\"\n\t\treturn THEM\n\telse\n\t\tprint \"Dartmouth controls the tap.\"\n\t\treturn US\n\tend if\nend function\n\ninputShot = function\n\twhile true\n\t\tglobals.shotType = input(\"Your shot (0-4): \")\n\t\tif shotType == \"0\" then\n\t\t\tinputDefense \"Your new defensive alignment is? \"\n\t\t\tcontinue\n\t\tend if\n\t\tglobals.shotType = shotType.val\n\t\tif 1 <= shotType <= 4 then return\n\tend while\nend function\n\nendFirstHalf = function\n\tprint \"   ***** End of first half *****\"; print\n\tprint \"Score: Dartmouth: \" + score[US] + \"   \" + opponent + \": \" + score[THEM]\n\tprint; print\n\tglobals.inControl = centerJump\nend function\n\ncheckGameOver = function\n\tprint\n\tif score[0] != score[1] then\n\t\tprint \"  ***** END OF GAME *****\"\n\t\tprint \"Final score: Dartmouth: \" + score[US] + \"   \" + opponent + \": \" + score[THEM]\n\t\tprint\n\t\treturn true\n\telse\n\t\tprint \"  ***** End of Second Half *****\"\n\t\tprint \"Score at end of regulation time:\"\n\t\tprint \"        Dartmouth: \" + score[US] + \"   \" + opponent + \": \" + score[THEM]\n\t\tprint\n\t\tprint \"Begin two minute overtime period\"\n\t\treturn false\n\tend if\nend function\n\nscoreBasket = function(who = null)\n\tif who == null then who = inControl\n\tscore[who] += 2\n\tprintScore\nend function\n\nprintScore = function\n\tprint \"Score: \" + score[1] + \" to \" + score[0]\n\tprint \"Time: \" + timer\nend function\n\n// Logic for a Dartmouth jump shot.  Return true to continue as Dartmouth,\n// false to pass the ball to the opponent.\ndartmouthJumpShot = function\n\tif rnd <= 0.341 * defense / 8 then\n\t\tprint \"Shot is good.\"\n\t\tscoreBasket\n\t\treturn false\n\tend if\n\n\tif rnd < 0.682 * defense / 8 then\n\t\tprint \"Shot is off target.\"\n\t\tif defense/6 * rnd > 0.45 then\n\t\t\tprint \"Rebound to \" + opponent\n\t\t\treturn false\n\t\tend if\n\t\tprint \"Dartmouth controls the rebound.\"\n\t\tif rnd <= 0.4 then\n\t\t\tglobals.shotType = 3 + (rnd > 0.5)\n\t\t\treturn true\n\t\tend if\n\t\tif defense == 6 and rnd < 0.6 then\n\t\t\tprint \"Pass stolen by \" + opponent + \", easy layup.\"\n\t\t\tscoreBasket THEM\n\t\t\treturn true\n\t\tend if\n\t\tprint \"Ball passed back to you.\"\n\t\treturn true\n\tend if\n\t\n\tif rnd < 0.782 * defense/8 then\n\t\tprint \"Shot is blocked.  Ball controlled by \", \"\"\n\t\tif rnd > 0.5 then\n\t\t\tprint opponent + \".\"\n\t\t\treturn false\n\t\telse\n\t\t\tprint \"Dartmouth.\"\n\t\t\treturn true\n\t\tend if\n\tend if\n\t\n\tif rnd > 0.843 * defense/8 then\n\t\tprint \"Charging foul.  Dartmouth loses ball.\"\n\telse\n\t\tprint \"Shooter is fouled.  Two shots.\"\n\t\tdoFoulShots US\n\tend if\n\treturn false\nend function\n\n// Logic for an opponent jump shot.  Return true to continue as opponent,\n// false to pass the ball to Dartmouth.\nopponentJumpShot = function\n\tif rnd <= 0.35 * defense / 8 then\n\t\tprint \"Shot is good.\"\n\t\tscoreBasket\n\t\treturn false\n\tend if\n\n\tif 8 / defense * rnd <= 0.75 then\n\t\tprint \"Shot is off rim.\"\n\t\treturn opponentMissed\n\tend if\n\t\n\tif 8 / defense * rnd <= 0.9 then\n\t\tprint \"Player fouled.  Two shots.\"\n\t\tdoFoulShots THEM\n\t\treturn false\n\tend if\n\tprint \"Offensive foul.  Dartmouth's ball.\"\n\treturn false\nend function\n\n// Do a Dartmouth set shot or lay-up.  Return true to continue as Dartmouth,\n// false to pass the ball to the opponent.\ndartmouthSetOrLay = function\n\tif 7 / defense * rnd <= 0.4 then\n\t\tprint \"Shot is good.  Two points.\"\n\t\tscoreBasket\n\telse if 7 / defense * rnd <= 0.7 then\n\t\tprint \"Shot is off the rim.\"\n\t\tif rnd < 0.667 then\n\t\t\tprint opponent + \" controls the rebound.\"\n\t\t\treturn false\n\t\tend if\n\t\tprint \"Dartmouth controls the rebound.\"\n\t\tif rnd < 0.4 then return true\n\t\tprint \"Ball passed back to you.\"\n\t\treturn true\n\telse if 7 / defense * rnd < 0.875 then\n\t\tprint \"Shooter fouled.  Two shots.\"\n\t\tdoFoulShots US\n\telse if 7 / defense * rnd < 0.925 then\n\t\tprint \"Shot blocked.  \" + opponent + \"'s ball.\"\n\telse\n\t\tprint \"Charging foul.  Dartmouth loses the ball.\"\n\tend if\t\t\t\n\treturn false\nend function\n\n// Do an opponent set shot or lay-up.  Return true to continue as opponent,\n// false to pass the ball to Dartmouth.\nopponentSetOrLay = function\n\tif 7 / defense * rnd <= 0.413 then\n\t\tprint \"Shot is missed.\"\n\t\treturn opponentMissed\n\telse\n\t\tprint \"Shot is good.\"\n\t\tscoreBasket\n\t\treturn false\n\tend if\nend function\n\n// Handle opponent missing a shot -- return true to continue as opponent,\n// false to pass the ball to Dartmouth.\nopponentMissed = function\n\tif defense / 6 * rnd <= 0.5 then\n\t\tprint \"Dartmouth controls the rebound.\"\n\t\treturn false\n\telse\n\t\tprint opponent + \" controls the rebound.\"\n\t\tif defense == 6 and rnd <= 0.75 then\n\t\t\tprint \"Ball stolen.  Easy lay up for Dartmouth.\"\n\t\t\tscoreBasket US\n\t\t\treturn true\n\t\tend if\n\t\tif rnd <= 0.5 then\n\t\t\tprint \"Pass back to \" + opponent + \" guard.\"\n\t\t\treturn true\n\t\tend if\n\t\tglobals.shotType = 4 - (rnd > 0.5)\n\t\treturn true\n\tend if\nend function\n\nplayOneSide = function\n\tprint\n\twhile true\n\t\tglobals.timer += 1\n\t\tif timer == 50 then return endFirstHalf\n\t\tif time == 92 then\n\t\t\tprint \"  *** Two minutes left in the game ***\"; print\n\t\tend if\n\t\tif shotType == 1 or shotType == 2 then\n\t\t\tprint \"Jump Shot\"\n\t\t\tif inControl == US then\n\t\t\t\tif dartmouthJumpShot then continue else break\n\t\t\telse\n\t\t\t\tif opponentJumpShot then continue else break\n\t\t\tend if\n\t\telse\t\t// (if shot type >= 3)\n\t\t\tif shotType > 3 then print \"Set shot.\" else print \"Lay up.\"\n\t\t\tif inControl == US then\n\t\t\t\tif dartmouthSetOrLay then continue else break\n\t\t\telse\n\t\t\t\tif opponentSetOrLay then continue else break\n\t\t\tend if\n\t\tend if\n\tend while\n\tglobals.inControl = 1 - globals.inControl\nend function\n\ndoFoulShots = function(who)\n\tif rnd > 0.49 then\n\t\tif rnd > 0.75 then\n\t\t\tprint \"Both shots missed.\"\n\t\telse\n\t\t\tprint \"Shooter makes one shot and misses one.\"\n\t\t\tscore[who] += 1\n\t\tend if\n\telse\n\t\tprint \"Shooter makes both shots.\"\n\t\tscore[who] += 2\n\tend if\n\tprintScore\nend function\n\nopponentPlay = function\n\tprint\n\twhile true\n\t\tglobals.timer += 1\n\t\tif timer == 50 then return endFirstHalf\n\t\tif time == 92 then\n\t\t\tprint \"  *** Two minutes left in the game ***\"; print\n\t\tend if\n\t\tif shotType == 1 or shotType == 2 then\n\t\t\tprint \"Jump Shot\"\n\t\t\tif opponentJumpShot then continue else break\n\t\telse\t\t// (if shot type >= 3)\n\t\t\tif shotType > 3 then print \"Set shot.\" else print \"Lay up.\"\n\t\t\tif opponentSetOrLay then continue else break\n\t\tend if\n\tend while\n\tglobals.inControl = US\nend function\n\n// Constants\nTHEM = 0\nUS = 1\n\n// Main program\ninputDefense \"Your starting defense will be? \"\nprint\nopponent = input(\"Choose your opponent? \")\nscore = [0,0]\t\t// score for each team (US and THEM)\ngameOver = false\ninControl = centerJump\ntimer = 0\nwhile not gameOver\n\tprint\n\tif inControl == US then\n\t\tinputShot\n\t\tplayOneSide\n\telse\n\t\tshotType = ceil(10 / 4 * rnd + 1)\n\t\tplayOneSide\n\tend if\n\tif timer >= 100 then\n\t\tif checkGameOver then break\n\t\ttimer = 93\n\t\tdartmouthHasBall = centerJump\n\tend if\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/07_Basketball/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/07_Basketball/basketball.bas",
    "content": "5 PRINT TAB(31);\"BASKETBALL\"\n7 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n8 PRINT:PRINT:PRINT\n10 PRINT \"THIS IS DARTMOUTH COLLEGE BASKETBALL.  YOU WILL BE DARTMOUTH\"\n20 PRINT \" CAPTAIN AND PLAYMAKER.  CALL SHOTS AS FOLLOWS:  1. LONG\"\n30 PRINT \" (30 FT.) JUMP SHOT; 2. SHORT (15 FT.) JUMP SHOT; 3. LAY\"\n40 PRINT \" UP; 4. SET SHOT.\"\n60 PRINT \"BOTH TEAMS WILL USE THE SAME DEFENSE.  CALL DEFENSE AS\"\n70 PRINT \"FOLLOWS:  6. PRESS; 6.5 MAN-TO MAN; 7. ZONE; 7.5 NONE.\"\n72 PRINT \"TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\"\n76 INPUT \"YOUR STARTING DEFENSE WILL BE\";D:IF D<6 THEN 2010\n79 PRINT\n80 INPUT \"CHOOSE YOUR OPPONENT\";O$\n370 PRINT \"CENTER JUMP\"\n390 IF RND(1)> 3/5 THEN 420\n400 PRINT O$;\" CONTROLS THE TAP.\"\n410 GOTO 3000\n420 PRINT \"DARTMOUTH CONTROLS THE TAP.\"\n425 PRINT\n430 INPUT \"YOUR SHOT\";Z\n440 P=0\n445 IF Z<>INT(Z) THEN 455\n446 IF Z<0 OR Z>4 THEN 455\n447 GOTO 460\n455 PRINT \"INCORRECT ANSWER.  RETYPE IT. \";:GOTO 430\n460 IF RND(1)<.5 THEN 1000\n480 IF T<100 THEN 1000\n490 PRINT\n491 IF S(1)<>S(0) THEN 510\n492 PRINT:PRINT \"   ***** END OF SECOND HALF *****\":PRINT\n493 PRINT \"SCORE AT END OF REGULATION TIME:\"\n494 PRINT \"        DARTMOUTH:\";S(1);\"  \";O$;\":\";S(0)\n495 PRINT\n496 PRINT \"BEGIN TWO MINUTE OVERTIME PERIOD\"\n499 T=93\n500 GOTO 370\n510 PRINT \"   ***** END OF GAME *****\"\n515 PRINT \"FINAL SCORE: DARTMOUTH:\";S(1);\"  \";O$;\":\";S(0)\n520 STOP\n600 PRINT\n610 PRINT \"   *** TWO MINUTES LEFT IN THE GAME ***\"\n620 PRINT\n630 RETURN\n1000 ON Z GOTO 1040,1040\n1030 GOTO 1300\n1040 T=T+1\n1041 IF T=50 THEN 8000\n1042 IF T=92 THEN 1046\n1043 GOTO 1050\n1046 GOSUB 600\n1050 PRINT \"JUMP SHOT\"\n1060 IF RND(1)>.341*D/8 THEN 1090\n1070 PRINT \"SHOT IS GOOD.\"\n1075 GOSUB 7000\n1085 GOTO 3000\n1090 IF RND(1)>.682*D/8 THEN 1200\n1100 PRINT \"SHOT IS OFF TARGET.\"\n1105 IF D/6*RND(1)>.45 THEN 1130\n1110 PRINT \"DARTMOUTH CONTROLS THE REBOUND.\"\n1120 GOTO 1145\n1130 PRINT \"REBOUND TO \";O$\n1140 GOTO 3000\n1145 IF RND(1)>.4 THEN 1158\n1150 GOTO 1300\n1158 IF D=6 THEN 5100\n1160 PRINT \"BALL PASSED BACK TO YOU. \";\n1170 GOTO 430\n1180 IF RND(1)>.9 THEN 1190\n1185 PRINT \"PLAYER FOULED, TWO SHOTS.\"\n1187 GOSUB 4000\n1188 GOTO 3000\n1190 PRINT \"BALL STOLEN. \";O$;\"'S BALL.\"\n1195 GOTO 3000\n1200 IF RND(1)>.782*D/8 THEN 1250\n1210 PRINT \"SHOT IS BLOCKED.  BALL CONTROLLED BY \";\n1230 IF RND(1)>.5 THEN 1242\n1235 PRINT \"DARTMOUTH.\"\n1240 GOTO 430\n1242 PRINT O$;\".\"\n1245 GOTO 3000\n1250 IF RND(1)>.843*D/8 THEN 1270\n1255 PRINT \"SHOOTER IS FOULED.  TWO SHOTS.\"\n1260 GOSUB 4000\n1265 GOTO 3000\n1270 PRINT \"CHARGING FOUL.  DARTMOUTH LOSES BALL.\"\n1280 GOTO 3000\n1300 T=T+1\n1301 IF T=50 THEN 8000\n1302 IF T=92 THEN 1304\n1303 GOTO 1305\n1304 GOSUB 600\n1305 IF Z=0 THEN 2010\n1310 IF Z>3 THEN 1700\n1320 PRINT \"LAY UP.\"\n1330 IF 7/D*RND(1)>.4 THEN 1360\n1340 PRINT \"SHOT IS GOOD.  TWO POINTS.\"\n1345 GOSUB 7000\n1355 GOTO 3000\n1360 IF 7/D*RND(1)>.7 THEN 1500\n1370 PRINT \"SHOT IS OFF THE RIM.\"\n1380 IF RND(1)>2/3 THEN 1415\n1390 PRINT O$;\" CONTROLS THE REBOUND.\"\n1400 GOTO 3000\n1415 PRINT \"DARTMOUTH CONTROLS THE REBOUND.\"\n1420 IF RND(1)>.4 THEN 1440\n1430 GOTO 1300\n1440 PRINT \"BALL PASSED BACK TO YOU.\";\n1450 GOTO 430\n1500 IF 7/D*RND(1)>.875 THEN 1600\n1510 PRINT \"SHOOTER FOULED.  TWO SHOTS.\"\n1520 GOSUB 4000\n1530 GOTO 3000\n1600 IF 7/D*RND(1)>.925 THEN 1630\n1610 PRINT \"SHOT BLOCKED. \";O$;\"'S BALL.\"\n1620 GOTO 3000\n1630 PRINT \"CHARGING FOUL.  DARTMOUTH LOSES THE BALL.\"\n1640 GOTO 3000\n1700 PRINT \"SET SHOT.\"\n1710 GOTO 1330\n2010 INPUT \"YOUR NEW DEFENSIVE ALLIGNMENT IS\";D\n2030 IF D<6 THEN 2010\n2040 GOTO 425\n3000 P=1\n3005 T=T+1\n3008 IF T=50 THEN 8000\n3012 GOTO 3018\n3015 GOSUB 600\n3018 PRINT\n3020 Z1=10/4*RND(1)+1\n3030 IF Z1>2 THEN 3500\n3040 PRINT \"JUMP SHOT.\"\n3050 IF 8/D*RND(1)>.35 THEN 3100\n3060 PRINT \"SHOT IS GOOD.\"\n3080 GOSUB 6000\n3090 GOTO 425\n3100 IF 8/D*RND(1)>.75 THEN 3200\n3105 PRINT \"SHOT IS OFF RIM.\"\n3110 IF D/6*RND(1)>.5 THEN 3150\n3120 PRINT \"DARTMOUTH CONTROLS THE REBOUND.\"\n3130 GOTO 425\n3150 PRINT O$;\" CONTROLS THE REBOUND.\"\n3160 IF D=6 THEN 5000\n3165 IF RND(1)>.5 THEN 3175\n3168 PRINT \"PASS BACK TO \";O$;\" GUARD.\"\n3170 GOTO 3000\n3175 GOTO 3500\n3200 IF 8/D*RND(1)>.9 THEN 3310\n3210 PRINT \"PLAYER FOULED.  TWO SHOTS.\"\n3220 GOSUB 4000\n3230 GOTO 425\n3310 PRINT \"OFFENSIVE FOUL.  DARTMOUTH'S BALL.\"\n3320 GOTO 425\n3500 IF Z1>3 THEN 3800\n3510 PRINT \"LAY UP.\"\n3520 IF 7/D*RND(1)>.413 THEN 3600\n3530 PRINT \"SHOT IS GOOD.\"\n3540 GOSUB 6000\n3550 GOTO 425\n3600 PRINT \"SHOT IS MISSED.\"\n3610 GOTO 3110\n3800 PRINT \"SET SHOT.\"\n3810 GOTO 3520\n4000 REM FOUL SHOOTING\n4010 IF RND(1)>.49 THEN 4050\n4020 PRINT \"SHOOTER MAKES BOTH SHOTS.\"\n4030 S(1-P)=S(1-P)+2\n4040 GOSUB 6010\n4041 RETURN\n4050 IF RND(1)>.75 THEN 4100\n4060 PRINT \"SHOOTER MAKES ONE SHOT AND MISSES ONE.\"\n4070 S(1-P)=S(1-P)+1\n4080 GOTO 4040\n4100 PRINT \"BOTH SHOTS MISSED.\"\n4110 GOTO 4040\n5000 IF RND(1)>.75 THEN 5010\n5005 GOTO 3165\n5010 PRINT \"BALL STOLEN.  EASY LAY UP FOR DARTMOUTH.\"\n5015 GOSUB 7000\n5030 GOTO 3000\n5100 IF RND(1)>.6 THEN 5120\n5110 GOTO 1160\n5120 PRINT \"PASS STOLEN BY \";O$;\" EASY LAYUP.\"\n5130 GOSUB 6000\n5140 GOTO 425\n6000 S(0)=S(0)+2\n6010 PRINT \"SCORE: \";S(1);\"TO\";S(0)\n6020 RETURN\n7000 S(1)=S(1)+2\n7010 GOSUB 6010\n7020 RETURN\n8000 PRINT:PRINT \"   ***** END OF FIRST HALF *****\":PRINT\n8010 PRINT \"SCORE: DARTMOUTH:\";S(1);\"  \";O$;\":\";S(0)\n8015 PRINT\n8016 PRINT\n8020 GOTO 370\n9999 END\n"
  },
  {
    "path": "00_Alternate_Languages/08_Batnum/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript batnum.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"batnum\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms",
    "content": "print \" \"*33 + \"Batnum\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"This program is a 'Battle of Numbers' game, where the\"\nprint \"computer is your opponent.\"\nprint\nprint \"The game starts with an assumed pile of objects. You\"\nprint \"and your opponent alternately remove objects from the pile.\"\nprint \"Winning is defined in advance as taking the last object or\"\nprint \"not. You can also specify some other beginning conditions.\"\nprint \"Don't use zero, however, in playing the game.\"\nprint \"Enter a negative number for new pile size to stop playing.\"\nprint\n\noptions = {}\ngetOptions = function\n\twhile true\n\t\toptions.pileSize = input(\"Enter pile size? \").val\n\t\tif options.pileSize != 0 and options.pileSize == floor(options.pileSize) then break\n\tend while\n\tif options.pileSize < 0 then return\n\n\twhile true\n\t\twinOption = input(\"Enter win option - 1 to take last, 2 to avoid last: \")\n\t\tif winOption == \"1\" or winOption == \"2\" then break\n\tend while\n\toptions.takeLast = (winOption == \"1\")\n\n\twhile true\n\t\tminMax = input(\"Enter min and max? \").replace(\",\", \" \").split\n\t\tif minMax.len < 2 then continue\n\t\toptions.minTake = minMax[0].val\n\t\toptions.maxTake = minMax[-1].val\n\t\tif options.minTake >= 1 and options.minTake < options.maxTake then break\n\tend while\n\n\twhile true\n\t\tstartOpt = input(\"Enter start option - 1 computer first, 2 you first: \")\n\t\tif startOpt == \"1\" or startOpt == \"2\" then break\n\tend while\n\toptions.computerFirst = (startOpt == \"1\")\nend function\n\ncomputerTurn = function\n\t// Random computer play (not in original program):\n\ttake = options.minTake + floor(rnd * (options.maxTake - options.minTake))\n\t\n\t// Proper (smart) computer play\n\tq = pile\n\tif not options.takeLast then q -= 1\n\ttake = q % (options.minTake + options.maxTake)\n\tif take < options.minTake then take = options.minTake\n\tif take > options.maxTake then take = options.maxTake\n\t\n\tif take >= pile then\n\t\tif options.takeLast then\n\t\t\tprint \"Computer takes \" + pile + \" and wins.\"\n\t\telse\n\t\t\tprint \"Computer takes \" + pile + \" and loses.\"\n\t\tend if\n\t\tglobals.gameOver = true\n\telse\n\t\tglobals.pile -= take\n\t\tprint \"Computer takes \" + take + \" and leaves \" + pile\n\tend if\nend function\n\nplayerTurn = function\n\twhile true\n\t\tprint; take = input(\"Your move? \").val\n\t\tif take == 0 then\n\t\t\tprint \"I told you not to use zero! Computer wins by forfeit.\"\n\t\t\tglobals.gameOver = true\n\t\t\treturn\n\t\tend if\n\t\tif options.minTake <= take <= options.maxTake and take <= pile then break\n\t\tprint \"Illegal move, reenter it\"\n\tend while\n\tif take >= pile then\n\t\tif options.takeLast then\n\t\t\tprint \"Congratulations, you win.\"\n\t\telse\n\t\t\tprint \"Tough luck, you lose.\"\n\t\tend if\n\t\tglobals.gameOver = true\n\telse\n\t\tglobals.pile -= take\n\t\t//print \"You take \" + take + \", leaving \" + pile\t// (not in original program)\n\tend if\nend function\n\nwhile true\n\tgetOptions\n\tif options.pileSize < 0 then break\n\tpile = options.pileSize\n\tgameOver = false\n\t\n\tprint; print\n\n\tif options.computerFirst then computerTurn\n\twhile not gameOver\n\t\tplayerTurn\n\t\tif gameOver then break\n\t\tcomputerTurn\n\tend while\n\t\n\tfor i in range(1,10); print; end for\nend while\nprint \"OK, bye!\""
  },
  {
    "path": "00_Alternate_Languages/08_Batnum/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/08_Batnum/batnum.bas",
    "content": "10 PRINT TAB(33);\"BATNUM\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n110 PRINT \"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\"\n120 PRINT \"COMPUTER IS YOUR OPPONENT.\"\n130 PRINT\n140 PRINT \"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\"\n150 PRINT \"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\"\n160 PRINT \"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\"\n170 PRINT \"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\"\n180 PRINT \"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\"\n190 PRINT \"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\"\n200 PRINT\n210 GOTO 330\n220 FOR I=1 TO 10\n230 PRINT\n240 NEXT I\n330 INPUT \"ENTER PILE SIZE\";N\n350 IF N>=1 THEN 370\n360 GOTO 330\n370 IF N<>INT(N) THEN 220\n380 IF N<1 THEN 220\n390 INPUT \"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \";M\n410 IF M=1 THEN 430\n420 IF M<>2 THEN 390\n430 INPUT \"ENTER MIN AND MAX \";A,B\n450 IF A>B THEN 430\n460 IF A<1 THEN 430\n470 IF A<>INT(A) THEN 430\n480 IF B<>INT(B) THEN 430\n490 INPUT \"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \";S\n500 PRINT:PRINT\n510 IF S=1 THEN 530\n520 IF S<>2 THEN 490\n530 C=A+B\n540 IF S=2 THEN 570\n550 GOSUB 600\n560 IF W=1 THEN 220\n570 GOSUB 810\n580 IF W=1 THEN 220\n590 GOTO 550\n600 Q=N\n610 IF M=1 THEN 630\n620 Q=Q-1\n630 IF M=1 THEN 680\n640 IF N>A THEN 720\n650 W=1\n660 PRINT \"COMPUTER TAKES\";N;\"AND LOSES.\"\n670 RETURN\n680 IF N>B THEN 720\n690 W=1\n700 PRINT \"COMPUTER TAKES\";N;\"AND WINS.\"\n710 RETURN\n720 P=Q-C*INT(Q/C)\n730 IF P>=A THEN 750\n740 P=A\n750 IF P<=B THEN 770\n760 P=B\n770 N=N-P\n780 PRINT \"COMPUTER TAKES\";P;\"AND LEAVES\";N\n790 W=0\n800 RETURN\n810 PRINT:PRINT \"YOUR MOVE \";\n820 INPUT P\n830 IF P<>0 THEN 870\n840 PRINT \"I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.\"\n850 W=1\n860 RETURN\n870 IF P<>INT(P) THEN 920\n880 IF P>=A THEN 910\n890 IF P=N THEN 960\n900 GOTO 920\n910 IF P<=B THEN 940\n920 PRINT \"ILLEGAL MOVE, REENTER IT \";\n930 GOTO 820\n940 N=N-P\n950 IF N<>0 THEN 1030\n960 IF M=1 THEN 1000\n970 PRINT \"TOUGH LUCK, YOU LOSE.\"\n980 W=1\n990 RETURN\n1000 PRINT \"CONGRATULATIONS, YOU WIN.\"\n1010 W=1\n1020 RETURN\n1030 IF N>=0 THEN 1060\n1040 N=N+P\n1050 GOTO 920\n1060 W=0\n1070 RETURN\n1080 END\n"
  },
  {
    "path": "00_Alternate_Languages/08_Batnum/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n)\r\n\r\ntype StartOption int8\r\n\r\nconst (\r\n\tStartUndefined StartOption = iota\r\n\tComputerFirst\r\n\tPlayerFirst\r\n)\r\n\r\ntype WinOption int8\r\n\r\nconst (\r\n\tWinUndefined WinOption = iota\r\n\tTakeLast\r\n\tAvoidLast\r\n)\r\n\r\ntype GameOptions struct {\r\n\tpileSize    int\r\n\twinOption   WinOption\r\n\tstartOption StartOption\r\n\tminSelect   int\r\n\tmaxSelect   int\r\n}\r\n\r\nfunc NewOptions() *GameOptions {\r\n\tg := GameOptions{}\r\n\r\n\tg.pileSize = getPileSize()\r\n\tif g.pileSize < 0 {\r\n\t\treturn &g\r\n\t}\r\n\r\n\tg.winOption = getWinOption()\r\n\tg.minSelect, g.maxSelect = getMinMax()\r\n\tg.startOption = getStartOption()\r\n\r\n\treturn &g\r\n}\r\n\r\nfunc getPileSize() int {\r\n\tps := 0\r\n\tvar err error\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"Enter Pile Size \")\r\n\t\tscanner.Scan()\r\n\t\tps, err = strconv.Atoi(scanner.Text())\r\n\t\tif err == nil {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\treturn ps\r\n}\r\n\r\nfunc getWinOption() WinOption {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST:\")\r\n\t\tscanner.Scan()\r\n\t\tw, err := strconv.Atoi(scanner.Text())\r\n\t\tif err == nil && (w == 1 || w == 2) {\r\n\t\t\treturn WinOption(w)\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc getStartOption() StartOption {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \")\r\n\t\tscanner.Scan()\r\n\t\ts, err := strconv.Atoi(scanner.Text())\r\n\t\tif err == nil && (s == 1 || s == 2) {\r\n\t\t\treturn StartOption(s)\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc getMinMax() (int, int) {\r\n\tminSelect := 0\r\n\tmaxSelect := 0\r\n\tvar minErr error\r\n\tvar maxErr error\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"ENTER MIN AND MAX \")\r\n\t\tscanner.Scan()\r\n\t\tenteredValues := scanner.Text()\r\n\t\tvals := strings.Split(enteredValues, \" \")\r\n\t\tminSelect, minErr = strconv.Atoi(vals[0])\r\n\t\tmaxSelect, maxErr = strconv.Atoi(vals[1])\r\n\t\tif (minErr == nil) && (maxErr == nil) && (minSelect > 0) && (maxSelect > 0) && (maxSelect > minSelect) {\r\n\t\t\treturn minSelect, maxSelect\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// This handles the player's turn - asking the player how many objects\r\n// to take and doing some basic validation around that input.  Then it\r\n// checks for any win conditions.\r\n// Returns a boolean indicating whether the game is over and the new pile_size.\r\nfunc playerMove(pile, min, max int, win WinOption) (bool, int) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tdone := false\r\n\tfor !done {\r\n\t\tfmt.Println(\"YOUR MOVE\")\r\n\t\tscanner.Scan()\r\n\t\tm, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tif m == 0 {\r\n\t\t\tfmt.Println(\"I TOLD YOU NOT TO USE ZERO!  COMPUTER WINS BY FORFEIT.\")\r\n\t\t\treturn true, pile\r\n\t\t}\r\n\r\n\t\tif m > max || m < min {\r\n\t\t\tfmt.Println(\"ILLEGAL MOVE, REENTER IT\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tpile -= m\r\n\t\tdone = true\r\n\r\n\t\tif pile <= 0 {\r\n\t\t\tif win == AvoidLast {\r\n\t\t\t\tfmt.Println(\"TOUGH LUCK, YOU LOSE.\")\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Println(\"CONGRATULATIONS, YOU WIN.\")\r\n\t\t\t}\r\n\t\t\treturn true, pile\r\n\t\t}\r\n\t}\r\n\treturn false, pile\r\n}\r\n\r\n// This handles the logic to determine how many objects the computer\r\n// will select on its turn.\r\nfunc computerPick(pile, min, max int, win WinOption) int {\r\n\tvar q int\r\n\tif win == AvoidLast {\r\n\t\tq = pile - 1\r\n\t} else {\r\n\t\tq = pile\r\n\t}\r\n\tc := min + max\r\n\r\n\tpick := q - (c * int(q/c))\r\n\r\n\tif pick < min {\r\n\t\tpick = min\r\n\t} else if pick > max {\r\n\t\tpick = max\r\n\t}\r\n\r\n\treturn pick\r\n}\r\n\r\n// This handles the computer's turn - first checking for the various\r\n// win/lose conditions and then calculating how many objects\r\n// the computer will take.\r\n// Returns a boolean indicating whether the game is over and the new pile_size.\r\nfunc computerMove(pile, min, max int, win WinOption) (bool, int) {\r\n\t// first check for end-game conditions\r\n\tif win == TakeLast && pile <= max {\r\n\t\tfmt.Printf(\"COMPUTER TAKES %d AND WINS\\n\", pile)\r\n\t\treturn true, pile\r\n\t}\r\n\r\n\tif win == AvoidLast && pile <= min {\r\n\t\tfmt.Printf(\"COMPUTER TAKES %d AND LOSES\\n\", pile)\r\n\t\treturn true, pile\r\n\t}\r\n\r\n\t// otherwise determine the computer's selection\r\n\tselection := computerPick(pile, min, max, win)\r\n\tpile -= selection\r\n\tfmt.Printf(\"COMPUTER TAKES %d AND LEAVES %d\\n\", selection, pile)\r\n\treturn false, pile\r\n}\r\n\r\n// This is the main game loop - repeating each turn until one\r\n// of the win/lose conditions is met.\r\nfunc play(pile, min, max int, start StartOption, win WinOption) {\r\n\tgameOver := false\r\n\tplayersTurn := (start == PlayerFirst)\r\n\r\n\tfor !gameOver {\r\n\t\tif playersTurn {\r\n\t\t\tgameOver, pile = playerMove(pile, min, max, win)\r\n\t\t\tplayersTurn = false\r\n\t\t\tif gameOver {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif !playersTurn {\r\n\t\t\tgameOver, pile = computerMove(pile, min, max, win)\r\n\t\t\tplayersTurn = true\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// Print out the introduction and rules of the game\r\nfunc printIntro() {\r\n\tfmt.Printf(\"%33s%s\\n\", \" \", \"BATNUM\")\r\n\tfmt.Printf(\"%15s%s\\n\", \" \", \"CREATIVE COMPUTING  MORRISSTOWN, NEW JERSEY\")\r\n\tfmt.Printf(\"\\n\\n\\n\")\r\n\tfmt.Println(\"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\")\r\n\tfmt.Println(\"COMPUTER IS YOUR OPPONENT.\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\")\r\n\tfmt.Println(\"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\")\r\n\tfmt.Println(\"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\")\r\n\tfmt.Println(\"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\")\r\n\tfmt.Println(\"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\")\r\n\tfmt.Println(\"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc main() {\r\n\tfor {\r\n\t\tprintIntro()\r\n\r\n\t\tg := NewOptions()\r\n\r\n\t\tif g.pileSize < 0 {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tplay(g.pileSize, g.minSelect, g.maxSelect, g.startOption, g.winOption)\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/09_Battle/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nNOTE: One feature has been added to the original game.  At the \"??\" prompt, instead of entering coordinates, you can enter \"?\" (a question mark) to reprint the fleet disposition code.\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript battle.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"battle\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/09_Battle/MiniScript/battle.ms",
    "content": "print \" \"*33 + \"Battle\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\n// -- BATTLE WRITTEN BY RAY WESTERGARD  10/70\n// COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF.\n// PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY\n// Converted to MiniScript by Joe Strout, July 2023.\n\nimport \"listUtil\"\n\nsetup = function\n\t// prepare the shield with the bad guys' ships\n\tglobals.field = list.init2d(6,6, 0)\t// matrix of enemy ships -- 0th row/column unused\n\tfor shipType in [1,2,3]\n\t\tfor ship in [1,2]\n\t\t\twhile not addShip(shipType, ship)\n\t\t\t\t// keep trying until we successfully add it!\n\t\t\tend while\n\t\tend for\n\tend for\n\t\n\t// prepare another matrix to keep track of where we have hit\n\tglobals.hits = list.init2d(6,6, 0)\n\t\n\t// and some some info per ship (ID) and ship type\n\tglobals.shipHitsLeft = [null, 2, 2, 3, 3, 4, 4]\t// hits left till each ship is sunk\n\tglobals.sunkPerType = [0] * 3\t// counts how many of each type were sunk\n\t\n\t// finally, keep track of hits and splashes\n\tglobals.splashCount = 0\n\tglobals.hitCount = 0\nend function\n\n// Try to add the given ship to field.\n// Return true on success, false on failure.\naddShip = function(shipType, shipNum)\n\tsize = 5 - shipType\n\tx = floor(rnd * 6)\n\ty = floor(rnd * 6)\n\tdirection = floor(rnd * 4)\n\tif direction == 0 then\n\t\tdx = 1; dy = 0\n\telse if direction == 1 then\n\t\tdx = 1; dy = 1\n\telse if direction == 2 then\n\t\tdx = 0; dy = 1\n\telse\n\t\tdx = -1; dy = 1\n\tend if\n\t// First make sure our placement doesn't go out of bounds\n\tif not (0 <= x + dx * size <= 5) then return false\n\tif not (0 <= y + dy * size <= 5) then return false\n\t// Then, make sure it's not blocked by another ship\n\tfor i in range(0, size-1)\n\t\tpx = x + dx * i\t// (point under consideration)\n\t\tpy = y + dy * i\n\t\t// make sure where we want to place the ship is still empty\n\t\tif field[px][py] then return false\n\t\t// if placing a ship diagonally, don't allow it to cross\n\t\t// another ship on the other diagonal\n\t\tif i > 0 and dx and dy then\n\t\t\tadjacent1 = field[px-dx][py]\n\t\t\tadjacent2 = field[px][py-dy]\n\t\t\tif adjacent1 and adjacent1 == adjacent2 then return false\n\t\tend if\n\tend for\n\t// Looks like it's all clear, so fill it in!\n\tid = 9 - 2 * shipType - shipNum;\n\tfor i in range(0, size-1)\n\t\tfield[x + dx * i][y + dy * i] = id\n\tend for\n\treturn true\nend function\n\n// Print the \"encoded\" fleet disposition.  This is just the regular field,\n// but rotated and flipped.\nprintField = function\n\tprint\n\tprint \"The following code of the bad guys' fleet disposition\"\n\tprint \"has been captured but not decoded:\"\n\tprint\n\tfor i in range(0,5)\n\t\tfor j in range(0,5)\n\t\t\tprint field[5-j][i], \" \"\n\t\tend for\n\t\tprint\n\tend for\nend function\n\ndoOneTurn = function\n\twhile true\n\t\txy = input(\"??\").replace(\",\", \" \")\n\t\tif xy == \"?\" then; printField; continue; end if\t// (not in original game)\n\t\tx = xy[0].val; y = xy[-1].val\n\t\tif xy.len < 2 or x != floor(x) or x < 1 or x > 6 or y != floor(y) or y < 1 or y > 6 then\n\t\t\t print \"Invalid input.  Try again.\"\n\t\t\t continue\n\t\tend if\n\t\tbreak\n\tend while\n\trow = x - 1\t// (minus one since our matrix is 0-based instead of 1-based)\n\tcol = y - 1\n\tshipId = field[row][col]\n\tif shipId == 0 then\n\t\t// fall through to 'end if' below\n\telse if shipHitsLeft[shipId] == 0 then\n\t\tprint \"There used to be a ship at that point, but you sank it.\"\n\telse if hits[row][col] then\n\t\tprint \"You already put a hole in ship number \" + shipId + \" at that point.\"\n\telse\n\t\thits[row][col] = shipId\n\t\tprint \"A direct hit on ship number \" + shipId\n\t\tglobals.hitCount += 1\n\t\tshipHitsLeft[shipId] -= 1\n\t\tif shipHitsLeft[shipId] == 0 then\n\t\t\tshipType = floor((shipId-1) / 2)  // get ship type, 0-2\n\t\t\tsunkPerType[shipType] += 1\n\t\t\tprint \"And you sunk it.  Hurray for the good guys.\"\n\t\t\tprint \"So far, the bad guys have lost\"\n\t\t\tprint sunkPerType[0] + \" destroyer(s), \" + sunkPerType[1] + \n\t\t\t  \" cruiser(s), and \" + sunkPerType[2] + \" aircraft carrier(s).\"\n\t\t\tprint \"Your current splash/hit ratio is \" + (splashCount / hitCount)\n\t\tend if\n\t\treturn\n\tend if\n\tprint \"Splash!  Try again.\"\n\tglobals.splashCount += 1\nend function\n\nplayOneGame = function\n\tsetup\n\tprintField\n\tprint\n\tprint \"De-code it and use it if you can\"\n\tprint \"but keep the de-coding method a secret.\"\n\tprint\n\tprint \"START GAME\"\n\t\n\twhile true\n\t\tdoOneTurn\n\t\tif sunkPerType.sum == 6 then break\n\tend while\n\t\n\tprint\n\tprint \"You have totally wiped out the bad guys' fleet\"\n\tprint \"with a final splash/hit ratio of \" + (splashCount / hitCount)\n\tif splashCount == 0 then\n\t\tprint \"Congratulations -- a direct hit every time.\"\n\tend if\nend function\n\n// Main loop\nwhile true\n\tplayOneGame\n\tprint\n\tprint \"****************************\"\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/09_Battle/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/09_Battle/battle.bas",
    "content": "5 PRINT TAB(33);\"BATTLE\"\n7 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n10 REM -- BATTLE WRITTEN BY RAY WESTERGARD  10/70\n20 REM COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF.\n30 REM PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY\n40 DIM F(6,6),H(6,6),A(4),B(4),C(6),L(3)\n50 FOR X=1 TO 6\n51 FOR Y=1 TO 6\n52 F(X,Y)=0\n53 NEXT Y\n54 NEXT X\n60 FOR I=1 TO 3\n70 N=4-I\n80 FOR J=1 TO 2\n90 A=INT(6*RND(1)+1)\n100 B=INT(6*RND(1)+1)\n110 D=INT(4*RND(1)+1)\n120 IF F(A,B)>0 THEN 90\n130 M=0\n140 ON D GOTO 150,340,550,740\n150 B(1)=B\n160 B(2)=7:B(3)=7\n170 FOR K=1 TO N\n180 IF M>1 THEN 240\n190 IF B(K)=6 THEN 230\n200 IF F(A,B(K)+1)>0 THEN 230\n210 B(K+1)=B(K)+1\n220 GOTO 280\n230 M=2\n240 IF B(1)<B(2) AND B(1)<B(3) THEN Z=B(1)\n242 IF B(2)<B(1) AND B(2)<B(3) THEN Z=B(2)\n244 IF B(3)<B(1) AND B(3)<B(2) THEN Z=B(3)\n250 IF Z=1 THEN 90\n260 IF F(A,Z-1)>0 THEN 90\n270 B(K+1)=Z-1\n280 NEXT K\n290 F(A,B)=9-2*I-J\n300 FOR K=1 TO N\n310 F(A,B(K+1))=F(A,B)\n320 NEXT K\n330 GOTO 990\n340 A(1)=A\n350 B(1)=B\n360 A(2)=0:A(3)=0:B(2)=0:B(3)=0\n370 FOR K=1 TO N\n380 IF M>1 THEN 460\n390 IF A(K)=1 OR B(K)=1 THEN 450\n400 IF F(A(K)-1,B(K)-1)>0 THEN 450\n410 IF F(A(K)-1,B(K))>0 AND F(A(K)-1,B(K))=F(A(K),B(K)-1) THEN 450\n420 A(K+1)=A(K)-1\n430 B(K+1)=B(K)-1\n440 GOTO 530\n450 M=2\n460 IF A(1)>A(2) AND A(1)>A(3) THEN Z1=A(1)\n462 IF A(2)>A(1) AND A(2)>A(3) THEN Z1=A(2)\n464 IF A(3)>A(1) AND A(3)>A(2) THEN Z1=A(3)\n470 IF B(1)>B(2) AND B(1)>B(3) THEN Z2=B(1)\n474 IF B(2)>B(1) AND B(2)>B(3) THEN Z2=B(2)\n476 IF B(3)>B(1) AND B(3)>B(2) THEN Z2=B(3)\n480 IF Z1=6 OR Z2=6 THEN 90\n490 IF F(Z1+1,Z2+1)>0 THEN 90\n500 IF F(Z1,Z2+1)>0 AND F(Z1,Z2+1)=F(Z1+1,Z2) THEN 90\n510 A(K+1)=Z1+1\n520 B(K+1)=Z2+1\n530 NEXT K\n540 GOTO 950\n550 A(1)=A\n560 A(2)=7:A(3)=7\n570 FOR K=1 TO N\n580 IF M>1 THEN 640\n590 IF A(K)=6 THEN 630\n600 IF F(A(K)+1,B)>0 THEN 630\n610 A(K+1)=A(K)+1\n620 GOTO 680\n630 M=2\n640 IF A(1)<A(2) AND A(1)<A(3) THEN Z=A(1)\n642 IF A(2)<A(1) AND A(2)<A(3) THEN Z=A(2)\n644 IF A(3)<A(1) AND A(3)<A(2) THEN Z=A(3)\n650 IF Z=1 THEN 90\n660 IF F(Z-1,B)>0 THEN 90\n670 A(K+1)=Z-1\n680 NEXT K\n690 F(A,B)=9-2*I-J\n700 FOR K=1 TO N\n710 F(A(K+1),B)=F(A,B)\n720 NEXT K\n730 GOTO 990\n740 A(1)=A\n750 B(1)=B\n760 A(2)=7:A(3)=7\n770 B(2)=0:B(3)=0\n780 FOR K=1 TO N\n790 IF M>1 THEN 870\n800 IF A(K)=6 OR B(K)=1 THEN 860\n810 IF F(A(K)+1,B(K)-1)>0 THEN 860\n820 IF F(A(K)+1,B(K))>0 AND F(A(K)+1,B(K))=F(A(K),B(K)-1) THEN 860\n830 A(K+1)=A(K)+1\n840 B(K+1)=B(K)-1\n850 GOTO 940\n860 M=2\n870 IF A(1)<A(2) AND A(1)<A(3) THEN Z1=A(1)\n872 IF A(2)<A(1) AND A(2)<A(3) THEN Z1=A(2)\n874 IF A(3)<A(1) AND A(3)<A(2) THEN Z1=A(3)\n880 IF B(1)>B(2) AND B(1)>B(3) THEN Z2=B(1)\n882 IF B(2)>B(1) AND B(2)>B(3) THEN Z2=B(2)\n884 IF B(3)>B(1) AND B(3)>B(2) THEN Z2=B(3)\n890 IF Z1=1 OR Z2=6 THEN 90\n900 IF F(Z1-1,Z2+1)>0 THEN 90\n910 IF F(Z1,Z2+1)>0 AND F(Z1,Z2+1)=F(Z1-1,Z2) THEN 90\n920 A(K+1)=Z1-1\n930 B(K+1)=Z2+1\n940 NEXT K\n950 F(A,B)=9-2*I-J\n960 FOR K=1 TO N\n970 F(A(K+1),B(K+1))=F(A,B)\n980 NEXT K\n990 NEXT J\n1000 NEXT I\n1010 PRINT\n1020 PRINT \"THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\"\n1030 PRINT \"HAS BEEN CAPTURED BUT NOT DECODED:\"\n1040 PRINT\n1050 FOR I=1 TO 6\n1051 FOR J=1 TO 6\n1052 H(I,J)=F(J,I)\n1053 NEXT J\n1054 NEXT I\n1060 FOR I=1 TO 6\n1061 FOR J=1 TO 6\n1062 PRINT H(I,J);\n1063 NEXT J\n1064 PRINT\n1065 NEXT I\n1070 PRINT\n1080 PRINT \"DE-CODE IT AND USE IT IF YOU CAN\"\n1090 PRINT \"BUT KEEP THE DE-CODING METHOD A SECRET.\"\n1100 PRINT\n1110 FOR I=1 TO 6\n1111 FOR J=1 TO 6\n1112 H(I,J)=0\n1113 NEXT J\n1114 NEXT I\n1120 FOR I=1 TO 3\n1121 L(I)=0\n1122 NEXT I\n1130 C(1)=2:C(2)=2\n1140 C(3)=1:C(4)=1\n1150 C(5)=0:C(6)=0\n1160 S=0:H=0\n1170 PRINT \"START GAME\"\n1180 INPUT X,Y\n1190 IF X<1 OR X>6 OR INT(X)<>ABS(X) THEN 1210\n1200 IF Y>0 AND Y<7 AND INT(Y)=ABS(Y) THEN 1230\n1210 PRINT \"INVALID INPUT.  TRY AGAIN.\"\n1220 GOTO 1180\n1230 R=7-Y\n1240 C=X\n1250 IF F(R,C)>0 THEN 1290\n1260 S=S+1\n1270 PRINT \"SPLASH!  TRY AGAIN.\"\n1280 GOTO 1180\n1290 IF C(F(R,C))<4 THEN 1340\n1300 PRINT \"THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT.\"\n1310 PRINT \"SPLASH!  TRY AGAIN.\"\n1320 S=S+1\n1330 GOTO 1180\n1340 IF H(R,C)>0 THEN 1420\n1350 H=H+1\n1360 H(R,C)=F(R,C)\n1370 PRINT \"A DIRECT HIT ON SHIP NUMBER\";F(R,C)\n1380 C(F(R,C))=C(F(R,C))+1\n1390 IF C(F(R,C))>=4 THEN 1470\n1400 PRINT \"TRY AGAIN.\"\n1410 GOTO 1180\n1420 PRINT \"YOU ALREADY PUT A HOLE IN SHIP NUMBER\";F(R,C);\n1430 PRINT \"AT THAT POINT.\"\n1440 PRINT \"SPLASH!  TRY AGAIN.\"\n1450 S=S+1\n1460 GOTO 1180\n1470 L((INT(F(R,C)-1)/2)+1)=L((INT(F(R,C)-1)/2)+1)+1\n1480 PRINT \"AND YOU SUNK IT.  HURRAH FOR THE GOOD GUYS.\"\n1490 PRINT \"SO FAR, THE BAD GUYS HAVE LOST\"\n1500 PRINT L(1);\"DESTROYER(S),\";L(2);\"CRUISER(S), AND\";\n1510 PRINT L(3);\"AIRCRAFT CARRIER(S).\"\n1520 PRINT \"YOUR CURRENT SPLASH/HIT RATIO IS\";S/H\n1530 IF (L(1)+L(2)+L(3))<6 THEN 1180\n1540 PRINT\n1550 PRINT \"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET\"\n1560 PRINT \"WITH A FINAL SPLASH/HIT RATIO OF\";S/H\n1570 IF S/H>0 THEN 1590\n1580 PRINT \"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\"\n1590 PRINT\n1600 PRINT \"****************************\"\n1610 PRINT\n1620 GOTO 50\n1630 END\n"
  },
  {
    "path": "00_Alternate_Languages/09_Battle/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nconst (\r\n\tSEA_WIDTH        = 6\r\n\tDESTROYER_LENGTH = 2\r\n\tCRUISER_LENGTH   = 3\r\n\tCARRIER_LENGTH   = 4\r\n)\r\n\r\ntype Point [2]int\r\ntype Vector Point\r\ntype Sea [][]int\r\n\r\nfunc NewSea() Sea {\r\n\ts := make(Sea, 6)\r\n\tfor r := 0; r < SEA_WIDTH; r++ {\r\n\t\tc := make([]int, 6)\r\n\t\ts[r] = c\r\n\t}\r\n\r\n\treturn s\r\n}\r\n\r\nfunc getRandomVector() Vector {\r\n\tv := Vector{}\r\n\r\n\tfor {\r\n\t\tv[0] = rand.Intn(3) - 1\r\n\t\tv[1] = rand.Intn(3) - 1\r\n\r\n\t\tif !(v[0] == 0 && v[1] == 0) {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\treturn v\r\n}\r\n\r\nfunc addVector(p Point, v Vector) Point {\r\n\tnewPoint := Point{}\r\n\r\n\tnewPoint[0] = p[0] + v[0]\r\n\tnewPoint[1] = p[1] + v[1]\r\n\r\n\treturn newPoint\r\n}\r\n\r\nfunc isWithinSea(p Point, s Sea) bool {\r\n\treturn (1 <= p[0] && p[0] <= len(s)) && (1 <= p[1] && p[1] <= len(s))\r\n}\r\n\r\nfunc valueAt(p Point, s Sea) int {\r\n\treturn s[p[1]-1][p[0]-1]\r\n}\r\n\r\nfunc reportInputError() {\r\n\tfmt.Printf(\"INVALID. SPECIFY TWO NUMBERS FROM 1 TO %d, SEPARATED BY A COMMA.\\n\", SEA_WIDTH)\r\n}\r\n\r\nfunc getNextTarget(s Sea) Point {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"\\n?\")\r\n\t\tscanner.Scan()\r\n\r\n\t\tvals := strings.Split(scanner.Text(), \",\")\r\n\r\n\t\tif len(vals) != 2 {\r\n\t\t\treportInputError()\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tx, xErr := strconv.Atoi(strings.TrimSpace(vals[0]))\r\n\t\ty, yErr := strconv.Atoi(strings.TrimSpace(vals[1]))\r\n\r\n\t\tif (len(vals) != 2) || (xErr != nil) || (yErr != nil) {\r\n\t\t\treportInputError()\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tp := Point{}\r\n\t\tp[0] = x\r\n\t\tp[1] = y\r\n\t\tif isWithinSea(p, s) {\r\n\t\t\treturn p\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc setValueAt(value int, p Point, s Sea) {\r\n\ts[p[1]-1][p[0]-1] = value\r\n}\r\n\r\nfunc hasShip(s Sea, code int) bool {\r\n\thasShip := false\r\n\tfor r := 0; r < SEA_WIDTH; r++ {\r\n\t\tfor c := 0; c < SEA_WIDTH; c++ {\r\n\t\t\tif s[r][c] == code {\r\n\t\t\t\thasShip = true\r\n\t\t\t\tbreak\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn hasShip\r\n}\r\n\r\nfunc countSunk(s Sea, codes []int) int {\r\n\tsunk := 0\r\n\r\n\tfor _, c := range codes {\r\n\t\tif !hasShip(s, c) {\r\n\t\t\tsunk += 1\r\n\t\t}\r\n\t}\r\n\r\n\treturn sunk\r\n}\r\n\r\nfunc placeShip(s Sea, size, code int) {\r\n\tfor {\r\n\t\tstart := Point{}\r\n\t\tstart[0] = rand.Intn(SEA_WIDTH) + 1\r\n\t\tstart[1] = rand.Intn(SEA_WIDTH) + 1\r\n\t\tvector := getRandomVector()\r\n\r\n\t\tpoint := start\r\n\t\tpoints := []Point{}\r\n\r\n\t\tfor i := 0; i < size; i++ {\r\n\t\t\tpoint = addVector(point, vector)\r\n\t\t\tpoints = append(points, point)\r\n\t\t}\r\n\r\n\t\tclearPosition := true\r\n\t\tfor _, p := range points {\r\n\t\t\tif !isWithinSea(p, s) {\r\n\t\t\t\tclearPosition = false\r\n\t\t\t\tbreak\r\n\t\t\t}\r\n\t\t\tif valueAt(p, s) > 0 {\r\n\t\t\t\tclearPosition = false\r\n\t\t\t\tbreak\r\n\t\t\t}\r\n\t\t}\r\n\t\tif !clearPosition {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tfor _, p := range points {\r\n\t\t\tsetValueAt(code, p, s)\r\n\t\t}\r\n\t\tbreak\r\n\t}\r\n}\r\n\r\nfunc setupShips(s Sea) {\r\n\tplaceShip(s, DESTROYER_LENGTH, 1)\r\n\tplaceShip(s, DESTROYER_LENGTH, 2)\r\n\tplaceShip(s, CRUISER_LENGTH, 3)\r\n\tplaceShip(s, CRUISER_LENGTH, 4)\r\n\tplaceShip(s, CARRIER_LENGTH, 5)\r\n\tplaceShip(s, CARRIER_LENGTH, 6)\r\n}\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"                BATTLE\")\r\n\tfmt.Println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\")\r\n\tfmt.Println(\"HAS BEEN CAPTURED BUT NOT DECODED:\t\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc printInstructions() {\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println(\"DE-CODE IT AND USE IT IF YOU CAN\")\r\n\tfmt.Println(\"BUT KEEP THE DE-CODING METHOD A SECRET.\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"START GAME\")\r\n}\r\n\r\nfunc printEncodedSea(s Sea) {\r\n\tfor x := 0; x < SEA_WIDTH; x++ {\r\n\t\tfmt.Println()\r\n\t\tfor y := SEA_WIDTH - 1; y > -1; y-- {\r\n\t\t\tfmt.Printf(\" %d\", s[y][x])\r\n\t\t}\r\n\t}\r\n\tfmt.Println()\r\n}\r\n\r\nfunc wipeout(s Sea) bool {\r\n\tfor c := 1; c <= 7; c++ {\r\n\t\tif hasShip(s, c) {\r\n\t\t\treturn false\r\n\t\t}\r\n\t}\r\n\treturn true\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\r\n\ts := NewSea()\r\n\r\n\tsetupShips(s)\r\n\r\n\tprintIntro()\r\n\r\n\tprintEncodedSea(s)\r\n\r\n\tprintInstructions()\r\n\r\n\tsplashes := 0\r\n\thits := 0\r\n\r\n\tfor {\r\n\t\ttarget := getNextTarget(s)\r\n\t\ttargetValue := valueAt(target, s)\r\n\r\n\t\tif targetValue < 0 {\r\n\t\t\tfmt.Printf(\"YOU ALREADY PUT A HOLE IN SHIP NUMBER %d AT THAT POINT.\\n\", targetValue)\r\n\t\t}\r\n\r\n\t\tif targetValue <= 0 {\r\n\t\t\tfmt.Println(\"SPLASH! TRY AGAIN.\")\r\n\t\t\tsplashes += 1\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tfmt.Printf(\"A DIRECT HIT ON SHIP NUMBER %d\\n\", targetValue)\r\n\t\thits += 1\r\n\t\tsetValueAt(targetValue*-1, target, s)\r\n\r\n\t\tif !hasShip(s, targetValue) {\r\n\t\t\tfmt.Println(\"AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS.\")\r\n\t\t\tfmt.Println(\"SO FAR, THE BAD GUYS HAVE LOST\")\r\n\t\t\tfmt.Printf(\"%d DESTROYER(S), %d CRUISER(S), AND %d AIRCRAFT CARRIER(S).\\n\", countSunk(s, []int{1, 2}), countSunk(s, []int{3, 4}), countSunk(s, []int{5, 6}))\r\n\t\t}\r\n\r\n\t\tif !wipeout(s) {\r\n\t\t\tfmt.Printf(\"YOUR CURRENT SPLASH/HIT RATIO IS %2f\\n\", float32(splashes)/float32(hits))\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tfmt.Printf(\"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET WITH A FINAL SPLASH/HIT RATIO OF %2f\\n\", float32(splashes)/float32(hits))\r\n\r\n\t\tif splashes == 0 {\r\n\t\t\tfmt.Println(\"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\")\r\n\t\t}\r\n\r\n\t\tfmt.Println(\"\\n****************************\")\r\n\t\tbreak\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/10_Blackjack/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript blackjack.ms\n```\nBut note that the current release (1.2.1) of command-line MiniScript does not properly flush the output buffer when line breaks are suppressed, as this program does when prompting for your next action after a Hit.  So, method 2 (below) is recommended for now.\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"blackjack\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms",
    "content": "import \"listUtil\"\nprint \" \"*31 + \"Black Jack\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nfna = function(q); return q - 11*(q >= 22); end function\nhands = [[]]*15\t\t// hands(i,j) is the jth card in hand i (P)\nhandValue = [0]*15\t// total value of each hand (Q)\ndeck = []\t\t\t// the deck being dealt from (C)\nplayerMoney = [0]*8\t// total $ for each player (T)\nroundWinnings = [0]*7 // total $ won/lost this hand for each player (S)\nbetPerHand = [0]*15\t// bet for each hand (B)\n\ncardNames = \" A 2 3 4 5 6 7 8 9 10 J Q K\".split\n\nreshuffle = function\n\tprint \"Reshuffling\"\n\tglobals.deck = range(1,13)*4\n\tdeck.shuffle\nend function\n\t\t\n// Function to draw a card from the deck (reshuffling if needed)\ngetCard = function\n\tif not deck then reshuffle\n\treturn deck.pop\nend function\n\n// Function to get a name for the given card, preceded by \"a\" or \"an\"\na = function(cardNum)\n\tarticle = \"a\" + \"n\" * (cardNum == 1 or cardNum == 8)\n\treturn article + \" \" + cardNames[cardNum]\nend function\n\n// Function to evaluate the given hand. Total is usually put into\n// handValue(handNum).  Totals have the following meaning:\n//      2-10...Hard 2-10\n//     11-21...Soft 11-21\n//     22-32...Hard 11-21\n// 33+ or -1...Busted\nevalHand = function(handNum)\n\tresult = 0\n\tfor card in hands[handNum]\n\t\tresult = addCardToTotal(result, card)\n\tend for\n\treturn result\nend function\n\n// Function to add a card into a total hand value.\naddCardToTotal = function(total, card)\n\tif total < 0 then return total\t// (already busted)\n\tx1 = card; if x1 > 10 then x1 = 10\n\tq1 = total + x1\n\tif total < 11 then\n\t\tif card == 1 then return total + 11\t// (ace)\n\t\treturn q1 + 11 * (q1 >= 11)\n\tend if\n\ttotal = q1 + (total <= 21 and q1 > 21)\n\tif total >= 33 then total = -1\n\treturn total\nend function\n\n// Print one of those totals as it should appear to the user.\ndisplayTotal = function(total)\n\treturn total - 11 * (total >= 22)\nend function\n\n// Get a yes/no response from the user\ngetYesNo = function(prompt)\n\twhile true\n\t\tinp = input(prompt).upper\n\t\tif inp and (inp[0] == \"Y\" or inp[0] == \"N\") then return inp[0]\n\tend while\nend function\n\n// Get a number, within a given range, from the user\ngetNumber = function(prompt, minVal=0, maxVal=500)\n\twhile true\n\t\tresult = input(prompt).val\n\t\tif result == floor(result) and minVal <= result <= maxVal then return result\n\t\tprint \"Please enter a number from \" + minVal + \" to \" + maxVal\n\tend while\nend function\n\n// Get one of a list of one-letter (uppercase) options.\ngetOption = function(prompt, options)\n\twhile true\n\t\tresult = input(prompt).upper\n\t\tif result and options.indexOf(result[0]) != null then return result[0]\n\t\tprint \"Type \" + options[:-1].join(\", \") + \" or \" + options[-1] + \" please\"\n\tend while\nend function\n\ngetBets = function\n\tprint \"Bets:\"\n\tfor i in range(0, numPlayers-1)\n\t\tbetPerHand[i] = getNumber(\"# \" + (i+1) + \"? \", 1, 500)\n\tend for\nend function\n\nplayOneRound = function\n\tglobals.roundWinnings = [0] * numPlayers\n\tif deck.len < (numPlayers+1) * 2 then reshuffle\n\tgetBets\n\tprint \"PLAYER \", \"\"\n\tfor i in range(0, numPlayers-1)\n\t\tprint i+1, \"     \"\n\t\thands[i] = []\n\tend for\n\tprint \"DEALER\"\n\thands[numPlayers] = []\n\tfor row in [1,2]\n\t\tprint \"     \", \"\"\n\t\tfor i in range(0, numPlayers)\n\t\t\thands[i].push getCard\n\t\t\tif row == 1 or i < numPlayers then \n\t\t\t\tprint \"  \" + (cardNames[hands[i][-1]] + \" \")[:2], \"  \"\n\t\t\tend if\n\t\tend for\n\t\tprint\n\tend for\n\tdealerCard0 = hands[numPlayers][0]\n\tdealerCard1 = hands[numPlayers][1]\n\t// Test for insurance\n\tif dealerCard0 == 1 and getYesNo(\"Any insurance? \") == \"Y\" then\n\t\tprint \"Insurance Bets\"\n\t\tfor i in range(0, numPlayers-1)\n\t\t\tinsurance = getNumber(\"# \" + (i+1) + \"? \", 0, betPerHand[i]/2)\n\t\t\troundWinnings[i] = insurance * (3 * (dealerCard1 >= 10) - 1)\n\t\tend for\n\tend if\n\t// Test for dealer blackjack\n\tif (dealerCard0==1 and dealerCard1 > 9) or\n\t  (dealerCard0 > 9 and dealerCard1==1) then\n\t\tprint; print \"Dealer has \" + a(dealerCard1) + \" in the hole for Blackjack\"\n\t\tfor i in range(0, numPlayers)\n\t\t\thandValue[i] = evalHand(i)\n\t\tend for\n\telse\n\t\t// no dealer blackjack\n\t\tif dealerCard0 == 1 or dealerCard0 >= 10 then\n\t\t\tprint; print \"No dealer Blackjack.\"\n\t\tend if\n\t\t// now play the hands\n\t\tfor i in range(0, numPlayers-1)\n\t\t\tplayHand i\n\t\tend for\n\t\thandValue[numPlayers] = evalHand(numPlayers)\t// (evaluate dealer hand)\n\t\t// Test for playing the dealer's hand... we only do so if\n\t\t// there are any player hands with cards left.\n\t\tanyLeft = false\n\t\tfor i in range(0, numPlayers-1)\n\t\t\tif hands[i] or hands[i+8] then anyLeft = true\n\t\tend for\n\t\tif not anyLeft then\n\t\t\tprint \"Dealer had \" + a(hands[numPlayers][1]) + \" concealed.\"\n\t\telse\n\t\t\t// Play dealer's hand.\n\t\t\tdispTotal = displayTotal(handValue[numPlayers])\n\t\t\tprint \"Dealer has \" + a(hands[numPlayers][1]) + \" concealed\" +\n\t\t\t  \" for a total of \" + dispTotal + \".\"\n\t\t\twhile handValue[numPlayers] > 0 and dispTotal <= 16\n\t\t\t\tcard = getCard\n\t\t\t\tif hands[numPlayers].len == 2 then print \"Draws  \", \"\"\n\t\t\t\tprint cardNames[card], \"    \"\n\t\t\t\thands[numPlayers].push card\n\t\t\t\thandValue[numPlayers] = evalHand(numPlayers)\n\t\t\t\tdispTotal = displayTotal(handValue[numPlayers])\n\t\t\tend while\n\t\t\tif hands[numPlayers].len > 2 then\n\t\t\t\tif handValue[numPlayers] < 0 then print \"  ---Busted\" else print \"  ---Total is \" + dispTotal\n\t\t\tend if\n\t\t\tprint\n\t\tend if\n\tend if\n\ttallyResults\nend function\n\nplayHand = function(handNum, prompt=null, allowSplit=true)\n\tif not prompt then prompt = \"Player \" + (handNum % 8 + 1)\n\twhile hands[handNum]\n\t\toptions = [\"H\", \"S\", \"D\"] + [\"/\"] * allowSplit\n\t\tchoice = getOption(prompt + \"? \", options)\n\t\tif choice == \"S\" then\t\t\t// player wants to stand\n\t\t\thandValue[handNum] = evalHand(handNum)\n\t\t\tif handValue[handNum] == 21 and hands[handNum].len == 2 then\n\t\t\t\tprint \"Blackjack\"\n\t\t\t\troundWinnings[handNum] += 1.5 * betPerHand[handNum]\n\t\t\t\tbetPerHand[handNum] = 0\n\t\t\t\tdiscardHand handNum\n\t\t\telse\n\t\t\t\tprint \"Total is \" + displayTotal(handValue[handNum])\n\t\t\tend if\n\t\t\tbreak\n\t\telse if choice == \"D\" or choice == \"H\" then\t\t// hit or double down\n\t\t\thandValue[handNum] = evalHand(handNum)\n\t\t\tif choice == \"D\" then betPerHand[handNum] *= 2\n\t\t\tcard = getCard\n\t\t\tprint \"Received \" + a(card), \"   \"\n\t\t\thands[handNum].push card\n\t\t\thandValue[handNum] = evalHand(handNum)\n\t\t\tif handValue[handNum] < 0 then\n\t\t\t\tprint \"...Busted\"\n\t\t\t\tdiscardHand handNum\n\t\t\t\troundWinnings[handNum] = -betPerHand[handNum]\n\t\t\t\tbetPerHand[handNum] = 0\n\t\t\tend if\n\t\t\tprompt = \"Hit\"\n\t\t\tif choice == \"D\" then; print; break; end if\n\t\telse if choice == \"/\" then\t\t// split\n\t\t\tcard1 = hands[handNum][0]; if card1 > 10 then card1 = 10\n\t\t\tcard2 = hands[handNum][1]; if card2 > 10 then card2 = 10\n\t\t\tif card1 != card2 then\n\t\t\t\tprint \"Splitting not allowed.\"\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\thand2 = handNum + 8\n\t\t\thands[hand2] = [hands[handNum].pop]\n\t\t\tbetPerHand[hand2] = betPerHand[handNum]\n\t\t\tcard = getCard\n\t\t\tprint \"First hand receives \" + a(card)\n\t\t\thands[handNum].push card\n\t\t\tcard = getCard\n\t\t\tprint \"Second hand receives \" + a(card)\n\t\t\thands[hand2].push card\n\t\t\tif card1 != 1 then\n\t\t\t\t// Now play the two hands\n\t\t\t\tplayHand handNum, \"Hand 1\", false\n\t\t\t\tplayHand hand2, \"Hand 2\", false\n\t\t\tend if\n\t\t\tbreak\n\t\tend if\n\t\tallowSplit = false\n\tend while\nend function\n\ndiscardHand = function(handNum)\n\thands[handNum] = []\n\thandValue[handNum] = 0\nend function\n\ntallyResults = function\n\tdealerTotal = displayTotal(evalHand(numPlayers))\n\tfor i in range(0, numPlayers-1)\n\t\tplayerHandATotal = displayTotal(evalHand(i))\n\t\tplayerHandBTotal = displayTotal(evalHand(i+8))\n\t\t// calculate roundWinnings[i], which is the $ won/lost for player i\n\t\troundWinnings[i] = roundWinnings[i] + betPerHand[i]*sign(playerHandATotal - dealerTotal) + betPerHand[i+8]*sign(playerHandBTotal - dealerTotal)\n\t\tbetPerHand[i+8] = 0\n\t\ts = \"Player \" + (i+1) + \" \"\n\t\ts += [\"loses\", \"pushes\", \"wins\"][sign(roundWinnings[i])+1]\t\t\n\t\tif roundWinnings[i] != 0 then s += \" \" + abs(roundWinnings[i])\n\t\tplayerMoney[i] += roundWinnings[i]\n\t\tplayerMoney[numPlayers] -= roundWinnings[i]\n\t\ts = (s + \" \"*25)[:25] + \"Total = \" + playerMoney[i]\n\t\tprint s\n\t\tdiscardHand i\n\t\tdiscardHand i+8\n\tend for\n\tprint \"Dealer's total = \" + playerMoney[numPlayers]\n\tprint\nend function\n\n// Main program starts here\n\nif getYesNo(\"Do you want instructions? \") == \"Y\" then\n\tprint \"This is the game of 21. As many as 7 players may play the\"\n\tprint \"game. On each deal, bets will be asked for, and the\"\n\tprint \"players' bets should be typed in. The cards will then be\"\n\tprint \"dealt, and each player in turn plays his hand. The\"\n\tprint \"first response should be either 'D', indicating that the\"\n\tprint \"player is doubling down, 'S', indicating that he is\"\n\tprint \"standing, 'H', indicating he wants another card, or '/',\"\n\tprint \"indicating that he wants to split his cards. After the\"\n\tprint \"initial response, all further responses should be 'S' or\"\n\tprint \"'H', unless the cards were split, in which case doubling\"\n\tprint \"down is again permitted. In order to collect for\"\n\tprint \"blackjack, the initial response should be 'S'.\"\n\tprint\nend if\nnumPlayers = getNumber(\"Number of players? \", 1, 7)\nprint\n// main loop!\nwhile true\n\tplayOneRound\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/10_Blackjack/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/10_Blackjack/blackjack.bas",
    "content": "2 PRINT TAB(31);\"BLACK JACK\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 DEF FNA(Q)=Q+11*(Q>=22)\n20 DIM P(15,12),Q(15),C(52),D(52),T(8),S(7),B(15)\n30 DIM R(15)\n40 REM--P(I,J) IS THE JTH CARD IN HAND I, Q(I) IS TOTAL OF HAND I\n50 REM--C IS THE DECK BEING DEALT FROM, D IS THE DISCARD PILE,\n60 REM--T(I) IS THE TOTAL FOR PLAYER I, S(I) IS THE TOTAL THIS HAND FOR\n70 REM--PLAYER I, B(I) IS TH BET FOR HAND I\n80 REM--R(I) IS THE LENGTH OF P(I,*)\n90 GOTO 1500\n100 REM--SUBROUTINE TO GET A CARD.  RESULT IS PUT IN X.\n110 IF C<51 THEN 230\n120 PRINT \"RESHUFFLING\"\n130 FOR D=D TO 1 STEP -1\n140 C=C-1\n150 C(C)=D(D)\n160 NEXT D\n170 FOR C1=52 TO C STEP -1\n180 C2=INT(RND(1)*(C1-C+1))+C\n190 C3=C(C2)\n200 C(C2)=C(C1)\n210 C(C1)=C3\n220 NEXT C1\n230 X=C(C)\n240 C=C+1\n250 RETURN\n300 REM--SUBROUTINE TO EVALUATE HAND I.  TOTAL IS PUT INTO\n310 REM--Q(I). TOTALS HAVE THE FOLLOWING MEANING:\n320 REM--  2-10...HARD 2-10\n330 REM-- 11-21...SOFT 11-21\n340 REM-- 22-32...HARD 11-21\n350 REM--  33+....BUSTED\n360 Q=0\n370 FOR Q2=1 TO R(I)\n380 X=P(I,Q2)\n390 GOSUB 500\n400 NEXT Q2\n410 Q(I)=Q\n420 RETURN\n500 REM--SUBROUTINE TO ADD CARD X TO TOTAL Q.\n510 X1=X: IF X1>10 THEN X1=10:  REM  SAME AS X1=10 MIN X\n520 Q1=Q+X1\n530 IF Q>=11 THEN 590\n540 IF X>1 THEN 570\n550 Q=Q+11\n560 RETURN\n570 Q=Q1-11*(Q1>=11)\n580 RETURN\n590 Q=Q1-(Q<=21 AND Q1>21)\n600 IF Q<33 THEN 620\n610 Q=-1\n620 RETURN\n700 REM--CARD PRINTING SUBROUTINE\n710 REM  D$ DEFINED ELSEWHERE\n720 PRINT MID$(D$,3*X-2,3);\n730 PRINT \"  \";\n740 RETURN\n750 REM--ALTERNATIVE PRINTING ROUTINE\n760 PRINT \" \";MID$(D$,3*X-1,2);\n770 PRINT \"   \";\n780 RETURN\n800 REM--SUBROUTINE TO PLAY OUT A HAND.\n810 REM--NO SPLITTING OR BLACKJACKS ALLOWED\n820 H1=5\n830 GOSUB 1410\n840 H1=3\n850 ON H GOTO 950,930\n860 GOSUB 100\n870 B(I)=B(I)*2\n880 PRINT \"RECEIVED A\";\n890 GOSUB 700\n900 GOSUB 1100\n910 IF Q>0 THEN GOSUB 1300\n920 RETURN\n930 GOSUB 1320\n940 RETURN\n950 GOSUB 100\n960 PRINT \"RECEIVED A\";\n970 GOSUB 700\n980 GOSUB 1100\n990 IF Q<0 THEN 940\n1000 PRINT \"HIT\";\n1010 GOTO 830\n1100 REM--SUBROUTINE TO ADD A CARD TO ROW I\n1110 R(I)=R(I)+1\n1120 P(I,R(I))=X\n1130 Q=Q(I)\n1140 GOSUB 500\n1150 Q(I)=Q\n1160 IF Q>=0 THEN 1190\n1170 PRINT \"...BUSTED\"\n1180 GOSUB 1200\n1190 RETURN\n1200 REM--SUBROUTINE TO DISCARD ROW I\n1210 IF R(I)<>0 THEN 1230\n1220 RETURN\n1230 D=D+1\n1240 D(D)=P(I,R(I))\n1250 R(I)=R(I)-1\n1260 GOTO 1210\n1300 REM--PRINTS TOTAL OF HAND I\n1310 PRINT\n1320 AA=Q(I): GOSUB 3400\n1325 PRINT \"TOTAL IS\";AA\n1330 RETURN\n1400 REM--SUBROUTINE TO READ REPLY\n1410 REM  I$ DEFINED ELSEWHERE\n1420 INPUT H$: H$=LEFT$(H$,1)\n1430 FOR H=1 TO H1 STEP 2\n1440 IF H$=MID$(I$,H,1) THEN 1480\n1450 NEXT H\n1460 PRINT \"TYPE \";MID$(I$,1,H1-1);\" OR \";MID$(I$,H1,2);\" PLEASE\";\n1470 GOTO 1420\n1480 H=(H+1)/2\n1490 RETURN\n1500 REM--PROGRAM STARTS HERE\n1510 REM--INITIALIZE\n1520 D$=\"N A  2  3  4  5  6  7N 8  9 10  J  Q  K\"\n1530 I$=\"H,S,D,/,\"\n1540 FOR I=1 TO 13\n1550 FOR J=4*I-3 TO 4*I\n1560 D(J)=I\n1570 NEXT J\n1580 NEXT I\n1590 D=52\n1600 C=53\n1610 PRINT \"DO YOU WANT INSTRUCTIONS\";\n1620 INPUT H$\n1630 IF LEFT$(H$,1)=\"N\" OR LEFT$(H$,1)=\"n\" THEN 1760\n1640 PRINT \"THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE\"\n1650 PRINT \"GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE\"\n1660 PRINT \"PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE\"\n1670 PRINT \"DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE\"\n1680 PRINT \"FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE\"\n1690 PRINT \"PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS\"\n1700 PRINT \"STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/',\"\n1710 PRINT \"INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE\"\n1720 PRINT \"INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR\"\n1730 PRINT \"'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING\"\n1740 PRINT \"DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR\"\n1750 PRINT \"BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'.\"\n1760 PRINT \"NUMBER OF PLAYERS\";\n1770 INPUT N\n1775 PRINT\n1780 IF N<1 OR N>7 OR N>INT(N) THEN 1760\n1790 FOR I=1 TO 8: T(I)=0: NEXT I\n1800 D1=N+1\n1810 IF 2*D1+C>=52 THEN GOSUB 120\n1820 IF C=2 THEN C=C-1\n1830 FOR I=1 TO N: Z(I)=0: NEXT I\n1840 FOR I=1 TO 15: B(I)=0: NEXT I\n1850 FOR I=1 TO 15: Q(I)=0: NEXT I\n1860 FOR I=1 TO 7: S(I)=0: NEXT I\n1870 FOR I=1 TO 15: R(I)=0: NEXT I\n1880 PRINT \"BETS:\"\n1890 FOR I=1 TO N: PRINT \"#\";I;: INPUT Z(I): NEXT I\n1900 FOR I=1 TO N\n1910 IF Z(I)<=0 OR Z(I)>500 THEN 1880\n1920 B(I)=Z(I)\n1930 NEXT I\n1940 PRINT \"PLAYER\";\n1950 FOR I=1 TO N\n1960 PRINT I;\"   \";\n1970 NEXT I\n1980 PRINT \"DEALER\"\n1990 FOR J=1 TO 2\n2000 PRINT TAB(5);\n2010 FOR I=1 TO D1\n2020 GOSUB 100\n2030 P(I,J)=X\n2040 IF J=1 OR I<=N THEN GOSUB 750\n2050 NEXT I\n2060 PRINT\n2070 NEXT J\n2080 FOR I=1 TO D1\n2090 R(I)=2\n2100 NEXT I\n2110 REM--TEST FOR INSURANCE\n2120 IF P(D1,1)>1 THEN 2240\n2130 PRINT \"ANY INSURANCE\";\n2140 INPUT H$\n2150 IF LEFT$(H$,1)<>\"Y\" THEN 2240\n2160 PRINT \"INSURANCE BETS\"\n2170 FOR I=1 TO N: PRINT \"#\";I;: INPUT Z(I): NEXT I\n2180 FOR I=1 TO N\n2190 IF Z(I)<0 OR Z(I)>B(I)/2 THEN 2160\n2200 NEXT I\n2210 FOR I=1 TO N\n2220 S(I)=Z(I)*(3*(-(P(D1,2)>=10))-1)\n2230 NEXT I\n2240 REM--TEST FOR DEALER BLACKJACK\n2250 L1=1: L2=1\n2252 IF P(D1,1)=1 AND P(D1,2)>9 THEN L1=0: L2=0\n2253 IF P(D1,2)=1 AND P(D1,1)>9 THEN L1=0: L2=0\n2254 IF L1<>0 OR L2<>0 THEN 2320\n2260 PRINT:PRINT \"DEALER HAS A\";MID$(D$,3*P(D1,2)-2,3);\" IN THE HOLE \";\n2270 PRINT \"FOR BLACKJACK\"\n2280 FOR I=1 TO D1\n2290 GOSUB 300\n2300 NEXT I\n2310 GOTO 3140\n2320 REM--NO DEALER BLACKJACK\n2330 IF P(D1,1)>1 AND P(D1,1)<10 THEN 2350\n2340 PRINT:PRINT \"NO DEALER BLACKJACK.\"\n2350 REM--NOW PLAY THE HANDS\n2360 FOR I=1 TO N\n2370 PRINT \"PLAYER\";I;\n2380 H1=7\n2390 GOSUB 1410\n2400 ON H GOTO 2550,2410,2510,2600\n2410 REM--PLAYER WANTS TO STAND\n2420 GOSUB 300\n2430 IF Q(I)<>21 THEN 2490\n2440 PRINT \"BLACKJACK\"\n2450 S(I)=S(I)+1.5*B(I)\n2460 B(I)=0\n2470 GOSUB 1200\n2480 GOTO 2900\n2490 GOSUB 1320\n2500 GOTO 2900\n2510 REM--PLAYER WANTS TO DOUBLE DOWN\n2520 GOSUB 300\n2530 GOSUB 860\n2540 GOTO 2900\n2550 REM--PLAYER WANTS TO BE HIT\n2560 GOSUB 300\n2570 H1=3\n2580 GOSUB 950\n2590 GOTO 2900\n2600 REM--PLAYER WANTS TO SPLIT\n2610 L1=P(I,1): IF P(I,1)>10 THEN L1=10\n2612 L2=P(I,2): IF P(I,2)>10 THEN L2=10\n2614 IF L1=L2 THEN 2640\n2620 PRINT \"SPLITTING NOT ALLOWED.\"\n2630 GOTO 2370\n2640 REM--PLAY OUT SPLIT\n2650 I1=I+D1\n2660 R(I1)=2\n2670 P(I1,1)=P(I,2)\n2680 B(I+D1)=B(I)\n2690 GOSUB 100\n2700 PRINT \"FIRST HAND RECEIVES A\";\n2710 GOSUB 700\n2720 P(I,2)=X\n2730 GOSUB 300\n2740 PRINT\n2750 GOSUB 100\n2760 PRINT \"SECOND HAND RECEIVES A\";\n2770 I=I1\n2780 GOSUB 700\n2790 P(I,2)=X\n2800 GOSUB 300\n2810 PRINT\n2820 I=I1-D1\n2830 IF P(I,1)=1 THEN 2900\n2840 REM--NOW PLAY THE TWO HANDS\n2850 PRINT \"HAND\";1-(I>D1);\n2860 GOSUB 800\n2870 I=I+D1\n2880 IF I=I1 THEN 2850\n2890 I=I1-D1\n2900 NEXT I\n2910 GOSUB 300\n2920 REM--TEST FOR PLAYING DEALER'S HAND\n2930 FOR I=1 TO N\n2940 IF R(I)>0 OR R(I+D1)>0 THEN 3010\n2950 NEXT I\n2960 PRINT \"DEALER HAD A\";\n2970 X=P(D1,2)\n2980 GOSUB 700\n2990 PRINT \" CONCEALED.\"\n3000 GOTO 3140\n3010 PRINT \"DEALER HAS A\";MID$(D$,3*P(D1,2)-2,3);\" CONCEALED \";\n3020 I=D1\n3030 AA=Q(I): GOSUB 3400\n3035 PRINT \"FOR A TOTAL OF\";AA\n3040 IF AA>16 THEN 3130\n3050 PRINT \"DRAWS\";\n3060 GOSUB 100\n3070 GOSUB 750\n3080 GOSUB 1100\n3090 AA=Q: GOSUB 3400\n3095 IF Q>0 AND AA<17 THEN 3060\n3100 Q(I)=Q-(Q<0)/2\n3110 IF Q<0 THEN 3140\n3120 AA=Q: GOSUB 3400\n3125 PRINT \"---TOTAL IS\";AA\n3130 PRINT\n3140 REM--TALLY THE RESULT\n3150 REM\n3160 Z$=\"LOSES PUSHES WINS \"\n3165 PRINT\n3170 FOR I=1 TO N\n3180 AA=Q(I): GOSUB 3400\n3182 AB=Q(I+D1): GOSUB 3410\n3184 AC=Q(D1): GOSUB 3420\n3186 S(I)=S(I)+B(I)*SGN(AA-AC)+B(I+D1)*SGN(AB-AC)\n3188 B(I+D1)=0\n3200 PRINT \"PLAYER\";I;\n3210 PRINT MID$(Z$,SGN(S(I))*6+7,6);\" \";\n3220 IF S(I)<>0 THEN 3250\n3230 PRINT \"      \";\n3240 GOTO 3260\n3250 PRINT ABS(S(I));\n3260 T(I)=T(I)+S(I)\n3270 PRINT \"TOTAL=\";T(I)\n3280 GOSUB 1200\n3290 T(D1)=T(D1)-S(I)\n3300 I=I+D1\n3310 GOSUB 1200\n3320 I=I-D1\n3330 NEXT I\n3340 PRINT \"DEALER'S TOTAL=\";T(D1)\n3345 PRINT\n3350 GOSUB 1200\n3360 GOTO 1810\n3400 AA=AA+11*(AA>=22): RETURN\n3410 AB=AB+11*(AB>=22): RETURN\n3420 AC=AC+11*(AC>=22): RETURN\n"
  },
  {
    "path": "00_Alternate_Languages/10_Blackjack/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "00_Alternate_Languages/11_Bombardment/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bombardment.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bombardment\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms",
    "content": "print \" \"*33 + \"Bombardment\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"You are on a battlefield with 4 platoons and you\"\nprint \"have 25 outposts available where they may be placed.\"\nprint \"You can only place one platoon at any one outpost.\"\nprint \"The computer does the same with its four platoons.\"\nprint\nprint \"The object of the game is to fire missiles at the\"\nprint \"outposts of the computer.  It will do the same to you.\"\nprint \"The one who destroys all four of the enemy's platoons\"\nprint \"first is the winner.\"\nprint\nprint \"Good luck... and tell us where you want the bodies sent!\"\nprint\ninput \"(Press Return.)\"\t// (so user can read the above)\nprint\nprint \"Tear off matrix and use it to check off the numbers.\"\nfor i in range(1,5); print; end for\nmemory = []  // records computer's guesses\nfor row in range(1,5)\n\tfor i in range(row*5-4, row*5)\n\t\tprint (\"     \" + i)[-6:], \"\"\n\tend for\n\tprint\nend for\nprint\n\n// Define a helper function to pick a random position (1-25)\n// that is not already in the given list.\npickOutpost = function(excludingThese)\n\twhile true\n\t\tpick = floor(rnd * 25) + 1\n\t\tif excludingThese.indexOf(pick) == null then return pick\n\tend while\nend function\n\n// Choose the computer's four positions.\ncomputerOutposts = []\nfor i in range(1,4)\n\tcomputerOutposts.push pickOutpost(computerOutposts)\nend for\n\nplayerOutposts = []\nwhile playerOutposts.len != 4\n\tinp = input(\"What are your four positions? \")\n\tinp = inp.replace(\", \", \" \").replace(\",\", \" \")\n\tinp = inp.split\n\tfor pos in inp\n\t\tpos = pos.val\n\t\tplayerOutposts.push pos\n\t\tif pos < 1 or pos > 25 then playerOutposts=[]\n\tend for\nend while\n\n// Main loop.\nwhile true\n\t// player's attack\n\tpos = input(\"Where do you wish to fire your missile? \").val\n\tif computerOutposts.indexOf(pos) == null then\n\t\tprint \"Ha, ha you missed. My turn now:\"\n\telse\n\t\tprint \"You got one of my outposts!\"\n\t\tcomputerOutposts.remove computerOutposts.indexOf(pos)\n\t\tleft = computerOutposts.len\n\t\tif left == 3 then\n\t\t\tprint \"One down, three to go.\"\n\t\telse if left == 2 then\n\t\t\tprint \"Two down, two to go.\"\n\t\telse if left == 3 then\n\t\t\tprint \"Three down, one to go.\"\n\t\telse\n\t\t\tprint \"You got me, I'm going fast. ButI'll get you when\"\n\t\t\tprint \"My transisto&s recup%ra*e!\"\n\t\t\tbreak\n\t\tend if\n\tend if\n\t\n\t// computer's attack\n\tpos = pickOutpost(memory)\n\tmemory.push pos\n\tif playerOutposts.indexOf(pos) == null then\n\t\tprint \"I missed you, you dirty rat. I picked \" + pos + \". Your turn:\"\n\telse\n\t\tplayerOutposts.remove playerOutposts.indexOf(pos)\n\t\tleft = playerOutposts.len\n\t\tif left == 0 then\n\t\t\tprint \"You're dead. Your last outpost was at \" + pos + \". Ha, ha, ha.\"\n\t\t\tprint \"Better luck next time.\"\n\t\t\tbreak\n\t\tend if\n\t\tprint \"I got you. It won't be long now. Post \" + pos + \" was hit.\"\n\t\tif left == 3 then\n\t\t\tprint \"You have only three outposts left.\"\n\t\telse if left == 2 then\n\t\t\tprint \"You have only two outposts left.\"\n\t\telse if left == 1 then\n\t\t\tprint \"You have only one outpost left.\"\n\t\tend if\n\tend if\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/11_Bombardment/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/11_Bombardment/bombardment.bas",
    "content": "10 PRINT TAB(33);\"BOMBARDMENT\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\"\n110 PRINT \"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\"\n120 PRINT \"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\"\n130 PRINT \"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\"\n135 PRINT\n140 PRINT \"THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\"\n150 PRINT \"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\"\n160 PRINT \"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\"\n170 PRINT \"FIRST IS THE WINNER.\"\n180 PRINT\n190 PRINT \"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\"\n200 PRINT\n210 PRINT \"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\"\n220 FOR R=1 TO 5: PRINT: NEXT R\n260 DIM M(100)\n270 FOR R=1 TO 5\n280 I=(R-1)*5+1\n290 PRINT I,I+1,I+2,I+3,I+4\n300 NEXT R\n350 FOR R=1 TO 10: PRINT: NEXT R\n380 C=INT(RND(1)*25)+1\n390 D=INT(RND(1)*25)+1\n400 E=INT(RND(1)*25)+1\n410 F=INT(RND(1)*25)+1\n420 IF C=D THEN 390\n430 IF C=E THEN 400\n440 IF C=F THEN 410\n450 IF D=E THEN 400\n460 IF D=F THEN 410\n470 IF E=F THEN 410\n480 PRINT \"WHAT ARE YOUR FOUR POSITIONS\";\n490 INPUT G,H,K,L\n495 PRINT\n500 PRINT \"WHERE DO YOU WISH TO FIRE YOUR MISSLE\";\n510 INPUT Y\n520 IF Y=C THEN 710\n530 IF Y=D THEN 710\n540 IF Y=E THEN 710\n550 IF Y=F THEN 710\n560 GOTO 630\n570 M=INT(RND(1)*25)+1\n575 GOTO 1160\n580 IF X=G THEN 920\n590 IF X=H THEN 920\n600 IF X=L THEN 920\n610 IF X=K THEN 920\n620 GOTO 670\n630 PRINT \"HA, HA YOU MISSED. MY TURN NOW:\"\n640 PRINT: PRINT: GOTO 570\n670 PRINT \"I MISSED YOU, YOU DIRTY RAT. I PICKED\";M\". YOUR TURN:\"\n680 PRINT: PRINT: GOTO 500\n710 Q=Q+1\n720 IF Q=4 THEN 890\n730 PRINT \"YOU GOT ONE OF MY OUTPOSTS!\"\n740 IF Q=1 THEN 770\n750 IF Q=2 THEN 810\n760 IF Q=3 THEN 850\n770 PRINT \"ONE DOWN, THREE TO GO.\"\n780 PRINT: PRINT: GOTO 570\n810 PRINT \"TWO DOWN, TWO TO GO.\"\n820 PRINT: PRINT: GOTO 570\n850 PRINT \"THREE DOWN, ONE TO GO.\"\n860 PRINT: PRINT: GOTO 570\n890 PRINT \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\"\n900 PRINT \"MY TRANSISTO&S RECUP%RA*E!\"\n910 GOTO 1235\n920 Z=Z+1\n930 IF Z=4 THEN 1110\n940 PRINT \"I GOT YOU. IT WON'T BE LONG NOW. POST\";X;\"WAS HIT.\"\n950 IF Z=1 THEN 990\n960 IF Z=2 THEN 1030\n970 IF Z=3 THEN 1070\n990 PRINT \"YOU HAVE ONLY THREE OUTPOSTS LEFT.\"\n1000 PRINT: PRINT: GOTO 500\n1030 PRINT \"YOU HAVE ONLY TWO OUTPOSTS LEFT.\"\n1040 PRINT: PRINT: GOTO 500\n1070 PRINT \"YOU HAVE ONLY ONE OUTPOST LEFT.\"\n1080 PRINT: PRINT: GOTO 500\n1110 PRINT \"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT\";X;\". HA, HA, HA.\"\n1120 PRINT \"BETTER LUCK NEXT TIME.\"\n1150 GOTO 1235\n1160 P=P+1\n1170 N=P-1\n1180 FOR T=1 TO N\n1190 IF M=M(T) THEN 570\n1200 NEXT T\n1210 X=M\n1220 M(P)=M\n1230 GOTO 580\n1235 END\n"
  },
  {
    "path": "00_Alternate_Languages/11_Bombardment/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\n// Messages correspond to outposts remaining (3, 2, 1, 0)\r\nvar PLAYER_PROGRESS_MESSAGES = []string{\r\n\t\"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\\nMY TRANSISTO&S RECUP%RA*E!\",\r\n\t\"THREE DOWN, ONE TO GO.\\n\\n\",\r\n\t\"TWO DOWN, TWO TO GO.\\n\\n\",\r\n\t\"ONE DOWN, THREE TO GO.\\n\\n\",\r\n}\r\n\r\nvar ENEMY_PROGRESS_MESSAGES = []string{\r\n\t\"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT %d. HA, HA, HA.\\nBETTER LUCK NEXT TIME.\",\r\n\t\"YOU HAVE ONLY ONE OUTPOST LEFT.\\n\\n\",\r\n\t\"YOU HAVE ONLY TWO OUTPOSTS LEFT.\\n\\n\",\r\n\t\"YOU HAVE ONLY THREE OUTPOSTS LEFT.\\n\\n\",\r\n}\r\n\r\nfunc displayField() {\r\n\tfor r := 0; r < 5; r++ {\r\n\t\tinitial := r*5 + 1\r\n\t\tfor c := 0; c < 5; c++ {\r\n\t\t\t//x := strconv.Itoa(initial + c)\r\n\t\t\tfmt.Printf(\"\\t%d\", initial+c)\r\n\t\t}\r\n\t\tfmt.Println()\r\n\t}\r\n\tfmt.Print(\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\")\r\n}\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"                                BOMBARDMENT\")\r\n\tfmt.Println(\"                CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println(\"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\")\r\n\tfmt.Println(\"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\")\r\n\tfmt.Println(\"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\")\r\n\tfmt.Println(\"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\")\r\n\tfmt.Println(\"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\")\r\n\tfmt.Println(\"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\")\r\n\tfmt.Println(\"FIRST IS THE WINNER.\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\")\r\n\tfmt.Print(\"\\n\\n\\n\\n\")\r\n}\r\n\r\nfunc positionList() []int {\r\n\tpositions := make([]int, 25)\r\n\tfor i := 0; i < 25; i++ {\r\n\t\tpositions[i] = i + 1\r\n\t}\r\n\treturn positions\r\n}\r\n\r\n// Randomly choose 4 'positions' out of a range of 1 to 25\r\nfunc generateEnemyPositions() []int {\r\n\tpositions := positionList()\r\n\trand.Shuffle(len(positions), func(i, j int) { positions[i], positions[j] = positions[j], positions[i] })\r\n\treturn positions[:4]\r\n}\r\n\r\nfunc isValidPosition(p int) bool {\r\n\treturn p >= 1 && p <= 25\r\n}\r\n\r\nfunc promptForPlayerPositions() []int {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tvar positions []int\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"\\nWHAT ARE YOUR FOUR POSITIONS (1-25)?\")\r\n\t\tscanner.Scan()\r\n\t\trawPositions := strings.Split(scanner.Text(), \" \")\r\n\r\n\t\tif len(rawPositions) != 4 {\r\n\t\t\tfmt.Println(\"PLEASE ENTER FOUR UNIQUE POSITIONS\")\r\n\t\t\tgoto there\r\n\t\t}\r\n\r\n\t\tfor _, p := range rawPositions {\r\n\t\t\tpos, err := strconv.Atoi(p)\r\n\t\t\tif (err != nil) || !isValidPosition(pos) {\r\n\t\t\t\tfmt.Println(\"ALL POSITIONS MUST RANGE (1-25)\")\r\n\t\t\t\tgoto there\r\n\t\t\t}\r\n\t\t\tpositions = append(positions, pos)\r\n\t\t}\r\n\t\tif len(positions) == 4 {\r\n\t\t\treturn positions\r\n\t\t}\r\n\r\n\tthere:\r\n\t}\r\n}\r\n\r\nfunc promptPlayerForTarget() int {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"\\nWHERE DO YOU WISH TO FIRE YOUR MISSILE?\")\r\n\t\tscanner.Scan()\r\n\t\ttarget, err := strconv.Atoi(scanner.Text())\r\n\r\n\t\tif (err != nil) || !isValidPosition(target) {\r\n\t\t\tfmt.Println(\"POSITIONS MUST RANGE (1-25)\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\treturn target\r\n\t}\r\n}\r\n\r\nfunc generateAttackSequence() []int {\r\n\tpositions := positionList()\r\n\trand.Shuffle(len(positions), func(i, j int) { positions[i], positions[j] = positions[j], positions[i] })\r\n\treturn positions\r\n}\r\n\r\n// Performs attack procedure returning True if we are to continue.\r\nfunc attack(target int, positions *[]int, hitMsg, missMsg string, progressMsg []string) bool {\r\n\tfor i := 0; i < len(*positions); i++ {\r\n\t\tif target == (*positions)[i] {\r\n\t\t\tfmt.Print(hitMsg)\r\n\r\n\t\t\t// remove the target just hit\r\n\t\t\t(*positions)[i] = (*positions)[len((*positions))-1]\r\n\t\t\t(*positions)[len((*positions))-1] = 0\r\n\t\t\t(*positions) = (*positions)[:len((*positions))-1]\r\n\r\n\t\t\tif len((*positions)) != 0 {\r\n\t\t\t\tfmt.Print(progressMsg[len((*positions))])\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Printf(progressMsg[len((*positions))], target)\r\n\t\t\t}\r\n\t\t\treturn len((*positions)) > 0\r\n\t\t}\r\n\t}\r\n\tfmt.Print(missMsg)\r\n\treturn len((*positions)) > 0\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\r\n\tprintIntro()\r\n\tdisplayField()\r\n\r\n\tenemyPositions := generateEnemyPositions()\r\n\tenemyAttacks := generateAttackSequence()\r\n\tenemyAttackCounter := 0\r\n\r\n\tplayerPositions := promptForPlayerPositions()\r\n\r\n\tfor {\r\n\t\t// player attacks\r\n\t\tif !attack(promptPlayerForTarget(), &enemyPositions, \"YOU GOT ONE OF MY OUTPOSTS!\\n\\n\", \"HA, HA YOU MISSED. MY TURN NOW:\\n\\n\", PLAYER_PROGRESS_MESSAGES) {\r\n\t\t\tbreak\r\n\t\t}\r\n\t\t// computer attacks\r\n\t\thitMsg := fmt.Sprintf(\"I GOT YOU. IT WON'T BE LONG NOW. POST %d WAS HIT.\\n\", enemyAttacks[enemyAttackCounter])\r\n\t\tmissMsg := fmt.Sprintf(\"I MISSED YOU, YOU DIRTY RAT. I PICKED %d. YOUR TURN:\\n\\n\", enemyAttacks[enemyAttackCounter])\r\n\t\tif !attack(enemyAttacks[enemyAttackCounter], &playerPositions, hitMsg, missMsg, ENEMY_PROGRESS_MESSAGES) {\r\n\t\t\tbreak\r\n\t\t}\r\n\t\tenemyAttackCounter += 1\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bombsaway.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bombsaway\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms",
    "content": "\ngetNum = function(prompt, maxVal=5)\n\twhile true\n\t\tnum = floor(input(prompt + \"? \").val)\n\t\tif num > 0 and num <= maxVal then return num\n\t\tprint \"Try again...\"\n\tend while\nend function\n\nshowReturn = function\n\tprint \"You made it through tremendous flak!!\" \nend function\n\nshowShotDown = function\n\tprint \"* * * * boom * * * *\"\n\tprint \"You have been shot down.....\"\n\tprint \"Dearly beloved, we are gathered here today to pay our\"\n\tprint \"last tribute...\"\t\nend function\n\nshowSuccess = function\n\tprint \"Direct hit!!!! \" + floor(100*rnd) + \" killed.\"\n\tprint \"Mission successful.\"\nend function\n\n// Function to calculate the mission result for all nations except Japan.\ndoNonJapanResult = function\n\tprint\n\td = input(\"How many missions have you flown? \").val\n\twhile d >= 160\n\t\tprint \"Missions, not miles...\"\n\t\tprint \"150 missions is high even for old-timers.\"\n\t\td = input(\"Now then, how many missions have you flown? \").val\n\tend while\n\tprint\n\tif d >= 100 then print \"That's pushing the odds!\"\n\tif d < 25 then print \"Fresh out of training, eh?\"\n\tprint\n\tif d >= 160 * rnd then\n\t\tshowSuccess\n\telse\n\t\tprint \"Missed target by \" + floor(2+30*rnd) + \" miles!\"\n\t\tprint \"Now you're really in for it !!\"; print\n\t\tr = getNum(\"Does the enemy have guns(1), missiles(2), or both(3)\")\n\t\tprint\n\t\tif r != 2 then\n\t\t\ts = input(\"What's the percent hit rate of enemy gunners (10 to 50)? \").val\n\t\t\tif s<10 then\n\t\t\t\tprint \"You lie, but you'll pay...\"\n\t\t\t\tshowShotDown\n\t\t\t\treturn\n\t\t\tend if\n\t\tend if\n\t\tprint\n\t\tprint\n\t\tif r > 1 then t = 35 else t = 0\n\t\tif s + t > 100 * rnd then\n\t\t\tshowShotDown\n\t\telse\n\t\t\tshowReturn\n\t\tend if\n\tend if\nend function\n\ns = 0\t// hit rate of enemy gunners\nr = 0\t// whether enemy has guns(1), missiles(2), or both(3)\n\n// Main Loop\nwhile true\n\tprint \"You are a pilot in a World War II bomber.\"\n\ta = getNum(\"What side -- Italy(1), Allies(2), Japan(3), Germany(4)\", 4)\n\t\n\tif a == 1 then\t\t// Italy\n\t\tb = getNum(\"Your target -- Albania(1), Greece(2), North Africa(3)\")\n\t\tprint\n\t\tprint [\"Should be easy -- you're flying a nazi-made plane.\",\n\t\t\t\"Be careful!!!\", \"You're going for the oil, eh?\"][b-1]\n\t\tdoNonJapanResult\n\n\telse if a == 2 then\t// Allies\n\t\tg = getNum(\"Aircraft -- Liberator(1), B-29(2), B-17(3), Lancaster(4)\", 4)\n\t\tprint [\"You've got 2 tons of bombs flying for Ploesti.\",\n\t\t\t\"You're dumping the A-bomb on Hiroshima.\",\n\t\t\t\"You're chasing the Aismark in the North Sea.\",\n\t\t\t\"You're busting a German heavy water plant in the Ruhr.\"][g-1]\n\t\tdoNonJapanResult\n\n\telse if a == 3 then\t// Japan (different logic than all others)\n\t\tprint \"You're flying a kamikaze mission over the USS Lexington.\"\n\t\tisFirst = input(\"Your first kamikaze mission(y or n)? \").lower\n\t\tif isFirst and isFirst[0] == \"n\" then\n\t\t\ts = 0\n\t\t\tshowReturn\n\t\telse\n\t\t\tprint\n\t\t\tif rnd > 0.65 then showSuccess else showShotDown\n\t\tend if\n\n\telse\t\t\t\t// Germany\n\t\tm = getNum(\"A nazi, eh?  Oh well.  Are you going for Russia(1),\" +\n\t\t  char(13) + \"England(2), or France(3)\")\n\t\tprint [\"You're nearing Stalingrad.\",\n\t\t\t\"Nearing London.  Be careful, they've got radar.\",\n\t\t\t\"Nearing Versailles.  Duck soup.  They're nearly defenseless.\"][m-1]\n\t\tdoNonJapanResult\n\tend if\n\t\n\tprint; print; print; another = input(\"Another mission (y or n)? \").lower\n\tif not another or another[0] != \"y\" then\n\t\tprint \"Chicken !!!\" ; print ; break\n\tend if\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/12_Bombs_Away/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/12_Bombs_Away/bombsaway.bas",
    "content": "8 PRINT \"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\"\n10 INPUT \"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)\";A\n20 IF A>0 AND A<5 THEN 25\n22 PRINT \"TRY AGAIN...\" : GOTO 10\n25 ON A GOTO 30, 110, 200, 220\n30 INPUT \"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)\";B\n40 IF B>0 AND B<4 THEN 45\n42 PRINT \"TRY AGAIN...\" : GOTO 30\n45 PRINT : ON B GOTO 50, 80,90\n50 PRINT \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\"\n60 GOTO 280\n80 PRINT \"BE CAREFUL!!!\" : GOTO 280\n90 PRINT \"YOU'RE GOING FOR THE OIL, EH?\" : GOTO 280\n110 INPUT \"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)\";G\n120 IF G>0 AND G<5 THEN 125\n122 PRINT \"TRY AGAIN...\" : GOTO 110\n125 PRINT : ON G GOTO 130, 150, 170, 190\n130 PRINT \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\" : GOTO 280\n150 PRINT \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\" : GOTO 280\n170 PRINT \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\" : GOTO 280\n190 PRINT \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\"\n195 GOTO 280\n200 PRINT \"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\"\n205 INPUT \"YOUR FIRST KAMIKAZE MISSION(Y OR N)\";F$\n207 IF F$=\"N\" THEN S=0 : GOTO 358\n210 PRINT : IF RND(1)>.65 THEN 325\n215 GOTO 380\n220 PRINT \"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\"\n230 INPUT \"ENGLAND(2), OR FRANCE(3)\";M : IF M>0 AND M<4 THEN 235\n232 PRINT \"TRY AGAIN...\" : GOTO 220\n235 PRINT : ON M GOTO 250, 260, 270\n250 PRINT \"YOU'RE NEARING STALINGRAD.\" : GOTO 280\n260 PRINT \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\" : GOTO 280\n270 PRINT \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\"\n280 PRINT\n285 INPUT \"HOW MANY MISSIONS HAVE YOU FLOWN\";D\n290 IF D<160 THEN 300\n292 PRINT \"MISSIONS, NOT MILES...\"\n295 PRINT \"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\"\n297 PRINT \"NOW THEN, \"; : GOTO 285\n300 PRINT:IF D<100 THEN 310\n305 PRINT \"THAT'S PUSHING THE ODDS!\" : GOTO 320\n310 IF D<25 THEN PRINT \"FRESH OUT OF TRAINING, EH?\"\n320 PRINT : IF D<160*RND(1) THEN 330\n325 PRINT \"DIRECT HIT!!!! \"INT(100*RND(1))\"KILLED.\"\n327 PRINT \"MISSION SUCCESSFUL.\" : GOTO 390\n330 PRINT \"MISSED TARGET BY\"INT(2+30*RND(1))\"MILES!\"\n335 PRINT \"NOW YOU'RE REALLY IN FOR IT !!\" : PRINT\n340 INPUT \"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)\";R\n345 IF R>0 AND R<4 THEN 350\n347 PRINT \"TRY AGAIN...\" : GOTO 340\n350 PRINT : T=0 : IF R=2 THEN 360\n355 INPUT \"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)\";S\n357 IF S<10 THEN PRINT \"YOU LIE, BUT YOU'LL PAY...\": GOTO 380\n358 PRINT\n360 PRINT : IF R>1 THEN T=35\n365 IF S+T>100*RND(1) THEN 380\n370 PRINT \"YOU MADE IT THROUGH TREMENDOUS FLAK!!\" : GOTO 390\n380 PRINT \"* * * * BOOM * * * *\"\n384 PRINT \"YOU HAVE BEEN SHOT DOWN.....\"\n386 PRINT \"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\"\n387 PRINT \"LAST TRIBUTE...\"\n390 PRINT:PRINT:PRINT:INPUT \"ANOTHER MISSION (Y OR N)\";U$\n395 IF U$=\"Y\" THEN 8\n400 PRINT \"CHICKEN !!!\" : PRINT : END\n"
  },
  {
    "path": "00_Alternate_Languages/12_Bombs_Away/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\ntype Choice struct {\r\n\tidx string\r\n\tmsg string\r\n}\r\n\r\nfunc playerSurvived() {\r\n\tfmt.Println(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\")\r\n}\r\n\r\nfunc playerDeath() {\r\n\tfmt.Println(\"* * * * BOOM * * * *\")\r\n\tfmt.Println(\"YOU HAVE BEEN SHOT DOWN.....\")\r\n\tfmt.Println(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\")\r\n\tfmt.Println(\"LAST TRIBUTE...\")\r\n}\r\n\r\nfunc missionSuccess() {\r\n\tfmt.Printf(\"DIRECT HIT!!!! %d KILLED.\\n\", int(100*rand.Int()))\r\n\tfmt.Println(\"MISSION SUCCESSFUL.\")\r\n}\r\n\r\n// Takes a float between 0 and 1 and returns a boolean\r\n// if the player has survived (based on random chance)\r\n// Returns True if death, False if survived\r\nfunc deathWithChance(probability float64) bool {\r\n\treturn probability > rand.Float64()\r\n}\r\n\r\nfunc startNonKamikaziAttack() {\r\n\tnumMissions := getIntInput(\"HOW MANY MISSIONS HAVE YOU FLOWN? \")\r\n\r\n\tfor numMissions > 160 {\r\n\t\tfmt.Println(\"MISSIONS, NOT MILES...\")\r\n\t\tfmt.Println(\"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS\")\r\n\t\tnumMissions = getIntInput(\"HOW MANY MISSIONS HAVE YOU FLOWN? \")\r\n\t}\r\n\r\n\tif numMissions > 100 {\r\n\t\tfmt.Println(\"THAT'S PUSHING THE ODDS!\")\r\n\t}\r\n\r\n\tif numMissions < 25 {\r\n\t\tfmt.Println(\"FRESH OUT OF TRAINING, EH?\")\r\n\t}\r\n\r\n\tfmt.Println()\r\n\r\n\tif float32(numMissions) > (160 * rand.Float32()) {\r\n\t\tmissionSuccess()\r\n\t} else {\r\n\t\tmissionFailure()\r\n\t}\r\n}\r\n\r\nfunc missionFailure() {\r\n\tfmt.Printf(\"MISSED TARGET BY %d MILES!\\n\", int(2+30*rand.Float32()))\r\n\tfmt.Println(\"NOW YOU'RE REALLY IN FOR IT !!\")\r\n\tfmt.Println()\r\n\r\n\tenemyWeapons := getInputFromList(\"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? \", []Choice{{idx: \"1\", msg: \"GUNS\"}, {idx: \"2\", msg: \"MISSILES\"}, {idx: \"3\", msg: \"BOTH\"}})\r\n\r\n\t// If there are no gunners (i.e. weapon choice 2) then\r\n\t// we say that the gunners have 0 accuracy for the purposes\r\n\t// of calculating probability of player death\r\n\tenemyGunnerAccuracy := 0.0\r\n\tif enemyWeapons.idx != \"2\" {\r\n\t\tenemyGunnerAccuracy = float64(getIntInput(\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? \"))\r\n\t\tif enemyGunnerAccuracy < 10.0 {\r\n\t\t\tfmt.Println(\"YOU LIE, BUT YOU'LL PAY...\")\r\n\t\t\tplayerDeath()\r\n\t\t}\r\n\t}\r\n\r\n\tmissileThreatWeighting := 35.0\r\n\tif enemyWeapons.idx == \"1\" {\r\n\t\tmissileThreatWeighting = 0\r\n\t}\r\n\r\n\tdeath := deathWithChance((enemyGunnerAccuracy + missileThreatWeighting) / 100)\r\n\r\n\tif death {\r\n\t\tplayerDeath()\r\n\t} else {\r\n\t\tplayerSurvived()\r\n\t}\r\n}\r\n\r\nfunc playItaly() {\r\n\ttargets := []Choice{{idx: \"1\", msg: \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\"}, {idx: \"2\", msg: \"BE CAREFUL!!!\"}, {idx: \"3\", msg: \"YOU'RE GOING FOR THE OIL, EH?\"}}\r\n\ttarget := getInputFromList(\"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)\", targets)\r\n\tfmt.Println(target.msg)\r\n\tstartNonKamikaziAttack()\r\n}\r\n\r\nfunc playAllies() {\r\n\taircraftMessages := []Choice{{idx: \"1\", msg: \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\"}, {idx: \"2\", msg: \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\"}, {idx: \"3\", msg: \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\"}, {idx: \"4\", msg: \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\"}}\r\n\taircraft := getInputFromList(\"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): \", aircraftMessages)\r\n\tfmt.Println(aircraft.msg)\r\n\tstartNonKamikaziAttack()\r\n}\r\n\r\nfunc playJapan() {\r\n\tacknowledgeMessage := []Choice{{idx: \"Y\", msg: \"Y\"}, {idx: \"N\", msg: \"N\"}}\r\n\tfirstMission := getInputFromList(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\\nYOUR FIRST KAMIKAZE MISSION? (Y OR N): \", acknowledgeMessage)\r\n\tif firstMission.msg == \"N\" {\r\n\t\tplayerDeath()\r\n\t}\r\n\tif rand.Float64() > 0.65 {\r\n\t\tmissionSuccess()\r\n\t} else {\r\n\t\tplayerDeath()\r\n\t}\r\n}\r\n\r\nfunc playGermany() {\r\n\ttargets := []Choice{{idx: \"1\", msg: \"YOU'RE NEARING STALINGRAD.\"}, {idx: \"2\", msg: \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\"}, {idx: \"3\", msg: \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\"}}\r\n\ttarget := getInputFromList(\"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\\nENGLAND(2), OR FRANCE(3)? \", targets)\r\n\tfmt.Println(target.msg)\r\n\tstartNonKamikaziAttack()\r\n}\r\n\r\nfunc playGame() {\r\n\tfmt.Println(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\")\r\n\tside := getInputFromList(\"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): \", []Choice{{idx: \"1\", msg: \"ITALY\"}, {idx: \"2\", msg: \"ALLIES\"}, {idx: \"3\", msg: \"JAPAN\"}, {idx: \"4\", msg: \"GERMANY\"}})\r\n\tswitch side.idx {\r\n\tcase \"1\":\r\n\t\tplayItaly()\r\n\tcase \"2\":\r\n\t\tplayAllies()\r\n\tcase \"3\":\r\n\t\tplayJapan()\r\n\tcase \"4\":\r\n\t\tplayGermany()\r\n\t}\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\r\n\tfor {\r\n\t\tplayGame()\r\n\t\tif getInputFromList(\"ANOTHER MISSION (Y OR N):\", []Choice{{idx: \"Y\", msg: \"Y\"}, {idx: \"N\", msg: \"N\"}}).msg == \"N\" {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc getInputFromList(prompt string, choices []Choice) Choice {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfor {\r\n\t\tfmt.Println(prompt)\r\n\t\tscanner.Scan()\r\n\t\tchoice := scanner.Text()\r\n\t\tfor _, c := range choices {\r\n\t\t\tif strings.EqualFold(strings.ToUpper(choice), strings.ToUpper(c.idx)) {\r\n\t\t\t\treturn c\r\n\t\t\t}\r\n\t\t}\r\n\t\tfmt.Println(\"TRY AGAIN...\")\r\n\t}\r\n}\r\n\r\nfunc getIntInput(prompt string) int {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfor {\r\n\t\tfmt.Println(prompt)\r\n\t\tscanner.Scan()\r\n\t\tchoice, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"TRY AGAIN...\")\r\n\t\t\tcontinue\r\n\t\t} else {\r\n\t\t\treturn choice\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/13_Bounce/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bounce.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bounce\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms",
    "content": "print \" \"*33 + \"Bounce\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nt = [0]*21\nprint \"This simulation lets you specify the initial velocity\"\nprint \"of a ball thrown straight up, and the coefficient of\"\nprint \"elasticity of the ball.  Please use a decimal fraction\"\nprint \"coefficiency (less than 1).\"\nprint\nprint \"You also specify the time increment to be used in\"\nprint \"'strobing' the ball's flight (try .1 initially).\"\nprint\n\naddToLine = function(line, tabPos, textToAdd)\n\treturn line + \" \" * (floor(tabPos) - line.len) + textToAdd\nend function\n\nwhile true\n\ts2 = input(\"Time increment (sec)? \").val\n\tprint\n\tv = input(\"Velocity (fps)? \").val\n\tprint\n\tc = input(\"Coefficient? \").val\n\tprint\n\tprint \"feet\"\n\tprint\n\ts1 = floor(70/(v/(16*s2)))\n\tfor i in range(1, s1)\n\t\tt[i]=v*c^(i-1)/16\n\tend for\n\tfor h in range(floor(-16*(v/32)^2+v^2/32+.5), 0, -0.5)\n\t\tline = \"\"\n\t\tif floor(h)==h then line = str(h)\n\t\tl=0\n\t\tfor i in range(1, s1)\n\t\t\tfor time in range(0, t[i], s2)\n\t\t\t\tl=l+s2\n\t\t\t\tif abs(h-(.5*(-32)*time^2+v*c^(i-1)*time))<=.25 then\n\t\t\t\t\tline = addToLine(line, l/s2, \"0\")\n\t\t\t\tend if\n\t\t\tend for\n\t\t\ttime = t[i+1]/2\n\t\t\tif -16*time^2+v*c^(i-1)*time < h then break\n\t\tend for\n\t\tprint line\n\tend for\n\tprint \" \" + \".\" * floor((l+1)/s2+1)\n\tline = \" 0\"\n\tfor i in range(1, l+.9995)\n\t\tline = addToLine(line, i/s2, i)\n\tend for\n\tprint line\n\tprint \" \" * floor((l+1)/(2*s2)-2) + \"seconds\"\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/13_Bounce/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/13_Bounce/bounce.bas",
    "content": "10 PRINT TAB(33);\"BOUNCE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n90 DIM T(20)\n100 PRINT \"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\"\n110 PRINT \"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\"\n120 PRINT \"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\"\n130 PRINT \"COEFFICIENCY (LESS THAN 1).\"\n131 PRINT\n132 PRINT \"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\"\n133 PRINT \"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\"\n134 PRINT\n135 INPUT \"TIME INCREMENT (SEC)\";S2\n140 PRINT\n150 INPUT \"VELOCITY (FPS)\";V\n160 PRINT\n170 INPUT \"COEFFICIENT\";C\n180 PRINT\n182 PRINT \"FEET\"\n184 PRINT\n186 S1=INT(70/(V/(16*S2)))\n190 FOR I=1 TO S1\n200 T(I)=V*C^(I-1)/16\n210 NEXT I\n220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5\n221 IF INT(H)<>H THEN 225\n222 PRINT H;\n225 L=0\n230 FOR I=1 TO S1\n240 FOR T=0 TO T(I) STEP S2\n245 L=L+S2\n250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270\n260 PRINT TAB(L/S2);\"0\";\n270 NEXT T\n275 T=T(I+1)/2\n276 IF -16*T^2+V*C^(I-1)*T<H THEN 290\n280 NEXT I\n290 PRINT\n300 NEXT H\n310 PRINT TAB(1);\n320 FOR I=1 TO INT(L+1)/S2+1\n330 PRINT \".\";\n340 NEXT I\n350 PRINT\n355 PRINT \" 0\";\n360 FOR I=1 TO INT(L+.9995)\n380 PRINT TAB(INT(I/S2));I;\n390 NEXT I\n400 PRINT\n410 PRINT TAB(INT(L+1)/(2*S2)-2);\"SECONDS\"\n420 PRINT\n430 GOTO 135\n440 END\n"
  },
  {
    "path": "00_Alternate_Languages/14_Bowling/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bowling.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bowling\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms",
    "content": "import \"listUtil\"\n\nprint \" \"*34 + \"Bowl\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\npinDown = [0]*10\t\t// state of each pin: 1=down, 0=standing\nplayer = 1\nframe = 1\nball = 1\nscores = list.init3d(10, 4, 3, 0)\t// index by [frame][player][ball], all 0-based\n\nprintInstructions = function\n\tprint \"The game of bowling takes mind and skill. During the game\"\n\tprint \"the computer will keep score. You may compete with\"\n\tprint \"other players [up to four]. You will be playing ten frames.\"\n\tprint \"On the pin diagram 'O' means the pin is down...'+' means the\"\n\tprint \"pin is standing. After the game the computer will show your\"\n\tprint \"scores.\"\nend function\n\nprintPinDiagram = function\n\tprint \"Player: \" + (player+1) + \"  Frame: \" + (frame+1) + \"  Ball: \" + (ball+1)\n\tprint\n\tk = 0\n\tfor row in range (0, 3)\n\t\tline = \" \" * row\n\t\tfor j in range(1, 4-row)\n\t\t\tline += \"+O\"[pinDown[k]] + \" \"\n\t\t\tk += 1\n\t\tend for\n\t\tprint line\n\tend for\nend function\n\nprintAnalysis = function(previousDown=0)\n\tpinsLeft = 10 - pinDown.sum\n\tif pinDown.sum == previousDown then print \"Gutter!!\"\n\tif ball == 0 and pinsLeft == 0 then\n\t\tprint \"Strike!!!!!\" + char(7)*4\n\t\tglobals.status = 3\n\telse if ball == 1 and pinsLeft == 0 then\n\t\tprint \"Spare!!!!\"\n\t\tglobals.status = 2\n\telse if ball == 1 and pinsLeft > 0 then\n\t\tprint \"Error!!!\"\t// (i.e., didn't clear all the pins in 2 balls)\n\t\tglobals.status = 1\n\tend if\nend function\n\nrollOneBall = function\n\tprint \"Type roll to get the ball going.\"\n\tinput\t\t// (response ignored)\n\tfor i in range(1, 20)\n\t\t// Generate a random number from 0-99, then take this mod 15.\n\t\t// This gives us a slightly higher chance of hitting a non-existent\n\t\t// pin than one of the actual 10.\n\t\tx = floor(rnd*100)\n\t\tif x % 15 < 10 then pinDown[x % 15] = 1\n\tend for\n\tprintPinDiagram\nend function\n\ndoOneFrame = function\n\tglobals.pinDown = [0]*10\n\tglobals.ball = 0\n\trollOneBall\n\tprintAnalysis\n\thitOnBall0 = pinDown.sum\n\tscores[frame][player][ball] = hitOnBall0\n\t\n\tglobals.ball = 1\n\tif hitOnBall0 < 10 then\n\t\tprint \"Roll your 2nd ball\"\n\t\tprint\n\t\trollOneBall\n\t\tprintAnalysis hitOnBall0\n\tend if\n\t// Note: scoring in this program is not like real bowling.\n\t// It just stores the number of pins down at the end of each ball,\n\t// and a status code (1, 2, or 3).\n\tscores[frame][player][ball] = pinDown.sum\n\tscores[frame][player][2] = status\nend function\n\npad = function(n, width=3)\n\treturn (\" \"*width + n)[-width:]\nend function\n\nprintFinalScores = function\n\tprint \"FRAMES\"\n\tfor i in range(1,10)\n\t\tprint pad(i), \"\"\n\tend for\n\tprint\n\tfor player in range(0, numPlayers-1)\n\t\tfor i in range(0, 2)\n\t\t\tfor frame in range(0, 9)\n\t\t\t\tprint pad(scores[frame][player][i]), \"\"\n\t\t\tend for\n\t\t\tprint\n\t\tend for\n\t\tprint\n\tend for\nend function\n\nplayOneGame = function\n\tfor f in range(0, 9)\n\t\tglobals.frame = f\n\t\tfor p in range(0, numPlayers-1)\n\t\t\tglobals.player = p\n\t\t\tdoOneFrame\n\t\tend for\n\tend for\n\tprint\n\tprintFinalScores\nend function\n\n// Main program\nprint \"Welcome to the alley\"\nprint \"Bring your friends\"\nprint \"Okay let's first get acquainted\"\nprint\nans = input(\"The instructions (Y/N)? \").upper\nif not ans or ans[0] != \"N\" then printInstructions\nwhile true\n\tnumPlayers = input(\"First of all...How many are playing? \").val\n\tif 0 < numPlayers < 5 then break\n\tprint \"Please enter a number from 1 to 4.\"\nend while\nprint\nprint \"Very good...\"\nwhile true\n\tplayOneGame\n\tprint\n\tans = input(\"Do you want another game? \").upper\n\tif not ans or ans[0] != \"Y\" then break\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/14_Bowling/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/14_Bowling/bowling.bas",
    "content": "10 PRINT TAB(34);\"BOWL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n270 DIM C(15),A(100,6)\n360 PRINT \"WELCOME TO THE ALLEY\"\n450 PRINT \"BRING YOUR FRIENDS\"\n540 PRINT \"OKAY LET'S FIRST GET ACQUAINTED\"\n630 PRINT \"\"\n720 PRINT \"THE INSTRUCTIONS (Y/N)\"\n810 INPUT Z$\n900 IF Z$=\"Y\" THEN 990\n960 IF Z$=\"N\" THEN 1530\n990 PRINT \"THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME\"\n1080 PRINT \"THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\"\n1170 PRINT \"OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES\"\n1260 PRINT \"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\"\n1350 PRINT \"PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR\"\n1440 PRINT \"SCORES .\"\n1530 PRINT \"FIRST OF ALL...HOW MANY ARE PLAYING\";\n1620 INPUT R\n1710 PRINT\n1800 PRINT \"VERY GOOD...\"\n1890 FOR I=1 TO 100: FOR J=1 TO 6: A(I,J)=0: NEXT J: NEXT I\n1980 F=1\n2070 FOR P=1 TO R\n2160 M=0\n2250 B=1\n2340 M=0: Q=0\n2430 FOR I=1 TO 15: C(I)=0: NEXT I\n2520 REM ARK BALL GENERATOR USING MOD '15' SYSTEM\n2610 PRINT \"TYPE ROLL TO GET THE BALL GOING.\"\n2700 INPUT N$\n2790 K=0: D=0\n2880 FOR I=1 TO 20\n2970 X=INT(RND(1)*100)\n3060 FOR J=1 TO 10\n3150 IF X<15*J THEN 3330\n3240 NEXT J\n3330 C(15*J-X)=1\n3420 NEXT I\n3510 REM ARK PIN DIAGRAM\n3600 PRINT \"PLAYER:\"P;\"FRAME:\";F\"BALL:\"B\n3690 FOR I=0 TO 3\n3780 PRINT\n3870 FOR J=1 TO 4-I\n3960 K=K+1\n4050 IF C(K)=1 THEN 4320\n4140 PRINT TAB(I);\"+ \";\n4230 GOTO 4410\n4320 PRINT TAB(I);\"O \";\n4410 NEXT J\n4500 NEXT I\n4590 PRINT \"\"\n4680 REM ARK ROLL ANALYSIS\n4770 FOR I=1 TO 10\n4860 D=D+C(I)\n4950 NEXT I\n5040 IF D-M <> 0 THEN 5220\n5130 PRINT \"GUTTER!!\"\n5220 IF B<>1 OR D<>10 THEN 5490\n5310 PRINT \"STRIKE!!!!!\u0007\u0007\u0007\u0007\"\n5400 Q=3\n5490 IF B<>2 OR D<>10 THEN 5760\n5580 PRINT \"SPARE!!!!\"\n5670 Q=2\n5760 IF B<>2 OR D>=10 THEN 6030\n5850 PRINT \"ERROR!!!\"\n5940 Q=1\n6030 IF B<>1 OR D>=10 THEN 6210\n6120 PRINT \"ROLL YOUR 2ND BALL\"\n6210 REM ARK STORAGE OF THE SCORES\n6300 PRINT\n6390 A(F*P,B)=D\n6480 IF B=2 THEN 7020\n6570 B=2\n6660 M=D\n6750 IF Q=3 THEN 6210\n6840 A(F*P,B)=D-M\n6930 IF Q=0 THEN 2520\n7020 A(F*P,3)=Q\n7110 NEXT P\n7200 F=F+1\n7290 IF F<11 THEN 2070\n7295 PRINT \"FRAMES\"\n7380 FOR I=1 TO 10\n7470 PRINT I;\n7560 NEXT I\n7650 PRINT\n7740 FOR P=1 TO R\n7830 FOR I=1 TO 3\n7920 FOR J=1 TO 10\n8010 PRINT A(J*P,I);\n8100 NEXT J\n8105 PRINT\n8190 NEXT I\n8280 PRINT\n8370 NEXT P\n8460 PRINT \"DO YOU WANT ANOTHER GAME\"\n8550 INPUT A$\n8640 IF LEFT$(A$,1)=\"Y\" THEN 2610\n8730 END\n"
  },
  {
    "path": "00_Alternate_Languages/15_Boxing/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript boxing.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"boxing\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms",
    "content": "print \" \"*33 + \"Boxing\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Boxing Olympic Style (3 Rounds -- 2 out of 3 Wins)\"\n\nplayerWins = 0\nopponentWins = 0\nprint\nopponentName = input(\"What is your opponent's name? \")\nplayerName = input(\"Input your man's name? \")\nprint \"Different punches are: (1) full swing; (2) hook; (3) uppercut; (4) jab.\"\nplayerBest = input(\"What is your man's best? \").val\nplayerWeakness = input(\"What is his vulnerability? \" ).val\nwhile true\n\topponentBest = floor(4 * rnd + 1)\n\topponentWeakness = floor(4 * rnd + 1)\n\tif opponentBest != opponentWeakness then break\nend while\nprint opponentName + \"'s advantage is \" + opponentBest + \" and vulnerability is secret.\"\nprint\n\nplayerConnects = function\n\tprint \"He connects!\"\n\tif playerPoints > 35 then\n\t\tprint opponentName + \" is knocked cold and \" + playerName + \" is the winner and champ!\"\n\t\tglobals.done = true\n\t\treturn\n\tend if\n\tglobals.playerPoints += 15\nend function\n\ndoPlayerPunch = function\n\tp = input(playerName + \"'s punch? \").val\n\tif p == playerBest then globals.playerPoints += 2\n\tif p == 1 then\t\t// Full Swing\n\t\tprint playerName + \" swings and \", \"\"\n\t\tif opponentWeakness == 4 then\t// (probably a bug in original code)\n\t\t\tplayerConnects\n\t\telse\n\t\t\tx3 = floor(30 * rnd+1)\n\t\t\tif x3 < 10 then\n\t\t\t\tplayerConnects\n\t\t\telse\n\t\t\t\tprint \"he misses \"\n\t\t\t\tif playerPoints != 1 then\n\t\t\t\t\tprint\n\t\t\t\t\tprint\n\t\t\t\tend if\n\t\t\tend if\n\t\tend if\n\telse if p == 2 then\t// Hook\n\t\tprint playerName + \" gives the hook... \", \"\"\n\t\tif opponentWeakness == 2 then\n\t\t\tglobals.playerPoints += 7\n\t\telse\n\t\t\th1 = floor(2 * rnd + 1)\n\t\t\tif h1 == 1 then\n\t\t\t\tprint \"But it's blocked!!!!!!!!!!!!!\"\n\t\t\telse\n\t\t\t\tprint \"Connects...\"\n\t\t\t\tglobals.playerPoints += 7\n\t\t\tend if\n\t\tend if\n\telse if p == 3 then\t// Uppercut\n\t\tprint playerName + \" tries an uppercut \", \"\"\n\t\tif opponentWeakness == 3 or floor(100 * rnd + 1) < 51 then\n\t\t\tprint \"and he connects!\"\n\t\t\tglobals.playerPoints += 4\n\t\telse\n\t\t\tprint \"and it's blocked (lucky block!)\"\n\t\tend if\n\telse\t\t\t\t// Jab\n\t\tprint playerName + \" jabs at \" + opponentName + \"'s head \", \"\"\n\t\tif opponentWeakness != 4 and floor(8 * rnd + 1) >= 4 then\n\t\t\tprint \"It's blocked.\"\n\t\telse\n\t\t\tglobals.playerPoints += 3\n\t\tend if\n\tend if\nend function\n\nplayerKnockedOut = function\n\tprint playerName + \" is knocked cold and \" + opponentName + \" is the winner and champ!\"\n\tglobals.done = true\nend function\n\ndoOpponentPunch = function\n\tj7 = floor(4 * rnd + 1)\n\tif j7 == playerBest then globals.opponentPoints += 2\n\tif j7 == 1 then\t\t\t// Full swing\n\t\tprint opponentName + \" takes a full swing and \", \"\"\n\t\tif playerWeakness == 1 or floor(60 * rnd + 1) < 30 then\n\t\t\tprint \"POW!!!!! He hits him right in the face!\"\n\t\t\tif opponentPoints > 35 then\n\t\t\t\tplayerKnockedOut\n\t\t\telse\n\t\t\t\tglobals.opponentPoints += 15\n\t\t\tend if\n\t\telse\n\t\t\tprint \"it's blocked!\"\n\t\tend if\n\tend if\n\tif j7 == 2 then\t// Hook\n\t\tprint opponentName + \" gets \" + playerName + \" in the jaw (ouch!)\"\n\t\tglobals.playerPoints += 7\n\t\tprint \"....and again!\"\n\t\tglobals.playerPoints += 5\n\t\tif opponentPoints > 35 then\n\t\t\tplayerKnockedOut\n\t\t\treturn\n\t\tend if\n\t\tprint\n\t\t// continue below as if an Uppercut (probably a bug in the original code)\n\tend if\n\tif j7 == 2 or j7 == 3 then\t// Uppercut, or Hook\n\t\tprint playerName + \" is attacked by an uppercut (oh,oh)...\"\n\t\tif playerWeakness == 3 or floor(200*rnd+1) <= 75 then\n\t\t\tprint \"and \" + opponentName + \" connects...\"\n\t\t\tglobals.opponentPoints += 8\t\t\t\t\t\n\t\telse\n\t\t\tprint \" blocks and hits \" + opponentName + \" with a hook.\"\n\t\t\tglobals.playerPoints += 5\n\t\tend if\n\tend if\n\tif j7 == 4 then\t\t\t// Jab\n\t\tprint opponentName + \" jabs and \", \"\"\n\t\tif playerWeakness == 4 or floor(7 * rnd + 1) > 4 then\n\t\t\tprint \"blood spills !!!\"\n\t\t\tglobals.opponentPoints += 5\n\t\telse\n\t\t\tprint \"It's blocked!\"\n\t\tend if\t\t\t\t\n\tend if\nend function\n\nplayOneRound = function\n\tglobals.playerPoints = 0\n\tglobals.opponentPoints = 0\n\tprint \"Round \" + round + \" begins...\"\n\tfor r1 in range(1, 7)\n\t\ti = floor(10 * rnd + 1)\n\t\tif i <= 5 then\n\t\t\tdoPlayerPunch\n\t\telse\n\t\t\tdoOpponentPunch\n\t\tend if\n\t\tif done then return\n\tend for\t\t// next R1 (sub-round)\n\tif playerPoints > opponentPoints then\n\t\tprint; print playerName + \" wins round \" + round\n\t\tglobals.playerWins += 1\n\telse\n\t\tprint; print opponentName + \" wins round \" + round\n\t\tglobals.opponentWins += 1\n\tend if\nend function\n\ndone = false\nfor round in range(1,3)\n\tplayOneRound\n\tif done then break\n\tif opponentWins >= 2 then\n\t\tprint opponentName + \" wins (nice going, \" + opponentName + \").\"\n\t\tbreak\n\telse if playerWins >= 2 then\n\t\tprint playerName + \" amazingly wins!!\"\n\t\tbreak\n\tend if\nend for\t// next round\n\nprint\nprint \nprint \"and now goodbye from the Olympic arena.\"\nprint\n"
  },
  {
    "path": "00_Alternate_Languages/15_Boxing/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/15_Boxing/boxing.bas",
    "content": "1 PRINT TAB(33);\"BOXING\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\"\n5 J=0\n6 L=0\n8 PRINT\n10 PRINT \"WHAT IS YOUR OPPONENT'S NAME\";\n20 INPUT J$\n30 PRINT \"INPUT YOUR MAN'S NAME\";\n40 INPUT L$\n50 PRINT \"DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\"\n60 PRINT \"WHAT IS YOUR MANS BEST\";\n64 INPUT B\n70 PRINT \"WHAT IS HIS VULNERABILITY\";\n80 INPUT D\n90 B1=INT(4*RND(1)+1)\n100 D1=INT(4*RND(1)+1)\n110 IF B1=D1 THEN 90\n120 PRINT J$;\"'S ADVANTAGE IS\";B1;\"AND VULNERABILITY IS SECRET.\":PRINT\n130 FOR R=1 TO 3\n140 IF J>= 2 THEN 1040\n150 IF L>=2 THEN 1060\n160 X=0\n170 Y=0\n180 PRINT \"ROUND\";R;\"BEGINS...\"\n185 FOR R1= 1 TO 7\n190 I=INT(10*RND(1)+1)\n200 IF I>5 THEN 600\n210 PRINT L$;\"'S PUNCH\";\n220 INPUT P\n221 IF P=B THEN 225\n222 GOTO 230\n225 X=X+2\n230 IF P=1 THEN 340\n240 IF P=2 THEN 450\n250 IF P=3 THEN 520\n270 PRINT L$;\" JABS AT \";J$\"'S HEAD \";\n271 IF D1=4 THEN 290\n275 C=INT(8*RND(1)+1)\n280 IF C<4 THEN 310\n290 X=X+3\n300 GOTO 950\n310 PRINT \"IT'S BLOCKED.\"\n330 GOTO 950\n340 PRINT L$ \" SWINGS AND \";\n341 IF D1=4 THEN 410\n345 X3=INT(30*RND(1)+1)\n350 IF X3<10 THEN 410\n360 PRINT \"HE MISSES \";\n370 PRINT\n375 IF X=1 THEN 950\n380 PRINT\n390 PRINT\n400 GOTO 300\n410 PRINT \"HE CONNECTS!\"\n420 IF X>35 THEN 980\n425 X=X+15\n440 GOTO 300\n450 PRINT L$;\" GIVES THE HOOK... \";\n455 IF D1=2 THEN 480\n460 H1=INT(2*RND(1)+1)\n470 IF H1=1 THEN 500\n475 PRINT \"CONNECTS...\"\n480 X=X+7\n490 GOTO 300\n500 PRINT \"BUT IT'S BLOCKED!!!!!!!!!!!!!\"\n510 GOTO 300\n520 PRINT L$ \" TRIES AN UPPERCUT \";\n530 IF D1=3 THEN 570\n540 D5=INT(100*RND(1)+1)\n550 IF D5<51 THEN 570\n560 PRINT \"AND IT'S BLOCKED (LUCKY BLOCK!)\"\n565 GOTO 300\n570 PRINT \"AND HE CONNECTS!\"\n580 X=X+4\n590 GOTO 300\n600 J7=INT(4*RND(1)+1)\n601 IF J7 =B1 THEN 605\n602 GOTO 610\n605 Y=Y+2\n610 IF J7=1 THEN 720\n620 IF J7=2 THEN 810\n630 IF J7 =3 THEN 860\n640 PRINT J$;\" JABS AND \";\n645 IF D=4 THEN 700\n650 Z4=INT(7*RND(1)+1)\n655 IF Z4>4 THEN 690\n660 PRINT \"IT'S BLOCKED!\"\n670 GOTO 300\n690 PRINT \" BLOOD SPILLS !!!\"\n700 Y=Y+5\n710 GOTO 300\n720 PRINT J$\" TAKES A FULL SWING AND\";\n730 IF D=1 THEN 770\n740 R6=INT(60*RND(1)+1)\n745 IF R6 <30 THEN 770\n750 PRINT \" IT'S BLOCKED!\"\n760 GOTO 300\n770 PRINT \" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\"\n780 IF Y>35 THEN 1010\n790 Y=Y+15\n800 GOTO 300\n810 PRINT J$;\" GETS \";L$;\" IN THE JAW (OUCH!)\"\n820 Y=Y+7\n830 PRINT \"....AND AGAIN!\"\n835 Y=Y+5\n840 IF Y>35 THEN 1010\n850 PRINT\n860 PRINT L$;\" IS ATTACKED BY AN UPPERCUT (OH,OH)...\"\n865 IF D=3 THEN 890\n870 Q4=INT(200*RND(1)+1)\n880 IF Q4>75 THEN 920\n890 PRINT \"AND \";J$;\" CONNECTS...\"\n900 Y=Y+8\n910 GOTO 300\n920 PRINT \" BLOCKS AND HITS \";J$;\" WITH A HOOK.\"\n930 X=X+5\n940 GOTO 300\n950 NEXT R1\n951 IF X>Y THEN 955\n952 PRINT:PRINT J$\" WINS ROUND\" R\n953 J=J+1\n954 GOTO 960\n955 PRINT:PRINT L$\" WINS ROUND\"R\n956 L=L+1\n960 NEXT R\n961 IF J>= 2 THEN 1040\n962 IF L>=2 THEN 1060\n980 PRINT J$ \" IS KNOCKED COLD AND \" L$\" IS THE WINNER AND CHAMP!\";\n1000 GOTO 1080\n1010 PRINT L$ \" IS KNOCKED COLD AND \" J$\" IS THE WINNER AND CHAMP!\";\n1030 GOTO 1000\n1040 PRINT J$ \" WINS (NICE GOING,\" J$;\").\"\n1050 GOTO 1000\n1060 PRINT L$ \" AMAZINGLY WINS!!\"\n1070 GOTO 1000\n1080 PRINT\n1085 PRINT\n1090 PRINT \"AND NOW GOODBYE FROM THE OLYMPIC ARENA.\"\n1100 PRINT\n1110 END\n"
  },
  {
    "path": "00_Alternate_Languages/16_Bug/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bug.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bug\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/16_Bug/MiniScript/bug.ms",
    "content": "print \" \"*34 + \"Bug\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"The game Bug\"\nprint \"I hope you enjoy this game.\"\nprint\nans = input(\"Do you want instructions? \").lower\nif not ans or ans[0] != \"n\" then\n\tprint \"The object of bug is to finish your bug before i finish\"\n\tprint \"mine. Each number stands for a part of the bug body.\"\n\tprint \"I will roll the die for you, tell you what i rolled for you\"\n\tprint \"what the number stands for, and if you can get the part.\"\n\tprint \"If you can get the part I will give it to you.\"\n\tprint \"The same will happen on my turn.\"\n\tprint \"If there is a change in either bug I will give you the\"\n\tprint \"option of seeing the pictures of the bugs.\"\n\tprint \"Ihe numbers stand for parts as follows:\"\n\tprint \"Number   Part    Number of part needed\"\n\tprint \"1        body    1\"\n\tprint \"2        neck    1\"\n\tprint \"3        head    1\"\n\tprint \"4        feelers 2\"\n\tprint \"5        tail    1\"\n\tprint \"6        legs    6\"\n\tprint\n\tinput \"(Press Return.)\"\t// (wait before starting the game)\n\tprint\nend if\n\n// define a class to represent a bug (with all its body parts)\nBug = {}\nBug.body = false\nBug.neck = false\nBug.head = false\nBug.feelers = 0\nBug.tail = false\nBug.legs = 0\nBug.feelerLetter = \"F\"\nBug.pronoun = \"I\"\n\n// add a method to determine if the bug is complete\nBug.complete = function\n\treturn self.tail and self.feelers >= 2 and self.legs >= 6\nend function\n\n// add a method to draw the bug using print\nBug.draw = function\n\tif self.feelers then\n\t\tfor row in range(1,4)\n\t\t\tprint \" \"*10 + (self.feelerLetter + \" \") * self.feelers\n\t\tend for\n\tend if\n\tif self.head then\n\t\tprint \"        HHHHHHH\"\n\t\tprint \"        H     H\"\n\t\tprint \"        H O O H\"\n\t\tprint \"        H     H\"\n\t\tprint \"        H  V  H\"\n\t\tprint \"        HHHHHHH\"\n\tend if\n\tif self.neck then\n\t\tprint \"          N N\"\n\t\tprint \"          N N\"\n\tend if\n\tif self.body then\n\t\tprint \"     BBBBBBBBBBBB\"\n\t\tprint \"     B          B\"\n\t\tprint \"     B          B\"\n\t\tif self.tail then print \"TTTTTB          B\"\n\t\tprint \"     BBBBBBBBBBBB\"\n\tend if\n\tif self.legs then\n\t\tfor row in [1,2]\n\t\t\tprint \" \"*5 + \"L \" * self.legs\n\t\tend for\n\tend if\nend function\n\n// add a method to add a part, if possible; return true if bug changed\nBug.addPart = function(partNum)\n\tif partNum == 1 then\n\t\tprint \"1=Body\"\n\t\tif self.body then\n\t\t\tprint self.pronoun + \" do not need a body.\"\n\t\telse\n\t\t\tprint self.pronoun + \" now have a body.\"\n\t\t\tself.body = true\n\t\t\treturn true\n\t\tend if\n\telse if partNum == 2 then\n\t\tprint \"2=neck\"\n\t\tif self.neck then\n\t\t\tprint self.pronoun + \" do not need a neck.\"\n\t\telse if not self.body then\n\t\t\tprint self.pronoun + \" do not have a body.\"\n\t\telse\n\t\t\tprint self.pronoun + \" now have a neck.\"\n\t\t\tself.neck = true\n\t\t\treturn true\n\t\tend if\n\telse if partNum == 3 then\n\t\tprint \"3=head\"\n\t\tif self.head then\n\t\t\tprint self.pronoun + \" have a head.\"\n\t\telse if not self.neck then\n\t\t\tprint self.pronoun + \" do not have a neck.\"\n\t\telse\n\t\t\tprint self.pronoun + \" needed a head.\"\n\t\t\tself.head = true\n\t\t\treturn true\n\t\tend if\n\telse if partNum == 4 then\n\t\tprint \"4=feelers\"\n\t\tif self.feelers >= 2 then\n\t\t\tprint self.pronoun + \" have two feelers already.\"\n\t\telse if not self.head then\n\t\t\tprint self.pronoun + \" do not have a head.\"\n\t\telse\n\t\t\tif self.pronoun == \"You\" then\n\t\t\t\tprint \"I now give you a feeler.\"\n\t\t\telse\n\t\t\t\tprint \"I get a feeler.\"\n\t\t\tend if\n\t\t\tself.feelers += 1\n\t\t\treturn true\n\t\tend if\n\telse if partNum == 5 then\n\t\tprint \"5=tail\"\n\t\tif self.tail then\n\t\t\tprint self.pronoun + \" already have a tail.\"\n\t\telse if not self.body then\n\t\t\tprint self.pronoun + \" do not have a body.\"\n\t\telse\n\t\t\tif self.pronoun == \"You\" then\t\t\t\n\t\t\t\tprint \"I now give you a tail.\"\n\t\t\telse\n\t\t\t\tprint \"I now have a tail.\"\n\t\t\tend if\n\t\t\tself.tail = true\n\t\t\treturn true\n\t\tend if\n\telse if partNum == 6 then\n\t\tprint \"6=legs\"\n\t\tif self.legs >= 6 then\n\t\t\tprint self.pronoun + \" have 6 feet.\"\n\t\telse if not self.body then\n\t\t\tprint self.pronoun + \" do not have a body.\"\n\t\telse\n\t\t\tself.legs += 1\n\t\t\tprint self.pronoun + \" now have \" + self.legs + \" leg\" + \"s\"*(self.legs>1) + \".\"\n\t\t\treturn true\n\t\tend if\n\tend if\n\treturn 0\nend function\n\n\n// ...then, instantiate a bug for You (human player) and Me (computer)\nyou = new Bug\nyou.feelerLetter = \"A\"\t// (don't ask me why)\nyou.pronoun = \"You\"\nme = new Bug\n\n// Main loop\nwhile not you.complete and not me.complete\n\tanyChange = false\n\tdie = floor(6 * rnd + 1)\n\tprint; print \"You rolled a \" + die\n\tif you.addPart(die) then anyChange = true\n\twait 2\n\tdie = floor(6 * rnd + 1)\n\tprint; print \"I rolled a \" + die\n\tif me.addPart(die) then anyChange = true\n\tif you.complete then print \"Your bug is finished.\"\n\tif me.complete then print \"My bug is finished.\"\n\tif anyChange then\n\t\tans = input(\"Do you want the pictures? \").lower\n\t\tif not ans or ans[0] != \"n\" then\n\t\t\tprint \"*****Your Bug*****\"\n\t\t\tprint; print\n\t\t\tyou.draw\n\t\t\twait 2\n\t\t\tprint\n\t\t\tprint \"*****My Bug*****\"\n\t\t\tprint; print\n\t\t\tme.draw\n\t\t\twait 2\n\t\tend if\n\tend if\nend while\nprint \"I hope you enjoyed the game, play it again soon!!\"\n\n"
  },
  {
    "path": "00_Alternate_Languages/16_Bug/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/16_Bug/bug.bas",
    "content": "10 PRINT TAB(34);\"BUG\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 REM\n50 A=0: B=0: H=0: L=0: N=0: P=0: Q=0: R=0: S=0: T=0: U=0: V=0: Y=0\n60 PRINT \"THE GAME BUG\"\n70 PRINT \"I HOPE YOU ENJOY THIS GAME.\"\n80 PRINT\n90 PRINT \"DO YOU WANT INSTRUCTIONS\";\n100 INPUT Z$\n110 IF Z$=\"NO\" THEN 300\n120 PRINT \"THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH\"\n130 PRINT \"MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.\"\n140 PRINT \"I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU\"\n150 PRINT \"WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.\"\n160 PRINT \"IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.\"\n170 PRINT \"THE SAME WILL HAPPEN ON MY TURN.\"\n180 PRINT \"IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE\"\n190 PRINT \"OPTION OF SEEING THE PICTURES OF THE BUGS.\"\n200 PRINT \"THE NUMBERS STAND FOR PARTS AS FOLLOWS:\"\n210 PRINT \"NUMBER\",\"PART\",\"NUMBER OF PART NEEDED\"\n220 PRINT \"1\",\"BODY\",\"1\"\n230 PRINT \"2\",\"NECK\",\"1\"\n240 PRINT \"3\",\"HEAD\",\"1\"\n250 PRINT \"4\",\"FEELERS\",\"2\"\n260 PRINT \"5\",\"TAIL\",\"1\"\n270 PRINT \"6\",\"LEGS\",\"6\"\n280 PRINT\n290 PRINT\n300 IF Y>0 THEN 2480\n310 Z=INT(6*RND(1)+1)\n320 C=1\n330 PRINT \"YOU ROLLED A\";Z\n340 ON Z GOTO 350,430,540,650,760,870\n350 PRINT \"1=BODY\"\n360 IF B=1 THEN 410\n370 PRINT \"YOU NOW HAVE A BODY.\"\n380 B=1\n390 C=0\n400 GOTO 970\n410 PRINT \"YOU DO NOT NEED A BODY.\"\n420 GOTO 970\n430 PRINT \"2=NECK\"\n440 IF N=1 THEN 500\n450 IF B=0 THEN 520\n460 PRINT \"YOU NOW HAVE A NECK.\"\n470 N=1\n480 C=0\n490 GOTO 970\n500 PRINT \"YOU DO NOT NEED A NECK.\"\n510 GOTO 970\n520 PRINT \"YOU DO NOT HAVE A BODY.\"\n530 GOTO 970\n540 PRINT \"3=HEAD\"\n550 IF N=0 THEN 610\n560 IF H=1 THEN 630\n570 PRINT \"YOU NEEDED A HEAD.\"\n580 H=1\n590 C=0\n600 GOTO 970\n610 PRINT \"YOU DO NOT HAVE A NECK.\"\n620 GOTO 970\n630 PRINT \"YOU HAVE A HEAD.\"\n640 GOTO 970\n650 PRINT \"4=FEELERS\"\n660 IF H=0 THEN 740\n670 IF A=2 THEN 720\n680 PRINT \"I NOW GIVE YOU A FEELER.\"\n690 A=A+1\n700 C=0\n710 GOTO 970\n720 PRINT \"YOU HAVE TWO FEELERS ALREADY.\"\n730 GOTO 970\n740 PRINT \"YOU DO NOT HAVE A HEAD.\"\n750 GOTO 970\n760 PRINT \"5=TAIL\"\n770 IF B=0 THEN 830\n780 IF T=1 THEN 850\n790 PRINT \"I NOW GIVE YOU A TAIL.\"\n800 T=T+1\n810 C=0\n820 GOTO 970\n830 PRINT \"YOU DO NOT HAVE A BODY.\"\n840 GOTO 970\n850 PRINT \"YOU ALREADY HAVE A TAIL.\"\n860 GOTO 970\n870 PRINT \"6=LEG\"\n880 IF L=6 THEN 940\n890 IF B=0 THEN 960\n900 L=L+1\n910 C=0\n920 PRINT \"YOU NOW HAVE\";L;\"LEGS.\"\n930 GOTO 970\n940 PRINT \"YOU HAVE 6 FEET ALREADY.\"\n950 GOTO 970\n960 PRINT \"YOU DO NOT HAVE A BODY.\"\n970 X=INT(6*RND(1)+1)\n971 PRINT\n975 FOR DELAY=1 TO 2000:NEXT DELAY\n980 PRINT \"I ROLLED A\";X\n990 ON X GOTO 1000,1080,1190,1300,1410,1520\n1000 PRINT \"1=BODY\"\n1010 IF P=1 THEN 1060\n1020 PRINT \"I NOW HAVE A BODY.\"\n1030 C=0\n1040 P=1\n1050 GOTO 1630\n1060 PRINT \"I DO NOT NEED A BODY.\"\n1070 GOTO 1630\n1080 PRINT \"2=NECK\"\n1090 IF Q=1 THEN 1150\n1100 IF P=0 THEN 1170\n1110 PRINT \"I NOW HAVE A NECK.\"\n1120 Q=1\n1130 C=0\n1140 GOTO 1630\n1150 PRINT \"I DO NOT NEED A NECK.\"\n1160 GOTO 1630\n1170 PRINT \"I DO NOT HAVE A BODY.\"\n1180 GOTO 1630\n1190 PRINT \"3=HEAD\"\n1200 IF Q=0 THEN 1260\n1210 IF R=1 THEN 1280\n1220 PRINT \"I NEEDED A HEAD.\"\n1230 R=1\n1240 C=0\n1250 GOTO 1630\n1260 PRINT \"I DO NOT HAVE A NECK.\"\n1270 GOTO 1630\n1280 PRINT \"I DO NOT NEED A HEAD.\"\n1290 GOTO 1630\n1300 PRINT \"4=FEELERS\"\n1310 IF R=0 THEN 1390\n1320 IF S=2 THEN 1370\n1330 PRINT \"I GET A FEELER.\"\n1340 S=S+1\n1350 C=0\n1360 GOTO 1630\n1370 PRINT \"I HAVE 2 FEELERS ALREADY.\"\n1380 GOTO 1630\n1390 PRINT \"I DO NOT HAVE A HEAD.\"\n1400 GOTO 1630\n1410 PRINT \"5=TAIL\"\n1420 IF P=0 THEN 1480\n1430 IF U=1 THEN 1500\n1440 PRINT \"I NOW HAVE A TAIL.\"\n1450 U=1\n1460 C=0\n1470 GOTO 1630\n1480 PRINT \"I DO NOT HAVE A BODY.\"\n1490 GOTO 1630\n1500 PRINT \"I DO NOT NEED A TAIL.\"\n1510 GOTO 1630\n1520 PRINT \"6=LEGS\"\n1530 IF V=6 THEN 1590\n1540 IF P=0 THEN 1610\n1550 V=V+1\n1560 C=0\n1570 PRINT \"I NOW HAVE\";V;\"LEGS.\"\n1580 GOTO 1630\n1590 PRINT,\"I HAVE 6 FEET.\"\n1600 GOTO 1630\n1610 PRINT \"I DO NOT HAVE A BODY.\"\n1620 GOTO 1630\n1630 IF A=2 AND T=1 AND L=6 THEN 1650\n1640 GOTO 1670\n1650 PRINT \"YOUR BUG IS FINISHED.\"\n1660 Y=Y+1\n1670 IF S=2 AND P=1 AND V=6 THEN 1690\n1680 GOTO 1710\n1690 PRINT \"MY BUG IS FINISHED.\"\n1700 Y=Y+2\n1710 IF C=1 THEN 300\n1720 PRINT \"DO YOU WANT THE PICTURES\";\n1730 INPUT Z$\n1740 IF Z$=\"NO\" THEN 300\n1750 PRINT \"*****YOUR BUG*****\"\n1760 PRINT\n1770 PRINT\n1780 IF A=0 THEN 1860\n1790 FOR Z=1 TO 4\n1800 FOR X=1 TO A\n1810 PRINT TAB(10);\n1820 PRINT \"A \";\n1830 NEXT X\n1840 PRINT\n1850 NEXT Z\n1860 IF H=0 THEN 1880\n1870 GOSUB 2470\n1880 IF N=0 THEN 1920\n1890 FOR Z=1 TO 2\n1900 PRINT \"          N N\"\n1910 NEXT Z\n1920 IF B=0 THEN 2000\n1930 PRINT \"     BBBBBBBBBBBB\"\n1940 FOR Z=1 TO 2\n1950 PRINT \"     B          B\"\n1960 NEXT Z\n1970 IF T<>1 THEN 1990\n1980 PRINT \"TTTTTB          B\"\n1990 PRINT \"     BBBBBBBBBBBB\"\n2000 IF L=0 THEN 2080\n2010 FOR Z=1 TO 2\n2020 PRINT TAB(5);\n2030 FOR X=1 TO L\n2040 PRINT \" L\";\n2050 NEXT X\n2060 PRINT\n2070 NEXT Z\n2080 FOR Z=1 TO 4\n2090 PRINT\n2100 NEXT Z\n2110 PRINT \"*****MY BUG*****\"\n2120 PRINT\n2130 PRINT\n2140 PRINT\n2150 IF S=0 THEN 2230\n2160 FOR Z=1 TO 4\n2170 PRINT TAB(10);\n2180 FOR X=1 TO S\n2190 PRINT \"F \";\n2200 NEXT X\n2210 PRINT\n2220 NEXT Z\n2230 IF R<>1 THEN 2250\n2240 GOSUB 2470\n2250 IF Q=0 THEN 2280\n2260 PRINT \"          N N\"\n2270 PRINT \"          N N\"\n2280 IF P=0 THEN 2360\n2290 PRINT \"     BBBBBBBBBBBB\"\n2300 FOR Z=1 TO 2\n2310 PRINT \"     B          B\"\n2320 NEXT Z\n2330 IF U<>1 THEN 2350\n2340 PRINT \"TTTTTB          B\"\n2350 PRINT \"     BBBBBBBBBBBB\"\n2360 IF V=0 THEN 2450\n2370 FOR Z=1 TO 2\n2380 PRINT TAB(5);\n2390 FOR X=1 TO V\n2400 PRINT \" L\";\n2410 NEXT X\n2420 PRINT\n2430 NEXT Z\n2450 IF Y<>0 THEN 2540\n2460 GOTO 300\n2470 PRINT \"        HHHHHHH\"\n2480 PRINT \"        H     H\"\n2490 PRINT \"        H O O H\"\n2500 PRINT \"        H     H\"\n2510 PRINT \"        H  V  H\"\n2520 PRINT \"        HHHHHHH\"\n2530 RETURN\n2540 PRINT \"I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!\"\n2550 END\n"
  },
  {
    "path": "00_Alternate_Languages/17_Bullfight/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bull.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bull\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms",
    "content": "print \" \"*34 + \"Bull\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\ngetYesNo = function(prompt)\n\twhile true\n\t\tans = input(prompt + \"? \").lower\n\t\tif ans and (ans[0] == \"y\" or ans[0] == \"n\") then return ans[0]\n\t\tprint \"Incorrect answer - - please type 'yes' or 'no'.\"\n\tend while\nend function\n\nif getYesNo(\"Do you want instructions\") == \"y\" then\n\tprint \"Hello, all you bloodlovers and aficionados.\"\n\tprint \"Here is your big chance to kill a bull.\"\n\tprint\n\tprint \"On each pass of the bull, you may try\"\n\tprint \"0 - Veronica (dangerous inside move of the cape)\"\n\tprint \"1 - Less dangerous outside move of the cape\"\n\tprint \"2 - Ordinary swirl of the cape.\"\n\tprint\n\tprint \"Instead of the above, you may try to kill the bull\"\n\tprint \"on any turn: 4 (over the horns), 5 (in the chest).\"\n\tprint \"But if I were you,\"\n\tprint \"I wouldn't try it before the seventh pass.\"\n\tprint\n\tprint \"The crowd will determine what award you deserve\"\n\tprint \"(posthumously if necessary).\"\n\tprint \"The braver you are, the better the award you receive.\"\n\tprint\n\tprint \"The better the job the picadores and toreadores do,\"\n\tprint \"the better your chances are.\"\n\tprint; input \"(Press return.)\"\nend if\nprint; print\nbravery = 1\noutcome = 1\nqualities = [null, \"superb\", \"good\", \"fair\", \"poor\", \"awful\"]\n\n// Select a bull (level 1-5, lower numbers are tougher)\nbullLevel = floor(rnd*5+1)\nprint \"You have drawn a \" + qualities[bullLevel] + \" bull.\"\nif bullLevel > 4 then print \"You're lucky.\"\nif bullLevel < 2 then print \"Good luck.  You'll need it.\"\nprint\n\n// Simulate one of the preliminary types of bullfighters\n// (picodores or toreadores).  Return their effect, 0.1 - 0.5.\nsimPreliminary = function(fighterType)\n\teffect = 0.1\n\ttemp = 3 / bullLevel * rnd\n\tif temp < 0.87 then effect = 0.2\n\tif temp < 0.63 then effect = 0.3\n\tif temp < 0.5 then effect = 0.4\n\tif temp < 0.37 then effect = 0.5\n\tt = floor(10 * effect + 0.2)\t// (get quality in range 1 - 5)\n\tprint \"The \" + fighterType + \" did a \" + qualities[t] + \" job.\"\n\tif t == 5 then\n\t\tif fighterType == \"picadores\" then\n\t\t\tprint floor(rnd*2+1) + \" of the horses of the picadores killed.\"\n\t\tend if\n\t\tprint floor(rnd*2+1) + \" of the \" + fighterType + \" killed.\"\n\telse if t == 4 then\n\t\tif rnd > 0.5 then\n\t\t\tprint \"One of the \" + fighterType + \" killed.\"\n\t\telse\n\t\t\tprint \"No \" + fighterType + \" were killed.\"\n\t\tend if\n\tend if\n\tprint\n\treturn effect\nend function\n\npicaEffect = simPreliminary(\"picadores\")\ntoreEffect = simPreliminary(\"toreadores\")\n\ngetGored = function\n\twhile not done\n\t\tif rnd > 0.5 then\n\t\t\tprint \"You are dead.\"\n\t\t\tglobals.bravery = 1.5\n\t\t\tglobals.done = true\n\t\telse\n\t\t\tprint \"You are still alive.\"; print\n\t\t\tif getYesNo(\"Do you run from the ring\") == \"y\" then\n\t\t\t\tprint \"Coward\"\n\t\t\t\tglobals.bravery = 0\n\t\t\t\tglobals.done = true\n\t\t\telse\n\t\t\t\tprint \"You are brave.  Stupid, but brave.\"\n\t\t\t\tif rnd > 0.5 then\n\t\t\t\t\tglobals.bravery = 2\n\t\t\t\t\tbreak\n\t\t\t\telse\n\t\t\t\t\tprint \"You are gored again!\"\n\t\t\t\tend if\n\t\t\tend if\n\t\tend if\n\tend while\nend function\n\npass = 0\ncourage = 1\t\t// cumulative effect of cape choices\nbravery = 1\t\t// set mainly by outcomes after getting gored\nvictory = false\t// true if we kill the bull\ndone = false\n\nwhile not done\n\tpass += 1\n\tprint\n\tprint \"Pass number \" + pass\n\tif pass < 3 then\n\t\tprint \"The bull is charging at you!  You are the matador--\"\n\t\ttryKill = (getYesNo(\"do you want to kill the bull\") == \"y\")\n\telse\n\t\ttryKill = (getYesNo(\"Here comes the bull.  Try for a kill\") == \"y\")\n\tend if\n\tif tryKill then\n\t\tprint; print \"It is the moment of truth.\"; print\n\t\th = input(\"How do you try to kill the bull? \" ).val\n\t\tif h != 4 and h != 5 then\n\t\t\tprint \"You panicked.  The bull gored you.\"\n\t\t\tgetGored\n\t\t\tbreak\n\t\tend if\n\t\tk = (6-bullLevel) * 10 * rnd / ((picaEffect + toreEffect) * 5 * pass)\n\t\tif h == 4 then\n\t\t\tvictory = (k <= 0.8)\n\t\telse\n\t\t\tvictory = (k <= 0.2)\n\t\tend if\n\t\tif victory then\n\t\t\tprint \"You killed the bull!\"\n\t\telse\n\t\t\tprint \"The bull has gored you!\"\n\t\t\tgetGored\n\t\tend if\n\t\tdone = true\n\telse\n\t\tif pass < 3 then\n\t\t\tcapeMove = input(\"What move do you make with the cape? \").val\n\t\telse\n\t\t\tcapeMove = input(\"Cape move? \").val\n\t\tend if\n\t\twhile capeMove < 0 or capeMove > 2 or capeMove != floor(capeMove)\n\t\t\tprint \"Don't panic, you idiot!  Put down a correct number\"\n\t\t\tcapeMove = input.val\n\t\tend while\n\t\tm = [3, 2, 0.5][capeMove]\n\t\tcourage += m\n\t\tf = (6-bullLevel+m/10)*rnd / ((picaEffect+toreEffect+pass/10)*5)\n\t\tif f >= 0.51 then\n\t\t\tprint \"The bull has gored you!\"\n\t\t\tgetGored\t\t\t\n\t\tend if\n\tend if\nend while\n\n// Final outcome\nif bravery == 0 then\n\tprint \"The crowd boos for ten minutes.  If you ever dare to show\"\n\tprint \"your face in a ring again, they swear they will kill you--\"\n\tprint \"unless the bull does first.\"\nelse\n\tfnd = (4.5+courage/6-(picaEffect+toreEffect)*2.5+4*bravery+2*(victory+1)-pass^2/120-bullLevel)\n\tfnc = function; return fnd * rnd; end function\n\tif bravery == 2 then\n\t\tprint \"The crowd cheers wildly!\"\n\telse if victory then\n\t\tprint \"The crowd cheers!\"; print\n\tend if\n\tprint \"The crowd awards you\"\n\tif fnc < 2.4 then\n\t\tprint \"nothing at all.\"\n\telse if fnc < 4.9 then\n\t\tprint \"one ear of the bull.\"\n\telse if fnc < 7.4 then\n\t\tprint \"Both ears of the bull!\"\n\t\tprint \"Ole!\"\n\telse\n\t\tprint \"Ole!  You are 'Muy Hombre!\"\" Ole!  Ole!\"\n\tend if\nend if\nprint\nprint \"Adios\"; print; print; print\n\n\t\n\t\t\n"
  },
  {
    "path": "00_Alternate_Languages/17_Bullfight/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/17_Bullfight/bullfight.bas",
    "content": "10 PRINT TAB(34);\"BULL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 DEF FNA(K)=INT(RND(1)*2+1)\n200 PRINT:PRINT:PRINT\n202 L=1\n205 PRINT \"DO YOU WANT INSTRUCTIONS\";\n206 INPUT Z$\n207 IF Z$=\"NO\" THEN 400\n210 PRINT \"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\"\n220 PRINT \"HERE IS YOUR BIG CHANCE TO KILL A BULL.\"\n230 PRINT\n240 PRINT \"ON EACH PASS OF THE BULL, YOU MAY TRY\"\n250 PRINT \"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\"\n260 PRINT \"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\"\n270 PRINT \"2 - ORDINARY SWIRL OF THE CAPE.\"\n280 PRINT\n290 PRINT \"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\"\n300 PRINT \"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\"\n310 PRINT \"BUT IF I WERE YOU,\"\n320 PRINT \"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\"\n330 PRINT\n340 PRINT \"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\"\n350 PRINT \"(POSTHUMOUSLY IF NECESSARY).\"\n360 PRINT \"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\"\n370 PRINT\n380 PRINT \"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\"\n390 PRINT \"THE BETTER YOUR CHANCES ARE.\"\n400 PRINT\n410 PRINT\n420 D(5)=1\n430 D(4)=1\n450 DIM L$(5)\n455 A=INT(RND(1)*5+1)\n460 FOR I=1 TO 5\n463 READ L$(I)\n467 NEXT I\n470 DATA \"SUPERB\",\"GOOD\",\"FAIR\",\"POOR\",\"AWFUL\"\n490 PRINT \"YOU HAVE DRAWN A \";L$(A);\" BULL.\"\n500 IF A>4 THEN 530\n510 IF A<2 THEN 550\n520 GOTO 570\n530 PRINT \"YOU'RE LUCKY.\"\n540 GOTO 570\n550 PRINT \"GOOD LUCK.  YOU'LL NEED IT.\"\n560 PRINT\n570 PRINT\n590 A$=\"PICADO\"\n595 B$=\"RES\"\n600 GOSUB 1610\n610 D(1)=C\n630 A$=\"TOREAD\"\n635 B$=\"ORES\"\n640 GOSUB 1610\n650 D(2)=C\n660 PRINT\n670 PRINT\n680 IF Z=1 THEN 1310\n690 D(3)=D(3)+1\n700 PRINT \"PASS NUMBER\";D(3)\n710 IF D(3)<3 THEN 760\n720 PRINT \"HERE COMES THE BULL.  TRY FOR A KILL\";\n730 GOSUB 1930\n735 IF Z1=1 THEN 1130\n740 PRINT \"CAPE MOVE\";\n750 GOTO 800\n760 PRINT \"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\"\n770 PRINT \"DO YOU WANT TO KILL THE BULL\";\n780 GOSUB 1930\n785 IF Z1=1 THEN 1130\n790 PRINT \"WHAT MOVE DO YOU MAKE WITH THE CAPE\";\n800 INPUT E\n810 IF E<>INT(ABS(E)) THEN 830\n820 IF E<3 THEN 850\n830 PRINT \"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\"\n840 GOTO 800\n850 REM\n860 IF E=0 THEN 920\n870 IF E=1 THEN 900\n880 M=.5\n890 GOTO 930\n900 M=2\n910 GOTO 930\n920 M=3\n930 L=L+M\n940 F=(6-A+M/10)*RND(1)/((D(1)+D(2)+D(3)/10)*5)\n950 IF F<.51 THEN 660\n960 PRINT \"THE BULL HAS GORED YOU!\"\n970 ON FNA(0) GOTO 980,1010\n980 PRINT \"YOU ARE DEAD.\"\n990 D(4)=1.5\n1000 GOTO 1310\n1010 PRINT \"YOU ARE STILL ALIVE.\":PRINT\n1020 PRINT \"DO YOU RUN FROM THE RING\";\n1030 GOSUB 1930\n1035 IF Z1=2 THEN 1070\n1040 PRINT \"COWARD\"\n1050 D(4)=0\n1060 GOTO 1310\n1070 PRINT \"YOU ARE BRAVE.  STUPID, BUT BRAVE.\"\n1080 ON FNA(0) GOTO 1090,1110\n1090 D(4)=2\n1100 GOTO 660\n1110 PRINT \"YOU ARE GORED AGAIN!\"\n1120 GOTO 970\n1130 REM\n1140 Z=1\n1150 PRINT:PRINT \"IT IS THE MOMENT OF TRUTH.\":PRINT\n1155 PRINT \"HOW DO YOU TRY TO KILL THE BULL\";\n1160 INPUT H\n1170 IF H=4 THEN 1230\n1180 IF H=5 THEN 1230\n1190 PRINT \"YOU PANICKED.  THE BULL GORED YOU.\"\n1220 GOTO 970\n1230 K=(6-A)*10*RND(1)/((D(1)+D(2))*5*D(3))\n1240 IF H=4 THEN 1290\n1250 IF K>.2 THEN 960\n1260 PRINT \"YOU KILLED THE BULL!\"\n1270 D(5)=2\n1280 GOTO 1320\n1290 IF K>.8 THEN 960\n1300 GOTO 1260\n1310 PRINT\n1320 PRINT\n1330 PRINT\n1340 IF D(4)<>0 THEN 1390\n1350 PRINT \"THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\"\n1360 PRINT \"YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\"\n1370 PRINT \"UNLESS THE BULL DOES FIRST.\"\n1380 GOTO 1580\n1390 DEF FNC(Q)=FND(Q)*RND(1)\n1395 DEF FND(Q)=(4.5+L/6-(D(1)+D(2))*2.5+4*D(4)+2*D(5)-D(3)^2/120-A)\n1400 IF D(4)<>2 THEN 1430\n1410 PRINT \"THE CROWD CHEERS WILDLY!\"\n1420 GOTO 1450\n1430 IF D(5)<>2 THEN 1450\n1440 PRINT \"THE CROWD CHEERS!\":PRINT\n1450 PRINT \"THE CROWD AWARDS YOU\"\n1460 IF FNC(Q)<2.4 THEN 1570\n1470 IF FNC(Q)<4.9 THEN 1550\n1480 IF FNC(Q)<7.4 THEN 1520\n1500 PRINT \"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\"\n1510 GOTO 1580\n1520 PRINT \"BOTH EARS OF THE BULL!\"\n1530 PRINT \"OLE!\"\n1540 GOTO 1580\n1550 PRINT \"ONE EAR OF THE BULL.\"\n1560 GOTO 1580\n1570 PRINT \"NOTHING AT ALL.\"\n1580 PRINT\n1590 PRINT \"ADIOS\":PRINT:PRINT:PRINT\n1600 GOTO 2030\n1610 B=3/A*RND(1)\n1620 IF B<.37 THEN 1740\n1630 IF B<.5 THEN 1720\n1640 IF B<.63 THEN 1700\n1650 IF B<.87 THEN 1680\n1660 C=.1\n1670 GOTO 1750\n1680 C=.2\n1690 GOTO 1750\n1700 C=.3\n1710 GOTO 1750\n1720 C=.4\n1730 GOTO 1750\n1740 C=.5\n1750 T=INT(10*C+.2)\n1760 PRINT \"THE \";A$;B$;\" DID A \";L$(T);\" JOB.\"\n1770 IF 4>T THEN 1900\n1780 IF 5=T THEN 1870\n1790 ON FNA(K) GOTO 1830,1850\n1800 IF A$=\"TOREAD\" THEN 1820\n1810 PRINT \"ONE OF THE HORSES OF THE \";A$;B$;\" WAS KILLED.\"\n1820 ON FNA(K) GOTO 1830,1850\n1830 PRINT \"ONE OF THE \";A$;B$;\" WAS KILLED.\"\n1840 GOTO 1900\n1850 PRINT \"NO \";A$;B$;\" WERE KILLED.\"\n1860 GOTO 1900\n1870 IF A$=\"TOREAD\" THEN 1890\n1880 PRINT FNA(K);\"OF THE HORSES OF THE \";A$;B$;\" KILLED.\"\n1890 PRINT FNA(K);\"OF THE \";A$;B$;\" KILLED.\"\n1900 PRINT\n1910 RETURN\n1920 REM\n1930 INPUT A$\n1940 IF A$=\"YES\" THEN 1990\n1950 IF A$=\"NO\" THEN 2010\n1970 PRINT \"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\"\n1980 GOTO 1930\n1990 Z1=1\n2000 GOTO 2020\n2010 Z1=2\n2020 RETURN\n2030 END\n"
  },
  {
    "path": "00_Alternate_Languages/18_Bullseye/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of bullseye.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bullseye.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bullseye\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms",
    "content": "print \" \"*32 + \"Bullseye\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"In this game, up to 20 players throw darts at a target\"\nprint \"with 10, 20, 30, and 40 point zones.  the objective is\"\nprint \"to get 200 points.\"; print\nprint \"throw       description            probable score\"\nprint \" 1          fast overarm           bullseye or complete miss\"\nprint \" 2          controlled overarm     10, 20 or 30 points\"\nprint \" 3          underarm               anything\";print\nnames = []\nn = input(\"How many players? \").val; print\nfor i in range(0, n-1)\n\tnames.push input(\"Name of player #\" + (i+1) + \"? \")\nend for\nscores = [0] * n\n\nround = 0\nwhile true\n\tround += 1; print; print \"round \" + round; print \"---------\"\n\tfor i in range(0, n-1)\n\t\twhile true\n\t\t\tprint; t = input(names[i] + \"'s throw? \").val\n\t\t\tif 1 <= t <= 3 then break\n\t\t\tprint \"Input 1, 2, or 3!\"\n\t\tend while\n\t\tif t == 1 then\n\t\t\tp1=.65; p2=.55; p3=.5; p4=.5\n\t\telse if t == 2 then\n\t\t\tp1=.99; p2=.77; p3=.43; p4=.01\n\t\telse\n\t\t\tp1=.95; p2=.75; p3=.45; p4=.05\n\t\tend if\n\t\tu = rnd\n\t\tif u>=p1 then\n\t\t\tprint \"Bullseye!!  40 points!\"; b=40\n\t\telse if u>=p2 then\n\t\t\tprint \"30-point zone!\"; b=30\n\t\telse if u>=p3 then\n\t\t\tprint \"20-point zone\"; b=20\n\t\telse if u>=p4 then\n\t\t\tprint \"Whew!  10 points.\"; b=10\n\t\telse\n\t\t\tprint \"Missed the target!  too bad.\"; b=0\n\t\tend if\n\t\tscores[i] += b; print \"Total score = \" + scores[i]\n\tend for\n\twinners = []\n\tfor i in range(0, n-1)\n\t\tif scores[i] >= 200 then winners.push i\n\tend for\n\tif winners then break\nend while\n\nprint; print \"We have a winner!!\"; print\nfor i in winners; print names[i] + \" scored \" + scores[i] + \" points.\"; end for\nprint; print \"Thanks for the game.\"\n\n"
  },
  {
    "path": "00_Alternate_Languages/18_Bullseye/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/18_Bullseye/bullseye.bas",
    "content": "5 PRINT TAB(32);\"BULLSEYE\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n20 PRINT:PRINT:PRINT\n30 PRINT \"IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\"\n40 PRINT \"WITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\"\n50 PRINT \"TO GET 200 POINTS.\": PRINT\n60 PRINT \"THROW\",TAB(20);\"DESCRIPTION\";TAB(45);\"PROBABLE SCORE\"\n70 PRINT\" 1\";TAB(20);\"FAST OVERARM\";TAB(45);\"BULLSEYE OR COMPLETE MISS\"\n80 PRINT\" 2\";TAB(20);\"CONTROLLED OVERARM\";TAB(45);\"10, 20 OR 30 POINTS\"\n90 PRINT\" 3\";TAB(20);\"UNDERARM\";TAB(45);\"ANYTHING\":PRINT\n100 DIM A$(20),S(20),W(10): M=0: R=0: FOR I=1 TO 20: S(I)=0: NEXT I\n110 INPUT \"HOW MANY PLAYERS\";N: PRINT\n120 FOR I=1 TO N\n130 PRINT \"NAME OF PLAYER #\";I;:INPUT A$(I)\n140 NEXT I\n150 R=R+1: PRINT: PRINT \"ROUND\";R:PRINT \"---------\"\n160 FOR I=1 TO N\n170 PRINT: PRINT A$(I)\"'S THROW\";: INPUT T\n180 IF T<1 OR T>3 THEN PRINT \"INPUT 1, 2, OR 3!\": GOTO 170\n190 ON T GOTO 200, 210, 200\n200 P1=.65: P2=.55: P3=.5: P4=.5: GOTO 230\n210 P1=.99: P2=.77: P3=.43: P4=.01: GOTO 230\n220 P1=.95: P2=.75: P3=.45: P4=.05\n230 U=RND(1)\n240 IF U>=P1 THEN PRINT \"BULLSEYE!!  40 POINTS!\":B=40: GOTO 290\n250 IF U>=P2 THEN PRINT \"30-POINT ZONE!\":B=30: GOTO 290\n260 IF U>=P3 THEN PRINT \"20-POINT ZONE\":B=20: GOTO 290\n270 IF U>=P4 THEN PRINT \"WHEW!  10 POINTS.\":B=10: GOTO 290\n280 PRINT \"MISSED THE TARGET!  TOO BAD.\": B=0\n290 S(I)=S(I)+B: PRINT \"TOTAL SCORE =\";S(I): NEXT I\n300 FOR I=1 TO N\n310 IF S(I)>=200 THEN M=M+1: W(M)=I\n320 NEXT I\n330 IF M=0 THEN 150\n340 PRINT: PRINT \"WE HAVE A WINNER!!\": PRINT\n350 FOR I=1 TO M: PRINT A$(W(I));\" SCORED\";S(W(I));\"POINTS.\": NEXT I\n360 PRINT: PRINT \"THANKS FOR THE GAME.\": END\n"
  },
  {
    "path": "00_Alternate_Languages/19_Bunny/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of bunny.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bunny.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bunny\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms",
    "content": "print \" \"*33 + \"Bunny\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\ndata = []\ndata += [1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1]\ndata += [1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1]\ndata += [5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1]\ndata += [9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1]\ndata += [13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1]\ndata += [19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1]\ndata += [8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1]\ndata += [4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1]\ndata += [2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1]\ndata += [14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1]\ndata += [14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1]\ndata += [12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1]\ndata += [10,11,17,18,22,22,24,24,29,29,-1]\ndata += [22,23,26,29,-1,27,29,-1,28,29,-1,4096]\n\nstring.pad = function(w)\n\treturn self + \" \" * (w - self.len)\nend function\n\nfor i in range(5); print; end for\n\nline = \"\"\nwhile true\n\tx = data.pull\n\tif x > 128 then break\n\tif x >= 0 then\n\t\tline = line.pad(x)\n\t\ty = data.pull\n\t\tfor i in range(x, y)\n\t\t\tline += \"BUNNY\"[i % 5]\n\t\tend for\n\telse\n\t\tprint line\n\t\tline = \"\"\n\t\twait 0.1\t// optional delay to make printing more visible\n\tend if\nend while\n\n"
  },
  {
    "path": "00_Alternate_Languages/19_Bunny/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/19_Bunny/bunny.bas",
    "content": "10 PRINT TAB(33);\"BUNNY\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 REM  \"BUNNY\" FROM AHL'S 'BASIC COMPUTER GAMES'\n110 REM\n120 FOR I=0 TO 4: READ B(I): NEXT I\n130 GOSUB 260\n140 L=64: REM  ASCII LETTER CODE...\n150 REM\n160 PRINT\n170 READ X: IF X<0 THEN 160\n175 IF X>128 THEN 240\n180 PRINT TAB(X);: READ Y\n190 FOR I=X TO Y: J=I-5*INT(I/5)\n200 PRINT CHR$(L+B(J));\n210 NEXT I\n220 GOTO 170\n230 REM\n240 GOSUB 260: GOTO 450\n250 REM\n260 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n270 RETURN\n280 REM\n290 DATA 2,21,14,14,25\n300 DATA 1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1\n310 DATA 1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1\n320 DATA 5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1\n330 DATA 9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1\n340 DATA 13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1\n350 DATA 19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1\n360 DATA 8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1\n370 DATA 4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1\n380 DATA 2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1\n390 DATA 14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1\n400 DATA 14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1\n410 DATA 12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1\n420 DATA 10,11,17,18,22,22,24,24,29,29,-1\n430 DATA 22,23,26,29,-1,27,29,-1,28,29,-1,4096\n440 REM\n450 END\n"
  },
  {
    "path": "00_Alternate_Languages/20_Buzzword/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of bunny.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript bunny.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"bunny\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms",
    "content": "print \" \"*26 + \"Buzzword Generator\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"This program prints highly acceptable phrases in\"\nprint \"'educator-speak' that you can work into reports\"\nprint \"and speeches.  Whenever a question mark is printed,\"\nprint \"type a 'y' for another phrase or 'n' to quit.\"\n\nwords1 = [\"ability\",\"basal\",\"behavioral\",\"child-centered\",\n\t\"differentiated\",\"discovery\",\"flexible\",\"heterogeneous\",\n\t\"homogeneous\",\"manipulative\",\"modular\",\"tavistock\",\n\t\"individualized\"]\n\nwords2 = [\"learning\", \"evaluative\",\"objective\",\n\t\"cognitive\",\"enrichment\",\"scheduling\",\"humanistic\",\n\t\"integrated\",\"non-graded\",\"training\",\"vertical age\",\n\t\"motivational\",\"creative\"]\n\nwords3 = [\"grouping\",\"modification\",\n\t\"accountability\",\"process\",\"core curriculum\",\"algorithm\",\n\t\"performance\",\"reinforcement\",\"open classroom\",\"resource\",\n\t\"structure\",\"facility\",\"environment\"]\n\nlist.any = function\n\treturn self[self.len * rnd]\nend function\n\nprint; print; print \"Here's the first phrase:\"\n\nwhile true\n\tprint [words1.any, words2.any, words3.any].join\n\tprint\n\tyn = input(\"?\").lower\n\tif yn != \"y\" then break\nend while\n\nprint \"Come back when you need help with another report!\"\n"
  },
  {
    "path": "00_Alternate_Languages/20_Buzzword/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/20_Buzzword/buzzword.bas",
    "content": "10 PRINT TAB(26);\"BUZZWORD GENERATOR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 PRINT \"THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\"\n50 PRINT \"'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\"\n60 PRINT \"AND SPEECHES.  WHENEVER A QUESTION MARK IS PRINTED,\"\n70 PRINT \"TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT.\"\n80 PRINT:PRINT:PRINT \"HERE'S THE FIRST PHRASE:\"\n90 DIM A$(40)\n100 FOR I=1 TO 39 : READ A$(I) : NEXT I\n110 PRINT A$(INT(13*RND(1)+1));\" \";\n120 PRINT A$(INT(13*RND(1)+14));\" \";\n130 PRINT A$(INT(13*RND(1)+27)) : PRINT\n150 INPUT Y$ : IF Y$=\"Y\" THEN 110\n160 GOTO 999\n200 DATA \"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\"\n210 DATA \"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\"HETEROGENEOUS\"\n220 DATA \"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\"\n230 DATA \"INDIVIDUALIZED\",\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\"\n240 DATA \"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\"\n250 DATA \"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\"\n260 DATA \"MOTIVATIONAL\",\"CREATIVE\",\"GROUPING\",\"MODIFICATION\"\n270 DATA \"ACCOUNTABILITY\",\"PROCESS\",\"CORE CURRICULUM\",\"ALGORITHM\"\n280 DATA \"PERFORMANCE\",\"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\"\n290 DATA \"STRUCTURE\",\"FACILITY\",\"ENVIRONMENT\"\n999 PRINT \"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\":END\n"
  },
  {
    "path": "00_Alternate_Languages/20_Buzzword/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\twords := [][]string{\r\n\t\t{\r\n\t\t\t\"Ability\",\r\n\t\t\t\"Basal\",\r\n\t\t\t\"Behavioral\",\r\n\t\t\t\"Child-centered\",\r\n\t\t\t\"Differentiated\",\r\n\t\t\t\"Discovery\",\r\n\t\t\t\"Flexible\",\r\n\t\t\t\"Heterogeneous\",\r\n\t\t\t\"Homogenous\",\r\n\t\t\t\"Manipulative\",\r\n\t\t\t\"Modular\",\r\n\t\t\t\"Tavistock\",\r\n\t\t\t\"Individualized\",\r\n\t\t}, {\r\n\t\t\t\"learning\",\r\n\t\t\t\"evaluative\",\r\n\t\t\t\"objective\",\r\n\t\t\t\"cognitive\",\r\n\t\t\t\"enrichment\",\r\n\t\t\t\"scheduling\",\r\n\t\t\t\"humanistic\",\r\n\t\t\t\"integrated\",\r\n\t\t\t\"non-graded\",\r\n\t\t\t\"training\",\r\n\t\t\t\"vertical age\",\r\n\t\t\t\"motivational\",\r\n\t\t\t\"creative\",\r\n\t\t}, {\r\n\t\t\t\"grouping\",\r\n\t\t\t\"modification\",\r\n\t\t\t\"accountability\",\r\n\t\t\t\"process\",\r\n\t\t\t\"core curriculum\",\r\n\t\t\t\"algorithm\",\r\n\t\t\t\"performance\",\r\n\t\t\t\"reinforcement\",\r\n\t\t\t\"open classroom\",\r\n\t\t\t\"resource\",\r\n\t\t\t\"structure\",\r\n\t\t\t\"facility\",\r\n\t\t\t\"environment\",\r\n\t\t},\r\n\t}\r\n\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\t// Display intro text\r\n\tfmt.Println(\"\\n           Buzzword Generator\")\r\n\tfmt.Println(\"Creative Computing  Morristown, New Jersey\")\r\n\tfmt.Println(\"\\n\\n\")\r\n\tfmt.Println(\"This program prints highly acceptable phrases in\")\r\n\tfmt.Println(\"'educator-speak' that you can work into reports\")\r\n\tfmt.Println(\"and speeches.  Whenever a question mark is printed,\")\r\n\tfmt.Println(\"type a 'Y' for another phrase or 'N' to quit.\")\r\n\tfmt.Println(\"\\n\\nHere's the first phrase:\")\r\n\r\n\tfor {\r\n\t\tphrase := \"\"\r\n\t\tfor _, section := range words {\r\n\t\t\tif len(phrase) > 0 {\r\n\t\t\t\tphrase += \" \"\r\n\t\t\t}\r\n\t\t\tphrase += section[rand.Intn(len(section))]\r\n\t\t}\r\n\t\tfmt.Println(phrase)\r\n\t\tfmt.Println()\r\n\r\n\t\t// continue?\r\n\t\tfmt.Println(\"?\")\r\n\t\tscanner.Scan()\r\n\t\tif strings.ToUpper(scanner.Text())[0:1] != \"Y\" {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\tfmt.Println(\"Come back when you need help with another report!\")\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/20_Buzzword/nim/buzzword.nim",
    "content": "import std/[random,strutils]\n\nrandomize()\n\nconst\n  words1 = [\"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\",\"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\n    \"HETEROGENEOUS\",\"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\",\"INDIVIDUALIZED\"]\n  words2 = [\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\",\"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\",\n    \"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\",\"MOTIVATIONAL\",\"CREATIVE\"]\n  words3 = [\"GROUPING\",\"MODIFICATION\",\"ACCOUNTABILITY\",\"PROCESS\",\"CORE CURRICULUM\",\"ALGORITHM\", \"PERFORMANCE\",\n    \"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\",\"STRUCTURE\",\"FACILITY\",\"ENVIRONMENT\"]\n\nvar\n  stillplaying: bool = true\n  prompt: string\n\necho spaces(26), \"BUZZWORD GENERATOR\"\necho spaces(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\necho \"\\n\"\necho \"THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\"\necho \"'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\"\necho \"AND SPEECHES.  AFTER EACH PHRASE, HIT 'ENTER' FOR\"\necho \"ANOTHER PHRASE, OR TYPE 'N' TO QUIT.\"\necho \"\\n\"\necho \"HERE'S THE FIRST PHRASE...\"\n\nwhile stillplaying:\n  echo \"\"\n  echo words1[rand(0..12)], \" \", words2[rand(0..12)], \" \", words3[rand(0..12)]\n  prompt = readLine(stdin).normalize()\n  if prompt.substr(0, 0) == \"n\":\n    stillplaying = false\n\necho \"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\"\n"
  },
  {
    "path": "00_Alternate_Languages/21_Calendar/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript calendar.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"calendar\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms",
    "content": "import \"stringUtil\"\n\nprint \" \"*32 + \"Calendar\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nstartingDOW = 0\nleapYear = false\n\n// Note: while the original program required changes to the code to configure\n// it for the current year, in this port we choose to ask the user.\n// Here's the function to do that.\ngetParameters = function\n\tdays = \"sunday monday tuesday wednesday thursday friday saturday\".split\n\tglobals.startingDOW = 999\n\twhile startingDOW == 999\n\t\tans = input(\"What is the first day of the week of the year? \").lower\n\t\tif not ans then continue\n\t\tfor i in days.indexes\n\t\t\tif days[i].startsWith(ans) then\n\t\t\t\tglobals.startingDOW = -i\n\t\t\t\tbreak\n\t\t\tend if\n\t\tend for\n\tend while\n\t\n\twhile true\n\t\tans = input(\"Is it a leap year? \").lower\n\t\tif ans and (ans[0] == \"y\" or ans[0] == \"n\") then break\n\tend while\n\tglobals.leapYear = (ans[0] == \"y\")\n\t\n\twhile true\n\t\tans = input(\"Pause after each month? \").lower\n\t\tif ans and (ans[0] == \"y\" or ans[0] == \"n\") then break\n\tend while\n\tglobals.pause = (ans[0] == \"y\")\nend function\n\ngetParameters\nmonthNames = [\n        \" JANUARY \",\n        \" FEBRUARY\",\n        \"  MARCH  \",\n        \"  APRIL  \",\n        \"   MAY   \",\n        \"   JUNE  \",\n        \"   JULY  \",\n        \"  AUGUST \",\n        \"SEPTEMBER\",\n        \" OCTOBER \",\n        \" NOVEMBER\",\n        \" DECEMBER\",\n    ]\nmonthDays = [31, 28 + leapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n\n// Function to print one month calendar.\n// month: numeric month number, 0-based (0-11)\nprintMonth = function(month)\n\tdaysSoFar = monthDays[:month].sum\n\tdaysLeft = monthDays[month:].sum\n\tprint \"** \" + str(daysSoFar).pad(4) + \"*\"*18 + \" \" + monthNames[month] +\n\t\t\" \" + \"*\"*18 + \" \" + str(daysLeft).pad(4) + \"**\"\n\tprint\n\tprint \"     S       M       T       W       T       F       S\"\n\tprint\n\tprint \"*\" * 61\n\t// calculate the day of the week, from 0=Sunday to 6=Saturday\n\tdow = (daysSoFar - startingDOW) % 7\n\tprint \" \" * 5 + \" \" * (8*dow), \"\"\n\tfor i in range(1, monthDays[month])\n\t\tprint str(i).pad(8), \"\"\n\t\tdow += 1\n\t\tif dow == 7 then\n\t\t\tdow = 0\n\t\t\tprint\n\t\t\tif i == monthDays[month] then break\n\t\t\tprint; print \" \" * 5, \"\"\n\t\tend if\n\tend for\n\tprint\nend function\n\n// Main loop.\nfor month in range(0, 11)\n\tprintMonth month\n\tprint\n\tif month < 11 and pause then input\nend for\n"
  },
  {
    "path": "00_Alternate_Languages/21_Calendar/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/21_Calendar/calendar.bas",
    "content": "10 PRINT TAB(32);\"CALENDAR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 REM     VALUES FOR 1979 - SEE NOTES\n110 DIM M(12)\n120 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n130 D=-1: REM 1979 STARTS ON MONDAY (0=SUN, -1=MON, -2=TUES...)\n140 S=0\n150 REM     READ DAYS OF EACH MONTH\n160 FOR N=0 TO 12: READ M(N): NEXT N\n170 REM\n180 FOR N=1 TO 12\n190 PRINT: PRINT: S=S+M(N-1)\n200 PRINT \"**\";S;TAB(7);\n210 FOR I=1 TO 18: PRINT \"*\";: NEXT I\n220 ON N GOTO 230,240,250,260,270,280,290,300,310,320,330,340\n230 PRINT \" JANUARY \";: GOTO 350\n240 PRINT \" FEBRUARY\";: GOTO 350\n250 PRINT \"  MARCH  \";: GOTO 350\n260 PRINT \"  APRIL  \";: GOTO 350\n270 PRINT \"   MAY   \";: GOTO 350\n280 PRINT \"   JUNE  \";: GOTO 350\n290 PRINT \"   JULY  \";: GOTO 350\n300 PRINT \"  AUGUST \";: GOTO 350\n310 PRINT \"SEPTEMBER\";: GOTO 350\n320 PRINT \" OCTOBER \";: GOTO 350\n330 PRINT \" NOVEMBER\";: GOTO 350\n340 PRINT \" DECEMBER\";\n350 FOR I=1 TO 18: PRINT \"*\";: NEXT I\n360 PRINT 365-S;\"**\";\n370 REM   366-S;     ON LEAP YEARS\n380 PRINT CHR$(10): PRINT \"     S       M       T       W\";\n390 PRINT \"       T       F       S\"\n400 PRINT\n410 FOR I=1 TO 59: PRINT \"*\";: NEXT I\n420 REM\n430 FOR W=1 TO 6\n440 PRINT CHR$(10)\n450 PRINT TAB(4)\n460 REM\n470 FOR G=1 TO 7\n480 D=D+1\n490 D2=D-S\n500 IF D2>M(N) THEN 580\n510 IF D2>0 THEN PRINT D2;\n520 PRINT TAB(4+8*G);\n530 NEXT G\n540 REM\n550 IF D2=M(N) THEN 590\n560 NEXT W\n570 REM\n580 D=D-G\n590 NEXT N\n600 REM\n610 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n620 DATA 0,31,28,31,30,31,30,31,31,30,31,30,31\n630 REM  0,31,29,  ..., ON LEAP YEARS\n640 END\n"
  },
  {
    "path": "00_Alternate_Languages/22_Change/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of change.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript change.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"change\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/22_Change/MiniScript/change.ms",
    "content": "print \" \"*33 + \"Change\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"I, your friendly microcomputer, will determine\"\nprint \"the correct change for items costing up to $100.\"\nprint; print\nwhile true\n\titemCost = input(\"Cost of item? \").val\n\tif itemCost == 0 then break\n\tpayment = input(\"Amount of payment? \").val\n\tchange = payment - itemCost\n\tif change < 0 then\n\t\tprint \"Sorry, you have short-changed me $\" + (itemCost - payment)\n\t\tcontinue\n\telse if change == 0 then\n\t\tprint \"Correct amount, thank you.\"\n\t\tcontinue\n\tend if\n\n\tprint \"Your change, $\" + change\n\n\tdollars = floor(change/10)\n\tif dollars then print dollars + \" ten dollar bill(s)\"\n\tchange -= dollars * 10\n\n\tfivers = floor(change/5)\n\tif fivers then print fivers + \" five dollar bill(s)\"\n\tchange -= fivers * 5\n\n\tones = floor(change)\n\tif ones then print ones + \" one dollar bill(s)\"\n\tchange -= ones\n\n\tchange *= 100\t\t// (now working in cents)\n\n\thalfs = floor(change / 50)\n\tif halfs then print halfs + \" one half dollar(s)\"\n\tchange -= halfs * 50\n\n\tquarters = floor(change / 25)\n\tif quarters then print quarters + \" quarter(s)\"\n\tchange -= quarters * 25\n\n\tdimes = floor(change / 10)\n\tif dimes then print dimes + \" dime(s)\"\n\tchange -= dimes * 10\n\n\tnickels = floor(change / 5)\n\tif nickels then print nickels + \" nickel(s)\"\n\tchange -= nickels * 5\n\n\tpennies = round(change)\n\tif pennies then print pennies + \" penny(s)\"\n\tprint \"Thank you, come again.\"\n\tprint; print\nend while"
  },
  {
    "path": "00_Alternate_Languages/22_Change/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/22_Change/change.bas",
    "content": "2 PRINT TAB(33);\"CHANGE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n5 PRINT:PRINT:PRINT\n6 PRINT \"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\"\n8 PRINT \"THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\"\n9 PRINT:PRINT\n10 PRINT \"COST OF ITEM\";:INPUT A:PRINT \"AMOUNT OF PAYMENT\";:INPUT P\n20 C=P-A:M=C:IF C<>0 THEN 90\n25 PRINT \"CORRECT AMOUNT, THANK YOU.\"\n30 GOTO 400\n90 IF C>0 THEN 120\n95 PRINT \"SORRY, YOU HAVE SHORT-CHANGED ME $\";A-P\n100 GOTO 10\n120 PRINT \"YOUR CHANGE, $\";C\n130 D=INT(C/10)\n140 IF D=0 THEN 155\n150 PRINT D;\"TEN DOLLAR BILL(S)\"\n155 C=M-(D*10)\n160 E=INT(C/5)\n170 IF E=0 THEN 185\n180 PRINT E;\"FIVE DOLLARS BILL(S)\"\n185 C=M-(D*10+E*5)\n190 F=INT(C)\n200 IF F=0 THEN 215\n210 PRINT F;\"ONE DOLLAR BILL(S)\"\n215 C=M-(D*10+E*5+F)\n220 C=C*100\n225 N=C\n230 G=INT(C/50)\n240 IF G=0 THEN 255\n250 PRINT G;\"ONE HALF DOLLAR(S)\"\n255 C=N-(G*50)\n260 H=INT(C/25)\n270 IF H=0 THEN 285\n280 PRINT H;\"QUARTER(S)\"\n285 C=N-(G*50+H*25)\n290 I=INT(C/10)\n300 IF I=0 THEN 315\n310 PRINT I;\"DIME(S)\"\n315 C=N-(G*50+H*25+I*10)\n320 J=INT(C/5)\n330 IF J=0 THEN 345\n340 PRINT J;\"NICKEL(S)\"\n345 C=N-(G*50+H*25+I*10+J*5)\n350 K=INT(C+.5)\n360 IF K=0 THEN 380\n370 PRINT K;\"PENNY(S)\"\n380 PRINT \"THANK YOU, COME AGAIN.\"\n390 PRINT:PRINT\n400 GOTO 10\n410 END\n"
  },
  {
    "path": "00_Alternate_Languages/22_Change/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n)\r\n\r\nfunc printWelcome() {\r\n\tfmt.Println(\"                 CHANGE\")\r\n\tfmt.Println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println(\"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\")\r\n\tfmt.Println(\"THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc computeChange(cost, payment float64) {\r\n\tchange := int(math.Round((payment - cost) * 100))\r\n\r\n\tif change == 0 {\r\n\t\tfmt.Println(\"\\nCORRECT AMOUNT, THANK YOU.\")\r\n\t\treturn\r\n\t}\r\n\r\n\tif change < 0 {\r\n\t\tfmt.Printf(\"\\nSORRY, YOU HAVE SHORT-CHANGED ME $%0.2f\\n\", float64(change)/-100.0)\r\n\t\tprint()\r\n\t\treturn\r\n\t}\r\n\r\n\tfmt.Printf(\"\\nYOUR CHANGE, $%0.2f:\\n\", float64(change)/100.0)\r\n\r\n\td := change / 1000\r\n\tif d > 0 {\r\n\t\tfmt.Printf(\"  %d TEN DOLLAR BILL(S)\\n\", d)\r\n\t\tchange -= d * 1000\r\n\t}\r\n\r\n\td = change / 500\r\n\tif d > 0 {\r\n\t\tfmt.Printf(\"  %d FIVE DOLLAR BILL(S)\\n\", d)\r\n\t\tchange -= d * 500\r\n\t}\r\n\r\n\td = change / 100\r\n\tif d > 0 {\r\n\t\tfmt.Printf(\"  %d ONE DOLLAR BILL(S)\\n\", d)\r\n\t\tchange -= d * 100\r\n\t}\r\n\r\n\td = change / 50\r\n\tif d > 0 {\r\n\t\tfmt.Println(\"  1 HALF DOLLAR\")\r\n\t\tchange -= d * 50\r\n\t}\r\n\r\n\td = change / 25\r\n\tif d > 0 {\r\n\t\tfmt.Printf(\"  %d QUARTER(S)\\n\", d)\r\n\t\tchange -= d * 25\r\n\t}\r\n\r\n\td = change / 10\r\n\tif d > 0 {\r\n\t\tfmt.Printf(\"  %d DIME(S)\\n\", d)\r\n\t\tchange -= d * 10\r\n\t}\r\n\r\n\td = change / 5\r\n\tif d > 0 {\r\n\t\tfmt.Printf(\"  %d NICKEL(S)\\n\", d)\r\n\t\tchange -= d * 5\r\n\t}\r\n\r\n\tif change > 0 {\r\n\t\tfmt.Printf(\"  %d PENNY(S)\\n\", change)\r\n\t}\r\n}\r\n\r\nfunc main() {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tprintWelcome()\r\n\r\n\tvar cost, payment float64\r\n\tvar err error\r\n\tfor {\r\n\t\tfmt.Println(\"COST OF ITEM?\")\r\n\t\tscanner.Scan()\r\n\t\tcost, err = strconv.ParseFloat(scanner.Text(), 64)\r\n\t\tif err != nil || cost < 0.0 {\r\n\t\t\tfmt.Println(\"INVALID INPUT. TRY AGAIN.\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\tbreak\r\n\t}\r\n\tfor {\r\n\t\tfmt.Println(\"\\nAMOUNT OF PAYMENT?\")\r\n\t\tscanner.Scan()\r\n\t\tpayment, err = strconv.ParseFloat(scanner.Text(), 64)\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"INVALID INPUT. TRY AGAIN.\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\tbreak\r\n\t}\r\n\r\n\tcomputeChange(cost, payment)\r\n\tfmt.Println()\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/23_Checkers/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript checkers.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"checkers\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms",
    "content": "print \" \"*32 + \"Checkers\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"This is the game of Checkers.  The computer is X,\"\nprint \"and you are O.  The computer will move first.\"\nprint \"Squares are referred to by a coordinate system.\"\nprint \"(0,0) is the lower left corner\"\nprint \"(0,7) is the upper left corner\"\nprint \"(7,0) is the lower right corner\"\nprint \"(7,7) is the upper right corner\"\nprint \"The computer will type '+TO' when you have another\"\nprint \"jump.  Type two negative numbers if you cannot jump.\"\nprint; print; print\n\ninput \"(Press Return.)\"; print\t\t// (give player a chance to read)\n\n// The board.  Pieces are represented by numeric values:\n//    - 0      =  empty square\n//    - -1,-2  =  computer (X) (-1 for regular piece, -2 for king)\n//    - 1,2    =  human (O)    (1 for regular piece, 2 for king)\n// Board is indexed by [x][y], so we have to initialize it sideways:\nboard = [\n\t[ 1,  0,  1,  0,  0,  0, -1,  0],\n\t[ 0,  1,  0,  0,  0, -1,  0, -1],\n\t[ 1,  0,  1,  0,  0,  0, -1,  0],\n\t[ 0,  1,  0,  0,  0, -1,  0, -1],\n\t[ 1,  0,  1,  0,  0,  0, -1,  0],\n\t[ 0,  1,  0,  0,  0, -1,  0, -1],\n\t[ 1,  0,  1,  0,  0,  0, -1,  0],\n\t[ 0,  1,  0,  0,  0, -1,  0, -1]]\n\n// Function to print the board\nprintBoard = function\t\n\tfor y in range(7, 0)\n\t\tfor x in range(0, 7)\n\t\t\t// We print by indexing with the board entry (-2 to 2) into a list\n\t\t\t// of possible representations.  Remember that in MiniScript, a\n\t\t\t// negative index counts from the end.\n\t\t\tprint [\". \", \"O \", \"O*\", \"X*\", \"X \"][board[x][y]], \"   \"\n\t\tend for\n\t\tprint; print\n\tend for\nend function\n\n// Function to get x,y coordinates from the player.\n// This is written to allow the two numbers to be \n// separated by any combination of ',' and ' '.\n// Returns input as [x,y].\ninputPosition = function(prompt, requiredPieceSign, allowCancel=false)\n\twhile true\n\t\tans = input(prompt + \"? \").replace(\",\", \" \").split\n\t\tif ans.len < 2 then\n\t\t\tprint \"Enter two coordinates, for example: 4 0\"\n\t\t\tcontinue\n\t\tend if\n\t\tx = val(ans[0])\n\t\ty = val(ans[-1])\n\t\tif x < 0 and y < 0 and allowCancel then\n\t\t\treturn [x, y]\n\t\telse if x < 0 or x > 7 or y < 0 or y > 7 then\n\t\t\tprint \"Coordinates must be in the range 0-7\"\n\t\telse if x%2 != y%2 then\n\t\t\tprint \"Invalid coordinates (both must be odd, or both even)\"\n\t\telse if sign(board[x][y]) != requiredPieceSign then\n\t\t\tprint \"Invalid coordinates\"\n\t\telse\n\t\t\treturn [x, y]\n\t\tend if\n\tend while\nend function\n\n// Evaluate a potential (computer) move.\nevalMove = function(fromX, fromY, toX, toY)\n\tscore = 0\n\t\n\t// +2 if it promotes this piece\n\tif toY == 0 and board[fromX][fromY] == -1 then score += 2\n\n\t// +5 if it jumps an opponent's piece\n\tif abs(fromY-toY) == 2 then score += 5\n\n\t// -2 if the piece is moving away from the top boundary\n\tif fromY == 7 then score -= 2\n\n\t// +1 for putting the piece against a vertical boundary\n\tif toX == 0 or toX == 7 then score += 1\n\n\t// check neighboring pieces of the target position\n\tfor c in [-1, 1]\n\t\tif toX+c < 0 or toX+c > 7 or toY-1 < 0 then continue\n\t\t// +1 for each adjacent friendly piece\n\t\tif board[toX+c][toY-1] < 0 then score += 1\n\n\t\t// -1 for each opponent piece that could now jump this one\n\t\tif toX-c >= 0 and toX-c <= 7 and toY+1 <= 7 and board[toX+c][toY-1] > 0 and (\n\t\t\tboard[toX-c][toY+1] == 0 or (toX-c == fromX and toY+1 == fromY)) then score -= 2\n\tend for\n\treturn score\nend function\n\n// Consider a possible (computer) move, including whether it's even valid.\n// Return it or the previous best, whichever is better.\nconsider = function(fromX, fromY, toX, toY, previousBest)\n\n\t// make sure it's within the bounds of the board\n\tif toX < 0 or toX > 7 or toY < 0 or toY > 7 then return previousBest\n\t\n\t// if it's an opponent's piece, consider jumping it instead\n\tdx = toX - fromX\n\tif board[toX][toY] > 0 and abs(dx) == 1 then\n\t\tdy = toY - fromY\n\t\treturn consider(fromX, fromY, fromX + dx*2, fromY + dy*2, previousBest)\n\tend if\n\t\n\t// if it's a jump, make sure it's over an opponent piece\n\tif abs(dx) == 2 then\n\t\tmidX = (fromX + toX)/2; midY = (fromY + toY)/2\n\t\tif board[midX][midY] < 1 then return previousBest\n\tend if\n\n\t// make sure the destination is empty\n\tif board[toX][toY] then return previousBest\n\t\t\n\t// all checks passed; score it, and return whichever is better\n\trating = evalMove(fromX, fromY, toX, toY)\n\tif not previousBest or rating > previousBest.rating then\n\t\tnewBest = {}\n\t\tnewBest.fromX = fromX; newBest.fromY = fromY\n\t\tnewBest.toX = toX; newBest.toY = toY\n\t\tnewBest.rating = rating\n\t\treturn newBest\n\telse\n\t\treturn previousBest\n\tend if\nend function\n\n// Do the computer's turn\ndoComputerTurn = function\n\t// For each square on the board containing one of my pieces, consider\n\t// possible moves and keep the best one so far.  Start with a step\n\t// size of 1 (ordinary move), but if we jump, then keep jumping.\n\tstepSize = 1\n\twhile true\n\t\tbestMove = null\n\t\tfor x in range(0, 7)\n\t\t\tfor y in range(0, 7)\n\t\t\t\tif board[x][y] >= 0 then continue\t// not my piece\n\t\t\t\tmove = {}\n\t\t\t\tmove.fromPos = [x,y]\n\t\t\t\n\t\t\t\t// Consider forward moves; if it's a king, also consider backward moves\n\t\t\t\tfor dx in [-stepSize, stepSize]\n\t\t\t\t\tmove.toPos = [dx, -stepSize]\n\t\t\t\t\tbestMove = consider(x, y, x+dx, y-stepSize, bestMove)\n\t\t\t\t\tif board[x][y] == -2 then bestMove = consider(x, y, x+dx, y+stepSize, bestMove)\n\t\t\t\tend for\n\t\t\tend for\n\t\tend for\n\t\n\t\tif not bestMove then\n\t\t\t// No valid move -- if step size is still 1, this means we \n\t\t\t// couldn't find ANY move on our turn, and we have lost.\n\t\t\t// Otherwise, we're done.\n\t\t\tif stepSize == 1 then\n\t\t\t\tglobals.gameOver = true\n\t\t\t\tglobals.winner = 1\n\t\t\tend if\n\t\t\tbreak\n\t\tend if\n\t\t\n\t\t// Do the move, and stop if we did not jump.\n\t\tif stepSize == 1 then\n\t\t\tprint \"From \" + bestMove.fromX + \" \" + bestMove.fromY, \"\"\n\t\tend if\n\t\tprint \" to \" + bestMove.toX + \" \" + bestMove.toY, \"\"\n\n\t\tmovePiece bestMove.fromX, bestMove.fromY, bestMove.toX, bestMove.toY\n\t\tif abs(bestMove.toX - bestMove.fromX) == 1 then break\n\t\tstepSize = 2\n\tend while\n\tprint\nend function\n\n// Move one piece (including captures and crowning\nmovePiece = function(fromX, fromY, toX, toY)\n\tpiece = board[fromX][fromY]\n\tboard[toX][toY] = piece\n\tboard[fromX][fromY] = 0\n\t// capture piece jumped over\n\tif abs(toX - fromX) == 2 then\n\t\tboard[(fromX+toX)/2][(fromY+toY)/2] = 0\n\tend if\n\t// crown (make into a king) a piece that reaches the back row\n\tif (toY == 7 and piece > 0) or (toY == 0 and piece < 0) then\n\t\tboard[toX][toY] = 2 * sign(piece)\n\tend if\nend function\n\n// Handle the player's move.\ndoPlayerTurn = function\n\tfromPos = inputPosition(\"From\", 1, true)\n\tfromX = fromPos[0]; fromY = fromPos[1]\n\tif fromX < 0 then\n\t\t// Player concedes the game.\n\t\tglobals.gameOver = true\n\t\tglobals.winner = -1\n\t\treturn\n\tend if\n\twhile true\n\t\ttoPos = inputPosition(\"To\", 0)\n\t\ttoX = toPos[0]; toY = toPos[1]\n\t\tdist = abs(toX - fromX)\n\t\tif dist <= 2 and abs(toY - fromY) == dist then break\n\tend while\n\twhile true\n\t\t// Make the move, and continue as long as we have a jump\n\t\tmovePiece fromX, fromY, toX, toY\n\t\tif dist != 2 then break\n\t\t\n\t\t// Prompt for another move, allowing a cancel (negative input).\n\t\tfromX = toX; fromY = toX\n\t\ttoPos = inputPosition(\"+To\", 0, true)\n\t\tif toPos[0] < 0 or toPos[1] < 0 then break\n\t\ttoX = toPos[0]; toY = toPos[1]\n\tend while\n\t// If piece has reached the end of the board, crown this piece\n\tif toY == 7 then board[toX][toY] = 2\nend function\n\n// Main loop.\ngameOver = false\nwhile not gameOver\n\tdoComputerTurn\n\tif gameOver then break\n\tprintBoard\n\tdoPlayerTurn\n\tif gameOver then break\n\tprintBoard\nend while\n\nprint\nif winner > 0 then print \"You win.\" else print \"I win.\"\n"
  },
  {
    "path": "00_Alternate_Languages/23_Checkers/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/23_Checkers/checkers.annotated.bas",
    "content": "     # Annotated version of CHECKERS.BAS, modified to improve readability.\n     #\n     # I've made the following changes:\n     #\n     #  1. Added many comments and blank lines.\n     #  2. Separated each statement into its own line.\n     #  3. Indented loops, conditionals and subroutines.\n     #  4. Turned *SOME* conditionals and loops into\n     #     structured-BASIC-style if/endif and loop/endloop blocks.\n     #  5. Switched to using '#' to delimit comments.\n     #  6. Subroutines now begin with \"Sub_Start\"\n     #  7. All non-string text has been converted to lower-case\n     #  8. All line numbers that are not jump destinations have been removed.\n     #\n     # This has helped me make sense of the code.  I hope it will also help you.\n     #\n\n     # Print the banner\n     print tab(32);\"CHECKERS\"\n     print tab(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n     print\n     print\n     print\n     print \"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\"\n     print \"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\"\n     print \"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\"\n     print \"(0,0) IS THE LOWER LEFT CORNER\"\n     print \"(0,7) IS THE UPPER LEFT CORNER\"\n     print \"(7,0) IS THE LOWER RIGHT CORNER\"\n     print \"(7,7) IS THE UPPER RIGHT CORNER\"\n     print \"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\"\n     print \"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\"\n     print\n     print\n     print\n\n     # Declare the \"globals\":\n\n     # The current move: (rating, current x, current y, new x, new y)\n     # 'rating' represents how good the move is; higher is better.\n     dim r(4)\n     r(0)=-99       # Start with minimum score\n\n     # The board.  Pieces are represented by numeric values:\n     #\n     #      - 0     = empty square\n     #      - -1,-2 = X (-1 for regular piece, -2 for king)\n     #      - 1,2   = O (1 for regular piece, 2 for king)\n     #\n     # This program's player (\"me\") plays X.\n     dim s(7,7)\n\n     g=-1           # constant holding -1\n\n     # Initialize the board.  Data is 2 length-wise strips repeated.\n     data 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15\n     for x=0 to 7\n       for y=0 to 7\n         read j\n         if j=15 then 180\n         s(x,y)=j\n         goto 200\n180      restore\n         read s(x,y)\n200  next y,x\n\n230  # Start of game loop.  First, my turn.\n\n     # For each square on the board, search for one of my pieces\n     # and if it can make the best move so far, store that move in 'r'\n     for x=0 to 7\n       for y=0 to 7\n\n         # Skip if this is empty or an opponent's piece\n         if s(x,y) > -1 then 350\n\n         # If this is one of my ordinary pieces, analyze possible\n         # forward moves.\n         if s(x,y) = -1 then\n           for a=-1 to 1 step 2\n             b=g\n             gosub 650\n           next a\n         endif\n\n         # If this is one of my kings, analyze possible forward\n         # and backward moves.\n         if s(x,y) = -2 then\n           for a=-1 to 1 step 2\n             for b=-1 to 1 step 2\n               gosub 650\n           next b,a\n         endif\n\n350  next y,x\n     goto 1140  # Skip the subs\n\n\n     # Analyze a move from (x,y) to (x+a, y+b) and schedule it if it's\n     # the best candidate so far.\n650  Sub_Start\n       u=x+a\n       v=y+b\n\n       # Done if it's off the board\n       if u<0 or u>7 or v<0 or v>7 then 870\n\n       # Consider the destination if it's empty\n       if s(u,v) = 0 then\n         gosub 910\n         goto 870\n       endif\n\n       # If it's got an opponent's piece, jump it instead\n       if s(u,v) > 0\n\n           # Restore u and v, then return if it's off the board\n           u=u+a\n           v=v+b\n           if u<0 or v<0 or u>7 or v>7 then 870\n\n           # Otherwise, consider u,v\n           if s(u,v)=0 then gosub 910\n       endif\n870  return\n\n     # Evaluate jumping (x,y) to (u,v).\n     #\n     # Computes a score for the proposed move and if it's higher\n     # than the best-so-far move, uses that instead by storing it\n     # and its score in array 'r'.\n910  Sub_Start\n\n       # q is the score; it starts at 0\n\n       # +2 if it promotes this piece\n       if v=0 and s(x,y)=-1 then q=q+2\n\n       # +5 if it takes an opponent's piece\n       if abs(y-v)=2 then q=q+5\n\n       # -2 if the piece is moving away from the top boundary\n       if y=7 then q=q-2\n\n       # +1 for putting the piece against a vertical boundary\n       if u=0 or u=7 then q=q+1\n\n       for c=-1 to 1 step 2\n         if u+c < 0 or u+c > 7 or v+g < 0 then 1080\n\n         # +1 for each adjacent friendly piece\n         if s(u+c, v+g) < 0 then\n           q=q+1\n           goto 1080\n         endif\n\n         # Prevent out-of-bounds testing\n         if u-c < 0 or u-c > 7 or v-g > 7 then 1080\n\n         # -2 for each opponent piece that can now take this piece here\n         if s(u+c,v+g) > 0 and(s(u-c,v-g)=0 or(u-c=x and v-g=y))then q=q-2\n1080   next c\n\n       # Use this move if it's better than the previous best\n       if q>r(0) then\n         r(0)=q\n         r(1)=x\n         r(2)=y\n         r(3)=u\n         r(4)=v\n       endif\n\n       q=0  # reset the score\n     return\n\n1140 if r(0)=-99 then 1880  # Game is lost if no move could be found.\n\n     # Print the computer's move.  (Note: chr$(30) is an ASCII RS\n     # (record separator) code; probably no longer relevant.)\n     print chr$(30)\"FROM\"r(1);r(2)\"TO\"r(3);r(4);\n     r(0)=-99\n\n     # Make the computer's move.  If the piece finds its way to the\n     # end of the board, crown it.\n1240 if r(4)=0 then\n       s(r(3),r(4))=-2\n       goto 1420\n     endif\n     s(r(3),r(4))=s(r(1),r(2))\n     s(r(1),r(2))=0\n\n     # If the piece has jumped 2 squares, it means the computer has\n     # taken an opponents' piece.\n     if abs(r(1)-r(3)) == 2 then\n       s((r(1)+r(3))/2,(r(2)+r(4))/2)=0     # Delete the opponent's piece\n\n       # See if we can jump again.  Evaluate all possible moves.\n       x=r(3)\n       y=r(4)\n       for a=-2 to 2 step 4\n         if s(x,y)=-1 then\n           b=-2\n           gosub 1370\n         endif\n         if s(x,y)=-2 then\n           for b=-2 to 2 step 4\n             gosub 1370\n           next b\n         endif\n       next a\n\n       # If we've found a move, go back and make that one as well\n       if r(0) <> -99 then\n         print \"TO\" r(3); r(4);\n         r(0)=-99\n         goto 1240\n       endif\n\n       goto 1420   # Skip the sub\n\n       # If (u,v) is in the bounds, evaluate it as a move using\n       # the sub at 910\n1370   Sub_Start\n         u=x+a\n         v=y+b\n         if u<0 or u>7 or v<0 or v>7 then 1400\n         if s(u,v)=0 and s(x+a/2,y+b/2)>0 then gosub 910\n1400   return\n\n1420 endif\n\n     # Now, print the board\n     print\n     print\n     print\n     for y=7 to 0 step-1\n       for x=0 to 7\n         i=5*x\n         print tab(i);\n         if s(x,y)=0 then print\".\";\n         if s(x,y)=1 then print\"O\";\n         if s(x,y)=-1 then print\"X\";\n         if s(x,y)=-2 then print\"X*\";\n         if s(x,y)=2 then print\"O*\";\n       next x\n       print\" \"\n       print\n     next y\n     print\n\n     # Check if either player is out of pieces.  If so, announce the\n     # winner.\n     for l=0 to 7\n       for m=0 to 7\n         if s(l,m)=1 or s(l,m)=2 then z=1\n         if s(l,m)=-1 or s(l,m)=-2 then t=1\n       next m\n     next l\n     if z<>1 then 1885\n     if t<>1 then 1880\n\n     # Prompt the player for their move.\n     z=0\n     t=0\n1590 input \"FROM\";e,h\n     x=e\n     y=h\n     if s(x,y)<=0 then 1590\n1670 input \"TO\";a,b\n     x=a\n     y=b\n     if s(x,y)=0 and abs(a-e)<=2 and abs(a-e)=abs(b-h)then 1700\n     print chr$(7)chr$(11);     # bell, vertical tab; invalid move\n     goto 1670\n\n1700 i=46       # Not used; probably a bug\n1750 loop\n       # Make the move and stop unless it might be a jump.\n       s(a,b) = s(e,h)\n       s(e,h) = 0\n       if abs(e-a) <> 2 then break\n\n       # Remove the piece jumped over\n       s((e+a)/2,(h+b)/2) = 0\n\n       # Prompt for another move; -1 means player can't, so I've won.\n       # Keep prompting until there's a valid move or the player gives\n       # up.\n1802   input \"+TO\";a1,b1\n       if a1 < 0 then break\n       if s(a1,b1) <> 0 or abs(a1-a) <>2  or abs(b1-b) <> 2 then 1802\n\n       # Update the move variables to correspond to the next jump\n       e=a\n       h=b\n       a=a1\n       b=b1\n\n       i=i+15   # Not used; probably a bug\n     endloop\n\n     # If the player has reached the end of the board, crown this piece\n1810 if b=7 then s(a,b)=2\n\n     # And play the next turn.\n     goto 230\n\n     # Endgame:\n1880 print\n     print \"YOU WIN.\"\n     end\n\n1885 print\n     print \"I WIN.\"\n     end\n"
  },
  {
    "path": "00_Alternate_Languages/23_Checkers/checkers.bas",
    "content": "5 PRINT TAB(32);\"CHECKERS\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n15 PRINT:PRINT:PRINT\n20 PRINT \"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\"\n25 PRINT \"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\"\n30 PRINT \"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\"\n35 PRINT \"(0,0) IS THE LOWER LEFT CORNER\"\n40 PRINT \"(0,7) IS THE UPPER LEFT CORNER\"\n45 PRINT \"(7,0) IS THE LOWER RIGHT CORNER\"\n50 PRINT \"(7,7) IS THE UPPER RIGHT CORNER\"\n55 PRINT \"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\"\n60 PRINT \"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\"\n65 PRINT:PRINT:PRINT\n80 DIM R(4),S(7,7):G=-1:R(0)=-99\n90 DATA 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15\n120 FOR X=0 TO 7:FOR Y=0 TO 7:READ J:IF J=15 THEN 180\n160 S(X,Y)=J:GOTO 200\n180 RESTORE:READ S(X,Y)\n200 NEXT Y,X\n230 FOR X=0 TO 7:FOR Y=0 TO 7:IF S(X,Y)>-1 THEN 350\n310 IF S(X,Y)=-1 THEN FOR A=-1 TO 1 STEP 2:B=G:GOSUB 650:NEXT A\n330 IF S(X,Y)=-2 THEN FOR A=-1 TO 1 STEP 2:FOR B=-1 TO 1 STEP 2:GOSUB 650:NEXT B,A\n350 NEXT Y,X:GOTO 1140\n650 U=X+A:V=Y+B:IF U<0 OR U>7 OR V<0 OR V>7 THEN 870\n740 IF S(U,V)=0 THEN GOSUB 910:GOTO 870\n770 IF S(U,V)<0 THEN 870\n790 U=U+A:V=V+B:IF U<0 OR V<0 OR U>7 OR V>7 THEN 870\n850 IF S(U,V)=0 THEN GOSUB 910\n870 RETURN\n910 IF V=0 AND S(X,Y)=-1 THEN Q=Q+2\n920 IF ABS(Y-V)=2 THEN Q=Q+5\n960 IF Y=7 THEN Q=Q-2\n980 IF U=0 OR U=7 THEN Q=Q+1\n1030 FOR C=-1 TO 1 STEP 2:IF U+C<0 OR U+C>7 OR V+G<0 THEN 1080\n1035 IF S(U+C,V+G)<0 THEN Q=Q+1:GOTO 1080\n1040 IF U-C<0 OR U-C>7 OR V-G>7 THEN 1080\n1045 IF S(U+C,V+G)>0 AND(S(U-C,V-G)=0 OR(U-C=X AND V-G=Y))THEN Q=Q-2\n1080 NEXT C:IF Q>R(0)THEN R(0)=Q:R(1)=X:R(2)=Y:R(3)=U:R(4)=V\n1100 Q=0:RETURN\n1140 IF R(0)=-99 THEN 1880\n1230 PRINT CHR$(30)\"FROM\"R(1);R(2)\"TO\"R(3);R(4);:R(0)=-99\n1240 IF R(4)=0 THEN S(R(3),R(4))=-2:GOTO 1420\n1250 S(R(3),R(4))=S(R(1),R(2))\n1310 S(R(1),R(2))=0:IF ABS(R(1)-R(3))<>2 THEN 1420\n1330 S((R(1)+R(3))/2,(R(2)+R(4))/2)=0\n1340 X=R(3):Y=R(4):IF S(X,Y)=-1 THEN B=-2:FOR A=-2 TO 2 STEP 4:GOSUB 1370\n1350 IF S(X,Y)=-2 THEN FOR A=-2 TO 2 STEP 4:FOR B=-2 TO 2 STEP 4:GOSUB 1370:NEXT B\n1360 NEXT A:IF R(0)<>-99 THEN PRINT\"TO\"R(3);R(4);:R(0)=-99:GOTO 1240\n1365 GOTO 1420\n1370 U=X+A:V=Y+B:IF U<0 OR U>7 OR V<0 OR V>7 THEN 1400\n1380 IF S(U,V)=0 AND S(X+A/2,Y+B/2)>0 THEN GOSUB 910\n1400 RETURN\n1420 PRINT:PRINT:PRINT:FOR Y=7 TO 0 STEP-1:FOR X=0 TO 7:I=5*X:PRINT TAB(I);\n1430 IF S(X,Y)=0 THEN PRINT\".\";\n1470 IF S(X,Y)=1 THEN PRINT\"O\";\n1490 IF S(X,Y)=-1 THEN PRINT\"X\";\n1510 IF S(X,Y)=-2 THEN PRINT\"X*\";\n1530 IF S(X,Y)=2 THEN PRINT\"O*\";\n1550 NEXT X:PRINT\" \":PRINT:NEXT Y:PRINT\n1552 FOR L=0 TO 7\n1554 FOR M=0 TO 7\n1556 IF S(L,M)=1 OR S(L,M)=2 THEN Z=1\n1558 IF S(L,M)=-1 OR S(L,M)=-2 THEN T=1\n1560 NEXT M\n1562 NEXT L\n1564 IF Z<>1 THEN 1885\n1566 IF T<>1 THEN 1880\n1570 Z=0: T=0\n1590 INPUT \"FROM\";E,H:X=E:Y=H:IF S(X,Y)<=0 THEN 1590\n1670 INPUT \"TO\";A,B:X=A:Y=B\n1680 IF S(X,Y)=0 AND ABS(A-E)<=2 AND ABS(A-E)=ABS(B-H)THEN 1700\n1690 PRINT CHR$(7)CHR$(11);:GOTO 1670\n1700 I=46\n1750 S(A,B)=S(E,H):S(E,H)=0:IF ABS(E-A)<>2 THEN 1810\n1800 S((E+A)/2,(H+B)/2)=0\n1802 INPUT \"+TO\";A1,B1:IF A1<0 THEN 1810\n1804 IF S(A1,B1)<>0 OR ABS(A1-A)<>2 OR ABS(B1-B)<>2 THEN 1802\n1806 E=A:H=B:A=A1:B=B1:I=I+15:GOTO 1750\n1810 IF B=7 THEN S(A,B)=2\n1830 GOTO 230\n1880 PRINT: PRINT \"YOU WIN.\": END\n1885 PRINT: PRINT \"I WIN.\": END\n"
  },
  {
    "path": "00_Alternate_Languages/24_Chemist/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of chemist.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript chemist.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"chemist\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms",
    "content": "print \" \"*33 + \"Chemist\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"The fictitious chemical kryptocyanic acid can only be\"\nprint \"diluted by the ratio of 7 parts water to 3 parts acid.\"\nprint \"If any other ratio is attempted, the acid becomes unstable\"\nprint \"and soon explodes.  Given the amount of acid, you must\"\nprint \"decide how much water to add for dilution.  If you miss\"\nprint \"you face the consequences.\"\n\ndeaths = 0\nwhile deaths < 9\n\tacid = floor(rnd * 50)\n\twater = 7 * acid/3\n\tresponse = input(acid +\" liters of kryptocyanic acid.  How much water? \").val\n\tdiff = abs(water - response)\n\tif diff > water/20 then\n\t\tprint \" SIZZLE!  You have just been desalinated into a blob\"\n\t\tprint \" of quivering protoplasm!\"\n\t\tdeaths += 1\n\t\tif deaths < 9 then\n\t\t\tprint \" However, you may try again with another life.\"\n\t\tend if\n\telse\n\t\tprint \" Good job! You may breathe now, but don't inhale the fumes!\"\n\t\tprint\n\tend if\nend while\nprint \" Your 9 lives are used, but you will be long remembered for\"\nprint \" your contributions to the field of comic book chemistry.\"\n"
  },
  {
    "path": "00_Alternate_Languages/24_Chemist/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/24_Chemist/chemist.bas",
    "content": "3 PRINT TAB(33);\"CHEMIST\"\n6 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n8 PRINT:PRINT:PRINT\n10 PRINT \"THE FICTITIOUS CHEMICAL KRYPTOCYANIC ACID CAN ONLY BE\"\n20 PRINT \"DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\"\n30 PRINT \"IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\"\n40 PRINT \"AND SOON EXPLODES.  GIVEN THE AMOUNT OF ACID, YOU MUST\"\n50 PRINT \"DECIDE WHO MUCH WATER TO ADD FOR DILUTION.  IF YOU MISS\"\n60 PRINT \"YOU FACE THE CONSEQUENCES.\"\n100 A=INT(RND(1)*50)\n110 W=7*A/3\n120 PRINT A;\"LITERS OF KRYPTOCYANIC ACID.  HOW MUCH WATER\";\n130 INPUT R\n140 D=ABS(W-R)\n150 IF D>W/20 THEN 200\n160 PRINT \" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\"\n170 PRINT\n180 GOTO 100\n200 PRINT \" SIZZLE!  YOU HAVE JUST BEEN DESALINATED INTO A BLOB\"\n210 PRINT \" OF QUIVERING PROTOPLASM!\"\n220 T=T+1\n230 IF T=9 THEN 260\n240 PRINT \" HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\"\n250 GOTO 100\n260 PRINT \" YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\"\n270 PRINT \" YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\"\n280 END\n"
  },
  {
    "path": "00_Alternate_Languages/25_Chief/C/chief.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n\n//check if windows or linux for the clear screen\n#ifdef _WIN32\n#define CLEAR \"cls\"\n#else\n#define CLEAR \"clear\"\n#endif\n\nvoid show_solution(float guess);\nfloat guess_number(float number);\nvoid game();\n\nfloat guess_number(float number){\n    float guess;\n    guess = ((((number - 4) * 5) / 8) * 5 - 3);\n    return guess;\n}\n\nvoid game(){\n    float number,guess;\n    char answer[4];\n    printf(\"Think a number\\n\");\n    printf(\"Then add to it 3 and divide it by 5\\n\");\n    printf(\"Now multiply by 8, divide by 5 and then add 5\\n\");\n    printf(\"Finally substract 1\\n\");\n    printf(\"What is the number you got?(if you got decimals put them ex: 23.6): \");\n    scanf(\"%f\",&number);\n    guess = guess_number(number);\n    printf(\"The number you thought was %f am I right(Yes or No)?\\n\",guess);\n    scanf(\"%s\",answer);\n    for(int i = 0; i < strlen(answer); i++){\n        answer[i] = tolower(answer[i]);\n    }\n    if(strcmp(answer,\"yes\") == 0){\n        printf(\"\\nHuh, I Knew I was unbeatable\");\n        printf(\"And here is how i did it:\\n\");\n        show_solution(guess);\n    }\n    else if (strcmp(answer,\"no\") == 0){\n        printf(\"HUH!! what was you original number?: \");\n        scanf(\"%f\",&number);\n        if(number == guess){\n            printf(\"Huh, I Knew I was unbeatable\");\n            printf(\"And here is how i did it:\\n\");\n            show_solution(guess);\n        }\n        else{\n            printf(\"If I got it wrong I guess you are smarter than me\");\n        }\n    }\n    else{\n        system(CLEAR);\n        printf(\"I don't understand what you said\\n\");\n        printf(\"Please answer with Yes or No\\n\");\n        game();\n    }\n\n}\n\nvoid show_solution(float guess){\n    printf(\"%f plus 3 is %f\\n\",guess,guess + 3);\n    printf(\"%f divided by 5 is %f\\n\",guess + 3,(guess + 3) / 5);\n    printf(\"%f multiplied by 8 is %f\\n\",(guess + 3) / 5,(guess + 3) / 5 * 8);\n    printf(\"%f divided by 5 is %f\\n\",(guess + 3) / 5 * 8,(guess + 3) / 5 * 8 / 5);\n    printf(\"%f plus 5 is %f\\n\",(guess + 3) / 5 * 8 / 5,(guess + 3) / 5 * 8 / 5 + 5);\n    printf(\"%f minus 1 is %f\\n\",(guess + 3) / 5 * 8 / 5 + 5,(guess + 3) / 5 * 8 / 5 + 5 - 1);\n}\n\nvoid main(){\n    char answer[4];\n    printf(\"I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.\\n\");\n    printf(\"Are you ready to take the test you called me out for(Yes or No)? \");\n    scanf(\"%s\",answer);\n    for(int i = 0; i < strlen(answer); i++){\n        answer[i] = tolower(answer[i]);\n    }\n    if(strcmp(answer,\"yes\") == 0){\n        game();\n    }else if (strcmp(answer,\"no\") == 0){\n        printf(\"You are a coward, I will not play with you.%d %s\\n\",strcmp(answer,\"yes\"),answer);\n    }\n    else{\n        system(CLEAR);\n        printf(\"I don't understand what you said\\n\");\n        printf(\"Please answer with Yes or No\\n\");\n        main();\n    }\n}"
  },
  {
    "path": "00_Alternate_Languages/25_Chief/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nNOTE: I have added `wait` statements before and while printing the lightning bolt, without which it appears too quickly to be properly dramatic.\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of chief.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript chief.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"chief\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/25_Chief/MiniScript/chief.ms",
    "content": "print \" \"*30 + \"Chief\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"I am chief Numbers Freek, the great Indian math god.\"\nyn = input(\"Are you ready to take the test you called me out for? \").lower\nif not yn or yn[0] != \"y\" then\n\tprint \"Shut up, pale face with wise tongue.\"\nend if\nprint \" Take a number and add 3.  Divide this number by 5 and\"\nprint \"multiply by 8. Divide by 5 and add the same. Subtract 1.\"\nb = input(\"  What do you have? \").val\nc = (b+1-5)*5/8*5-3\nyn = input(\"I bet your number was \" + c + \". Am I right? \").lower\nif yn and yn[0] == \"y\" then\n\tprint \"Bye!!!\"\nelse\n\tk = input(\"What was your original number? \").val\n\tf=k+3\n\tg=f/5\n\th=g*8\n\ti=h/5+5\n\tj=i-1\n\tprint \"So you think you're so smart, eh?\"\n\tprint \"Now watch.\"\n\tprint k + \" plus 3 equals \" + f +\". This divided by 5 equals \" + g + \";\"\n\tprint \"this times 8 equals \" + h + \". If we divide by 5 and add 5,\"\n\tprint \"we get \" + i + \", which, minus 1, equals \" + j + \".\"\n\tyn = input(\"Now do you believe me? \").lower\n\tif yn and yn[0] == \"y\" then\n\t\tprint \"Bye!!!\"\n\telse\n\t\tprint \"You have made me mad!!!\"\n\t\tprint \"There must be a great lightning bolt!\"\n\t\tprint; print; wait 2\n\t\tfor x in range(30, 22)\n\t\t\tprint \" \"*x + \"x x\"; wait 0.1\n\t\tend for\n\t\tprint \" \"*21 + \"x xxx\"; wait 0.1\n\t\tprint \" \"*20 + \"x   x\"; wait 0.1\n\t\tprint \" \"*19 + \"xx x\"; wait 0.1\n\t\tfor y in range(20, 13)\n\t\t\tprint \" \"*y + \"x x\"; wait 0.1\n\t\tend for\n\t\tprint \" \"*12 + \"xx\"; wait 0.1\n\t\tprint \" \"*11 + \"x\"; wait 0.1\n\t\tprint \" \"*10 + \"*\"; wait 0.1\n\t\tprint; print\"#########################\"; print\n\t\tprint \"I hope you believe me now, for your sake!!\"\n\tend if\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/25_Chief/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/25_Chief/chief.bas",
    "content": "2 PRINT TAB(30) \"CHIEF\"\n4 PRINT TAB(15) \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 PRINT \"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\"\n20 PRINT \"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR\";\n30 INPUT A$\n40 IF A$=\"YES\" THEN 60\n50 PRINT \"SHUT UP, PALE FACE WITH WISE TONGUE.\"\n60 PRINT \" TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\"\n70 PRINT \"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\"\n80 PRINT \"  WHAT DO YOU HAVE\";\n90 INPUT B\n100 LET C = (B+1-5)*5/8*5-3\n110 PRINT \"I BET YOUR NUMBER WAS\" C\". AM I RIGHT\";\n120 INPUT D$\n130 IF D$=\"YES\" THEN 500\n140 PRINT \"WHAT WAS YOUR ORIGINAL NUMBER\";\n150 INPUT K\n155 LET F=K+3\n160 LET G=F/5\n170 LET H=G*8\n180 LET I=H/5+5\n190 LET J=I-1\n200 PRINT \"SO YOU THINK YOU'RE SO SMART, EH?\"\n210 PRINT \"NOW WATCH.\"\n230 PRINT K\"PLUS 3 EQUALS\"F\". THIS DIVIDED BY 5 EQUALS\"G\";\"\n240 PRINT \"THIS TIMES 8 EQUALS\"H\". IF WE DIVIDE BY 5 AND ADD 5,\"\n250 PRINT \"WE GET\"I\", WHICH, MINUS 1, EQUALS\"J\".\"\n260 PRINT \"NOW DO YOU BELIEVE ME\";\n270 INPUT Z$\n290 IF Z$=\"YES\" THEN 500\n295 PRINT \"YOU HAVE MADE ME MAD!!!\"\n300 PRINT \"THERE MUST BE A GREAT LIGHTNING BOLT!\"\n310 PRINT:PRINT\n330 FOR X=30 TO 22 STEP -1\n340 PRINT TAB(X) \"X X\"\n350 NEXT X\n360 PRINT TAB(21) \"X XXX\"\n370 PRINT TAB(20) \"X   X\"\n380 PRINT TAB(19) \"XX X\"\n390 FOR Y=20 TO 13 STEP -1\n400 PRINT TAB(Y) \"X X\"\n410 NEXT Y\n420 PRINT TAB(12) \"XX\"\n430 PRINT TAB(11) \"X\"\n440 PRINT TAB(10) \"*\"\n450 PRINT:PRINT\"#########################\":PRINT\n470 PRINT \"I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\"\n480 GOTO 520\n500 PRINT \"BYE!!!\"\n520 END\n"
  },
  {
    "path": "00_Alternate_Languages/25_Chief/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n)\r\n\r\nfunc printLightning() {\r\n\tfmt.Println(\"************************************\")\r\n\tn := 24\r\n\tfor n > 16 {\r\n\t\tvar b strings.Builder\r\n\t\tb.Grow(n + 3)\r\n\t\tfor i := 0; i < n; i++ {\r\n\t\t\tb.WriteString(\" \")\r\n\t\t}\r\n\t\tb.WriteString(\"x x\")\r\n\t\tfmt.Println(b.String())\r\n\t\tn--\r\n\t}\r\n\tfmt.Println(\"                x xxx\")\r\n\tfmt.Println(\"               x   x\")\r\n\tfmt.Println(\"              xx xx\")\r\n\tn--\r\n\tfor n > 8 {\r\n\t\tvar b strings.Builder\r\n\t\tb.Grow(n + 3)\r\n\t\tfor i := 0; i < n; i++ {\r\n\t\t\tb.WriteString(\" \")\r\n\t\t}\r\n\t\tb.WriteString(\"x x\")\r\n\t\tfmt.Println(b.String())\r\n\t\tn--\r\n\t}\r\n\tfmt.Println(\"        xx\")\r\n\tfmt.Println(\"       x\")\r\n\tfmt.Println(\"************************************\")\r\n}\r\n\r\nfunc printSolution(n float64) {\r\n\tfmt.Printf(\"\\n%f plus 3 gives %f. This divided by 5 equals %f\\n\", n, n+3, (n+3)/5)\r\n\tfmt.Printf(\"This times 8 gives %f. If we divide 5 and add 5.\\n\", ((n+3)/5)*8)\r\n\tfmt.Printf(\"We get %f, which, minus 1 equals %f\\n\", (((n+3)/5)*8)/5+5, ((((n+3)/5)*8)/5+5)-1)\r\n}\r\n\r\nfunc play() {\r\n\tfmt.Println(\"\\nTake a Number and ADD 3. Now, Divide this number by 5 and\")\r\n\tfmt.Println(\"multiply by 8. Now, Divide by 5 and add the same. Subtract 1\")\r\n\r\n\tyouHave := getFloat(\"\\nWhat do you have?\")\r\n\tcompGuess := (((youHave-4)*5)/8)*5 - 3\r\n\tif getYesNo(fmt.Sprintf(\"\\nI bet your number was %f was I right(Yes or No)? \", compGuess)) {\r\n\t\tfmt.Println(\"\\nHuh, I knew I was unbeatable\")\r\n\t\tfmt.Println(\"And here is how i did it\")\r\n\t\tprintSolution(compGuess)\r\n\t} else {\r\n\t\toriginalNumber := getFloat(\"\\nHUH!! what was you original number? \")\r\n\t\tif originalNumber == compGuess {\r\n\t\t\tfmt.Println(\"\\nThat was my guess, AHA i was right\")\r\n\t\t\tfmt.Println(\"Shamed to accept defeat i guess, don't worry you can master mathematics too\")\r\n\t\t\tfmt.Println(\"Here is how i did it\")\r\n\t\t\tprintSolution(compGuess)\r\n\t\t} else {\r\n\t\t\tfmt.Println(\"\\nSo you think you're so smart, EH?\")\r\n\t\t\tfmt.Println(\"Now, Watch\")\r\n\t\t\tprintSolution(originalNumber)\r\n\r\n\t\t\tif getYesNo(\"\\nNow do you believe me? \") {\r\n\t\t\t\tprint(\"\\nOk, Lets play again sometime bye!!!!\")\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Println(\"\\nYOU HAVE MADE ME VERY MAD!!!!!\")\r\n\t\t\t\tfmt.Println(\"BY THE WRATH OF THE MATHEMATICS AND THE RAGE OF THE GODS\")\r\n\t\t\t\tfmt.Println(\"THERE SHALL BE LIGHTNING!!!!!!!\")\r\n\t\t\t\tprintLightning()\r\n\t\t\t\tfmt.Println(\"\\nI Hope you believe me now, for your own sake\")\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc getFloat(prompt string) float64 {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(prompt)\r\n\t\tscanner.Scan()\r\n\t\tval, err := strconv.ParseFloat(scanner.Text(), 64)\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"INVALID INPUT, TRY AGAIN\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\treturn val\r\n\t}\r\n}\r\n\r\nfunc getYesNo(prompt string) bool {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfmt.Println(prompt)\r\n\tscanner.Scan()\r\n\r\n\treturn (strings.ToUpper(scanner.Text())[0:1] == \"Y\")\r\n\r\n}\r\n\r\nfunc main() {\r\n\tfmt.Println(\"I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.\")\r\n\r\n\tif getYesNo(\"\\nAre you ready to take the test you called me out for(Yes or No)? \") {\r\n\t\tplay()\r\n\t} else {\r\n\t\tfmt.Println(\"Ok, Nevermind. Let me go back to my great slumber, Bye\")\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/26_Chomp/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript chomp.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"chomp\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms",
    "content": "print \" \"*33 + \"Chomp\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n// *** THE GAME OF CHOMP *** COPYRIGHT PCC 1973 ***\n\ninitBoard = function(rows, columns)\n\tglobals.rows = rows\n\tglobals.columns = columns\n\tglobals.board = [[null]]\t\t// indexed as [row][column], 1-based\n\tfor i in range(1, rows)\n\t\tboard.push [\".\"] + [\"*\"] * columns\n\tend for\n\tboard[1][1] = \"P\"\nend function\n\nprintBoard = function\n\tprint\n\tprint \" \"*7 + \"1 2 3 4 5 6 7 8 9\"\n\tfor i in range(1, rows)\n\t\tprint i + \" \"*6 + board[i][1:].join\n\tend for\n\tprint\nend function\t\n\nintroduction = function\n\tprint\n\tprint \"This is the game of chomp (Scientific American, Jan 1973)\"\n\tr = input(\"Do you want the rules (1=yes, 0=no!)? \").val\n\tif r == 0 then return\n\tprint \"Chomp is for 1 or more players (humans only).\"\n\tprint\n\tprint \"Here's how a board looks (this one is 5 by 7):\"\n\tinitBoard 5, 7\n\tprintBoard \n\tprint\n\tprint \"The board is a big cookie - R rows high and C columns\"\n\tprint \"wide. You input R and C at the start. In the upper left\"\n\tprint \"corner of the cookie is a poison square (P). The one who\"\n\tprint \"chomps the poison square loses. To take a chomp, type the\"\n\tprint \"row and column of one of the squares on the cookie.\"\n\tprint \"All of the squares below and to the right of that square\"\n\tprint \"(including that square, too) disappear -- chomp!!\"\n\tprint \"No fair chomping squares that have already been chomped,\"\n\tprint \"or that are outside the original dimensions of the cookie.\"\n\tprint\nend function\n\nsetup = function\t\n\tprint\n\tglobals.numPlayers = input(\"How many players? \").val\n\trows = input(\"How many rows? \").val\n\twhile rows > 9\n\t\trows = input(\"Too many rows (9 is maximum). Now, how many rows? \").val\n\tend while\n\tcolumns = input(\"How many columns? \").val\n\twhile rows > 9\n\t\tcolumns = input(\"Too many columns (9 is maximum). Now, how many columns? \").val\n\tend while\n\tprint\n\tinitBoard rows, columns\nend function\n\ndoOneTurn = function(player)\n\tprintBoard\n\tprint \"Player \" + player\n\twhile true\n\t\tinp = input(\"Coordinates of chomp (row,column)? \")\n\t\tinp = inp.replace(\",\", \" \").split\n\t\tif inp.len < 2 then continue\n\t\tr = inp[0].val\n\t\tc = inp[-1].val\n\t\tif 1 <= r <= rows and 1 <= c <= columns and board[r][c] != \" \" then break\n\t\tprint \"No fair. You're trying to chomp on empty space!\"\n\tend while\n\tif board[r][c] == \"P\" then\n\t\tprint \"You lose, player \" + player\n\t\tglobals.gameOver = true\n\telse\n\t\n\tend if\n\tfor row in range(r, rows)\n\t\tfor col in range(c, columns)\n\t\t\tboard[row][col] = \" \"\n\t\tend for\n\tend for\nend function\n\n// Main program\nintroduction\nwhile true\n\tsetup\n\tgameOver = false\n\tplayer = 0\n\twhile not gameOver\n\t\tplayer += 1\n\t\tif player > numPlayers then player = 1\n\t\tdoOneTurn player\n\tend while\n\tprint\n\tr = input(\"Again (1=yes, 0=no!)? \").val\n\tif r != 1 then break\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/26_Chomp/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/26_Chomp/chomp.bas",
    "content": "10 PRINT TAB(33);\"CHOMP\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 DIM A(10,10)\n100 REM *** THE GAME OF CHOMP *** COPYRIGHT PCC 1973 ***\n110 PRINT\n120 PRINT \"THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\"\n130 PRINT \"DO YOU WANT THE RULES (1=YES, 0=NO!)\";\n140 INPUT R\n150 IF R=0 THEN 340\n160 F=1\n170 R=5\n180 C=7\n190 PRINT \"CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\"\n200 PRINT\n210 PRINT \"HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\"\n220 GOSUB 540\n230 PRINT\n240 PRINT \"THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\"\n250 PRINT \"WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\"\n260 PRINT \"CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\"\n270 PRINT \"CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\"\n280 PRINT \"ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\"\n290 PRINT \"ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\"\n300 PRINT \"(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\"\n310 PRINT \"NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\"\n320 PRINT \"OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\"\n330 PRINT\n340 PRINT \"HERE WE GO...\"\n350 REM\n360 F=0\n370 FOR I=1 TO 10\n372 FOR J=1 TO 10\n375 A(I,J)=0\n377 NEXT J\n379 NEXT I\n380 PRINT\n390 PRINT \"HOW MANY PLAYERS\";\n400 INPUT P\n410 I1=0\n420 PRINT \"HOW MANY ROWS\";\n430 INPUT R\n440 IF R <= 9 THEN 470\n450 PRINT \"TOO MANY ROWS (9 IS MAXIMUM). NOW, \";\n460 GOTO 420\n470 PRINT \"HOW MANY COLUMNS\";\n480 INPUT C\n490 IF C <= 9 THEN 530\n500 PRINT \"TOO MANY COLUMNS (9 IS MAXIMUM). NOW, \";\n510 GOTO 470\n530 PRINT\n540 FOR I=1 TO R\n550 FOR J=1 TO C\n560 A(I,J)=1\n570 NEXT J\n580 NEXT I\n590 A(1,1)=-1\n600 REM PRINT THE BOARD\n610 PRINT\n620 PRINT TAB(7);\"1 2 3 4 5 6 7 8 9\"\n630 FOR I=1 TO R\n640 PRINT I;TAB(7);\n650 FOR J=1 TO C\n660 IF A(I,J)=-1 THEN 700\n670 IF A(I,J)=0 THEN 720\n680 PRINT \"* \";\n690 GOTO 710\n700 PRINT \"P \";\n710 NEXT J\n720 PRINT\n730 NEXT I\n740 PRINT\n750 IF F=0 THEN 770\n760 RETURN\n770 REM GET CHOMPS FOR EACH PLAYER IN TURN\n780 LET I1=I1+1\n790 LET P1=I1-INT(I1/P)*P\n800 IF P1 <> 0 THEN 820\n810 P1=P\n820 PRINT \"PLAYER\";P1\n830 PRINT \"COORDINATES OF CHOMP (ROW,COLUMN)\";\n840 INPUT R1,C1\n850 IF R1<1 THEN 920\n860 IF R1>R THEN 920\n870 IF C1<1 THEN 920\n880 IF C1>C THEN 920\n890 IF A(R1,C1)=0 THEN 920\n900 IF A(R1,C1)=-1 THEN 1010\n910 GOTO 940\n920 PRINT \"NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\"\n930 GOTO 820\n940 FOR I=R1 TO R\n950 FOR J=C1 TO C\n960 A(I,J)=0\n970 NEXT J\n980 NEXT I\n990 GOTO 610\n1000 REM END OF GAME DETECTED IN LINE 900\n1010 PRINT \"YOU LOSE, PLAYER\";P1\n1020 PRINT\n1030 PRINT \"AGAIN (1=YES, 0=NO!)\";\n1040 INPUT R\n1050 IF R=1 THEN 340\n1060 END\n"
  },
  {
    "path": "00_Alternate_Languages/27_Civil_War/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript civilwar.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"civilwar\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms",
    "content": "print \" \"*26 + \"Civil War\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n// ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S.\n// MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973\n// Conversion to MiniScript: J. Strout, 2023\n\nsides = [\"Confederate\", \"Union\"]\n\ngetYesNo = function(prompt)\n\twhile true\n\t\tyn = input(prompt + \"? \").lower\n\t\tif yn and yn[0] == \"y\" then return \"YES\"\n\t\tif yn and yn[0] == \"n\" then return \"NO\"\n\t\tprint \"Yes or no -- \"\n\tend while\nend function\n\ninstructions = function\n\tprint; print; print; print\n\tprint \"This is a civil war simulation.\"\n\tprint \"To play type a response when the computer asks.\"\n\tprint \"Remember that all factors are interrelated and that your\"\n\tprint \"responses could change history. Facts and figures used are\"\n\tprint \"based on the actual occurrence. Most battles tend to result\"\n\tprint \"as they did in the civil war, but it all depends on you!!\"\n\tprint\n\tprint \"The object of the game is to win as many battles as \";\n\tprint \"possible.\"\n\tprint\n\tprint \"Your choices for defensive strategy are:\"\n\tprint \"        (1) artillery attack\"\n\tprint \"        (2) fortification against frontal attack\"\n\tprint \"        (3) fortification against flanking maneuvers\"\n\tprint \"        (4) falling back\"\n\tprint \" Your choices for offensive strategy are:\"\n\tprint \"        (1) artillery attack\"\n\tprint \"        (2) frontal attack\"\n\tprint \"        (3) flanking maneuvers\"\n\tprint \"        (4) encirclement\"\n\tprint \"You may surrender by typing a '5' for your strategy.\"\nend function\n\nhistoricalBattles = []\naddBattle = function(name, men0, men1, cas0, cas1, offDef, desc)\n\tbattle = {}\n\tbattle.name = name\n\tbattle.men = [men0, men1]\n\tbattle.casualties = [cas0, cas1]\n\tbattle.offDef = offDef\t\t// 1=Confederate Defense, 2=both Offense, 3=Confederate Offense\n\tbattle.description = desc\n\thistoricalBattles.push battle\nend function\n\nloadData = function\n\t// Historical data\n\taddBattle \"Bull Run\",18000,18500,1967,2708,1, [\n\"July 21, 1861.  Gen. Beauregard, commanding the South, met\",\n\"Union forces with Gen. Mcdowell in a premature battle at\",\n\"Bull Run. Gen. Jackson helped push back the Union attack.\"]\n\n\taddBattle \"Shiloh\",40000.,44894.,10699,13047,3, [\n\"April 6-7, 1862.  The Confederate surprise attack at\",\n\"Shiloh failed due to poor organization.\"]\n\n\taddBattle \"Seven Days\",95000.,115000.,20614,15849,3, [\n\"June 25-july 1, 1862.  General Lee (CSA) upheld the\",\n\"offensive throughout the battle and forced Gen. McClellan\",\n\"and the Union forces away from Richmond.\"]\n\n\taddBattle \"Second Bull Run\",54000.,63000.,10000,14000,2, [\n\"Aug 29-30, 1862.  The combined Confederate forces under Lee\",\n\"and Jackson drove the Union forces back into washington.\"]\n\n\taddBattle \"Antietam\",40000.,50000.,10000,12000,3, [\n\"Sept 17, 1862.  The South failed to incorporate Maryland\",\n\"into the Confederacy.\"]\n\n\taddBattle \"Fredericksburg\",75000.,120000.,5377,12653,1, [\n\"Dec 13, 1862.  The Confederacy under Lee successfully\",\n\"repulsed an attack by the Union under Gen. Burnside.\"]\n\n\taddBattle \"Murfreesboro\",38000.,45000.,11000,12000,1, [\n\"Dec 31, 1862.  The South under Gen. Bragg won a close battle.\"]\n\n\taddBattle \"Chancellorsville\",32000,90000.,13000,17197,2, [\n\"May 1-6, 1863.  The South had a costly victory and lost\",\n\"one of their outstanding generals, 'Stonewall' Jackson.\"]\n\n\taddBattle \"Vicksburg\",50000.,70000.,12000,19000,1, [\n\"July 4, 1863.  Vicksburg was a costly defeat for the South\",\n\"because it gave the Union access to the Mississippi.\"]\n\n\taddBattle \"Gettysburg\",72500.,85000.,20000,23000,3, [\n\"July 1-3, 1863.  A Southern mistake by Gen. Lee at Gettysburg\",\n\"cost them one of the most crucial battles of the war.\"]\n\n\taddBattle \"Chickamauga\",66000.,60000.,18000,16000,2, [\n\"Sept. 15, 1863. Confusion in a forest near Chickamauga led\",\n\"to a costly Southern victory.\"]\n\n\taddBattle \"Chattanooga\",37000.,60000.,36700.,5800,2, [\n\"Nov. 25, 1863. After the South had sieged Gen. Rosencrans'\",\n\"army for three months, Gen. Grant broke the siege.\"]\n\n\taddBattle \"Spotsylvania\",62000.,110000.,17723,18000,2, [\n\"May 5, 1864.  Grant's plan to keep Lee isolated began to\",\n\"fail here, and continued at Cold Harbor and Petersburg.\"]\n\n\taddBattle \"Atlanta\",65000.,100000.,8500,3700,1, [\n\"August, 1864.  Sherman and three veteran armies converged\",\n\"on Atlanta and dealt the death blow to the Confederacy.\"]\n\nend function\n\nsetup = function\n\tprint; print; print\n\tif getYesNo(\"Are there two generals present\") == \"YES\" then\n\t\tglobals.numPlayers = 2\n\telse\n\t\tglobals.numPlayers = 1\n\t\tprint; print \"You are the Confederacy.  Good luck!\"\n\t\tprint\n\tend if\n\tprint \"Select a battle by typing a number from 1 to 14 on\"\n\tprint \"request.  Type any other number to end the simulation.\"\n\tprint \"But '0' brings back exact previous battle situation\"\n\tprint \"allowing you to replay it.\"\n\tprint\n\tprint \"Note: a negative food$ entry causes the program to \"\n\tprint \"use the entries from the previous battle.\"\n\tprint\n\tyn = getYesNo(\"After requesting a battle, do you wish battle descriptions\")\n\tglobals.battleDesc = (yn == \"YES\")\nend function\n\n// Game variables -- the 2-element arrays below represent the stats for\n// player 0 (Confederacy) and 1 (Union)\nD = [0,0]\t\t// money\nF = [0,0]\t\t// food budget\nH = [0,0]\t\t// salary budget\nB = [0,0]\t\t// ammo budget\nmen = [0,0]\t\t// men at start of battle?  (M1, M2)\nmenAdded = [0,0]\t// men added (M3, M4)\nmenAvail = [0,0]\t// men available (M5, M6)\nP = [0,0]\t// casualties?\nT = [0,0]\t// total losses?\nresources = [0,0]\t// total resources (money) available to each side (R1, R2)\nspending = [0,0]\t// total expenditures for each side (Q1, Q2)\nmorale = [0,0]\t\t// troop morale (O)\nstrategy = [0,0]\t// strategy choice (Y1, Y2)\ninflation = [0,0]\t// inflation (I1, I2)\n\nR = 0\t\t\t// previous battle\nlosses = 0\t\t// Confederate losses\nwins = 0\t\t// Confederate wins\nunresolved = 0\t// battles where neither side clearly won\n\nprintInColumns = function(a, b, c)\n\tprint (a + \" \"*20)[:20] + (b + \" \"*16)[:16] + c\nend function\n\npickBattle = function\n\tprint; print; print\n\tglobals.replay = false\n\twhile true\n\t\tnum = input(\"Which battle do you wish to simulate? \").val\n\t\tif num == 0 and R > 0 then\n\t\t\tnum = R\n\t\t\tglobals.replay = true\n\t\tend if\n\t\tif 0 < num <= historicalBattles.len then break\n\tend while\n\tglobals.bat = historicalBattles[num - 1]\n\tif not replay then\n\t\tmen[0] = bat.men[0]\n\t\tmen[1] = bat.men[1]\n\t\t\n\t\t// inflation calc\n\t\tinflation[0] = 10 + (losses - wins) * 2\n\t\tinflation[1] = 10 + (wins - losses) * 2\n\n\t\t// money available\n\t\tD[0] = 100 * floor((men[0]*(100-inflation[0])/2000) * (1+(resources[0]-spending[0])/(resources[0]+1))+0.5)\n\t\tD[1] = 100 * floor(men[1]*(100-inflation[1])/2000 + 0.5)\n\t\tif numPlayers == 2 then\n\t\t\tD[1] = 100 * floor((men[1]*(100-inflation[1])/2000) * (1+(resources[1]-spending[1])/(resources[1]+1))+0.5)\n\t\tend if\n\t\t\n\t\t// men available\n\t\tmenAvail[0] = floor(men[0]*(1 + (P[0]-T[0])/(menAdded[0]+1)))\n\t\tmenAvail[1] = floor(men[1]*(1 + (P[1]-T[1])/(menAdded[1]+1)))\n\t\tglobals.F1 = 5/6 * men[0]\t// ?!?\n\t\tprint; print; print; print; print\nprint \"P:\" + P + \"; T:\" + T + \"; menAdded:\" + menAdded\nprint \"men[0]:\" + men[0] + \"   ...F1:\" + F1\n\n\t\tprint \"This is the battle of \" + bat.name\n\t\tif battleDesc then\n\t\t\tfor line in bat.description\n\t\t\t\tprint line\n\t\t\tend for\n\t\tend if\n\telse\n\t\tprint bat.name + \" Instant Replay\"\n\tend if\n\tprint\n\tprintInColumns \" \", \"CONFEDERACY\", \" UNION\"\n\tprintInColumns \"MEN\", \"  \"+menAvail[0], \"  \"+menAvail[1]\n\tprintInColumns \"MONEY\", \"$ \"+D[0], \"$ \"+D[1]\n\tprintInColumns \"INFLATION\", \"  \"+(inflation[0]+15)+\" %\", \"  \" +inflation[1]+\" %\"\n\t// (Note: printout lies and shows confederate inflation 15% higher than actual)\n\tprint\nend function\n\ngetBudget = function(player)\n\tprint sides[player] + \" General---How much do you wish to spend for\"\n\tgetNum = function(prompt, allowNegative)\n\t\twhile true\n\t\t\tn = input(prompt)\n\t\t\tif not n then continue\n\t\t\tif n[-1] == \"k\" then n = n[:-1] + \"000\"\t// (allow entries like \"60k\")\n\t\t\tif n.val >= 0 or allowNegative then return n.val\n\t\t\tprint \"Negative values are not allowed.\"\n\t\tend while\n\tend function\n\t\n\twhile true\n\t\tf = getNum(\" - Food......? \", true)\n\t\tif f < 0 then\n\t\t\tif resources[player] == 0 then\n\t\t\t\tprint \"No previous entries.\"\n\t\t\t\tprint \"How much do you wish to spend for\"\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\tbreak\t// keep all previous entries\n\t\tend if\n\t\tF[player] = f\n\t\tH[player] = getNum(\" - Salaries..? \", false)\n\t\tB[player] = getNum(\" - Ammunition? \", false)\n\t\tif F[player] + H[player] + B[player] <= D[player] then break\n\t\tprint \"Think again! You have only $\" + D[player]\n\tend while\t\nend function\n\ncalcMorale = function(player)\n\tm = ((2*F[player]^2 + H[player]^2) / F1^2 + 1)\n\tprint (\" \"*11 + sides[player])[-11:], \" \"\n\tif m >= 10 then\n\t\tprint \"morale is high\"\n\telse if m >= 5 then\n\t\tprint \"morale is fair\"\n\telse\n\t\tprint \"morale is poor\"\n\tend if\n\tmorale[player] = m\nend function\n\ngetStrategy = function(player)\n\tif numPlayers == 1 then\tprompt = \"Your strategy\" else prompt = sides[player] + \" strategy\"\n\twhile true\n\t\tstrat = input(prompt + \"? \").val\n\t\tif 0 < strat < 6 then break\n\t\tprint \"Strategy \" + strat + \" not allowed.\"\n\tend while\n\tstrategy[player] = strat\n\tif strat == 5 then\n\t\tprint \"The \" + [\"Confederacy\", \"Union\"][player] + \" has surrendered.\"\n\t\tglobals.gameOver = true\n\tend if\nend function\n\ncalcComputerStrategy = function\n\t// Union strategy is computer chosen\n\tprint \"Union strategy is \", \"\"\n\ts0 = 0\n\tr = 100 * rnd\n\tfor i in range(0, 3)\n\t\ts0 += unionStrats[i]\n\t\tif r < s0 then\n\t\t\tstrategy[1] = i+1\n\t\t\tbreak\n\t\tend if\n\tend for\n\tprint strategy[1]\nend function\n\nlearnStrategy = function\n\t// Learn present strategy, start forgetting old ones.\n\t// - Present strategy of south gains 3*s, others lose s\n\t//   probability points, unless a strategy falls below 5%.\n\ts = 3; s0 = 0\n\tfor i in range(0,3)\n\t\tif unionStrats[i] < 5 then continue\n\t\tunionStrats[i] -= s\n\t\ts0 += s\n\tend for\n\tunionStrats[strategy[1]-1] += s0\t\nend function\n\ndoBattle = function\n\tU = 0; U2 = 0\n\t// simulated losses -- North\n\tC6 = (2 * bat.casualties[1]/5) * (1+1/(2*(abs(strategy[1]-strategy[0])+1)))\n\tC6 = C6 * (1.28 + (5*men[1]/6) / (B[1]+1))\n\tC6 = floor(C6 * (1+1/morale[1]) + .5)\n\t// - IF LOSS > MEN PRESENT, RESCALE LOSSES\n\tE2 = 100/morale[1]\t\t// desertions (Union)\n\tif floor(C6 + E2) >= menAvail[1] then\n\t\tC6 = floor(13*menAvail[1]/20)\n\t\tE2 = 7 * C6/13\n\t\tU2=1\t// Union loss\n\tend if\n\t// simulated losses -- South\n\tC5 = (2 * bat.casualties[0]/5) * (1+1/(2*(abs(strategy[1]-strategy[0])+1)))\n\tprint \"step A:\" + C5\n\tC5 = floor(C5 * (1+1/morale[0])*(1.28+F1/(B[0]+1))+.5)\n\tprint \"step B:\" + C5\n\tprint \"based on morale[0]:\"+morale[0]+\", F1:\"+F1+\", B[0]:\"+B[0]\n\tE=100/morale[0]\n\tif C5+100/morale[0] >= men[0]*(1+(P1-T1)/(menAdded[0]+1)) then\n\t\tC5 = floor(13*men[0]/20 * (1+(P1-T1)/(menAdded[0]+1)))\n\tprint \"step C:\" + C5\n\tprint \"men: \" + men; print \"menAdded: \" + menAdded; print \"P1,T1:\" + P1 + \",\" + T1\n\t\tE=7*C5/13\t\t// desertions (Confed)\n\t\tU=1\t\t\t// Confederate loss\n\tend if\n\tprint\n\tprint; print; printInColumns \"\", \"CONFEDERACY\", \"UNION\"\n\tif numPlayers == 1 then\n\t\tC6 = floor(17 * bat.casualties[1] * bat.casualties[0] / (C5*20))\n\t\tE2 = 5 * morale[0]\n\tend if\n\tprintInColumns \"CASUALTIES\", C5, C6\n\tprintInColumns \"DESERTIONS\", floor(E), floor(E2)\n\tprint\n\tif numPlayers == 2 then\n\t\tprint \"Compared to the actual casualties at \" + bat.name\n\t\tprint \"Confederate: \" + round(100*C5/bat.casualties[0]) + \"% of the original\"\n\t\tprint \"Union:       \" + round(100*C6/bat.casualties[1]) + \"% of the original\"\n\t\tprint\n\t\t// Who won?\n\t\tprint \"U:\"+U+ \"   U2:\"+U2\n\t\tif (U == 1 and U2 != 1) or (U == U2 and C5+E > C6+E2) then\n\t\t\tprint \"The Union wins \" + bat.name\n\t\t\tglobals.losses += 1\n\t\telse if (U2 == 1 and U != 1) or (U == U2 and C5+E < C6+E2) then\n\t\t\tprint \"The confederacy wins \" + bat.name\n\t\t\tglobals.wins += 1\n\t\telse\n\t\t\tprint \"Battle outcome unresolved\"\n\t\t\tglobals.unresolved += 1\n\t\tend if\n\telse\n\t\tprint \"Your casualties were \" + round(100*C5/bat.casualties[0]) + \"% of\"\n\t\tprint \"the actual casualties at \" + bat.name\n\t\tprint\n\t\tif U == 1 or C5+E >= 17*bat.casualties[1]*bat.casualties[0]/(C5*20)+5*morale[0] then\n\t\t\tprint \"You lose \" + bat.name\n\t\t\tif not replay then globals.losses += 1\n\t\telse\n\t\t\tprint \"You win \" + bat.name\n\t\t\tif not replay then globals.wins += 1\n\t\tend if\n\tend if\n\tif not replay then\n\t\t// Cumulative battle factors which alter historical\n\t\t// resources availeble.  (If a replay, don't update.)\n\t\tT[0] += C5 + E\n\t\tT[1] += C6 + E2\n\t\tP[0] += bat.casualties[0]\n\t\tP[1] += bat.casualties[1]\n\t\tspending[0] += F[0] + H[0] + B[0]\n\t\tspending[1] += F[1] + H[1] + B[1]\n\t\tresources[0] += men[0]*(100-inflation[0])/20\n\t\tresources[1] += men[1]*(100-inflation[1])/20\n\t\tmenAdded[0] += men[0]\n\t\tmenAdded[1] += men[1]\n\n\t\tlearnStrategy\n\tend if\n\tprint \"---------------\"\nend function\n\n// Main Program\nloadData\nunionStrats = [25, 25, 25, 25]\nP1=0; P2=0; T1=0; T2=0\t\t// cumulative stat thingies\nprint\nif getYesNo(\"Do you want instructions\") == \"YES\" then instructions\nsetup\ngameOver = false\nwhile not gameOver\n\tpickBattle\n\tif gameOver then break\n\tfor i in range(0, numPlayers-1)\n\t\tgetBudget i\n\tend for\n\tfor i in range(0, numPlayers-1)\n\t\tcalcMorale i\n\tend for\n\tprint \"Confederate General---\", \"\"\n\tif bat.offDef == 3 then\n\t\tprint \"you are on the offensive\"\n\telse if bat.offDef == 1 then\n\t\tprint \"you are on the defensive\"\n\telse\n\t\tprint \"both sides are on the offensive \"\n\tend if\n\tprint\n\tgetStrategy 0\n\tif numPlayers == 2 then getStrategy 1 else calcComputerStrategy\n\tif gameOver then break\n\tdoBattle\nend while\n\n// Finish off\nprint; print; print; print; print; print\nprint \"The Confederacy has won \" + wins + \" battles and lost \" + losses\nif strategy[0] == 5 or (strategy[1] != 5 and losses > wins) then\n\tprint \"The Union has won the war\"\nelse\n\tprint \"The Confederacy has won the war\"\nend if\nprint \"For the \" + (wins + losses + unresolved) + \" battles fought (excluding reruns)\"\nprint\nprintInColumns \"\", \"Confederacy\", \"Union\"\nprintInColumns \"Historical Losses\", round(P[0]), round(P[1])\nprintInColumns \"Simulated Losses\", round(T[0]), round(T[1])\nprint\nprintInColumns \"    % of Original\", round(100*T[0]/P[0]), round(100*T[1]/P[1])\nif numPlayers == 1 then\n\tprint\n\tprint \"Union intelligence suggsets that the South used \"\n\tprint \"strategies 1, 2, 3, 4 in the following percentages\"\n\tprint unionStrats.join\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/27_Civil_War/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/27_Civil_War/civilwar.bas",
    "content": "2 PRINT TAB(26) \"CIVIL WAR\"\n4 PRINT TAB(15) \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT : PRINT : PRINT\n20 REM ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S.\n30 REM MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973\n50  DIM S(4),C$(14),M1(14),M2(14),C1(14),C2(14),M(14)\n60  REM UNION INFO ON LIKELY CONFEDERATE STRATEGY\n70  S(1)=25 : S(2)=25 : S(3)=25 : S(4)=25\n82  REM READ HISTORICAL DATA.\n84  FOR D=1 TO 14\n86  READ C$(D),M1(D),M2(D),C1(D),C2(D),M(D)\n88  NEXT D\n89  LET D=RND(-1)\n90  PRINT\n100  PRINT \"DO YOU WANT INSTRUCTIONS\";\n110  INPUT X$\n120  IF X$=\"YES\" THEN 160\n130  IF X$=\"NO\" THEN 370\n140  PRINT \"YES OR NO -- \";\n150  GOTO 110\n160  PRINT : PRINT : PRINT : PRINT\n170  PRINT \"THIS IS A CIVIL WAR SIMULATION.\"\n180  PRINT \"TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS.\"\n190  PRINT \"REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR\"\n200  PRINT \"RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE\"\n210  PRINT \"BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT\"\n220  PRINT \"AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!\"\n230  PRINT\n240  PRINT \"THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS \";\n245  PRINT \"POSSIBLE.\"\n250  PRINT\n260  PRINT \"YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:\"\n270  PRINT \"        (1) ARTILLERY ATTACK\"\n280  PRINT \"        (2) FORTIFICATION AGAINST FRONTAL ATTACK\"\n290  PRINT \"        (3) FORTIFICATION AGAINST FLANKING MANEUVERS\"\n300  PRINT \"        (4) FALLING BACK\"\n310  PRINT \" YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:\"\n320  PRINT \"        (1) ARTILLERY ATTACK\"\n330  PRINT \"        (2) FRONTAL ATTACK\"\n340  PRINT \"        (3) FLANKING MANEUVERS\"\n350  PRINT \"        (4) ENCIRCLEMENT\"\n360  PRINT \"YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY.\"\n370  PRINT : PRINT : PRINT : PRINT \"ARE THERE TWO GENERALS PRESENT \";\n380  PRINT \"(ANSWER YES OR NO)\";\n390  INPUT B$\n400  IF B$=\"YES\" THEN 430\n410  IF B$ <> \"NO\" THEN 380\n420  PRINT : PRINT \"YOU ARE THE CONFEDERACY.   GOOD LUCK!\"\n425  PRINT\n430  LET D=1\n440  IF B$ <> \"YES\" THEN 460\n450  LET D=2\n460  PRINT \"SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON\"\n470  PRINT \"REQUEST.  TYPE ANY OTHER NUMBER TO END THE SIMULATION.\"\n480  PRINT \"BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION\"\n490  PRINT \"ALLOWING YOU TO REPLAY IT\"\n500  PRINT\n510  PRINT \"NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO \"\n520  PRINT \"USE THE ENTRIES FROM THE PREVIOUS BATTLE\"\n530  PRINT\n540  PRINT \"AFTER REQUESTING A BATTLE, DO YOU WISH \";\n550  PRINT \"BATTLE DESCRIPTIONS \";\n560  PRINT \"(ANSWER YES OR NO)\";\n570  INPUT X$\n580  IF X$=\"YES\" THEN 600\n590  IF X$ <> \"NO\" THEN 560\n600  L=0:W=0:R1=0:Q1=0:M3=0:M4=0:P1=0:P2=0:T1=0:T2=0\n610  F(2)=0:H(2)=0:B(2)=0:R2=0:Q2=0:C6=0:F=0:W0=0:Y=0:Y2=0:U=0:U2=0\n620  PRINT : PRINT : PRINT\n630  PRINT \"WHICH BATTLE DO YOU WISH TO SIMULATE\";\n640  INPUT A\n650  IF A <> 0 THEN 660\n655  IF R <> 0 THEN 1140\n660  IF A <=0 THEN 2860\n665  IF A >= 15 THEN 2860\n670  LET C$=C$(A)\n680  LET M1=M1(A)\n690  LET M2=M2(A)\n700  LET C1=C1(A)\n710  LET C2=C2(A)\n720  LET M=M(A)\n960  LET U=0\n970  REM  INFLATION CALC\n980  LET I1=10+(L-W)*2\n990  LET I2=10+(W-L)*2\n1000  REM - MONEY AVAILABLE\n1010  LET D(1)=100*INT((M1*(100-I1)/2000)*(1+(R1-Q1)/(R1+1))+.5)\n1020  LET D(2)=100*INT(M2*(100-I2)/2000+.5)\n1030  IF B$ <> \"YES\" THEN 1050\n1040  LET D(2)=100*INT((M2*(100-I2)/2000)*(1+(R2-Q2)/(R2+1))+.5)\n1050  REM - MEN   AVAILABLE\n1060  LET M5=INT(M1*(1+(P1-T1)/(M3+1)))\n1070  LET M6=INT(M2*(1+(P2-T2)/(M4+1)))\n1080  LET F1=5*M1/6\n1090  PRINT : PRINT : PRINT : PRINT : PRINT\n1100  PRINT \"THIS IS THE BATTLE OF \";C$\n1110  IF X$=\"NO\" THEN 1150\n1120  IF A>11 THEN 1130\n1125  ON A GOTO 3580,3620,3650,3690,3720,3750,3780,3800,3830,3860,3890\n1130  ON A-11 GOTO 3920,3950,3980\n1140  PRINT C$\" INSTANT REPLAY\"\n1150  PRINT\n1160  PRINT \" \",\"CONFEDERACY\",\" UNION\"\n1170  PRINT \"MEN\",\" \"M5,\" \"M6\n1180  PRINT \"MONEY\",\"$\";D(1),\"$\";D(2)\n1190  PRINT \"INFLATION\",\" \";I1+15;\"%\",\" \";I2;\"%\"\n1195  PRINT\n1200  REM - ONLY IN PRINTOUT IS CONFED INFLATION = I1+15%\n1210  REM - IF TWO GENERALS, INPUT CONFED. FIRST\n1220  FOR I=1 TO D\n1230  IF B$ <> \"YES\" THEN 1260\n1240  IF I=2 THEN 1260\n1250  PRINT \"CONFEDERATE GENERAL---\";\n1260  PRINT \"HOW MUCH DO YOU WISH TO SPEND FOR\"\n1270  PRINT \" - FOOD......\";\n1280  INPUT F\n1290  IF F >= 0 THEN 1360\n1300  IF R1 <> 0 THEN 1330\n1310  PRINT \"NO PREVIOUS ENTRIES\"\n1320  GOTO 1270\n1330  PRINT \"ASSUME YOU WANT TO KEEP SAME ALLOCATIONS\"\n1340  PRINT\n1350  GOTO 1510\n1360  LET F(I)=F\n1370  PRINT \" - SALARIES..\";\n1380  INPUT H(I)\n1390  LET N=1\n1400  IF H(I)<0 THEN 1490\n1410  PRINT \" - AMMUNITION\";\n1420  INPUT B(I)\n1430  LET N=2\n1440  IF B(I)<0 THEN 1490\n1450  PRINT\n1460  IF F(I)+H(I)+B(I) <= D(I) THEN 1510\n1470  PRINT \"THINK AGAIN! YOU HAVE ONLY $\"D(I)\n1480  GOTO 1270\n1490  PRINT \"NEGATIVE VALUES NOT ALLOWED.\"\n1500  ON N GOTO 1370,1410\n1510  IF B$ <> \"YES\" THEN 1550\n1520  IF I=2 THEN 1550\n1530  PRINT \"UNION GENERAL---\";\n1540  NEXT I\n1550  FOR Z=1 TO D\n1560  IF B$ <> \"YES\" THEN 1620\n1570  ON Z GOTO 1580,1600\n1580  PRINT \"CONFEDERATE \";\n1590  GOTO 1620\n1600  PRINT \"      UNION \";\n1610  REM - FIND MORALE\n1620  LET O=((2*F(Z)^2+H(Z)^2)/F1^2+1)\n1630  IF O<10 THEN 1660\n1640  PRINT \"MORALE IS HIGH\"\n1650  GOTO 1700\n1660  IF O<5 THEN 1690\n1670  PRINT \"MORALE IS FAIR\"\n1680  GOTO 1700\n1690  PRINT \"MORALE IS POOR\"\n1700  IF B$ <> \"YES\" THEN 1760\n1710  LET O(Z)=O\n1720  NEXT Z\n1730  LET O2=O(2)\n1740  LET O=O(1)\n1750  PRINT \"CONFEDERATE GENERAL---\";\n1760  REM - ACTUAL OFF/DEF BATTLE SITUATION\n1770  IF M <> 3 THEN 1800\n1780  PRINT \"YOU ARE ON THE OFFENSIVE\"\n1790  GOTO 1840\n1800  IF M <> 1 THEN 1830\n1810  PRINT \"YOU ARE ON THE DEFENSIVE\"\n1820  GOTO 1840\n1830  PRINT \"BOTH SIDES ARE ON THE OFFENSIVE \"\n1840  PRINT\n1850  REM - CHOOSE STRATEGIES\n1860  IF B$ <> \"YES\" THEN 1910\n1870  FOR I=1 TO 2\n1880  ON I GOTO 1890,1920\n1890  PRINT \"CONFEDERATE STRATEGY \";\n1900  GOTO 1920\n1910  PRINT \"YOUR STRATEGY \";\n1920  INPUT Y\n1930  IF ABS(Y-3)<3 THEN 1960\n1940  PRINT \"STRATEGY\";Y;\"NOT ALLOWED.\"\n1950  GOTO 1910\n1960  IF B$=\"YES\" THEN 2000\n1970  IF Y=5 THEN 2830\n1980  GOSUB 3110\n1990  GOTO 2170\n2000  IF I=2 THEN 2040\n2010  LET Y1=Y\n2020  PRINT \"UNION STRATEGY \";\n2030  NEXT I\n2040  LET Y2=Y\n2050  LET Y=Y1\n2060  IF Y2=5 THEN 2020\n2070  REM : SIMULATED LOSSES-NORTH\n2080  LET C6=(2*C2/5)*(1+1/(2*(ABS(Y2-Y)+1)))\n2090  LET C6=C6*(1.28+(5*M2/6)/(B(2)+1))\n2100  LET C6=INT(C6*(1+1/O2)+.5)\n2110  REM - IF LOSS > MEN PRESENT, RESCALE LOSSES\n2120  LET E2=100/O2\n2130  IF INT(C6+E2)<M6 THEN 2190\n2140  LET C6=INT(13*M6/20)\n2150  LET E2=7*C6/13\n2160  LET U2=1\n2170  REM - CALCULATE SIMULATED LOSSES\n2180  PRINT\n2190  PRINT : PRINT : PRINT ,\"CONFEDERACY\",\"UNION\"\n2200  LET C5=(2*C1/5)*(1+1/(2*(ABS(Y2-Y)+1)))\n2210  LET C5=INT(C5*(1+1/O)*(1.28+F1/(B(1)+1))+.5)\n2220  LET E=100/O\n2230  IF C5+100/O<M1*(1+(P1-T1)/(M3+1)) THEN 2270\n2240  LET C5=INT(13*M1/20*(1+(P1-T1)/(M3+1)))\n2250  LET E=7*C5/13\n2260  LET U=1\n2270  IF D=1 THEN 2500\n2280  PRINT \"CASUALTIES\",C5,C6\n2290  PRINT \"DESERTIONS\",INT(E),INT(E2)\n2300  PRINT\n2310  IF B$ <> \"YES\" THEN 2530\n2320  PRINT \"COMPARED TO THE ACTUAL CASUALTIES AT \"C$\n2330  PRINT \"CONFEDERATE:\"INT(100*(C5/C1)+.5)\"% OF THE ORIGINAL\"\n2340  PRINT \"UNION:      \"INT(100*(C6/C2)+.5)\"% OF THE ORIGINAL\"\n2350  PRINT\n2360  REM - 1 WHO WON\n2370  IF U <> 1 THEN 2380\n2375  IF U2=1 THEN 2460\n2380  IF U=1 THEN 2420\n2390  IF U2=1 THEN 2440\n2400  IF C5+E=C6+E2 THEN 2460\n2410  IF C5+E<C6+E2 THEN 2440\n2420  PRINT \"THE UNION WINS \"C$\n2430  GOTO 2600\n2440  PRINT \"THE CONFEDERACY WINS \"C$\n2450  GOTO 2660\n2460  PRINT \"BATTLE OUTCOME UNRESOLVED\"\n2470  LET W0=W0+1\n2480  IF A=0 THEN 2790\n2490  GOTO 2680\n2500  LET C6=INT(17*C2*C1/(C5*20))\n2510  LET E2=5*O\n2520  GOTO 2280\n2530  PRINT \"YOUR CASUALTIES WERE \"INT(100*(C5/C1)+.5)\"% OF \"\n2540  PRINT \"THE ACTUAL CASUALTIES AT \";C$\n2550  PRINT\n2560  REM - FIND WHO WON\n2570  IF U=1 THEN 2590\n2580  IF C5+E<17*C2*C1/(C5*20)+5*O THEN 2630\n2590  PRINT \"YOU LOSE \";C$\n2600  IF A=0 THEN 2790\n2610  LET L=L+1\n2620  GOTO 2680\n2630  PRINT \"YOU WIN \";C$\n2640  REM - CUMULATIVE BATTLE FACTORS WHICH ALTER HISTORICAL\n2650  REM  RESOURCES AVAILABLE.IF A REPLAY DON'T UPDATE.\n2660  IF A=0 THEN 2790\n2670  LET W=W+1\n2680  LET T1=T1+C5+E\n2690  LET T2=T2+C6+E2\n2700  LET P1=P1+C1\n2710  LET P2=P2+C2\n2720  LET Q1=Q1+(F(1)+H(1)+B(1))\n2730  LET Q2=Q2+(F(2)+H(2)+B(2))\n2740  LET R1=R1+M1*(100-I1)/20\n2750  LET R2=R2+M2*(100-I2)/20\n2760  LET M3=M3+M1\n2770  LET M4=M4+M2\n2780  GOSUB 3300\n2790  U=0:U2=0\n2800  PRINT \"---------------\"\n2810  GOTO 620\n2820  REM------FINISH OFF\n2830  PRINT \"THE CONFEDERACY HAS SURRENDERED\"\n2840  GOTO 2860\n2850  PRINT \"THE UNION HAS SURRENDERED.\"\n2860  PRINT : PRINT : PRINT : PRINT : PRINT : PRINT\n2870  PRINT \"THE CONFEDERACY \";\n2880  PRINT \"HAS WON \"W\" BATTLES AND LOST \"L\n2890  IF Y=5 THEN 2940\n2900  IF Y2=5 THEN 2920\n2910  IF W <= L THEN 2940\n2915  IF Y=5 THEN 2940\n2920  PRINT \"THE CONFEDERACY HAS WON THE WAR\"\n2930  GOTO 2950\n2940  PRINT \"THE UNION HAS WON THE WAR\"\n2950  PRINT\n2960  IF R1=0 THEN 3100\n2970  PRINT \"FOR THE \"W+L+W0\" BATTLES FOUGHT (EXCLUDING RERUNS)\"\n2980  PRINT \" \",\" \",\" \";\n2990  PRINT \"CONFEDERACY\",\" UNION\"\n3000  PRINT \"HISTORICAL LOSSES\",INT(P1+.5),INT(P2+.5)\n3010  PRINT \"SIMULATED LOSSES\",INT(T1+.5),INT(T2+.5)\n3020  PRINT\n3030  PRINT \"    % OF ORIGINAL\",INT(100*(T1/P1)+.5),INT(100*(T2/P2)+.5)\n3040  IF B$=\"YES\" THEN 3100\n3050  PRINT\n3060  PRINT \"UNION INTELLIGENCE SUGGESTS THAT THE SOUTH USED \"\n3070  PRINT \"STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES\"\n3080  PRINT S(1);S(2);S(3);S(4)\n3090  REM---------------------------------\n3100  STOP\n3110  REM - UNION STRATEGY IS COMPUTER CHOSEN\n3120  PRINT \"UNION STRATEGY IS \";\n3130  IF A <> 0 THEN 3180\n3140  INPUT Y2\n3150  IF Y2 <=0 THEN 3160\n3155  IF Y2<5 THEN 3290\n3160  PRINT \"ENTER 1 , 2 ,3 , OR 4 (USUALLY PREVIOUS UNION STRATEGY)\"\n3170  GOTO 3140\n3180  LET S0=0\n3190  LET R=100*RND(0)\n3200  FOR I=1 TO 4\n3210  LET S0=S0+S(I)\n3220  REM - IF ACTUAL STRATEGY INFO IS IN PROGRAM DATA STATEMENTS\n3230  REM   THEN R-100 IS EXTRA WEIGHT GIVEN TO THAT STATEGY.\n3240  IF R<S0 THEN 3270\n3250  NEXT I\n3260  REM - IF ACTUAL STRAT. IN,THEN HERE IS Y2= HIST. STRAT.\n3270  LET Y2=I\n3280  PRINT Y2\n3290  RETURN\n3300  REM LEARN  PRESENT STRATEGY, START FORGETTING OLD ONES\n3310  REM - PRESENT STRATEGY OF SOUTH GAINS 3*S, OTHERS LOSE S\n3320  REM   PROBABILITY POINTS, UNLESS A STRATEGY FALLS BELOW 5%.\n3330  LET S=3\n3340  LET S0=0\n3350  FOR I=1 TO 4\n3360  IF S(I) <= 5 THEN 3390\n3370  LET S(I)=S(I)-S\n3380  LET S0=S0+S\n3390  NEXT I\n3400  LET S(Y)=S(Y)+S0\n3410  RETURN\n3420  REM - HISTORICAL DATA...CAN ADD MORE (STRAT.,ETC) BY INSERTING\n3430  REM   DATA STATEMENTS AFTER APPRO. INFO, AND ADJUSTING READ\n3440  DATA \"BULL RUN\",18000,18500,1967,2708,1\n3450  DATA \"SHILOH\",40000.,44894.,10699,13047,3\n3460  DATA \"SEVEN DAYS\",95000.,115000.,20614,15849,3\n3470  DATA \"SECOND BULL RUN\",54000.,63000.,10000,14000,2\n3480  DATA \"ANTIETAM\",40000.,50000.,10000,12000,3\n3490  DATA \"FREDERICKSBURG\",75000.,120000.,5377,12653,1\n3500  DATA \"MURFREESBORO\",38000.,45000.,11000,12000,1\n3510  DATA \"CHANCELLORSVILLE\",32000,90000.,13000,17197,2\n3520  DATA \"VICKSBURG\",50000.,70000.,12000,19000,1\n3530  DATA \"GETTYSBURG\",72500.,85000.,20000,23000,3\n3540  DATA \"CHICKAMAUGA\",66000.,60000.,18000,16000,2\n3550  DATA \"CHATTANOOGA\",37000.,60000.,36700.,5800,2\n3560  DATA \"SPOTSYLVANIA\",62000.,110000.,17723,18000,2\n3570  DATA \"ATLANTA\",65000.,100000.,8500,3700,1\n3580  PRINT \"JULY 21, 1861.  GEN. BEAUREGARD, COMMANDING THE SOUTH, MET\"\n3590  PRINT \"UNION FORCES WITH GEN. MCDOWELL IN A PREMATURE BATTLE AT\"\n3600  PRINT \"BULL RUN. GEN. JACKSON HELPED PUSH BACK THE UNION ATTACK.\"\n3610  GOTO 1150\n3620  PRINT \"APRIL 6-7, 1862.  THE CONFEDERATE SURPRISE ATTACK AT\"\n3630  PRINT \"SHILOH FAILED DUE TO POOR ORGANIZATION.\"\n3640  GOTO 1150\n3650  PRINT \"JUNE 25-JULY 1, 1862.  GENERAL LEE (CSA) UPHELD THE\"\n3660  PRINT \"OFFENSIVE THROUGHOUT THE BATTLE AND FORCED GEN. MCCLELLAN\"\n3670  PRINT \"AND THE UNION FORCES AWAY FROM RICHMOND.\"\n3680  GOTO 1150\n3690  PRINT \"AUG 29-30, 1862.  THE COMBINED CONFEDERATE FORCES UNDER\";\n3695  PRINT \" LEE\"\n3700  PRINT \"AND JACKSON DROVE THE UNION FORCES BACK INTO WASHINGTON.\"\n3710  GOTO 1150\n3720  PRINT \"SEPT 17, 1862.  THE SOUTH FAILED TO INCORPORATE MARYLAND\"\n3730  PRINT \"INTO THE CONFEDERACY.\"\n3740  GOTO 1150\n3750  PRINT \"DEC 13, 1862.  THE CONFEDERACY UNDER LEE SUCCESSFULLY\"\n3760  PRINT \"REPULSED AN ATTACK BY THE UNION UNDER GEN. BURNSIDE.\"\n3770  GOTO 1150\n3780  PRINT \"DEC 31, 1862.  THE SOUTH UNDER GEN. BRAGG WON A CLOSE \";\n3785  PRINT \"BATTLE.\"\n3790  GOTO 1150\n3800  PRINT \"MAY 1-6, 1863.  THE SOUTH HAD A COSTLY VICTORY AND LOST\"\n3810  PRINT \"ONE OF THEIR OUTSTANDING GENERALS, 'STONEWALL' JACKSON.\"\n3820  GOTO 1150\n3830  PRINT \"JULY 4, 1863.  VICKSBURG WAS A COSTLY DEFEAT FOR THE SOUTH\"\n3840  PRINT \"BECAUSE IT GAVE THE UNION ACCESS TO THE MISSISSIPPI.\"\n3850  GOTO 1150\n3860  PRINT \"JULY 1-3, 1863.  A SOUTHERN MISTAKE BY GEN. LEE AT \";\n3865  PRINT \"GETTYSBURG\"\n3870  PRINT \"COST THEM ONE OF THE MOST CRUCIAL BATTLES OF THE WAR.\"\n3880  GOTO 1150\n3890  PRINT \"SEPT. 15, 1863. CONFUSION IN A FOREST NEAR CHICKAMAUGA LED\"\n3900  PRINT \"TO A COSTLY SOUTHERN VICTORY.\"\n3910  GOTO 1150\n3920  PRINT \"NOV. 25, 1863. AFTER THE SOUTH HAD SIEGED GEN. ROSENCRANS'\"\n3930  PRINT \"ARMY FOR THREE MONTHS, GEN. GRANT BROKE THE SIEGE.\"\n3940  GOTO 1150\n3950  PRINT \"MAY 5, 1864.  GRANT'S PLAN TO KEEP LEE ISOLATED BEGAN TO\"\n3960  PRINT \"FAIL HERE, AND CONTINUED AT COLD HARBOR AND PETERSBURG.\"\n3970  GOTO 1150\n3980  PRINT \"AUGUST, 1864.  SHERMAN AND THREE VETERAN ARMIES CONVERGED\"\n3990  PRINT \"ON ATLANTA AND DEALT THE DEATH BLOW TO THE CONFEDERACY.\"\n4000  GOTO 1150\n4010  END\n"
  },
  {
    "path": "00_Alternate_Languages/28_Combat/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript combat.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"combat\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/28_Combat/MiniScript/combat.ms",
    "content": "print \" \"*33 + \"Combat\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprintInColumns2 = function(a, b, lineBreak=true)\n\tprint (a+\" \"*16)[:16] + (b+\" \"*16)[:16], \"\"\n\tif lineBreak then print\nend function\n\nprintInColumns3 = function(a, b, c, lineBreak=true)\n\tprint (a+\" \"*16)[:16] + (b+\" \"*16)[:16] + (c+\" \"*16)[:16], \"\"\n\tif lineBreak then print\nend function\n\n// computer forces:\nd = 30000\t\t// army\ne = 20000\t\t// navy\nf = 22000\t\t// air force\n\nprint \"I am at war with you.\"; print \"We have 72000 soldiers apiece.\"\nwhile true\n\tprint; print \"Distribute your forces.\"\n\tprintInColumns3 \"\", \"ME\", \"YOU\"\n\tprintInColumns2 \"army\", d, false\n\ta = input(\"?\").val\n\tprintInColumns2 \"navy\", e, false\n\tb = input(\"?\").val\n\tprintInColumns2 \"a. f.\", f, false\n\tc = input(\"?\").val\n\tif a+b+c <= 72000 then break\nend while\n\n\nprint \"You attack first. Type (1) for army; (2) for navy;\"\nprint \"and (3) for air force.\"\ny = input.val\nwhile true\n\tx = input(\"How many men? \").val\n\tif x < 0 then continue\n\tif y <= 1 or y > 3 then\n\t\t// Army attack\n\t\tif x > a then continue\n\t\tif x < a/3 then\n\t\t\tprint \"You lost \"+x+\" men from your army.\"\n\t\t\ta=floor(a-x)\n\t\telse if x < 2*a/3 then\n\t\t\tprint \"You lost \" + floor(x/3) + \" men, but I lost \" + floor(2*d/3)\n\t\t\ta=floor(a-x/3)\n\t\t\td=0\t\t// (message above lied!)\n\t\telse\n\t\t\tprint \"You sunk one of my patrol boats, but I wiped out two\"\n\t\t\tprint \"of your air force bases and 3 army bases.\"\n\t\t\ta=floor(a/3)\n\t\t\tc=floor(c/3)\n\t\t\te=floor(2*e/3)\n\t\tend if\n\telse if y == 2 then\n\t\t// Naval attack\n\t\tif x > b then continue\n\t\tif x < e/3 then\n\t\t\tprint \"Your attack was stopped!\"\n\t\t\tb = floor(b-x)\n\t\telse if x < 2*e/3 then\n\t\t\tprint \"You destroyed \" + floor(2*e/3) + \"of my army.\"\n\t\t\te=floor(e/3)\n\t\telse\n\t\t\tprint \"You sunk one of my patrol boats, but I wiped out two\"\n\t\t\tprint \"of your air force bases and 3 army bases.\"\n\t\t\ta=floor(a/3)\n\t\t\tc=floor(c/3)\n\t\t\te=floor(2*e/3)\n\t\tend if\n\telse\n\t\t// Air force attack\n\t\tif x > c then continue\n\t\tif x < c/3 then\n\t\t\tprint \"Your attack was wiped out.\"\n\t\t\tc = floor(c-x)\n\t\telse if x < 2*c/3 then\n\t\t\tprint \"We had a dogfight. You won - and finished your mission.\"\n\t\t\td=floor(2*d/3)\n\t\t\te=floor(e/3)\n\t\t\tf=floor(f/3)\n\t\telse\n\t\t\tprint \"You wiped out one of my army patrols, but I destroyed\"\n\t\t\tprint \"two navy bases and bombed three army bases.\"\n\t\t\ta=floor(a/4)\n\t\t\tb=floor(b/3)\n\t\t\td=floor(2*d/3)\n\t\tend if\n\tend if\n\tbreak\nend while\n\nresult = null\t\t// 1 you win, -1 you lose, 0 tie (treaty)\nprint\nprintInColumns3 \"\", \"YOU\", \"ME\"\nprintInColumns3 \"army\", a, d\nprintInColumns3 \"navy\", b, e\nprintInColumns3 \"a. f.\", c, f\nprint \"What is your next move?\"\nprint \"army=1  navy=2  air force=3\"\ng = input.val\nwhile true\n\tt = input(\"How many men? \").val\n\tif t < 0 then continue\n\tif g <= 1 or g > 3 then\n\t\t// Army attack\n\t\tif t > a then continue\n\t\tif t < d/2 then\n\t\t\tprint \"I wiped out your attack!\"\n\t\t\ta = a-t\n\t\telse\n\t\t\tprint \"You destroyed my army!\"\n\t\t\td=0\n\t\tend if\n\telse if g == 2 then\n\t\t// Naval attack\n\t\tif t > b then continue\n\t\tif t < e/2 then\n\t\t\tprint \"I sunk two of your battleships, and my air force\"\n\t\t\tprint \"wiped out your ungaurded capitol.\"\t// (sic)\n\t\t\ta = a/4\n\t\t\tb = b/2\n\t\telse\n\t\t\tprint \"Your navy shot down three of my xiii planes,\"\n\t\t\tprint \"and sunk three battleships.\"\n\t\t\tf = 2*f/3\n\t\t\te = (e/2)\n\t\tend if\n\telse\n\t\t// Air Force attack\n\t\tif t > c then continue\n\t\tif t > f/2 then\n\t\t\tprint \"My navy and air force in a combined attack left\"\n\t\t\tprint \"your country in shambles.\"\n\t\t\ta = a/3\n\t\t\tb = b/3\n\t\t\tc = c/3\n\t\telse\n\t\t\tprint \"One of your planes crashed into my house. I am dead.\"\n\t\t\tprint \"My country fell apart.\"\n\t\t\tresult = 1\n\t\tend if\n\tend if\n\tbreak\nend while\n\nif result == null then\n\tprint\n\tprint \"From the results of both of your attacks,\"\n\tresult = 0\n\tif a+b+c > 3/2*(d+e+f) then result = 1\n\tif a+b+c < 2/3*(d+e+f) then result = -1\nend if\n\nif result == 0 then\n\tprint \"the treaty of paris concluded that we take our\"\n\tprint \"respective countries and live in peace.\"\nelse if result == 1 then\n\tprint \"You won, oh! shucks!!!!\"\nelse\n\tprint \"You lost-I conquered your country.  It serves you\"\n\tprint \"right for playing this stupid game!!!\"\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/28_Combat/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/28_Combat/combat.bas",
    "content": "1 PRINT TAB(33);\"COMBAT\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT: PRINT: PRINT\n4 PRINT \"I AM AT WAR WITH YOU.\": PRINT \"WE HAVE 72000 SOLDIERS APIECE.\"\n5 PRINT:PRINT \"DISTRIBUTE YOUR FORCES.\"\n6 PRINT ,\"ME\",\"  YOU\"\n7 PRINT \"ARMY\",30000,\n8 INPUT A\n9 PRINT \"NAVY\",20000,\n10 INPUT B\n11 PRINT \"A. F.\",22000,\n12 INPUT C\n13 IF A+B+C>72000 THEN 5\n14 D=30000\n15 E=20000\n16 F=22000\n17 PRINT \"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\"\n18 PRINT \"AND (3) FOR AIR FORCE.\"\n19 INPUT Y\n20 PRINT \"HOW MANY MEN\"\n21 INPUT X\n22 IF X<0 THEN 20\n23 ON Y GOTO 100,200,300\n100 IF X>A THEN 20\n105 IF X<A/3 THEN 120\n110 IF X<2*A/3 THEN 150\n115 GOTO 270\n120 PRINT \"YOU LOST\";X;\"MEN FROM YOUR ARMY.\"\n125 A=INT(A-X)\n130 GOTO 500\n150 PRINT \"YOU LOST\";INT(X/3);\"MEN, BUT I LOST \";INT(2*D/3)\n155 A=INT(A-X/3)\n160 D=0\n165 GOTO 500\n200 IF X>B THEN 20\n210 IF X<E/3 THEN 230\n215 IF X<2*E/3 THEN 250\n220 GOTO 270\n230 PRINT \"YOUR ATTACK WAS STOPPED!\"\n232 B=INT(B-X)\n235 GOTO 500\n250 PRINT \"YOU DESTROYED\";INT(2*E/3);\"OF MY ARMY.\"\n255 E=INT(E/3)\n260 GOTO 500\n270 PRINT \"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\"\n275 PRINT \"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\"\n280 A=INT(A/3)\n285 C=INT(C/3)\n290 E=INT(2*E/3)\n293 GOTO 500\n300 IF X>C THEN 20\n310 IF X<C/3 THEN 350\n320 IF X<2*C/3 THEN 370\n330 GOTO 380\n350 PRINT \"YOUR ATTACK WAS WIPED OUT.\"\n355 C=INT(C-X)\n360 GOTO 500\n370 PRINT \"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\"\n375 D=INT(2*D/3)\n377 E=INT(E/3)\n378 F=INT(F/3)\n379 GOTO 500\n380 PRINT \"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\"\n381 PRINT \"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\"\n385 A=INT(A/4)\n387 B=INT(B/3)\n390 D=INT(2*D/3)\n500 PRINT\n501 PRINT,\"YOU\",\"ME\"\n510 PRINT \"ARMY\",A,D\n520 PRINT \"NAVY\",B,E\n530 PRINT \"A. F.\",C,F\n1000 PRINT \"WHAT IS YOUR NEXT MOVE?\"\n1010 PRINT \"ARMY=1  NAVY=2  AIR FORCE=3\"\n1020 INPUT G\n1030 PRINT \"HOW MANY MEN\"\n1040 INPUT T\n1045 IF T<0 THEN 1030\n1050 ON G GOTO 1600,1700,1800\n1600 IF T>A THEN 1030\n1610 IF T<D/2 THEN 1630\n1615 PRINT \"YOU DESTROYED MY ARMY!\"\n1616 D=0\n1617 GOTO 2000\n1630 PRINT \"I WIPED OUT YOUR ATTACK!\"\n1635 A=A-T\n1640 GOTO 2000\n1700 IF T>B THEN 1030\n1710 IF T<E/2 THEN 1750\n1720 GOTO 1770\n1750 PRINT \"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\"\n1751 PRINT \"WIPED OUT YOUR UNGAURDED CAPITOL.\"\n1755 A=A/4\n1760 B=B/2\n1765 GOTO 2000\n1770 PRINT \"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\"\n1771 PRINT \"AND SUNK THREE BATTLESHIPS.\"\n1775 F=2*F/3\n1780 E=(E/2)\n1790 GOTO 2000\n1800 IF T>C THEN 1030\n1810 IF T>F/2 THEN 1830\n1820 GOTO 1850\n1830 PRINT \"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\"\n1831 PRINT \"YOUR COUNTRY IN SHAMBLES.\"\n1835 A=A/3\n1837 B=B/3\n1840 C=C/3\n1845 GOTO 2000\n1850 PRINT \"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\"\n1851 PRINT \"MY COUNTRY FELL APART.\"\n1860 GOTO 2010\n2000 PRINT\n2001 PRINT \"FROM THE RESULTS OF BOTH OF YOUR ATTACKS,\"\n2002 IF A+B+C>3/2*(D+E+F) THEN 2010\n2005 IF A+B+C<2/3*(D+E+F) THEN 2015\n2006 PRINT \"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\"\n2007 PRINT \"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\"\n2008 GOTO 2020\n2010 PRINT \"YOU WON, OH! SHUCKS!!!!\"\n2012 GOTO 2020\n2015 PRINT \"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\"\n2016 PRINT \"RIGHT FOR PLAYING THIS STUPID GAME!!!\"\n2020 END\n"
  },
  {
    "path": "00_Alternate_Languages/29_Craps/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript craps.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"craps\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/29_Craps/MiniScript/craps.ms",
    "content": "// Craps\n// Ported from BASIC to MiniScript by Joe Strout (2023)\n\nprint \" \"*33 + \"CRAPS\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\n\nprint \"2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.\"\nwinnings = 0\n\nrollDice = function\n\twait 0.5  // (a small delay makes the game more dramatic)\n\treturn ceil(rnd*6) + ceil(rnd*6)\nend function\n\ndoOneBet = function\n\twhile true\n\t\twager = input(\"Input the amount of your wager: \").val\n\t\tif wager > 0 then break\n\tend while\n\tprint \"I will now throw the dice.\"\n\tresult = 0\t\t// 1 if we win, 2 if win double, -1 if we lose\n\troll = rollDice\n\tif roll == 7 or roll == 11 then\n\t\tprint roll + \"- natural....a winner!!!!\"\n\t\tprint roll + \" pays even money, you win \" + wager + \" dollars\"\n\t\tresult = 1\n\telse if roll == 2 then\n\t\tprint \"2- snake eyes....you lose.\"\n\t\tprint \"You lose \" + wager + \" dollars.\"\n\t\tresult = -1\n\telse if roll == 3 or roll == 12 then\n\t\tprint roll + \" - craps...you lose.\"\n\t\tprint \"You lose \" + wager + \" dollars.\"\n\t\tresult = -1\t\t\n\telse\n\t\tpoint = roll\n\t\tprint point + \" is the point. I will roll again\"\n\t\twhile true\n\t\t\troll = rollDice\n\t\t\tif roll == 7 then\n\t\t\t\tprint \"7 - craps. You lose.\"\n\t\t\t\tprint \"You lose $\" + wager\n\t\t\t\tresult = -1\n\t\t\t\tbreak\n\t\t\telse if roll == point then\n\t\t\t\tprint roll + \"- a winner.........CONGRATS!!!!!!!!\"\n\t\t\t\tprint roll + \" at 2 to 1 odds pays you...let me see...\" + \n\t\t\t\t  (2*wager) + \" dollars\"\n\t\t\t\tresult = 2\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tprint roll + \" - no point. I will roll again\"\n\t\t\tend if  \n\t\tend while\n\tend if\n\tglobals.winnings += wager * result\nend function\n\n// Main loop.\nwhile true\n\tdoOneBet\n\t\n\twhile true\n\t\t// Why you have to enter 5 to continue is anyone's guess,\n\t\t// but that's what the original program did.\n\t\tagain = input(\" If you want to play again print 5 if not print 2: \")\n\t\tif again == \"5\" or again == \"2\" then break\n\tend while\n\t\n\tif winnings < 0 then\n\t\tprint \"You are now under $\" + (-winnings)\n\telse if winnings > 0 then\n\t\tprint \"You are now ahead $\" + winnings\n\telse\n\t\tprint \"You are now even at 0\"\n\tend if\n\tif again != \"5\" then break\nend while\n\nif winnings < 0 then\n\tprint \"Too bad, you are in the hole. Come again.\"\nelse if winnings > 0 then\n\tprint \"Congratulations---You came out a winner. Come again!\"\nelse\n\tprint \"Congrtulations---You came out even, not bad for an amateur\"\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/29_Craps/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/29_Craps/craps.bas",
    "content": "5 PRINT TAB(33);\"CRAPS\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n12 PRINT:PRINT:PRINT\n15 LET R=0\n20 PRINT\"2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS.\"\n21 LET T=1\n22 PRINT \"PICK A NUMBER AND INPUT TO ROLL DICE\";\n23 INPUT Z\n24 LET X=(RND(0))\n25 LET T =T+1\n26 IF T<=Z THEN 24\n27 PRINT\"INPUT THE AMOUNT OF YOUR WAGER.\";\n28 INPUT F\n30 PRINT \"I WILL NOW THROW THE DICE\"\n40 LET E=INT(7*RND(1))\n41 LET S=INT(7*RND(1))\n42 LET X=E+S\n50 IF X=7 THEN 180\n55 IF X=11 THEN 180\n60 IF X=1 THEN 40\n62 IF X=2 THEN 195\n65 IF X=0 THEN 40\n70 IF X=2 THEN 200\n80 IF X=3 THEN 200\n90 IF X=12 THEN 200\n125 IF X=5 THEN 220\n130 IF X =6 THEN 220\n140 IF X=8 THEN 220\n150 IF X=9 THEN 220\n160 IF X =10 THEN 220\n170 IF X=4 THEN 220\n180 PRINT X \"- NATURAL....A WINNER!!!!\"\n185 PRINT X\"PAYS EVEN MONEY, YOU WIN\"F\"DOLLARS\"\n190 GOTO 210\n195 PRINT X\"- SNAKE EYES....YOU LOSE.\"\n196 PRINT \"YOU LOSE\"F \"DOLLARS.\"\n197 LET F=0-F\n198 GOTO 210\n200 PRINT X \" - CRAPS...YOU LOSE.\"\n205 PRINT \"YOU LOSE\"F\"DOLLARS.\"\n206 LET F=0-F\n210 LET R= R+F\n211 GOTO 320\n220 PRINT X \"IS THE POINT. I WILL ROLL AGAIN\"\n230 LET H=INT(7*RND(1))\n231 LET Q=INT(7*RND(1))\n232 LET O=H+Q\n240 IF O=1 THEN 230\n250 IF O=7 THEN 290\n255 IF O=0 THEN 230\n260 IF O=X THEN 310\n270 PRINT O \" - NO POINT. I WILL ROLL AGAIN\"\n280 GOTO 230\n290 PRINT O \"- CRAPS. YOU LOSE.\"\n291 PRINT \"YOU LOSE $\"F\n292 F=0-F\n293 GOTO 210\n300 GOTO 320\n310 PRINT X\"- A WINNER.........CONGRATS!!!!!!!!\"\n311 PRINT X \"AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...\"2*F\"DOLLARS\"\n312 LET F=2*F\n313 GOTO 210\n320 PRINT \" IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2\";\n330 INPUT M\n331 IF R<0 THEN 334\n332 IF R>0 THEN 336\n333 IF R=0 THEN 338\n334 PRINT \"YOU ARE NOW UNDER $\";-R\n335 GOTO 340\n336 PRINT \"YOU ARE NOW AHEAD $\";R\n337 GOTO 340\n338 PRINT \"YOU ARE NOW EVEN AT 0\"\n340 IF M=5 THEN 27\n341 IF R<0 THEN 350\n342 IF R>0 THEN 353\n343 IF R=0 THEN 355\n350 PRINT\"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN.\"\n351 GOTO 360\n353 PRINT\"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\"\n354 GOTO 360\n355 PRINT\"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR\"\n360 END\n"
  },
  {
    "path": "00_Alternate_Languages/29_Craps/distributions.bas",
    "content": "10 PRINT \"DISTRIBUTION OF DICE ROLLS WITH  INT(7*RND(1))  VS  INT(6*RND(1)+1)\"\n20 DIM A(12)\n30 DIM B(12)\n100 FOR X = 1 TO 100000 : REM CHOOSE A LARGE NUMBER TO GET A FINER GRAINED HISTOGRAM\n140 REM GET A NUMBER FROM 0 TO 6 INCLUSIVE WITH THE INTENT TO THROW AWAY ZEROES.\n150 LET D1 = INT(7*RND(1))\n155 LET D2 = INT(7*RND(1))\n160 LET S1 = D1+D2\n165 REM IF THIS SUM IS LESS THAN TWO THEN TRY AGAIN.\n170 IF S1<2 THEN 150\n199 REM GET A NUMBER FROM 0 TO 5 THEN ADD 1 TO IT TO MAKE IT 1 TO 6\n200 LET D3 = INT(6*RND(1))+1\n210 LET D4 = INT(6*RND(1))+1\n220 LET S2 = D3+D4\n245 REM USE OUR ARRAY AS A HISTOGRAM, COUNTING EACH OCCURRENCE OF DICE ROLL\n250 A(S1) = A(S1) + 1\n260 B(S2) = B(S2) + 1\n290 NEXT X\n300 PRINT \"THE INT(7*RND(1)) DISTRIBUTION:\"\n310 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT\n320 FOR I = 2 TO 12 :PRINT A(I),:NEXT:PRINT\n325 PRINT \"THE INT(6*RND(1)+1) DISTRIBUTION\"\n330 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT\n340 FOR I = 2 TO 12 :PRINT B(I),:NEXT:PRINT\n"
  },
  {
    "path": "00_Alternate_Languages/29_Craps/nim/craps.nim",
    "content": "import std/[random,strutils]\n\nvar\n  wager, winnings, rollResult: int\n  stillplaying: bool = true\n\nrandomize() # Seed the random number generator\n\nproc tryAgain(): bool =\n  echo \"WANT TO PLAY AGAIN? (YES OR NO)\"\n  var answer = readLine(stdin).normalize()\n  result = (answer == \"y\") or (answer == \"yes\")\n\nproc takePoint(point: int) =\n  var flag = true\n  while flag:\n    var pointRoll: int = (rand 1..6) + (rand 1..6) # roll dice, then add the sum\n    if pointRoll == 7:\n      echo pointRoll, \"- CRAPS. YOU LOSE.\"\n      echo \"YOU LOSE \", wager, \" DOLLARS.\"\n      winnings -= wager\n      flag = false\n    if pointRoll == point:\n      echo point, \"- A WINNER.........CONGRATS!!!!!!!!\"\n      echo \"AT 2 TO 1 ODDS PAYS YOU...LET ME SEE... \", 2*wager, \" DOLLARS\"\n      winnings += (2*wager)\n      flag = false\n    if flag:\n      echo pointRoll, \" - NO POINT. I WILL ROLL AGAIN\"\n\necho spaces(33), \"CRAPS\"\necho spaces(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\necho \"\\n\"\necho \"2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS.\"\nwinnings = 0\n\n# play the game\nwhile stillplaying:\n  echo \"\"\n  echo \"INPUT THE AMOUNT OF YOUR WAGER.\"\n  wager = readline(stdin).parseInt()\n  echo \"I WILL NOW THROW THE DICE\"\n  rollResult = (rand 1..6) + (rand 1..6) # roll dice, then add the sum\n  case rollResult:\n    of 7, 11:\n      echo rollResult, \"- NATURAL....A WINNER!!!!\"\n      echo rollResult, \" PAYS EVEN MONEY, YOU WIN \", wager, \" DOLLARS\"\n      winnings += wager\n    of 2:\n      echo rollResult, \"- SNAKE EYES....YOU LOSE.\"\n      echo \"YOU LOSE \", wager, \" DOLLARS.\"\n      winnings -= wager\n    of 3, 12:\n      echo rollResult, \"- CRAPS...YOU LOSE.\"\n      echo \"YOU LOSE \", wager, \" DOLLARS.\"\n      winnings -= wager\n    else:\n      echo rollResult, \" IS THE POINT. I WILL ROLL AGAIN\"\n      takePoint(rollResult)\n  if winnings < 0: echo \"YOU ARE NOW UNDER $\", winnings\n  if winnings > 0: echo \"YOU ARE NOW AHEAD $\", winnings\n  if winnings == 0: echo \"YOU ARE NOW EVEN AT 0\"\n  stillplaying = tryAgain()\n\n# done playing\nif winnings < 0: echo \"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN.\"\nif winnings > 0: echo \"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\"\nif winnings == 0: echo \"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR\"\n"
  },
  {
    "path": "00_Alternate_Languages/30_Cube/C/cube.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n//check if windows or linux for the clear screen\n#ifdef _WIN32\n#define CLEAR \"cls\"\n#else\n#define CLEAR \"clear\"\n#endif\n\ntypedef struct{\n    int x;\n    int y;\n    int z;\n}coords;\n\nvoid instuctions(){\n    printf(\"\\nThis is a game in which you will be playing against the\\n\");\n    printf(\"random decisions of the computer. The field of play is a\\n\");\n    printf(\"cube of side 3. Any of the 27 locations can be designated\\n\");\n    printf(\"by inputing three numbers such as 2,3,1. At the start,\\n\");\n    printf(\"you are automatically at location 1,1,1. The object of\\n\");\n    printf(\"the game is to get to location 3,3,3. One minor detail:\\n\");\n    printf(\"the computer will pick, at random, 5 locations at which\\n\");\n    printf(\"it will plant land mines. If you hit one of these locations\\n\");\n    printf(\"you lose. One other detail: You may move only one space\\n\");\n    printf(\"in one direction each move. For example: From 1,1,2 you\\n\");\n    printf(\"may move to 2,1,2 or 1,1,3. You may not change\\n\");\n    printf(\"two of the numbers on the same move. If you make an illegal\\n\");\n    printf(\"move, you lose and the computer takes the money you may\\n\");\n    printf(\"have bet on that round.\\n\\n\");\n    printf(\"When stating the amount of a wager, printf only the number\\n\");\n    printf(\"of dollars (example: 250) you are automatically started with\\n\");\n    printf(\"500 dollars in your account.\\n\\n\");\n    printf(\"Good luck!\\n\");\n}\n\nvoid game(int money){\n    coords player,playerold,mines[5];\n    int wager,account = money;\n    char choice;\n    if(money == 0){\n        printf(\"You have no money left. See ya next time.\\n\");\n        exit(0);\n    }\n    player.x = 1;\n    player.y = 1;\n    player.z = 1;\n    \n    printf(\"You have $%d in your account.\\n\",account);\n    printf(\"How much do you want to wager? \");\n    scanf(\"%d\",&wager);\n    while(wager > account){\n        system(CLEAR);\n        printf(\"You do not have that much money in your account.\\n\");\n        printf(\"How much do you want to wager? \");\n        scanf(\"%d\",&wager);\n    }\n    srand(time(NULL));\n    for(int i=0;i<5;i++){\n        mines[i].x = rand()%3+1;\n        mines[i].y = rand()%3+1;\n        mines[i].z = rand()%3+1;\n        if(mines[i].x == 3 && mines[i].y == 3 && mines[i].z == 3){\n            i--;\n        }\n    }\n    while(player.x != 3 || player.y != 3 || player.z != 3){\n        printf(\"You are at location %d.%d.%d\\n\",player.x,player.y,player.z);\n        if(player.x == 1 && player.y == 1 && player.z == 1)\n        printf(\"Enter new location(use commas like 1,1,2 or else the program will break...): \");\n        else printf(\"Enter new location: \");\n        playerold.x = player.x;\n        playerold.y = player.y;\n        playerold.z = player.z;\n        scanf(\"%d,%d,%d\",&player.x,&player.y,&player.z);\n        if(((player.x + player.y + player.z) > (playerold.x + playerold.y + playerold.z + 1)) || ((player.x + player.y + player.z) < (playerold.x + playerold.y + playerold.z -1))){\n            system(CLEAR);\n            printf(\"Illegal move!\\n\");\n            printf(\"You lose $%d.\\n\",wager);\n            game(account -= wager);\n            break;\n        }\n        if(player.x < 1 || player.x > 3 || player.y < 1 || player.y > 3 || player.z < 1 || player.z > 3){\n            system(CLEAR);\n            printf(\"Illegal move. You lose!\\n\");\n            game(account -= wager);\n            break;\n        }\n        for(int i=0;i<5;i++){\n            if(player.x == mines[i].x && player.y == mines[i].y && player.z == mines[i].z){\n                system(CLEAR);\n                printf(\"You hit a mine!\\n\");\n                printf(\"You lose $%d.\\n\",wager);\n                game(account -= wager);\n                exit(0);\n            }\n        }\n        if(account == 0){\n            system(CLEAR);\n            printf(\"You have no money left!\\n\");\n            printf(\"Game over!\\n\");\n            exit(0);\n        }\n    }\n    if(player.x == 3 && player.y == 3 && player.z == 3){\n        system(CLEAR);\n        printf(\"You made it to the end. You win!\\n\");\n        game(account += wager);\n        exit(0);\n    }\n}\n\nvoid init(){\n    int account = 500;\n    char choice;\n\n    printf(\"Welcome to the game of Cube!\\n\");\n    printf(\"wanna see the instructions? (y/n): \");\n    scanf(\"%c\",&choice);\n    if(choice == 'y'){\n        system(CLEAR);\n        instuctions();\n    }\n    else if (choice == 'n'){\n        system(CLEAR);\n        printf(\"Ok, let's play!\\n\");\n    }\n    else{\n        system(CLEAR);\n        printf(\"Invalid choice. Try again...\\n\");\n        init();\n        exit(0);\n    }\n    game(account);\n    exit(0);\n}\n\nvoid main(){\n    init();\n}"
  },
  {
    "path": "00_Alternate_Languages/30_Cube/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript cube.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"cube\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/30_Cube/MiniScript/cube.ms",
    "content": "print \" \"*34 + \"Bullseye\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nif input(\"Do you want to see the instructions? (yes--1,no--0) \").val then\n\tprint \"This is a game in which you will be playing against the\"\n\tprint \"random decision of the computer. The field of play is a\"\n\tprint \"cube of size 3. Any of the locations can be designated\"\n\tprint \"by inputing three numbers such as 2,3,1. At the start,\"\n\tprint \"you are automatically at location 1,1,1. The object of\"\n\tprint \"the game is to get to location 3,3,3. One minor detail:\"\n\tprint \"the computer will pick, at random, locations at which\"\n\tprint \"it will plant land mines. If you hit one of these locations\"\n\tprint \"you lose. One other detail: you may move only one space \"\n\tprint \"in one direction each move. For  example: from 1,1,2 you\"\n\tprint \"may move to 2,1,2 or 1,1,3. You may not change\"\n\tprint \"two of the numbers on the same move. If you make an illegal\"\n\tprint \"move, you lose and the computer takes the money you may\"\n\tprint \"have bet on that round.\"\n\tprint\n\tprint\n\tprint \"All yes or no questions will be answered by a 1 for yes\"\n\tprint \"or a 0 (zero) for no.\"\n\tprint\n\tprint \"When stating the amount of a wager, print only the number\"\n\tprint \"of dollars (example: 250). You are automatically started with\"\n\tprint \"500 dollars in your account.\"\n\tprint\n\tprint \"Good luck!\"\nend if\n\nmoney = 500\n\nwhile money >= 0\n\tmineLocs = []\n\t// Note: unlike the original BASIC program, which doesn't actually pick random\n\t// numbers unless you manually set X to a positive value before running the \n\t// program, we do pick five random mine locations here.\n\t// But like that program, we make no attempt to avoid 1,1,1 or 3,3,3, or to\n\t// ensure that we have picked five DIFFERENT locations.\n\tfor i in range(1,5)\n\t\tmineLocs.push [floor(3 * rnd + 1), floor(3 * rnd + 1), floor(3 * rnd + 1)]\n\tend for\n\twager = 0\n\tif input(\"Want to make a wager? \").val then\n\t\twager = input(\"How much? \").val\n\t\twhile money < wager\n\t\t\twager = input(\"Tried to fool me; bet again? \").val\n\t\tend while\n\tend if\n\tposition = [1,1,1]\n\tprint\n\tinp = input(\"It's your move:  \")\n\twon = 0\n\twhile true\n\t\tinp = inp.replace(\",\", \" \").replace(\"  \", \" \").split\n\t\tnewPos = []\n\t\tif inp.len == 3 then newPos = [inp[0].val, inp[1].val, inp[2].val]\n\t\tlegal = newPos.len == 3\n\t\ttotalChange = 0\n\t\tfor i in newPos.indexes\n\t\t\t// The original game allowed you to walk outside the 1-3 range,\n\t\t\t// thus safely avoiding all the mines.  To disallow this exploit,\n\t\t\t// uncomment the following line.\n\t\t\t//if newPos[i] < 1 or newPos[i] > 3 then legal = false\n\t\t\ttotalChange += abs(newPos[i] - position[i])\n\t\tend for\n\t\tif totalChange > 1 then legal = false\n\t\tif not legal then\n\t\t\tprint; print \"Illegal move. You lose.\"\n\t\t\twon = -wager\n\t\t\tbreak\n\t\tend if\n\t\tif newPos == [3,3,3] then\n\t\t\tprint \"Congratulations!\"\n\t\t\twon = wager\n\t\t\tbreak\n\t\telse if mineLocs.indexOf(newPos) != null then\n\t\t\tprint \"******BANG******\"\n\t\t\tprint \"You lose!\"\n\t\t\tprint\n\t\t\tprint\n\t\t\twon = -wager\n\t\t\tbreak\n\t\tend if\n\t\tposition = newPos\n\t\tinp = input(\"Next move: \")\n\tend while\n\tif won != 0 then\n\t\tglobals.money += won\n\t\tif money <= 0 then print \"You bust.\"\n\tend if\n\tif wager then\n\t\tprint \" You now have \" + money + \" dollars.\"\n\tend if\n\tif not input(\"Do you want to try again? \").val then break\nend while\nprint \"Tough luck!\"\nprint\nprint \"Goodbye.\"\n"
  },
  {
    "path": "00_Alternate_Languages/30_Cube/README.md",
    "content": "#### External Links\n - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp\n - PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1\n"
  },
  {
    "path": "00_Alternate_Languages/30_Cube/cube.bas",
    "content": "10 PRINT TAB(34);\"CUBE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT : PRINT : PRINT\n100 PRINT \"DO YOU WANT TO SEE THE INSTRUCTIONS? (YES--1,NO--0)\"\n110 INPUT B7\n120 IF B7=0 THEN 370\n130 PRINT\"THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE\"\n140 PRINT\"RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A\"\n150 PRINT\"CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED\"\n160 PRINT\"BY INPUTING THREE NUMBERS SUCH AS 2,3,1. AT THE START,\"\n170 PRINT\"YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF\"\n180 PRINT\"THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:\"\n190 PRINT\"THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH\"\n200 PRINT\"IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS\"\n210 PRINT\"YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE \"\n220 PRINT\"IN ONE DIRECTION EACH MOVE. FOR  EXAMPLE: FROM 1,1,2 YOU\"\n230 PRINT\"MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE\"\n240 PRINT\"TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL\"\n250 PRINT\"MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY\"\n260 PRINT\"HAVE BET ON THAT ROUND.\"\n270 PRINT\n280 PRINT\n290 PRINT\"ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES\"\n300 PRINT\"OR A 0 (ZERO) FOR NO.\"\n310 PRINT\n320 PRINT\"WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER\"\n330 PRINT\"OF DOLLARS (EXAMPLE: 250)  YOU ARE AUTOMATICALLY STARTED WITH\"\n340 PRINT\"500 DOLLARS IN YOUR ACCOUNT.\"\n350 PRINT\n360 PRINT \"GOOD LUCK!\"\n370 LET A1=500\n380 LET A=INT(3*(RND(X)))\n390 IF A<>0 THEN 410\n400 LET A=3\n410 LET B=INT(3*(RND(X)))\n420 IF B<>0 THEN 440\n430 LET B=2\n440 LET C=INT(3*(RND(X)))\n450 IF C<>0 THEN 470\n460 LET C=3\n470 LET D=INT(3*(RND(X)))\n480 IF D<>0 THEN 500\n490 LET D=1\n500 LET E=INT(3*(RND(X)))\n510 IF E<>0 THEN 530\n520 LET E=3\n530 LET F=INT(3*(RND(X)))\n540 IF F<>0 THEN 560\n550 LET F=3\n560 LET G=INT(3*(RND(X)))\n570 IF G<>0 THEN 590\n580 LET G=3\n590 LET H=INT(3*(RND(X)))\n600 IF H<>0 THEN 620\n610 LET H=3\n620 LET I=INT(3*(RND(X)))\n630 IF I<>0 THEN 650\n640 LET I=2\n650 LET J=INT(3*(RND(X)))\n660 IF J<>0 THEN 680\n670 LET J=3\n680 LET K=INT(3*(RND(X)))\n690 IF K<>0 THEN 710\n700 LET K=2\n710 LET L=INT(3*(RND(X)))\n720 IF L<>0 THEN 740\n730 LET L=3\n740 LET M=INT(3*(RND(X)))\n750 IF M<>0 THEN 770\n760 LET M=3\n770 LET N=INT(3*(RND(X)))\n780 IF N<>0 THEN 800\n790 LET N=1\n800 LET O=INT (3*(RND(X)))\n810 IF O <>0 THEN 830\n820 LET O=3\n830 PRINT \"WANT TO MAKE A WAGER?\"\n840 INPUT Z\n850 IF Z=0 THEN 880\n860 PRINT \"HOW MUCH \";\n870 INPUT Z1\n876 IF A1<Z1 THEN 1522\n880 LET W=1\n890 LET X=1\n900 LET Y=1\n910 PRINT\n920 PRINT \"IT'S YOUR MOVE:  \";\n930 INPUT P,Q,R\n940 IF P>W+1 THEN 1030\n950 IF P=W+1 THEN 1000\n960 IF Q>X+1 THEN 1030\n970 IF Q=(X+1) THEN 1010\n980 IF R >(Y+1)  THEN 1030\n990 GOTO 1050\n1000 IF Q>= X+1 THEN 1030\n1010 IF R>=Y+1 THEN 1030\n1020 GOTO 1050\n1030 PRINT:PRINT \"ILLEGAL MOVE. YOU LOSE.\"\n1040 GOTO 1440\n1050 LET W=P\n1060 LET X=Q\n1070 LET Y=R\n1080 IF P=3 THEN 1100\n1090 GOTO 1130\n1100 IF  Q=3 THEN 1120\n1110 GOTO 1130\n1120 IF R=3 THEN 1530\n1130 IF P=A THEN 1150\n1140 GOTO 1180\n1150 IF Q=B THEN 1170\n1160 GOTO 1180\n1170 IF R=C THEN 1400\n1180 IF P=D THEN 1200\n1190 GOTO 1230\n1200 IF Q=E THEN 1220\n1210 GOTO 1230\n1220 IF  R=F THEN 1400\n1230 IF P=G THEN 1250\n1240 GOTO 1280\n1250 IF Q=H THEN 1270\n1260 GOTO 1280\n1270 IF R=I THEN 1400\n1280 IF P=J THEN 1300\n1290 GOTO 1330\n1300 IF Q=K THEN 1320\n1310 GOTO 1330\n1320 IF R=L THEN 1400\n1330 IF P=M THEN 1350\n1340 GOTO 1380\n1350 IF Q=N THEN 1370\n1360 GOTO 1380\n1370 IF R=O THEN 1400\n1380 PRINT \"NEXT MOVE: \";\n1390 GOTO 930\n1400 PRINT\"******BANG******\"\n1410 PRINT \"YOU LOSE!\"\n1420 PRINT\n1430 PRINT\n1440 IF   Z=0 THEN 1580\n1450 PRINT\n1460 LET Z2=A1-Z1\n1470 IF Z2>0 THEN 1500\n1480 PRINT \"YOU BUST.\"\n1490 GOTO 1610\n1500 PRINT \" YOU NOW HAVE\"; Z2; \"DOLLARS.\"\n1510 LET A1=Z2\n1520 GOTO 1580\n1522 PRINT\"TRIED TO FOOL ME; BET AGAIN\";\n1525 GOTO 870\n1530 PRINT\"CONGRATULATIONS!\"\n1540 IF Z=0 THEN 1580\n1550 LET Z2=A1+Z1\n1560 PRINT \"YOU NOW HAVE\"; Z2;\"DOLLARS.\"\n1570 LET A1=Z2\n1580 PRINT\"DO YOU WANT TO TRY AGAIN \";\n1590 INPUT S\n1600 IF S=1 THEN 380\n1610 PRINT \"TOUGH LUCK!\"\n1620 PRINT\n1630 PRINT \"GOODBYE.\"\n1640 END\n"
  },
  {
    "path": "00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript depthcharge.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"depthcharge.ms\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms",
    "content": "// Depth Charge\r\n// Originally by Dana Noftle (1978)\r\n// Translated from BASIC to MiniScript by Ryushinaka and Joe Strout (2023)\r\n\r\naskYesNo = function(prompt)\r\n\twhile true\r\n\t\tanswer = input(prompt).lower[:1]\r\n\t\tif answer == \"y\" or answer == \"n\" then return answer\r\n\tend while\r\nend function\r\n\r\nshowWelcome = function\r\n\tprint\r\n\tprint \" \"*34 + \"Depth Charge\"\r\n\tprint \" \"*15 + \"Creative Computing Morristown, New Jersey\"\r\n\tprint\r\nend function\r\n\r\nsetup = function\r\n\twhile true\r\n\t\tglobals.size = input(\"Dimension of search area? \").val\r\n\t\tif size > 0 then break\r\n\tend while\r\n\r\n\tglobals.numCharges = ceil(log(size,2))\r\n\tif numCharges == 0 then globals.numCharges = 1  // ensure we have at least 1 shot\r\n\r\n\tprint \"You are the captain of the destroyer USS Computer.\"\r\n\tprint \"An enemy sub has been causing you trouble. Your\"\t\r\n\tprint \"mission is to destroy it. You have \" + numCharges + \" shots.\"\r\n\tprint \"Specify depth charge explosion point with a\"\r\n\tprint \"trio of numbers -- the first two are the\"\r\n\tprint \"surface coordinates; the third is the depth.\"\r\nend function\r\n\r\nshowShotResult = function(shot,location)\r\n\tresult = \"Sonar reports shot was \"\r\n\tif shot[1] > location[1] then\r\n\t\tresult = result + \"north\"\r\n\telse if shot[1] < location[1] then\r\n\t\tresult = result + \"south\"\t\t\r\n\tend if\r\n\t\r\n\tif shot[0] > location[0] then\r\n\t\tresult = result + \"east\"\r\n\telse if shot[0] < location[0] then\r\n\t\tresult = result + \"west\"\r\n\tend if\r\n\t\r\n\tif shot[1] != location[1] or shot[0] != location[0] then\r\n\t\tresult = result + \" and \"\r\n\tend if\r\n\t\r\n\tif shot[2] > location[2] then\r\n\t\tresult = result + \"too low.\"\r\n\telse if shot[2] < location[2] then\r\n\t\tresult = result + \"too high.\"\r\n\telse\r\n\t\tresult = result + \"depth OK.\"\r\n\tend if\r\n\t\r\n\tprint result\r\nend function\r\n\r\ngetShot = function\r\n\tshotPos = [0,0,0]\r\n\twhile true\r\n\t\trawGuess = input(\"Enter coordinates: \").split(\" \")\r\n\t\tif rawGuess.len == 3 then\r\n\t\t\tshotPos[0] = rawGuess[0].val\r\n\t\t\tshotPos[1] = rawGuess[1].val\r\n\t\t\tshotPos[2] = rawGuess[2].val\r\n\t\t\treturn shotPos\r\n\t\telse\r\n\t\t\tprint \"Please enter coordinates separated by spaces\"\r\n\t\t\tprint \"Example: 3 2 1\"\r\n\t\tend if\r\n\tend while\r\nend function\r\n\r\n\r\nplayGame = function\r\n\tprint \"Good luck!\"\r\n\tprint \r\n\t\r\n\tsubPos = [floor(rnd*size), floor(rnd*size), floor(rnd*size)]\r\n\t\r\n\t// For debugging, you can give away the answer:\r\n\t//print \"(Sub is hidden at: \" + subPos.join(\" \") + \")\"\r\n\t\r\n\tfor c in range(1, numCharges)\r\n\t\tprint \"Trial \" + c\r\n\t\t\r\n\t\tshot = getShot\r\n\t\t\r\n\t\tif shot[0] == subPos[0] and shot[1] == subPos[1] and shot[2] == subPos[2] then\r\n\t\t\tprint \"B O O M ! ! You found it in \" + c + \" tries!\"\r\n\t\t\treturn\r\n\t\telse\r\n\t\t\tshowShotResult(shot,subPos)\r\n\t\tend if\r\n\tend for\r\n\t\r\n\tprint \"You have been torpedoed! Abandon ship!\"\r\n\tprint \"The submarine was at \" + subPos.join(\" \") + \".\"\r\nend function\r\n\r\nshowWelcome\r\nsetup\r\nwhile true\r\n\tplayGame\r\n\tif askYesNo(\"Another game (Y or N): \") == \"n\" then\r\n\t\tprint \"OK. Hope you enjoyed yourself.\"\r\n\t\tbreak\r\n\tend if\r\nend while\r\n"
  },
  {
    "path": "00_Alternate_Languages/31_Depth_Charge/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/31_Depth_Charge/depthcharge.bas",
    "content": "2 PRINT TAB(30);\"DEPTH CHARGE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n20 INPUT \"DIMENSION OF SEARCH AREA\";G: PRINT\n30 N=INT(LOG(G)/LOG(2))+1\n40 PRINT \"YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\"\n50 PRINT \"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\"\n60 PRINT \"MISSION IS TO DESTROY IT.  YOU HAVE\";N;\"SHOTS.\"\n70 PRINT \"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\"\n80 PRINT \"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\"\n90 PRINT \"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\"\n100 PRINT : PRINT \"GOOD LUCK !\": PRINT\n110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1))\n120 FOR D=1 TO N : PRINT : PRINT \"TRIAL #\";D; : INPUT X,Y,Z\n130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300\n140 GOSUB 500 : PRINT : NEXT D\n200 PRINT : PRINT \"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\"\n210 PRINT \"THE SUBMARINE WAS AT\";A;\",\";B;\",\";C : GOTO 400\n300 PRINT : PRINT \"B O O M ! ! YOU FOUND IT IN\";D;\"TRIES!\"\n400 PRINT : PRINT: INPUT \"ANOTHER GAME (Y OR N)\";A$\n410 IF A$=\"Y\" THEN 100\n420 PRINT \"OK.  HOPE YOU ENJOYED YOURSELF.\" : GOTO 600\n500 PRINT \"SONAR REPORTS SHOT WAS \";\n510 IF Y>B THEN PRINT \"NORTH\";\n520 IF Y<B THEN PRINT \"SOUTH\";\n530 IF X>A THEN PRINT \"EAST\";\n540 IF X<A THEN PRINT \"WEST\";\n550 IF Y<>B OR X<>A THEN PRINT \" AND\";\n560 IF Z>C THEN PRINT \" TOO LOW.\"\n570 IF Z<C THEN PRINT \" TOO HIGH.\"\n580 IF Z=C THEN PRINT \" DEPTH OK.\"\n590 RETURN\n600 END\n"
  },
  {
    "path": "00_Alternate_Languages/31_Depth_Charge/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\ntype Position []int\r\n\r\nfunc NewPosition() Position {\r\n\tp := make([]int, 3)\r\n\treturn Position(p)\r\n}\r\n\r\nfunc showWelcome() {\r\n\tfmt.Print(\"\\033[H\\033[2J\")\r\n\tfmt.Println(\"                DEPTH CHARGE\")\r\n\tfmt.Println(\"    Creative Computing  Morristown, New Jersey\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc getNumCharges() (int, int) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"Dimensions of search area?\")\r\n\t\tscanner.Scan()\r\n\t\tdim, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"Must enter an integer number. Please try again...\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\treturn dim, int(math.Log2(float64(dim))) + 1\r\n\t}\r\n}\r\n\r\nfunc askForNewGame() {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfmt.Println(\"Another game (Y or N): \")\r\n\tscanner.Scan()\r\n\tif strings.ToUpper(scanner.Text()) == \"Y\" {\r\n\t\tmain()\r\n\t}\r\n\tfmt.Println(\"OK. Hope you enjoyed yourself\")\r\n\tos.Exit(1)\r\n}\r\n\r\nfunc showShotResult(shot, location Position) {\r\n\tresult := \"Sonar reports shot was \"\r\n\r\n\tif shot[1] > location[1] { // y-direction\r\n\t\tresult += \"north\"\r\n\t} else if shot[1] < location[1] { // y-direction\r\n\t\tresult += \"south\"\r\n\t}\r\n\r\n\tif shot[0] > location[0] { // x-direction\r\n\t\tresult += \"east\"\r\n\t} else if shot[0] < location[0] { // x-direction\r\n\t\tresult += \"west\"\r\n\t}\r\n\r\n\tif shot[1] != location[1] || shot[0] != location[0] {\r\n\t\tresult += \" and \"\r\n\t}\r\n\tif shot[2] > location[2] {\r\n\t\tresult += \"too low.\"\r\n\t} else if shot[2] < location[2] {\r\n\t\tresult += \"too high.\"\r\n\t} else {\r\n\t\tresult += \"depth OK.\"\r\n\t}\r\n\r\n\tfmt.Println(result)\r\n}\r\n\r\nfunc getShot() Position {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tshotPos := NewPosition()\r\n\t\tfmt.Println(\"Enter coordinates: \")\r\n\t\tscanner.Scan()\r\n\t\trawGuess := strings.Split(scanner.Text(), \" \")\r\n\t\tif len(rawGuess) != 3 {\r\n\t\t\tgoto there\r\n\t\t}\r\n\t\tfor i := 0; i < 3; i++ {\r\n\t\t\tval, err := strconv.Atoi(rawGuess[i])\r\n\t\t\tif err != nil {\r\n\t\t\t\tgoto there\r\n\t\t\t}\r\n\t\t\tshotPos[i] = val\r\n\t\t}\r\n\t\treturn shotPos\r\n\tthere:\r\n\t\tfmt.Println(\"Please enter coordinates separated by spaces\")\r\n\t\tfmt.Println(\"Example: 3 2 1\")\r\n\t}\r\n}\r\n\r\nfunc getRandomPosition(searchArea int) Position {\r\n\tpos := NewPosition()\r\n\tfor i := 0; i < 3; i++ {\r\n\t\tpos[i] = rand.Intn(searchArea)\r\n\t}\r\n\treturn pos\r\n}\r\n\r\nfunc playGame(searchArea, numCharges int) {\r\n\trand.Seed(time.Now().UTC().UnixNano())\r\n\tfmt.Println(\"\\nYou are the captain of the destroyer USS Computer.\")\r\n\tfmt.Println(\"An enemy sub has been causing you trouble. Your\")\r\n\tfmt.Printf(\"mission is to destroy it. You have %d shots.\\n\", numCharges)\r\n\tfmt.Println(\"Specify depth charge explosion point with a\")\r\n\tfmt.Println(\"trio of numbers -- the first two are the\")\r\n\tfmt.Println(\"surface coordinates; the third is the depth.\")\r\n\tfmt.Println(\"\\nGood luck!\")\r\n\tfmt.Println()\r\n\r\n\tsubPos := getRandomPosition(searchArea)\r\n\r\n\tfor c := 0; c < numCharges; c++ {\r\n\t\tfmt.Printf(\"\\nTrial #%d\\n\", c+1)\r\n\r\n\t\tshot := getShot()\r\n\r\n\t\tif shot[0] == subPos[0] && shot[1] == subPos[1] && shot[2] == subPos[2] {\r\n\t\t\tfmt.Printf(\"\\nB O O M ! ! You found it in %d tries!\\n\", c+1)\r\n\t\t\taskForNewGame()\r\n\t\t} else {\r\n\t\t\tshowShotResult(shot, subPos)\r\n\t\t}\r\n\t}\r\n\r\n\t// out of depth charges\r\n\tfmt.Println(\"\\nYou have been torpedoed! Abandon ship!\")\r\n\tfmt.Printf(\"The submarine was at %d %d %d\\n\", subPos[0], subPos[1], subPos[2])\r\n\taskForNewGame()\r\n\r\n}\r\n\r\nfunc main() {\r\n\tshowWelcome()\r\n\r\n\tsearchArea, numCharges := getNumCharges()\r\n\r\n\tplayGame(searchArea, numCharges)\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/32_Diamond/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript diamond.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"diamond\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms",
    "content": "// Diamond\n//\n// Ported from BASIC to MiniScript by Joe Strout\n\nprint \" \"*33 + \"DIAMOND\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\nprint \"For a pretty diamond pattern,\"\nmaxw = input(\"type in an odd number between 5 and 21: \").val\ns = \"CC\" + \"!\" * maxw\ncolumns = floor(68/maxw)\nfor row in range(1, columns)\n\tfor w in range(1, maxw, 2) + range(maxw-2, 1, -2)\n\t\tprint \" \"*(maxw-w)/2, \"\"\n\t\tfor column in range(1, columns)\n\t\t\tprint s[:w], \"\"\n\t\t\tif column < columns then print \" \"*(maxw-w), \"\"\n\t\tend for\n\t\tprint\n\t\twait 0.01\n\tend for\nend for\n\n"
  },
  {
    "path": "00_Alternate_Languages/32_Diamond/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/32_Diamond/diamond.bas",
    "content": "1 PRINT TAB(33);\"DIAMOND\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"FOR A PRETTY DIAMOND PATTERN,\"\n5 INPUT \"TYPE IN AN ODD NUMBER BETWEEN 5 AND 21\";R:PRINT\n6 Q=INT(60/R):A$=\"CC\"\n8 FOR L=1 TO Q\n10 X=1:Y=R:Z=2\n20 FOR N=X TO Y STEP Z\n25 PRINT TAB((R-N)/2);\n28 FOR M=1 TO Q\n29 C=1\n30 FOR A=1 TO N\n32 IF C>LEN(A$) THEN PRINT \"!\";:GOTO 50\n34 PRINT MID$(A$,C,1);\n36 C=C+1\n50 NEXT A\n53 IF M=Q THEN 60\n55 PRINT TAB(R*M+(R-N)/2);\n56 NEXT M\n60 PRINT\n70 NEXT N\n83 IF X<>1 THEN 95\n85 X=R-2:Y=1:Z=-2\n90 GOTO 20\n95 NEXT L\n99 END\n"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/C/dice.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\nfloat percent(int number, int total){\n    float percent;\n    percent = (float)number / (float)total * 100;\n    return percent;\n}\n\nint main(){\n    int dice1,dice2,times,rolls[13] = {0};\n    srand(time(NULL));\n    printf(\"This program simulates the rolling of a pair of dice\\n\");\n    printf(\"How many times do you want to roll the dice?(Higher the number longer the waiting time): \");\n    scanf(\"%d\",&times);\n    for(int i = 0; i < times; i++){\n        dice1 = rand() % 6 + 1;\n        dice2 = rand() % 6 + 1;\n        rolls[dice1 + dice2]+=1;\n    }\n    printf(\"The number of times each sum was rolled is:\\n\");\n    for(int i = 2; i <= 12; i++){\n        printf(\"%d: rolled %d times, or %f%c of the times\\n\",i,rolls[i],percent(rolls[i],times),(char)37);\n    }\n}"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/Julia/Dice.jl",
    "content": "#=\nPort of Dice from BASIC Computer Games (1978)\n\nThis \"game\" simulates a given number of dice rolls, and returns the \ncount for each possible total.\n\nThe only change that has been made from the original program, is that \nwhen asking if the user wants to play again, any string starting with\ny or Y will be accepted, instead of only YES.\n=#\n\nfunction main()\n    # Array to store the counts for each total.\n    # There are 11 possible totals.\n    counts = [0 for i in 1:11]\n\n    # Print intro text\n    println(\"\\n                   Dice\")\n    println(\"Creative Computing  Morristown, New Jersey\")\n    println(\"\\n\\n\")\n    println(\"This program simulates the rolling of a\")\n    println(\"pair of dice.\")\n    println(\"You enter the number of times you want the computer to\")\n    println(\"'roll' the dice.   Watch out, very large numbers take\")\n    println(\"a long time.  In particular, numbers over 5000.\")\n\n    still_playing = true\n    while still_playing\n        println()\n        print(\"How many rolls? \")\n\n        # Get user input for number of dice rolls\n        rolls = readline()\n        rolls = parse(Int64, rolls)\n\n        # Roll dice the specified number of times and update total count\n        for _ in 1:rolls\n            dice_roll = rand(1:6, 2)\n            dice_sum = sum(dice_roll)\n\n            # The index is one less than the sum, as a sum of 1 is impossible,\n            # the array will only have 11 values\n            counts[dice_sum-1] += 1\n        end\n\n        # Display results\n        println(\"\\nTotal Spots   Number of Times\")\n        for i in 1:8\n            print(\" \")\n            print(i+1)\n            print(\"             \")\n            println(counts[i])\n        end\n        for i in 9:11\n            print(\" \")\n            print(i+1)\n            print(\"            \")\n            println(counts[i])\n        end\n\n        # Ask try again\n        print(\"\\nTry Again? \")\n        input = readline()\n        if length(input) > 0 && uppercase(input)[1] == 'Y'\n             # If game is continued, resets total counts\n            counts = [0 for i in 1:11]\n        else\n            still_playing = false\n        end\n    end\nend\n\nif abspath(PROGRAM_FILE) == @__FILE__\n    main()\nend"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/Julia/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.julialang.org/)"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript dice.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"dice\"\n\trun\n```\n3. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of dice.ms, and click the \"Run Script\" button.\n"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/MiniScript/dice.ms",
    "content": "// Dice\n//\n// Danny Freidus\n// Ported from BASIC to MiniScript by Joe Strout\n\nprint \" \"*34 + \"DICE\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\nprint \"This program simulates the rolling of a\"\nprint \"pair of dice.\"\nprint \"You enter the number of times you want the computer to\"\nprint \"'roll' the dice.  Watch out, very large numbers take\"\nprint \"a long time.  In particular, numbers over 5000.\"\n\n// Function to do one run of the simulation.\nrunOnce = function\n\t// Clear the array we'll use to hold the counts\n\tcounts = [0] * 13\n\t// Loop the desired number of times\n\tx = input(\"How many rolls? \").val\n\tfor s in range(1, x)\n\t\t// roll two dice and find the sum\n\t\tdie1 = ceil(6 * rnd)\n\t\tdie2 = ceil(6 * rnd)\n\t\tsum = die1 + die2\n\t\t// update the count for that sum\n\t\tcounts[sum] += 1\n\tend for\n\tprint\n\t\n\t// print a table showing how many times each sum was rolled\n\tprint \"Total Spots   Number of Times\"\n\tfor v in range(2, 12)\n\t\t// (the [-6:] trick below right-aligns the number)\n\t\tprint (\"     \" + v)[-6:] + \" \"*10 + counts[v]\n\tend for\n\tprint; print\nend function\n\n// Get a yes/no (or at least y/n) response from the user.\naskYesNo = function(prompt)\n\twhile true\n\t\tanswer = input(prompt).lower[:1]\n\t\tif answer == \"y\" or answer == \"n\" then return answer\n\tend while\nend function\n\n// main loop\nwhile true\n\tprint\n\trunOnce\t\n\tif askYesNo(\"Try again? \") == \"n\" then break\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/33_Dice/dice.bas",
    "content": "2 PRINT TAB(34);\"DICE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 DIM F(12)\n20 REM  DANNY FREIDUS\n30 PRINT \"THIS PROGRAM SIMULATES THE ROLLING OF A\"\n40 PRINT \"PAIR OF DICE.\"\n50 PRINT \"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\"\n60 PRINT \"'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\"\n70 PRINT \"A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\"\n80 FOR Q=1 TO 12\n90 F(Q)=0\n100 NEXT Q\n110 PRINT:PRINT \"HOW MANY ROLLS\";\n120 INPUT X\n130 FOR S=1 TO X\n140 A=INT(6*RND(1)+1)\n150 B=INT(6*RND(1)+1)\n160 R=A+B\n170 F(R)=F(R)+1\n180 NEXT S\n185 PRINT\n190 PRINT \"TOTAL SPOTS\",\"NUMBER OF TIMES\"\n200 FOR V=2 TO 12\n210 PRINT V,F(V)\n220 NEXT V\n221 PRINT\n222 PRINT:PRINT \"TRY AGAIN\";\n223 INPUT Z$\n224 IF Z$=\"YES\" THEN 80\n240 END\n"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n)\r\n\r\nfunc printWelcome() {\r\n\tfmt.Println(\"\\n                   Dice\")\r\n\tfmt.Println(\"Creative Computing  Morristown, New Jersey\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println(\"This program simulates the rolling of a\")\r\n\tfmt.Println(\"pair of dice.\")\r\n\tfmt.Println(\"You enter the number of times you want the computer to\")\r\n\tfmt.Println(\"'roll' the dice.   Watch out, very large numbers take\")\r\n\tfmt.Println(\"a long time.  In particular, numbers over 5000.\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc main() {\r\n\tprintWelcome()\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"\\nHow many rolls? \")\r\n\t\tscanner.Scan()\r\n\t\tnumRolls, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"Invalid input, try again...\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\t// We'll track counts of roll outcomes in a 13-element list.\r\n\t\t// The first two indices (0 & 1) are ignored, leaving just\r\n\t\t// the indices that match the roll values (2 through 12).\r\n\t\tresults := make([]int, 13)\r\n\r\n\t\tfor n := 0; n < numRolls; n++ {\r\n\t\t\td1 := rand.Intn(6) + 1\r\n\t\t\td2 := rand.Intn(6) + 1\r\n\t\t\tresults[d1+d2] += 1\r\n\t\t}\r\n\r\n\t\t// Display final results\r\n\t\tfmt.Println(\"\\nTotal Spots   Number of Times\")\r\n\t\tfor i := 2; i < 13; i++ {\r\n\t\t\tfmt.Printf(\" %-14d%d\\n\", i, results[i])\r\n\t\t}\r\n\r\n\t\tfmt.Println(\"\\nTry again? \")\r\n\t\tscanner.Scan()\r\n\t\tif strings.ToUpper(scanner.Text()) == \"Y\" {\r\n\t\t\tcontinue\r\n\t\t} else {\r\n\t\t\tos.Exit(1)\r\n\t\t}\r\n\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/33_Dice/nim/dice.nim",
    "content": "import std/[random,strutils]\n\nvar\n  a,b,r,x: int\n  f: array[2..12, int]\n  z: string\n  retry: bool = true\n\nrandomize() # Seed the random number generator\n\necho spaces(34), \"DICE\"\necho spaces(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\necho \"\\n\"\necho \"THIS PROGRAM SIMULATES THE ROLLING OF A PAIR OF DICE.\"\necho \"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\"\necho \"'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\"\necho \"A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\"\n\nwhile(retry):\n  echo \"\\n\"\n  echo \"HOW MANY ROLLS\"\n  x = readLine(stdin).parseInt()\n  for v in 2..12:\n    f[v] = 0 # Initialize array to 0\n  for s in 1..x:\n    a = rand(1..6) # Die 1\n    b = rand(1..6) # Die 2\n    r = a + b # Sum of dice\n    f[r] += 1 # Increment array count of dice sum result\n  echo \"\"\n  echo \"TOTAL SPOTS: \", \"NUMBER OF TIMES\"\n  for v in 2..12:\n    echo v, \": \", f[v] # Print out counts for each possible result\n  echo \"\\n\"\n  echo \"TRY AGAIN?\"\n  z = readLine(stdin).normalize()\n  retry = (z==\"yes\") or (z==\"y\")\n"
  },
  {
    "path": "00_Alternate_Languages/34_Digits/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript digits.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"digits\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/34_Digits/MiniScript/digits.ms",
    "content": "import \"listUtil\"\n\nprint \" \"*33 + \"Digits\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprintInColumns = function(a, b, c, d)\n\tprint (a+\" \"*16)[:16] + (b+\" \"*16)[:16] + (c+\" \"*16)[:16] + (d+\" \"*16)[:16]\nend function\n\nprint \"This is a game of guessing.\"\nprint \"For instructions, type '1', else type '0'\"\nif input != \"0\" then\n\tprint\n\tprint \"Please take a piece of paper and write down\"\n\tprint \"the digits '0', '1', or '2' thirty times at random.\"\n\tprint \"Arrange them in three lines of ten digits each.\"\n\tprint \"I will ask for then ten at a time.\"\n\tprint \"I will always guess them first and then look at your\"\n\tprint \"next number to see if i was right. By pure luck,\"\n\tprint \"I ought to be right ten times. But i hope to do better\"\n\tprint \"than that *****\"\n\tprint; print\nend if\n\na = 0; b = 1; c = 3\n\nwhile true\n\tm = list.init2d(27, 3, 1)\n\tk = list.init2d(3, 3, 9)\n\tl = list.init2d(9, 3, 3)\n\tl[0][0] = 2; l[4][1] = 2; l[8][2] = 2\n\tz=26; z1=8; z2=2\n\tqtyRight = 0\n\tguess = 0\n\tfor t in range(1,3)\n\t\twhile true\n\t\t\tprint\n\t\t\tprint \"Ten numbers, please\";\n\t\t\tn = input.replace(\",\", \" \").replace(\"  \", \"\").split\n\t\t\tif n.len != 10 then continue\n\t\t\tvalid = true\n\t\t\tfor i in n.indexes\n\t\t\t\tn[i] = n[i].val\n\t\t\t\tif n[i] < 0 or n[i] > 2 then\n\t\t\t\t\tprint \"Only use the digits '0', '1', or '2'.\"\n\t\t\t\t\tprint \"Let's try again.\"\n\t\t\t\t\tvalid = false\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\tend for\n\t\t\tif valid then break\n\t\tend while\n\t\n\t\tprint; printInColumns \"My guess\",\"Your no.\",\"Result\",\"No. right\"; print\n\t\tfor u in range(0, 9)\n\t\t\tyourNum = n[u]; s=0\n\t\t\tfor j in range(0,2)\n\t\t\t\ts1 = a*k[z2][j] + b*l[z1][j] + c*m[z][j]\n\t\t\t\tif s > s1 then continue\n\t\t\t\tif s < s1 or rnd >= 0.5 then\n\t\t\t\t\ts = s1; guess = j\n\t\t\t\tend if\n\t\t\tend for\n\t\t\tif guess == yourNum then\n\t\t\t\toutcome = \" right\"\n\t\t\t\tqtyRight += 1\n\t\t\telse\n\t\t\t\toutcome = \" wrong\"\n\t\t\tend if\n\t\t\tprintInColumns \"  \"+guess, \"   \" + yourNum, outcome, qtyRight\n\n\t\t\tm[z][yourNum] += 1\n\t\t\tl[z1][yourNum] += 1\n\t\t\tk[z2][yourNum] += 1\n\t\t\tz -= floor(z/9)*9\n\t\t\tz = 3*z + yourNum\n\t\t\tz1 = z - floor(z/9)*9\n\t\t\tz2 = yourNum\n\t\tend for\n\tend for\n\n\tprint\n\tif qtyRight > 10 then\n\t\tprint \"I guessed more than 1/3 of your numbers.\"\n\t\tprint \"I win.\"\n\t\tprint char(7) * 10\n\telse if qtyRight < 10 then\n\t\tprint \"I guessed less than 1/3 of your numbers.\"\n\t\tprint \"You beat me.  Congratulations *****\"\n\telse\n\t\tprint \"I guessed exactly 1/3 of your numbers.\"\n\t\tprint \"It's a tie game.\"\n\tend if\n\tprint \"Do you want to try again (1 for yes, 0 for no)\";\n\tif input != \"1\" then break\nend while\n\nprint; print \"Thanks for the game.\"\n"
  },
  {
    "path": "00_Alternate_Languages/34_Digits/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/34_Digits/digits.bas",
    "content": "10 PRINT TAB(33);\"DIGITS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n210 PRINT \"THIS IS A GAME OF GUESSING.\"\n220 PRINT \"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0'\";\n230 INPUT E\n240 IF E=0 THEN 360\n250 PRINT\n260 PRINT \"PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\"\n270 PRINT \"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\"\n280 PRINT \"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\"\n290 PRINT \"I WILL ASK FOR THEN TEN AT A TIME.\"\n300 PRINT \"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\"\n310 PRINT \"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\"\n320 PRINT \"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\"\n330 PRINT \"THAN THAT *****\"\n340 PRINT:PRINT\n360 READ A,B,C\n370 DATA 0,1,3\n380 DIM M(26,2),K(2,2),L(8,2)\n400 FOR I=0 TO 26: FOR J=0 TO 2: M(I,J)=1: NEXT J: NEXT I\n410 FOR I=0 TO 2: FOR J=0 TO 2: K(I,J)=9: NEXT J: NEXT I\n420 FOR I=0 TO 8: FOR J=0 TO 2: L(I,J)=3: NEXT J: NEXT I\n450 L(0,0)=2: L(4,1)=2: L(8,2)=2\n480 Z=26: Z1=8: Z2=2\n510 X=0\n520 FOR T=1 TO 3\n530 PRINT\n540 PRINT \"TEN NUMBERS, PLEASE\";\n550 INPUT N(1),N(2),N(3),N(4),N(5),N(6),N(7),N(8),N(9),N(10)\n560 FOR I=1 TO 10\n570 W=N(I)-1\n580 IF W=SGN(W) THEN 620\n590 PRINT \"ONLY USE THE DIGITS '0', '1', OR '2'.\"\n600 PRINT \"LET'S TRY AGAIN.\":GOTO 530\n620 NEXT I\n630 PRINT: PRINT \"MY GUESS\",\"YOUR NO.\",\"RESULT\",\"NO. RIGHT\":PRINT\n660 FOR U=1 TO 10\n670 N=N(U): S=0\n690 FOR J=0 TO 2\n700 S1=A*K(Z2,J)+B*L(Z1,J)+C*M(Z,J)\n710 IF S>S1 THEN 760\n720 IF S<S1 THEN 740\n730 IF RND(1)<.5 THEN 760\n740 S=S1: G=J\n760 NEXT J\n770 PRINT \"  \";G,\"   \";N(U),\n780 IF G=N(U) THEN 810\n790 PRINT \" WRONG\",X\n800 GOTO 880\n810 X=X+1\n820 PRINT \" RIGHT\",X\n830 M(Z,N)=M(Z,N)+1\n840 L(Z1,N)=L(Z1,N)+1\n850 K(Z2,N)=K(Z2,N)+1\n860 Z=Z-INT(Z/9)*9\n870 Z=3*Z+N(U)\n880 Z1=Z-INT(Z/9)*9\n890 Z2=N(U)\n900 NEXT U\n910 NEXT T\n920 PRINT\n930 IF X>10 THEN 980\n940 IF X<10 THEN 1010\n950 PRINT \"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\"\n960 PRINT \"IT'S A TIE GAME.\"\n970 GOTO 1030\n980 PRINT \"I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\"\n990 PRINT \"I WIN.\": FOR Q=1 TO 10: PRINT CHR$(7);: NEXT Q\n1000 GOTO 1030\n1010 PRINT \"I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\"\n1020 PRINT \"YOU BEAT ME.  CONGRATULATIONS *****\"\n1030 PRINT\n1040 PRINT \"DO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO)\";\n1060 INPUT X\n1070 IF X=1 THEN 400\n1080 PRINT:PRINT \"THANKS FOR THE GAME.\"\n1090 END\n"
  },
  {
    "path": "00_Alternate_Languages/34_Digits/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"time\"\r\n)\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"                                DIGITS\")\r\n\tfmt.Println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println(\"THIS IS A GAME OF GUESSING.\")\r\n}\r\n\r\nfunc readInteger(prompt string) int {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfor {\r\n\t\tfmt.Println(prompt)\r\n\t\tscanner.Scan()\r\n\t\tresponse, err := strconv.Atoi(scanner.Text())\r\n\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"INVALID INPUT, TRY AGAIN... \")\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\treturn response\r\n\t}\r\n}\r\n\r\nfunc printInstructions() {\r\n\tfmt.Println()\r\n\tfmt.Println(\"PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\")\r\n\tfmt.Println(\"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\")\r\n\tfmt.Println(\"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\")\r\n\tfmt.Println(\"I WILL ASK FOR THEN TEN AT A TIME.\")\r\n\tfmt.Println(\"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\")\r\n\tfmt.Println(\"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\")\r\n\tfmt.Println(\"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\")\r\n\tfmt.Println(\"THAN THAT *****\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc readTenNumbers() []int {\r\n\tnumbers := make([]int, 10)\r\n\r\n\tnumbers[0] = readInteger(\"FIRST NUMBER: \")\r\n\tfor i := 1; i < 10; i++ {\r\n\t\tnumbers[i] = readInteger(\"NEXT NUMBER:\")\r\n\t}\r\n\r\n\treturn numbers\r\n}\r\n\r\nfunc printSummary(correct int) {\r\n\tfmt.Println()\r\n\r\n\tif correct > 10 {\r\n\t\tfmt.Println()\r\n\t\tfmt.Println(\"I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\")\r\n\t\tfmt.Println(\"I WIN.\\u0007\")\r\n\t} else if correct < 10 {\r\n\t\tfmt.Println(\"I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\")\r\n\t\tfmt.Println(\"YOU BEAT ME.  CONGRATULATIONS *****\")\r\n\t} else {\r\n\t\tfmt.Println(\"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\")\r\n\t\tfmt.Println(\"IT'S A TIE GAME.\")\r\n\t}\r\n}\r\n\r\nfunc buildArray(val, row, col int) [][]int {\r\n\ta := make([][]int, row)\r\n\tfor r := 0; r < row; r++ {\r\n\t\tb := make([]int, col)\r\n\t\tfor c := 0; c < col; c++ {\r\n\t\t\tb[c] = val\r\n\t\t}\r\n\t\ta[r] = b\r\n\t}\r\n\treturn a\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\r\n\tprintIntro()\r\n\tif readInteger(\"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? \") == 1 {\r\n\t\tprintInstructions()\r\n\t}\r\n\r\n\ta := 0\r\n\tb := 1\r\n\tc := 3\r\n\r\n\tm := buildArray(1, 27, 3)\r\n\tk := buildArray(9, 3, 3)\r\n\tl := buildArray(3, 9, 3)\r\n\r\n\tfor {\r\n\t\tl[0][0] = 2\r\n\t\tl[4][1] = 2\r\n\t\tl[8][2] = 2\r\n\r\n\t\tz := float64(26)\r\n\t\tz1 := float64(8)\r\n\t\tz2 := 2\r\n\t\trunningCorrect := 0\r\n\r\n\t\tvar numbers []int\r\n\t\tfor round := 1; round <= 4; round++ {\r\n\t\t\tvalidNumbers := false\r\n\t\t\tfor !validNumbers {\r\n\t\t\t\tnumbers = readTenNumbers()\r\n\t\t\t\tvalidNumbers = true\r\n\t\t\t\tfor _, n := range numbers {\r\n\t\t\t\t\tif n < 0 || n > 2 {\r\n\t\t\t\t\t\tfmt.Println(\"ONLY USE THE DIGITS '0', '1', OR '2'.\")\r\n\t\t\t\t\t\tfmt.Println(\"LET'S TRY AGAIN.\")\r\n\t\t\t\t\t\tvalidNumbers = false\r\n\t\t\t\t\t\tbreak\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfmt.Printf(\"\\n%-14s%-14s%-14s%-14s\\n\", \"MY GUESS\", \"YOUR NO.\", \"RESULT\", \"NO. RIGHT\")\r\n\r\n\t\t\tfor _, n := range numbers {\r\n\t\t\t\ts := 0\r\n\t\t\t\tmyGuess := 0\r\n\r\n\t\t\t\tfor j := 0; j < 3; j++ {\r\n\t\t\t\t\ts1 := a*k[z2][j] + b*l[int(z1)][j] + c*m[int(z)][j]\r\n\r\n\t\t\t\t\tif s < s1 {\r\n\t\t\t\t\t\ts = s1\r\n\t\t\t\t\t\tmyGuess = j\r\n\t\t\t\t\t} else if s1 == s && rand.Float64() > 0.5 {\r\n\t\t\t\t\t\tmyGuess = j\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tresult := \"\"\r\n\r\n\t\t\t\tif myGuess != n {\r\n\t\t\t\t\tresult = \"WRONG\"\r\n\t\t\t\t} else {\r\n\t\t\t\t\trunningCorrect += 1\r\n\t\t\t\t\tresult = \"RIGHT\"\r\n\t\t\t\t\tm[int(z)][n] = m[int(z)][n] + 1\r\n\t\t\t\t\tl[int(z1)][n] = l[int(z1)][n] + 1\r\n\t\t\t\t\tk[int(z2)][n] = k[int(z2)][n] + 1\r\n\t\t\t\t\tz = z - (z/9)*9\r\n\t\t\t\t\tz = 3.0*z + float64(n)\r\n\t\t\t\t}\r\n\t\t\t\tfmt.Printf(\"\\n%-14d%-14d%-14s%-14d\\n\", myGuess, n, result, runningCorrect)\r\n\r\n\t\t\t\tz1 = z - (z/9)*9\r\n\t\t\t\tz2 = n\r\n\t\t\t}\r\n\t\t\tprintSummary(runningCorrect)\r\n\t\t\tif readInteger(\"\\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? \") != 1 {\r\n\t\t\t\tfmt.Println(\"\\nTHANKS FOR THE GAME.\")\r\n\t\t\t\tos.Exit(0)\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nNote that this folder (like the original BASIC programs) contains TWO different programs based on the same idea.  evenwins.ms plays deterministically; gameofevenwins.ms learns from its failures over multiple games.\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript evenwins.ms\n```\nor\n\n```\n\tminiscript gameofevenwins.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"evenwins\"\n\trun\n```\nor\n\n```\n\tload \"gameofevenwins\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms",
    "content": "print \" \"*31 + \"Digits\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print\n\ny1 = 0\nm1 = 0\nprint \"     This is a two person game called 'Even Wins.'\"\nprint \"To play the game, the players need 27 marbles or\"\nprint \"other objects on a table.\"\nprint\nprint\nprint \"     The 2 players alternate turns, with each player\"\nprint \"removing from 1 to 4 marbles on each move.  The game\"\nprint \"ends when there are no marbles left, and the winner\"\nprint \"is the one with an even number of marbles.\"\nprint\nprint\nprint \"     The only rules are that (1) you must alternate turns,\"\nprint \"(2) you must take between 1 and 4 marbles each turn,\"\nprint \"and (3) you cannot skip a turn.\"\nprint\nprint\nprint\nwhile true\n\tprint \"     Type a '1' if you want to go first, and type\"\n\tprint \"a '0' if you want me to go first.\"\n\tc = input.val\n\tprint\n\tif c != 0 then\n\t\tt = 27\n\t\tprint\n\t\tprint\n\t\tprint\n\t\tprint \"Total=\" + t \n\t\tprint\n\t\tprint\n\t\tprint \"What is your first move?\"\n\t\tm = 0\n\telse\n\t\tt = 27\n\t\tm = 2\n\t\tprint\n\t\tprint \"Total= \" + t\n\t\tprint\n\t\tm1 += m\n\t\tt -= m\n\tend if\n\twhile true\n\t\tif m then\n\t\t\tprint \"I pick up \" + m + \" marbles.\"\n\t\t\tif t == 0 then break\n\t\t\tprint\n\t\t\tprint \"Total=\" + t\n\t\t\tprint\n\t\t\tprint \"     And what is your next move, my total is \" + m1\n\t\tend if\n\t\twhile true\n\t\t\ty = input.val\n\t\t\tprint\n\t\t\tif y < 1 or y > 4 then\n\t\t\t\tprint\n\t\t\t\tprint \"The number of marbles you must take be a positive\"\n\t\t\t\tprint \"integer between 1 and 4.\"\n\t\t\t\tprint\n\t\t\t\tprint \"     What is your next move?\"\n\t\t\t\tprint\n\t\t\telse if y > t then\n\t\t\t\tprint \"     You have tried to take more marbles than there are\"\n\t\t\t\tprint \"left.  Try again.\"\n\t\t\telse\n\t\t\t\tbreak\n\t\t\tend if\n\t\tend while\n\n\t\ty1 += y\n\t\tt -= y\n\t\tif t == 0 then break\n\t\tprint \"Total=\" + t\n\t\tprint\n\t\tprint \"Your total is \" + y1\n\t\tif t < 0.5 then break\n\t\tr = t % 6\n\t\tif y1 % 2 != 0 then\n\t\t\tif t >= 4.2 then\n\t\t\t\tif r <= 3.4 then\n\t\t\t\t\tm = r + 1\n\t\t\t\t\tm1 += m\n\t\t\t\t\tt -= m\n\t\t\t\telse if r < 4.7 or r > 3.5 then\n\t\t\t\t\tm = 4\n\t\t\t\t\tm1 += m\n\t\t\t\t\tt -= m\n\t\t\t\telse\n\t\t\t\t\tm = 1\n\t\t\t\t\tm1 += m\n\t\t\t\t\tt -= m\n\t\t\t\tend if\n\t\t\telse\n\t\t\t\tm = t\n\t\t\t\tt -= m\n\t\t\t\tprint \"I pick up \" + m + \" marbles.\"\n\t\t\t\tprint\n\t\t\t\tprint \"Total = 0\"\n\t\t\t\tm1 += m\n\t\t\t\tbreak\n\t\t\tend if\n\t\telse\n\t\t\tif r < 1.5 or r > 5.3 then\n\t\t\t\tm = 1\n\t\t\t\tm1 += m\n\t\t\t\tt -= m\n\t\t\telse\n\t\t\t\tm = r - 1\n\t\t\t\tm1 += m\n\t\t\t\tt -= m\n\t\t\t\tif t < 0.2 then\n\t\t\t\t\tprint \"I pick up \" + m + \" marbles.\"\n\t\t\t\t\tprint\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\tend if\n\t\tend if\n\tend while\n\tprint \"That is all of the marbles.\"\n\tprint\n\tprint \" My total is \" + m1 + \", your total is \" + y1\n\tprint\n\tif m1 % 2 then\n\t\tprint \"     You won.  Do you want to play\"\n\telse\n\t\tprint \"     I won.  Do you want to play\"\n\tend if\n\tprint \"again?  Type 1 for yes and 0 for no.\"\n\ta1 = input.val\n\tif a1 == 0 then break\n\tm1 = 0\n\ty1 = 0\nend while\nprint\nprint \"OK.  See you later\"\n"
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/MiniScript/gameofevenwins.ms",
    "content": "print \" \"*28 + \"Game Of Even Wins\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint\nprint\nyesNo = input(\"Do you want instructions (yes or no)? \").lower\nif not yesNo or yesNo[0] != \"n\" then\n\tprint \"The game is played as follows:\"\n\tprint\n\tprint \"At the beginning of the game, a random number of chips are\"\n\tprint \"placed on the board.  The number of chips always starts\"\n\tprint \"as an odd number.  On each turn, a player must take one,\"\n\tprint \"two, three, or four chips.  The winner is the player who\"\n\tprint \"finishes with a total number of chips that is even.\"\n\tprint \"The computer starts out knowing only the rules of the\"\n\tprint \"game.  It gradually learns to play well.  It should be\"\n\tprint \"difficult to beat the computer after twenty games in a row.\"\n\tprint \"Try it!!!!\"\n\tprint\n\tprint \"To quit at any time, type a '0' as your move.\"\n\tprint\nend if\n\nl = 0\nb = 0\nr = [[4]*6, [4]*6]\n\nwhile true\n\ta = 0\n\tb = 0\n\te = 0\n\tl = 0\n\tp = floor((13 * rnd + 9) / 2) * 2 + 1;\n\twhile true\n\t\tif p == 1 then\n\t\t\tprint \"There is 1 chip on the board.\"\n\t\telse\n\t\t\tprint \"There are \" + p + \" chips on the board.\"\n\t\tend if\n\t\te1 = e\n\t\tl1 = l\n\t\te = a % 2\n\t\tl = p % 6\n\t\tif r[e][l] < p then\n\t\t\tm = r[e][l]\n\t\t\tif m <= 0 then\n\t\t\t\tm = 1\n\t\t\t\tb = 1\n\t\t\t\tbreak\n\t\t\tend if\n\t\t\tp -= m\n\t\t\tif m == 1 then\n\t\t\t\tprompt = \"Computer takes 1 chip leaving \" + p + \"... Your move? \"\n\t\t\telse\n\t\t\t\tprompt = \"Computer takes \" + m + \" chips leaving \" + p + \"... Your move? \"\n\t\t\tend if\n\t\t\tb += m\n\t\t\twhile true\n\t\t\t\tm = input(prompt).val\n\t\t\t\tif m == 0 then break\n\t\t\t\tif 1 <= m <= p and m <= 4 then break\n\t\t\t\tprompt = m + \" is an illegal move ... Your move? \"\n\t\t\tend while\n\t\t\tif m == 0 then break\n\t\t\tif m == p then break\t\t// <--  Really?  Before we've done the math?\n\t\t\tp -= m\n\t\t\ta += m\n\t\telse\n\t\t\tif p == 1 then\n\t\t\t\tprint \"Computer takes 1 chip.\"\n\t\t\telse\n\t\t\t\tprint \"Computer takes \" + p + \" chips.\"\n\t\t\tend if\n\t\t\tr[e][l] = p\n\t\t\tb += p\n\t\t\tbreak\n\t\tend if\n\tend while\n\tif m == 0 then break\n\tif b % 2 != 0 then\n\t\tprint \"Game over ... you win!!!\"\n\t\tif r[e][l] != 1 then\n\t\t\tr[e][l] -= 1\n\t\telse if (r[e1][l1] != 1) then\n\t\t\tr[e1][l1] -= 1\n\t\tend if\n\telse\n\t\tprint \"Game over ... I win!!!\"\n\tend if\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/evenwins.bas",
    "content": "1 PRINT TAB(31);\"EVEN WINS\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT\n4 Y1=0\n10 M1=0\n20 DIM M(20),Y(20)\n30 PRINT \"     THIS IS A TWO PERSON GAME CALLED 'EVEN WINS.'\"\n40 PRINT \"TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR\"\n50 PRINT \"OTHER OBJECTS ON A TABLE.\"\n60 PRINT\n70 PRINT\n80 PRINT \"     THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER\"\n90 PRINT \"REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE.  THE GAME\"\n100 PRINT \"ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER\"\n110 PRINT \"IS THE ONE WITH AN EVEN NUMBER OF MARBLES.\"\n120 PRINT\n130 PRINT\n140 PRINT \"     THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS,\"\n150 PRINT \"(2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN,\"\n160 PRINT \"AND (3) YOU CANNOT SKIP A TURN.\"\n170 PRINT\n180 PRINT\n190 PRINT\n200 PRINT \"     TYPE A '1' IF YOU WANT TO GO FIRST, AND TYPE\"\n210 PRINT \"A '0' IF YOU WANT ME TO GO FIRST.\"\n220 INPUT C\n225 PRINT\n230 IF C=0 THEN 250\n240 GOTO 1060\n250 T=27\n260 M=2\n270 PRINT:PRINT \"TOTAL=\";T:PRINT\n280 M1=M1+M\n290 T=T-M\n300 PRINT \"I PICK UP\";M;\"MARBLES.\"\n310 IF T=0 THEN 880\n320 PRINT:PRINT \"TOTAL=\";T\n330 PRINT\n340 PRINT \"     AND WHAT IS YOUR NEXT MOVE, MY TOTAL IS\";M1\n350 INPUT Y\n360 PRINT\n370 IF Y<1 THEN 1160\n380 IF Y>4 THEN 1160\n390 IF Y<=T THEN 430\n400 PRINT \"     YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE\"\n410 PRINT \"LEFT.  TRY AGAIN.\"\n420 GOTO 350\n430 Y1=Y1+Y\n440 T=T-Y\n450 IF T=0 THEN 880\n460 PRINT \"TOTAL=\";T\n470 PRINT\n480 PRINT \"YOUR TOTAL IS\";Y1\n490 IF T<.5 THEN 880\n500 R=T-6*INT(T/6)\n510 IF INT(Y1/2)=Y1/2 THEN 700\n520 IF T<4.2 THEN 580\n530 IF R>3.4 THEN 620\n540 M=R+1\n550 M1=M1+M\n560 T=T-M\n570 GOTO 300\n580 M=T\n590 T=T-M\n600 GOTO 830\n610 REM     250 IS WHERE I WIN.\n620 IF R<4.7 THEN 660\n630 IF R>3.5 THEN 660\n640 M=1\n650 GOTO 670\n660 M=4\n670 T=T-M\n680 M1=M1+M\n690 GOTO 300\n700 REM     I AM READY TO ENCODE THE STRAT FOR WHEN OPP TOT IS EVEN\n710 IF R<1.5 THEN 1020\n720 IF R>5.3 THEN 1020\n730 M=R-1\n740 M1=M1+M\n750 T=T-M\n760 IF T<.2 THEN 790\n770 REM     IS # ZERO HERE\n780 GOTO 300\n790 REM     IS = ZERO HERE\n800 PRINT \"I PICK UP\";M;\"MARBLES.\"\n810 PRINT\n820 GOTO 880\n830 REM    THIS IS WHERE I WIN\n840 PRINT \"I PICK UP\";M;\"MARBLES.\"\n850 PRINT\n860 PRINT \"TOTAL = 0\"\n870 M1=M1+M\n880 PRINT \"THAT IS ALL OF THE MARBLES.\"\n890 PRINT\n900 PRINT \" MY TOTAL IS\";M1;\", YOUR TOTAL IS\";Y1\n910 PRINT\n920 IF INT(M1/2)=M1/2 THEN 950\n930 PRINT \"     YOU WON.  DO YOU WANT TO PLAY\"\n940 GOTO 960\n950 PRINT \"     I WON.  DO YOU WANT TO PLAY\"\n960 PRINT \"AGAIN?  TYPE 1 FOR YES AND 0 FOR NO.\"\n970 INPUT A1\n980 IF A1=0 THEN 1030\n990 M1=0\n1000 Y1=0\n1010 GOTO 200\n1020 GOTO 640\n1030 PRINT\n1040 PRINT \"OK.  SEE YOU LATER.\"\n1050 GOTO 1230\n1060 T=27\n1070 PRINT\n1080 PRINT\n1090 PRINT\n1100 PRINT \"TOTAL=\";T\n1110 PRINT\n1120 PRINT\n1130 PRINT \"WHAT IS YOUR FIRST MOVE\";\n1140 INPUT Y\n1150 GOTO 360\n1160 PRINT\n1170 PRINT \"THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE\"\n1180 PRINT \"INTEGER BETWEEN 1 AND 4.\"\n1190 PRINT\n1200 PRINT \"     WHAT IS YOUR NEXT MOVE?\"\n1210 PRINT\n1220 GOTO 350\n1230 END\n"
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/gameofevenwins.bas",
    "content": "1 PRINT TAB(28);\"GAME OF EVEN WINS\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT\n4 INPUT \"DO YOU WANT INSTRUCTIONS (YES OR NO)\";A$:PRINT\n5 IF A$=\"NO\" THEN 20\n6 PRINT \"THE GAME IS PLAYED AS FOLLOWS:\":PRINT\n7 PRINT \"AT THE BEGINNING OF THE GAME, A RANDOM NUMBER OF CHIPS ARE\"\n8 PRINT \"PLACED ON THE BOARD.  THE NUMBER OF CHIPS ALWAYS STARTS\"\n9 PRINT \"AS AN ODD NUMBER.  ON EACH TURN, A PLAYER MUST TAKE ONE,\"\n10 PRINT \"TWO, THREE, OR FOUR CHIPS.  THE WINNER IS THE PLAYER WHO\"\n11 PRINT \"FINISHES WITH A TOTAL NUMBER OF CHIPS THAT IS EVEN.\"\n12 PRINT \"THE COMPUTER STARTS OUT KNOWING ONLY THE RULES OF THE\"\n13 PRINT \"GAME.  IT GRADUALLY LEARNS TO PLAY WELL.  IT SHOULD BE\"\n14 PRINT \"DIFFICULT TO BEAT THE COMPUTER AFTER TWENTY GAMES IN A ROW.\"\n15 PRINT \"TRY IT!!!!\": PRINT\n16 PRINT \"TO QUIT AT ANY TIME, TYPE A '0' AS YOUR MOVE.\": PRINT\n20 DIM R(1,5)\n25 L=0: B=0\n30 FOR I=0 TO 5\n40 R(1,I)=4\n50 R(0,I)=4\n60 NEXT I\n70 A=0: B=0\n90 P=INT((13*RND(1)+9)/2)*2+1\n100 IF P=1 THEN 530\n110 PRINT \"THERE ARE\";P;\"CHIPS ON THE BOARD.\"\n120 E1=E\n130 L1=L\n140 E=(A/2-INT(A/2))*2\n150 L=INT((P/6-INT(P/6))*6+.5)\n160 IF R(E,L)>=P THEN 320\n170 M=R(E,L)\n180 IF M<=0 THEN 370\n190 P=P-M\n200 IF M=1 THEN 510\n210 PRINT \"COMPUTER TAKES\";M;\"CHIPS LEAVING\";P;\"... YOUR MOVE\";\n220 B=B+M\n230 INPUT M\n240 M=INT(M)\n250 IF M<1 THEN 450\n260 IF M>4 THEN 460\n270 IF M>P THEN 460\n280 IF M=P THEN 360\n290 P=P-M\n300 A=A+M\n310 GOTO 100\n320 IF P=1 THEN 550\n330 PRINT \"COMPUTER TAKES\";P;\"CHIPS.\"\n340 R(E,L)=P\n350 B=B+P\n360 IF B/2=INT(B/2) THEN 420\n370 PRINT \"GAME OVER ... YOU WIN!!!\": PRINT\n390 IF R(E,L)=1 THEN 480\n400 R(E,L)=R(E,L)-1\n410 GOTO 70\n420 PRINT \"GAME OVER ... I WIN!!!\": PRINT\n430 GOTO 70\n450 IF M=0 THEN 570\n460 PRINT M;\"IS AN ILLEGAL MOVE ... YOUR MOVE\";\n470 GOTO 230\n480 IF R(E1,L1)=1 THEN 70\n490 R(E1,L1)=R(E1,L1)-1\n500 GOTO 70\n510 PRINT \"COMPUTER TAKES 1 CHIP LEAVING\";P;\"... YOUR MOVE\";\n520 GOTO 220\n530 PRINT \"THERE IS 1 CHIP ON THE BOARD.\"\n540 GOTO 120\n550 PRINT \"COMPUTER TAKES 1 CHIP.\"\n560 GOTO 340\n570 END\n"
  },
  {
    "path": "00_Alternate_Languages/35_Even_Wins/go/evenwins.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n)\r\n\r\nconst MAXTAKE = 4\r\n\r\ntype PlayerType int8\r\n\r\nconst (\r\n\tHUMAN PlayerType = iota\r\n\tCOMPUTER\r\n)\r\n\r\ntype Game struct {\r\n\ttable    int\r\n\thuman    int\r\n\tcomputer int\r\n}\r\n\r\nfunc NewGame() Game {\r\n\tg := Game{}\r\n\tg.table = 27\r\n\r\n\treturn g\r\n}\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"Welcome to Even Wins!\")\r\n\tfmt.Println(\"Based on evenwins.bas from Creative Computing\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"Even Wins is a two-person game. You start with\")\r\n\tfmt.Println(\"27 marbles in the middle of the table.\")\r\n\tfmt.Println()\r\n\tfmt.Println(\"Players alternate taking marbles from the middle.\")\r\n\tfmt.Println(\"A player can take 1 to 4 marbles on their turn, and\")\r\n\tfmt.Println(\"turns cannot be skipped. The game ends when there are\")\r\n\tfmt.Println(\"no marbles left, and the winner is the one with an even\")\r\n\tfmt.Println(\"number of marbles.\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc (g *Game) printBoard() {\r\n\tfmt.Println()\r\n\tfmt.Printf(\" marbles in the middle: %d\\n\", g.table)\r\n\tfmt.Printf(\"    # marbles you have: %d\\n\", g.human)\r\n\tfmt.Printf(\"# marbles computer has: %d\\n\", g.computer)\r\n\tfmt.Println()\r\n}\r\n\r\nfunc (g *Game) gameOver() {\r\n\tfmt.Println()\r\n\tfmt.Println(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\")\r\n\tfmt.Println(\"!! All the marbles are taken: Game Over!\")\r\n\tfmt.Println(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\")\r\n\tfmt.Println()\r\n\tg.printBoard()\r\n\tif g.human%2 == 0 {\r\n\t\tfmt.Println(\"You are the winner! Congratulations!\")\r\n\t} else {\r\n\t\tfmt.Println(\"The computer wins: all hail mighty silicon!\")\r\n\t}\r\n\tfmt.Println()\r\n}\r\n\r\nfunc getPlural(count int) string {\r\n\tm := \"marble\"\r\n\tif count > 1 {\r\n\t\tm += \"s\"\r\n\t}\r\n\treturn m\r\n}\r\n\r\nfunc (g *Game) humanTurn() {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tmaxAvailable := MAXTAKE\r\n\tif g.table < MAXTAKE {\r\n\t\tmaxAvailable = g.table\r\n\t}\r\n\r\n\tfmt.Println(\"It's your turn!\")\r\n\tfor {\r\n\t\tfmt.Printf(\"Marbles to take? (1 - %d) --> \", maxAvailable)\r\n\t\tscanner.Scan()\r\n\t\tn, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tfmt.Printf(\"\\n  Please enter a whole number from 1 to %d\\n\", maxAvailable)\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\tif n < 1 {\r\n\t\t\tfmt.Println(\"\\n  You must take at least 1 marble!\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\tif n > maxAvailable {\r\n\t\t\tfmt.Printf(\"\\n  You can take at most %d %s\\n\", maxAvailable, getPlural(maxAvailable))\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\tfmt.Printf(\"\\nOkay, taking %d %s ...\\n\", n, getPlural(n))\r\n\t\tg.table -= n\r\n\t\tg.human += n\r\n\t\treturn\r\n\t}\r\n}\r\n\r\nfunc (g *Game) computerTurn() {\r\n\tmarblesToTake := 0\r\n\r\n\tfmt.Println(\"It's the computer's turn ...\")\r\n\tr := float64(g.table - 6*int((g.table)/6))\r\n\r\n\tif int(g.human/2) == g.human/2 {\r\n\t\tif r < 1.5 || r > 5.3 {\r\n\t\t\tmarblesToTake = 1\r\n\t\t} else {\r\n\t\t\tmarblesToTake = int(r - 1)\r\n\t\t}\r\n\t} else if float64(g.table) < 4.2 {\r\n\t\tmarblesToTake = 4\r\n\t} else if r > 3.4 {\r\n\t\tif r < 4.7 || r > 3.5 {\r\n\t\t\tmarblesToTake = 4\r\n\t\t}\r\n\t} else {\r\n\t\tmarblesToTake = int(r + 1)\r\n\t}\r\n\r\n\tfmt.Printf(\"Computer takes %d %s ...\\n\", marblesToTake, getPlural(marblesToTake))\r\n\tg.table -= marblesToTake\r\n\tg.computer += marblesToTake\r\n}\r\n\r\nfunc (g *Game) play(playersTurn PlayerType) {\r\n\tg.printBoard()\r\n\r\n\tfor {\r\n\t\tif g.table == 0 {\r\n\t\t\tg.gameOver()\r\n\t\t\treturn\r\n\t\t} else if playersTurn == HUMAN {\r\n\t\t\tg.humanTurn()\r\n\t\t\tg.printBoard()\r\n\t\t\tplayersTurn = COMPUTER\r\n\t\t} else {\r\n\t\t\tg.computerTurn()\r\n\t\t\tg.printBoard()\r\n\t\t\tplayersTurn = HUMAN\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc getFirstPlayer() PlayerType {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"Do you want to play first? (y/n) --> \")\r\n\t\tscanner.Scan()\r\n\r\n\t\tif strings.ToUpper(scanner.Text()) == \"Y\" {\r\n\t\t\treturn HUMAN\r\n\t\t} else if strings.ToUpper(scanner.Text()) == \"N\" {\r\n\t\t\treturn COMPUTER\r\n\t\t} else {\r\n\t\t\tfmt.Println()\r\n\t\t\tfmt.Println(\"Please enter 'y' if you want to play first,\")\r\n\t\t\tfmt.Println(\"or 'n' if you want to play second.\")\r\n\t\t\tfmt.Println()\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc main() {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tprintIntro()\r\n\r\n\tfor {\r\n\t\tg := NewGame()\r\n\r\n\t\tg.play(getFirstPlayer())\r\n\r\n\t\tfmt.Println(\"\\nWould you like to play again? (y/n) --> \")\r\n\t\tscanner.Scan()\r\n\t\tif strings.ToUpper(scanner.Text()) == \"Y\" {\r\n\t\t\tfmt.Println(\"\\nOk, let's play again ...\")\r\n\t\t} else {\r\n\t\t\tfmt.Println(\"\\nOk, thanks for playing ... goodbye!\")\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript flipflop.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"flipflop\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms",
    "content": "print \" \"*32 + \"FlipFlop\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint\n// Created by Michael Cass (1978)\n// Ported to MiniScript by Joe Strout (2023)\n\nprint \"The object of this puzzle is to change this:\"\nprint\nprint \"X X X X X X X X X X\"\nprint\nprint \"to this:\"\nprint\nprint \"O O O O O O O O O O\"\nprint\nprint \"By typing the number corresponding to the position of the\"\nprint \"letter on some numbers, one position will change, on\"\nprint \"others, two will change.  To reset line to all X's, type 0\"\nprint \"(zero) and to start over in the middle of a game, type \"\nprint \"11 (eleven).\"\nprint\n\nstartNewGame = function\n\tglobals.q = rnd\n\tglobals.guesses = 0\n\tprint \"Here is the starting line of X's.\"\n\tprint\n\tprint \"1 2 3 4 5 6 7 8 9 10\"\n\tprint \"X X X X X X X X X X\"\n\tprint\nend function\n\ngetInput = function\n\twhile true\n\t\tn = input(\"Input the number: \").val\n\t\tif n == floor(n) and 0 <= n <= 11 then break\n\t\tprint \"Illegal entry--try again.\"\t\t\n\tend while\n\treturn n\nend function\n\nstartNewGame\nwhile true\n\tA = [\"\"] + [\"X\"] * 10\t// (include empty 0th element so we can index 1-based\n\tm = 0\t\t// (previous input)\n\twhile true\n\t\tn = getInput\n\t\tif n == 11 then\n\t\t\tstartNewGame\n\t\t\tcontinue\n\t\telse if n == 0 then\n\t\t\tA = [\"X\"] * 10\n\t\t\tcontinue\n\t\tend if\n\t\n\t\tif n != m then\n\t\t\t// when user enters a different number from previous time\n\t\t\tm = n\n\t\t\tif A[n] == \"O\" then A[n] = \"X\" else A[n] = \"O\"\n\t\t\twhile m == n\n\t\t\t\tr = tan(q + n/q - n) - sin(q/n) + 336*sin(8*n)\n\t\t\t\tn = floor(10 * (r - floor(r)))\n\t\t\t\tif A[n] != \"O\" then\n\t\t\t\t\tA[n] = \"O\"\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\t\tA[n] = \"X\"\n\t\t\tend while\t\t\n\t\telse\n\t\t\t// when n == m, i.e., user entered the same number twice in a row\n\t\t\twhile m == n\n\t\t\t\tif A[n] == \"O\" then A[n] = \"X\" else A[n] = \"O\"\n\t\t\t\tr = 0.592 * (1 / tan(q/n + q)) / sin(n*2 + q) - cos(n)\n\t\t\t\tn = floor(10 * (r - floor(r)))\n\t\t\t\tif A[n] != \"O\" then\n\t\t\t\t\tA[n] = \"O\"\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\t\tA[n] = \"X\"\n\t\t\tend while\n\t\tend if\n\n\t\tprint \"1 2 3 4 5 6 7 8 9 10\"\n\t\tprint A[1:].join\n\t\tguesses += 1\n\t\tif A[1:] == [\"O\"]*10 then break\n\tend while\n\n\tif guesses <= 12 then\n\t\tprint \"Very good.  You guessed it in only \" + guesses + \" guesses.\"\n\telse\n\t\tprint \"Try harder next time.  It took you \" + guesses + \" guesses.\"\n\tend if\n\n\tyesNo = input(\"Do you want to try another puzzle? \").lower\n\tif not yesNo or yesNo[0] == \"n\" then break\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/36_Flip_Flop/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/36_Flip_Flop/flipflop.bas",
    "content": "2 PRINT TAB(32);\"FLIPFLOP\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT\n10 REM *** CREATED BY MICHAEL CASS\n15 DIM A$(20)\n20 PRINT \"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\"\n30 PRINT\n40 PRINT \"X X X X X X X X X X\"\n50 PRINT\n60 PRINT \"TO THIS:\"\n70 PRINT\n80 PRINT \"O O O O O O O O O O\"\n90 PRINT\n100 PRINT \"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\"\n110 PRINT \"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\"\n120 PRINT \"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\"\n130 PRINT \"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \"\n140 PRINT \"11 (ELEVEN).\"\n170 PRINT\n180 REM\n190 Q=RND(1)\n200 PRINT \"HERE IS THE STARTING LINE OF X'S.\"\n210 PRINT\n220 C=0\n230 PRINT \"1 2 3 4 5 6 7 8 9 10\"\n240 PRINT \"X X X X X X X X X X\"\n250 PRINT\n260 REM\n270 FOR X=1 TO 10\n280 A$(X)=\"X\"\n290 NEXT X\n300 GOTO 320\n310 PRINT \"ILLEGAL ENTRY--TRY AGAIN.\"\n320 PRINT \"INPUT THE NUMBER\";\n330 INPUT N\n340 IF N<>INT(N) THEN 310\n350 IF N=11 THEN 180\n360 IF N>11 THEN 310\n370 IF N=0 THEN 230\n380 IF M=N THEN 510\n390 M=N\n400 IF A$(N)=\"O\" THEN 480\n410 A$(N)=\"O\"\n420 R=TAN(Q+N/Q-N)-SIN(Q/N)+336*SIN(8*N)\n430 N=R-INT(R)\n440 N=INT(10*N)\n450 IF A$(N)=\"O\" THEN 480\n460 A$(N)=\"O\"\n470 GOTO 610\n480 A$(N)=\"X\"\n490 IF M=N THEN 420\n500 GOTO 610\n510 IF A$(N)=\"O\" THEN 590\n520 A$(N)=\"O\"\n530 R=.592*(1/TAN(Q/N+Q))/SIN(N*2+Q)-COS(N)\n540 N=R-INT(R)\n550 N=INT(10*N)\n560 IF A$(N)=\"O\" THEN 590\n570 A$(N)=\"O\"\n580 GOTO 610\n590 A$(N)=\"X\"\n600 IF M=N THEN 530\n610 PRINT \"1 2 3 4 5 6 7 8 9 10\"\n620 FOR Z=1 TO 10: PRINT A$(Z);\" \";: NEXT Z\n630 C=C+1\n640 PRINT\n650 FOR Z=1 TO 10\n660 IF A$(Z)<>\"O\" THEN 320\n670 NEXT Z\n680 IF C>12 THEN 710\n690 PRINT \"VERY GOOD.  YOU GUESSED IT IN ONLY\";C;\"GUESSES.\"\n700 GOTO 720\n710 PRINT \"TRY HARDER NEXT TIME.  IT TOOK YOU\";C;\"GUESSES.\"\n720 PRINT \"DO YOU WANT TO TRY ANOTHER PUZZLE\";\n730 INPUT X$\n740 IF LEFT$(X$,1)=\"N\" THEN 780\n760 PRINT\n770 GOTO 180\n780 END\n"
  },
  {
    "path": "00_Alternate_Languages/37_Football/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript football.ms\n```or\n```\n\tminiscript ftball.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"football\"\n\trun\n```or\n```\n\tload \"ftball\"\n\trun\n```\n\n#### Apology from the Translator\n\nThese MiniScript programs were actually ported from the JavaScript ports of the original BASIC programs.  I did that because the BASIC code (of both programs) was incomprehensible spaghetti.  The JavaScript port, however, was essentially the same — and so are the MiniScript ports.  The very structure of these programs makes them near-impossible to untangle.\n\nIf I were going to write a football simulation from scratch, I would approach it very differently.  But in that case I would have either a detailed specification of how the program should behave, or at least enough understanding of American football to design it myself as I go.  Neither is the case here (and we're supposed to be porting the original programs, not making up our own).\n\nSo, I'm sorry.  Please take these programs as proof that you can write bad code even in the most simple, elegant languages.  And I promise to try harder on future translations!\n"
  },
  {
    "path": "00_Alternate_Languages/37_Football/MiniScript/football.ms",
    "content": "player_data = [17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6,\n                   20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3]\naa = [0]*21\nba = [0]*21\nca = [0]*41\nha = [0]*3\nta = [0]*3\nwa = [0]*3\nxa = [0]*3\nya = [0]*3\nza = [0]*3\nms = [null, \"\",\"\"]\nda = [0]*3\nps = [\"\", \"PITCHOUT\",\"TRIPLE REVERSE\",\"DRAW\",\"QB SNEAK\",\"END AROUND\",\n          \"DOUBLE REVERSE\",\"LEFT SWEEP\",\"RIGHT SWEEP\",\"OFF TACKLE\",\n          \"WISHBONE OPTION\",\"FLARE PASS\",\"SCREEN PASS\",\n          \"ROLL OUT OPTION\",\"RIGHT CURL\",\"LEFT CURL\",\"WISHBONE OPTION\",\n          \"SIDELINE PASS\",\"HALF-BACK OPTION\",\"RAZZLE-DAZZLE\",\"BOMB!!!!\"]\nglobals.p = 0\nglobals.t = 0\n\nprintFieldHeaders = function\n    print \"TEAM 1 [0   10   20   30   40   50   60   70   80   90  100] TEAM 2\"\n    print\nend function\n\nprintSeparator = function\n\tprint \"+\" * 67\nend function\n\nshowBall = function\n    print \" \" * (da[t] + 5 + p / 2) + ms[t]\n    printFieldHeaders\nend function\n\nshowScores = function\n    print\n    print \"TEAM 1 SCORE IS \" + ha[1]\n    print \"TEAM 2 SCORE IS \" + ha[2]\n    print\n    if ha[t] >= e then\n        print \"TEAM \" + t + \" WINS*******************\"\n        return true\n    end if\n    return false\nend function\n\nlosePossession = function\n    print\n    print \"** LOSS OF POSSESSION FROM TEAM \" + t + \" TO TEAM \" + ta[t]\n    print\n    printSeparator\n    print\n    globals.t = ta[t]\nend function\n\ntouchdown = function\n    print\n    print \"TOUCHDOWN BY TEAM \" + t + \" *********************YEA TEAM\"\n    q = 7\n    if rnd <= 0.1 then\n        q = 6\n        print \"EXTRA POINT NO GOOD\"\n    else\n        print \"EXTRA POINT GOOD\"\n    end if\n    ha[t] += q\nend function\n\naskYesNo = function(prompt)\n\twhile true\n\t\tyn = input(prompt + \"? \").lower\n\t\tif not yn then continue\n\t\tif yn[0] == \"y\" then return \"YES\"\n\t\tif yn[0] == \"n\" then return \"NO\"\n\tend while\nend function\n\n\nprint \" \"*32 + \"FOOTBALL\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Presenting N.F.U. Football (No FORTRAN Used)\"\nprint; print\nif askYesNo(\"Do you want instructions\") == \"YES\" then\n\tprint \"This is a football game for two teams in which players must\"\n\tprint \"prepare a tape with a data statement (1770 for team 1,\"\n\tprint  \"1780 for team 2) in which each team scrambles nos. 1-20\"\n\tprint \"These numbers are then assigned to twenty given plays.\"\n\tprint \"A list of nos. and their plays is provided with\"\n\tprint \"both teams having the same plays. The more similar the\"\n\tprint \"plays the less yardage gained.  Scores are given\"\n\tprint \"whenever scores are made. Scores may also be obtained\"\n\tprint \"by inputting 99,99 for play nos. To punt or attempt a\"\n\tprint \"field goal, input 77,77 for play numbers. Questions will be\"\n\tprint \"asked then. On 4th down, you will also be asked whether\"\n\tprint \"you want to punt or attempt a field goal. If the answer to\"\n\tprint \"both questions is no it will be assumed you want to\"\n\tprint \"try and gain yardage. Answer all questions Yes or No.\"\n\tprint \"The game is played until players terminate (control-c).\"\n\tprint \"Please prepare a tape and run.\"\nend if\nprint\ne = input(\"Please input score limit on game: \").val\nfor i in range(1, 40)\n\tif i <= 20 then\n\t\taa[player_data[i - 1]] = i\n\telse\n\t\tba[player_data[i - 1]] = i - 20\n\tend if\n\tca[i] = player_data[i - 1]\nend for\nl = 0\nglobals.t = 1\nwhile true\n\tprint \"TEAM \" + t + \" PLAY CHART\"\n\tprint \"NO.      PLAY\"\n\tfor i in range(1, 20)\n\t\tprint (ca[i+1] + \" \"*6)[:6] + ps[i]\n\tend for\n\tl += 20\n\tglobals.t = 2\n\tprint\n\tprint \"TEAR OFF HERE----------------------------------------------\"\n\tfor x in range(1, 11); print; end for\n\twait 3\n\tif l != 20 then break\nend while\n\nplayGame = function\n\tda[1] = 0\n\tda[2] = 3\n\tms[1] = \"--->\"\n\tms[2] = \"<---\"\n\tha[1] = 0\n\tha[2] = 0\n\tta[1] = 2\n\tta[2] = 1\n\twa[1] = -1\n\twa[2] = 1\n\txa[1] = 100\n\txa[2] = 0\n\tya[1] = 1\n\tya[2] = -1\n\tza[1] = 0\n\tza[2] = 100\n\tglobals.p = 0\n\tprintFieldHeaders\n\tprint \"TEAM 1 defend 0 YD goal -- TEAM 2 defends 100 YD goal.\"\n\tglobals.t = floor(2 * rnd + 1)\n\tprint\n\tprint \"The coin is flipped\"\n\troutine = 1\n\twhile true\n\t\tif routine <= 1 then\n\t\t\tglobals.p = xa[t] - ya[t] * 40\n\t\t\tprintSeparator\n\t\t\tprint\n\t\t\tprint \"Team \" + t + \" receives kick-off\"\n\t\t\tk = floor(26 * rnd + 40)\n\t\tend if\n\t\tif routine <= 2 then\n\t\t\tglobals.p = p - ya[t] * k\n\t\tend if\n\t\tif routine <= 3 then\n\t\t\tif wa[t] * p >= za[t] + 10 then\n\t\t\t\tprint\n\t\t\t\tprint \"Ball went out of endzone --automatic touchback--\"\n\t\t\t\tglobals.p = za[t] - wa[t] * 20\n\t\t\t\tif routine <= 4 then routine = 5\n\t\t\telse\n\t\t\t\tprint \"Ball went \" + k + \" yards.  Now on \" + p\n\t\t\t\tshowBall\n\t\t\tend if\n\t\tend if\n\t\tif routine <= 4 then\n\t\t\tif askYesNo(\"Team \" + t + \" do you want to runback\") == \"YES\" then\n\t\t\t\tk = floor(9 * rnd + 1)\n\t\t\t\tr = floor(((xa[t] - ya[t] * p + 25) * rnd - 15) / k)\n\t\t\t\tglobals.p = p - wa[t] * r\n\t\t\t\tprint\n\t\t\t\tprint \"Runback team \" + t + \" \" + r + \" yards\"\n\t\t\t\tg = rnd\n\t\t\t\tif g < 0.25 then\n\t\t\t\t\tlosePossession\n\t\t\t\t\troutine = 4\n\t\t\t\t\tcontinue\n\t\t\t\telse if ya[t] * p >= xa[t] then\n\t\t\t\t\ttouchdown\n\t\t\t\t\tif showScores then return\n\t\t\t\t\tglobals.t = ta[t]\n\t\t\t\t\troutine = 1\n\t\t\t\t\tcontinue\n\t\t\t\telse if wa[t] * p >= za[t] then\n\t\t\t\t\tprint\n\t\t\t\t\tprint \"Safety against team \" + t + \" **********************OH-OH\"\n\t\t\t\t\tha[ta[t]] += 2\n\t\t\t\t\tif showScores then return\n\t\t\t\t\tglobals.p = za[t] - wa[t] * 20\n\t\t\t\t\tif askYesNo(\"Team \" + t + \" do you want to punt instead of a kickoff\") == \"YES\" then\n\t\t\t\t\t\tprint\n\t\t\t\t\t\tprint \"Team \" + t + \" will punt\"\n\t\t\t\t\t\tg = rnd\n\t\t\t\t\t\tif g < 0.25 then\n\t\t\t\t\t\t\tlosePossession\n\t\t\t\t\t\t\troutine = 4\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tend if\n\t\t\t\t\t\tprint\n\t\t\t\t\t\tprintSeparator\n\t\t\t\t\t\tk = floor(25 * rnd + 35)\n\t\t\t\t\t\tglobals.t = ta[t]\n\t\t\t\t\t\troutine = 2\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tend if\n\t\t\t\t\ttouchdown\n\t\t\t\t\tif showScores then return\n\t\t\t\t\tglobals.t = ta[t]\n\t\t\t\t\troutine = 1\n\t\t\t\t\tcontinue\n\t\t\t\telse\n\t\t\t\t\troutine = 5\n\t\t\t\t\tcontinue\n\t\t\t\tend if\n\t\t\telse\t\t// player does not want to runback\n\t\t\t\tif wa[t] * p >= za[t] then globals.p = za[t] - wa[t] * 20\n\t\t\tend if\n\t\tend if\n\t\tif routine <= 5 then\n\t\t\td = 1\n\t\t\ts = p\n\t\tend if\n\t\tif routine <= 6 then\n\t\t\tprint \"=\" * 67\n\t\t\tprint \"TEAM \" + t + \" DOWN \" + d + \" ON \" + p\n\t\t\tif d == 1 then\n\t\t\t\tif ya[t] * (p + ya[t] * 10) >= xa[t] then\n\t\t\t\t\tc = 8\n\t\t\t\telse\n\t\t\t\t\tc = 4\n\t\t\t\tend if\n\t\t\tend if\n\t\t\tif c != 8 then\n\t\t\t\tprint \" \"*27 + (10 - (ya[t] * p - ya[t] * s)) + \" yards to 1st down\"\n\t\t\telse\n\t\t\t\tprint \" \"*27 + (xa[t] - ya[t] * p) + \" yards\"\n\t\t\tend if\n\t\t\tshowBall\n\t\t\tif d == 4 then routine = 8\n\t\tend if\n\t\tif routine <= 7 then\n\t\t\tu = floor(3 * rnd - 1)\n\t\t\twhile true\n\t\t\t\tstr = input(\"Input offensive play, defensive play: \")\n\t\t\t\tstr = str.replace(\",\", \" \").replace(\"  \", \" \").split\n\t\t\t\tif t == 1 then\n\t\t\t\t\tp1 = str[0].val\n\t\t\t\t\tp2 = str[1].val\n\t\t\t\telse\n\t\t\t\t\tp2 = str[0].val\n\t\t\t\t\tp1 = str[1].val\n\t\t\t\tend if\n\t\t\t\tif p1 == 99 then\n\t\t\t\t\tif showScores then return\n\t\t\t\t\tcontinue\n\t\t\t\tend if\n\t\t\t\tif 1 <= p1 <= 20 and 1 <= p2 <= 20 then break\n\t\t\t\tprint \"Illegal play number, check and\"\n\t\t\tend while\n\t\tend if\n\t\tif d == 4 or p1 == 77 then\n\t\t\tif askYesNo(\"Does team \" + t + \" want to punt\") == \"YES\" then\n\t\t\t\tprint\n\t\t\t\tprint \"Team \" + t + \" will punt\"\n\t\t\t\tif rnd < 0.25 then\n\t\t\t\t\tlosePossession\n\t\t\t\t\troutine = 4\n\t\t\t\t\tcontinue\n\t\t\t\tend if\n\t\t\t\tprint\n\t\t\t\tprintSeparator\n\t\t\t\tk = floor(25 * rnd + 35)\n\t\t\t\tglobals.t = ta[t]\n\t\t\t\troutine = 2\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\tif askYesNo(\"Does team \" + t + \" want to attempt a field goal\") == \"YES\" then\n\t\t\t\tprint\n\t\t\t\tprint \"Team \" + t + \" will attempt a field goal\"\n\t\t\t\tif rnd < 0.025 then\n\t\t\t\t\tlosePossession\n\t\t\t\t\troutine = 4\n\t\t\t\t\tcontinue\n\t\t\t\telse\n\t\t\t\t\tf = floor(35 * rnd + 20)\n\t\t\t\t\tprint\n\t\t\t\t\tprint \"Kick is \" + f + \" yards long\"\n\t\t\t\t\tglobals.p = p - wa[t] * f\n\t\t\t\t\tif rnd < 0.35 then\n\t\t\t\t\t\tprint \"Ball went wide\"\n\t\t\t\t\telse if ya[t] * p >= xa[t] then\n\t\t\t\t\t\tprint \"FIELD GOLD GOOD FOR TEAM \" + t + \" *********************YEA\"\n\t\t\t\t\t\tq = 3\n\t\t\t\t\t\tha[t] = ha[t] + q\n\t\t\t\t\t\tif showScores then return\n\t\t\t\t\t\tglobals.t = ta[t]\n\t\t\t\t\t\troutine = 1\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tend if\n\t\t\t\t\tprint \"Field goal unsuccesful team \" + t + \"-----------------too bad\"\n\t\t\t\t\tprint\n\t\t\t\t\tprintSeparator\n\t\t\t\t\tif ya[t] * p < xa[t] + 10 then\n\t\t\t\t\t\tprint\n\t\t\t\t\t\tprint \"Ball now on \" + p\n\t\t\t\t\t\tglobals.t = ta[t]\n\t\t\t\t\t\tshowBall\n\t\t\t\t\t\troutine = 4\n\t\t\t\t\t\tcontinue\n\t\t\t\t\telse\n\t\t\t\t\t\tglobals.t = ta[t]\n\t\t\t\t\t\troutine = 3\n\t\t\t\t\t\tcontinue\n\t\t\t\t\tend if\n\t\t\t\tend if\n\t\t\telse\n\t\t\t\troutine = 7\n\t\t\t\tcontinue\n\t\t\tend if\n\t\tend if\n\t\ty = floor(abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * rnd - 15))\n\t\tprint\n\t\tif t == 1 and aa[p1] < 11 or t == 2 and ba[p2] < 11 then\n\t\t\tprint \"The ball was run\"\n\t\telse if u == 0 then\n\t\t\tprint \"Pass incomplete team \" + t\n\t\t\ty = 0\n\t\telse\n\t\t\tif rnd <= 0.025 and y > 2 then\n\t\t\t\tprint \"Pass completed\"\n\t\t\telse\n\t\t\t\tprint \"Quarterback scrambled\"\n\t\t\tend if\n\t\tend if\n\t\tglobals.p = p - wa[t] * y\n\t\tprint\n\t\tprint \"Net yards gained on down \" + d + \" are \" + y\n\n\t\tif rnd <= 0.025 then\n\t\t\tlosePossession\n\t\t\troutine = 4\n\t\t\tcontinue\n\t\telse if ya[t] * p >= xa[t] then\n\t\t\ttouchdown\n\t\t\tif showScores then return\n\t\t\tglobals.t = ta[t]\n\t\t\troutine = 1\n\t\t\tcontinue\n\t\telse if wa[t] * p >= za[t] then\n\t\t\tprint\n\t\t\tprint \"SAFETY AGAINST TEAM \" + t + \" **********************OH-OH\"\n\t\t\tha[ta[t]] = ha[ta[t]] + 2\n\t\t\tif showScores then return\n\t\t\tglobals.p = za[t] - wa[t] * 20\n\t\t\tif askYesNo(\"Team \" + t + \" do you want to punt instead of a kickoff\") == \"YES\" then\n\t\t\t\tprint\n\t\t\t\tprint \"Team \" + t + \" will punt\"\n\t\t\t\tif rnd < 0.25 then\n\t\t\t\t\tlosePossession\n\t\t\t\t\troutine = 4\n\t\t\t\t\tcontinue\n\t\t\t\tend if\n\t\t\t\tprint\n\t\t\t\tprintSeparator\n\t\t\t\tk = floor(25 * rnd + 35)\n\t\t\t\tglobals.t = ta[t]\n\t\t\t\troutine = 2\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\ttouchdown\n\t\t\tif showScores then return\n\t\t\tglobals.t = ta[t]\n\t\t\troutine = 1\n\t\telse if ya[t] * p - ya[t] * s >= 10 then\n\t\t\troutine = 5\n\t\telse\n\t\t\td += 1\n\t\t\tif d != 5 then\n\t\t\t\troutine = 6\n\t\t\telse\n\t\t\t\tprint\n\t\t\t\tprint \"Conversion unsuccessful team \" + t\n\t\t\t\tglobals.t = ta[t]\n\t\t\t\tprint\n\t\t\t\tprintSeparator\n\t\t\t\troutine = 5\n\t\t\tend if\n\t\tend if\n\tend while\nend function\n\nplayGame\n"
  },
  {
    "path": "00_Alternate_Languages/37_Football/MiniScript/ftball.ms",
    "content": "os = [\"Dartmouth\", \"\"]\nsa = [0, 1]\nls = [\"\", \"Kick\",\"receive\",\" yard \",\"run back for \",\"ball on \",\n         \"yard line\",\" simple run\",\" tricky run\",\" short pass\",\n         \" long pass\",\"punt\",\" quick kick \",\" place kick\",\" loss \",\n         \" no gain\",\"gain \",\" touchdown \",\" touchback \",\"safety***\",\n         \"junk\"]\np = 0\nx = 0\nx1 = 0\n\nfnf = function(x); return 1 - 2 * p; end function\nfng = function(z); return p * (x1 - x) + (1 - p) * (x - x1); end function\n\nshow_score = function\n   print\n   print \"SCORE:  \" + sa[0] + \" TO \" + sa[1]\n   print\n   print\nend function\n\nshow_position = function\n   if x <= 50 then\n       print ls[5] + os[0] + \" \" + x + \" \" + ls[6]\n   else\n       print ls[5] + os[1] + \" \" + (100 - x) + \" \" + ls[6]\n   end if\nend function\n\noffensive_td = function\n   print ls[17] + \"***\"\n   if rnd <= 0.8 then\n       sa[p] += 7\n       print \"Kick is good.\"\n   else\n       print \"Kick is off to the side\"\n       sa[p] += 6\n   end if\n   show_score\n   print os[p] + \" kicks off\"\n   globals.p = 1 - p\nend function\n\n// Main program\nmain = function\n   print \" \"*33 + \"FTBALL\"\n   print \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\n   print\n   print\n   print \"This is Dartmouth championship football.\"\n   print\n   print \"You will quarterback Dartmouth. Call plays as follows:\"\n   print \"1= simple run; 2= tricky run; 3= short pass;\"\n   print \"4= long pass; 5= punt; 6= quick kick; 7= place kick.\"\n   print\n   os[1] = input(\"Choose your opponent: \").upper\n   os[0] = \"DARMOUTH\"\n   print\n   sa[0] = 0\n   sa[1] = 0   \n   globals.p = floor(rnd * 2)\n   print os[p] + \" won the toss\"\n   if p != 0 then\n       print os[1] + \" Elects to receive.\"\n       print\n   else\n       print \"Do you elect to kick or receive? \"\n       while true\n           str = input.lower\n           if str and (str[0] == \"k\" or str[0] == \"r\") then break\n           print \"Incorrect answer.  Please type 'kick' or 'receive'\"\n       end while\n       if str[0] == \"k\" then e = 1 else e = 2\n       if e == 1 then globals.p = 1\n   end if\n   globals.t = 0\n   start = 1\n   while true\n       if start <= 1 then\n           x = 40 + (1 - p) * 20\n       end if\n       if start <= 2 then\n           y = floor(200 * ((rnd - 0.5))^3 + 55)\n           print \" \" + y + \" \" + ls[3] + \" kickoff\"\n           x = x - fnf(1) * y\n           if abs(x - 50) >= 50 then\n               print \"Touchback for \" + os[p] + \".\"\n               x = 20 + p * 60\n               start = 4\n           else\n               start = 3\n           end if\n       end if\n       if start <= 3 then\n           y = floor(50 * (rnd)^2) + (1 - p) * floor(50 * (rnd)^4)\n           x = x + fnf(1) * y\n           if abs(x - 50) < 50 then\n               print \" \" + y + \" \" + ls[3] + \" runback\"\n           else\n               print ls[4]\n               offensive_td\n               start = 1\n               continue\n           end if\n       end if\n       if start <= 4 then\n           // First down\n           show_position\n       end if\n       if start <= 5 then\n           x1 = x\n           d = 1\n           print\n           print \"First down \" + os[p] + \"***\"\n           print\n           print\n       end if\n       // New play\n       globals.t += 1\n       if t == 30 then\n           if rnd <= 1.3 then\n               print \"Game delayed.  Dog on field.\"\n               print\n           end if\n       end if\n       if t >= 50 and rnd <= 0.2 then break\n       if p != 1 then\n           // Opponent's play\n           if d <= 1 then\n               if rnd > 1/3 then z = 1 else z = 3\n           else if d != 4 then\n               if 10 + x - x1 < 5 or x < 5 then\n                   if rnd > 1/3 then z = 1 else z = 3\n               else if x <= 10 then\n                   a = floor(2 * rnd)\n                   z = 2 + a\n               else if x <= x1 or d < 3 or x < 45 then\n                   a = floor(2 * rnd)\n                   z = 2 + a * 2\n               else\n                   if (rnd > 1 / 4) then\n                       z = 4\n                   else\n                       z = 6\n                   end if\n               end if\n           else\n               if x <= 30 then\n                   z = 5\n               else if 10 + x - x1 < 3 or x < 3 then\n                   if rnd > 1/3 then z = 1 else z = 3\n               else\n                   z = 7\n               end if\n           end if\n       else\n\t\t\twhile true\n\t\t\t\tz = input(\"Next play? \").val\n                if 1 <= z <= 7 then break\n\t\t\t\tprint \"Illegal play number, retype\"\n            end while\n       end if\n       f = 0\n       print ls[z + 6] + \".  \"\n       r = rnd * (0.98 + fnf(1) * 0.02)\n       r1 = rnd\n       if z == 1 or z == 2 then\t\t// Simple Run or Tricky Run\n       \t\t   done = false\n               if z == 1 then\n                   y = floor(24 * (r - 0.5)^3 + 3)\n                   if rnd >= 0.05 then\n                       routine = 1                       \n                       done = true\n                   end if\n               else\n                   y = floor(20 * r - 5)\n                   if rnd > 0.1 then\n                   \t\troutine = 1\n                   \t\tdone = true\n                   end if\n               end if\n               if not done then\n\t\t\t\t   f = -1\n\t\t\t\t   x3 = x\n\t\t\t\t   x = x + fnf(1) * y\n\t\t\t\t   if abs(x - 50) < 50 then\n\t\t\t\t\t   print \"***  Fumble after \"\n\t\t\t\t\t   routine = 2\n\t\t\t\t   else\n\t\t\t\t\t   print \"***  Fumble.\"\n\t\t\t\t\t   routine = 4\n\t\t\t\t   end if\n               end if\n     \t   else if z == 3 or z == 4 then\t// Short Pass or Long Pass\n               if z == 3 then\n                   y = floor(60 * (r1 - 0.5)^3 + 10)\n               else\n                   y = floor(160 * ((r1 - 0.5))^3 + 30)\n               end if\n               if z == 3 and r < 0.05 or z == 4 and r < 0.1 then\n                   if d != 4 then\n                       print \"Intercepted.\"\n                       f = -1\n                       x = x + fnf(1) * y\n                       if abs(x - 50) >= 50 then\n                           routine = 4\n                       else\n\t                       routine = 3\n                       end if\n                   else\n                       y = 0\n                       if rnd < 0.3 then\n                           print \"Batted down.  \", \"\"\n                       else\n                           print \"Incomplete.  \", \"\"\n                       end if\n                       routine = 1\n                   end if\n               else if z == 4 and r < 0.3 then\n                   print \"Passer tackled.  \", \"\"\n                   y = -floor(15 * r1 + 3)\n                   routine = 1\n               else if z == 3 and r < 0.15 then\n                   print \"Passer taclked.  \", \"\"\n                   y = -floor(10 * r1)\n                   routine = 1\n               else if z == 3 and r < 0.55 or z == 4 and r < 0.75 then\n                   y = 0\n                   if rnd < 0.3 then\n                       print \"Batted down.  \", \"\"\n                   else\n                       print \"Incomplete.  \", \"\"\n                   end if\n                   routine = 1\n               else\n                   print \"Complete.  \", \"\"\n                   routine = 1\n               end if\n     \t   else if z == 5 or z == 6 then\t\t// Punt or Quick Kick\n               y = floor(100 * ((r - 0.5))^3 + 35)\n               if (d != 4) then y = floor(y * 1.3)\n               print \" \" + y + \" \" + ls[3] + \" punt\"\n               if abs(x + y * fnf(1) - 50) < 50 and d >= 4 then\n                   y1 = floor((r1)^2 * 20)\n                   print \" \" + y1 + \" \" + ls[3] + \" Run back\"\n                   y = y - y1\n               end if\n               f = -1\n               x = x + fnf(1) * y\n               if abs(x - 50) >= 50 then routine = 4 else routine = 3\n     \t   else if z == 7 then \t\t// Place kick\n               y = floor(100 * ((r - 0.5))^3 + 35)\n               if r1 <= 0.15 then\n                   print \"Kick is blocked  ***\"\n                   x = x - 5 * fnf(1)\n                   globals.p = 1 - p\n                   start = 4\n                   continue\n               end if\n               x = x + fnf(1) * y\n               if abs(x - 50) >= 60 then\n                   if r1 <= 0.5 then\n                       print \"Kick is off to the side.\"\n                       print ls[18]\n                       globals.p = 1 - p\n                       x = 20 + p * 60\n                       start = 4\n                       continue\n                   else\n                       print \"Field goal ***\"\n                       sa[p] = sa[p] + 3\n                       show_score\n                       print os[p] + \" kicks off\"\n                       globals.p = 1 - p\n                       start = 1\n                       continue\n                   end if\n               else\n                   print \"Kick is short.\"\n                   if abs(x - 50) >= 50 then\n                       // Touchback\n                       print ls[18]\n                       globals.p = 1 - p\n                       x = 20 + p * 60\n                       start = 4\n                       continue\n                   end if\n                   globals.p = 1 - p\n                   start = 3\n                   continue\n               end if            \n\t   end if\n       // Gain or loss\n       if routine <= 1 then\n           x3 = x\n           x = x + fnf(1) * y\n           if abs(x - 50) >= 50 then\n               routine = 4\n           end if\n       end if\n       if routine <= 2 then\n           if y != 0 then\n               print \" \" + abs(y) + \" \" + ls[3]\n               if (y < 0) then\n                   yt = -1\n               else if y > 0 then\n                   yt = 1\n               else\n                   yt = 0\n               end if\n               print ls[15 + yt]\n               if abs(x3 - 50) <= 40 and rnd < 0.1 then\n                   // Penalty\n                   p3 = floor(2 * rnd)\n                   print os[p3] + \" offsides -- penalty of 5 yards.\"\n                   print\n                   print\n                   if p3 != 0 then\n                       print \"Do you accept the penalty?\"\n                       while true\n                           str = input.lower\n                           if str and (str[0] == \"y\" or str[0] == \"n\") then break\n                           print \"Yype 'yes' or 'no'\"\n                       end while\n                       if str[0] == \"y\" then\n                           f = 0\n                           d = d - 1\n                           if (p != p3) then\n                               x = x3 + fnf(1) * 5\n                           else\n                               x = x3 - fnf(1) * 5\n                           end if\n                       end if\n                   else\n                       // opponent's strategy on penalty\n                       if ((p != 1 and (y <= 0 or f < 0 or fng(1) < 3 * d - 2)) or\n                           (p == 1 and ((y > 5 and f >= 0) or d < 4 or fng(1) >= 10))) then\n                           print \"penalty refused.\"\n                       else\n                           print \"penalty accepted.\"\n                           f = 0\n                           d = d - 1\n                           if (p != p3) then\n                               x = x3 + fnf(1) * 5\n                           else\n                               x = x3 - fnf(1) * 5\n                           end if\n                       end if\n                   end if\n                   routine = 3\n               end if\n           end if\n       end if\n       if routine <= 3 then\n           show_position\n           if f != 0 then\n               globals.p = 1 - p\n               start = 5\n               continue\n           else if fng(1) >= 10 then\n               start = 5\n               continue\n           else if d == 4 then\n               globals.p = 1 - p\n               start = 5\n               continue\n           else\n               d += 1\n               print \"DOWN: \" + d + \"     \"\n               if (x1 - 50) * fnf(1) >= 40 then\n                   print \"Goal to go\"\n               else\n                   print \"Yards to go: \" + (10 - fng(1))\n               end if\n               print\n               print\n               start = 6\n               continue\n           end if\n       end if\n       if routine <= 4 then\n           // Ball in end-zone\n           e = (x >= 100)\n           case = 1 + e - f * 2 + p * 4\n           if case == 1 or case == 5 then\n                   // Safety\n                   sa[1 - p] = sa[1 - p] + 2\n                   print ls[19]\n                   show_score\n                   print os[p] + \" kicks off from its 20 yard line.\"\n                   x = 20 + p * 60\n                   globals.p = 1 - p\n                   start = 2\n                   continue\n           end if\n           if case == 3 or case == 6 then\n                   // defensive td\n                   print ls[17] + \"for \" + os[1 - p] + \"***\"\n                   globals.p = 1 - p\n           end if\n           if case == 3 or case == 6 or case == 2 or case == 8 then\n                   // offensive td\n                   print ls[17] + \"***\"\n                   if rnd <= 0.8 then\n                       sa[p] = sa[p] + 7\n                       print \"kick is good.\"\n                   else\n                       print \"kick is off to the side\"\n                       sa[p] = sa[p] + 6\n                   end if\n                   show_score\n                   print os[p] + \" kicks off\"\n                   globals.p = 1 - p\n                   start = 1\n                   continue\n            end if\n            if case == 4 or case == 7 then\n                   // Touchback\n                   print ls[18]\n                   globals.p = 1 - p\n                   x = 20 + p * 60\n                   start = 4\n                   continue\n           end if\n       end if\n   end while\n   print \"END OF GAME  ***\"\n   print \"FINAL SCORE:  \" + os[0] + \": \" + sa[0] + \"  \" + os[1] + \": \" + sa[1]\nend function\n\nmain\n"
  },
  {
    "path": "00_Alternate_Languages/37_Football/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/37_Football/football.bas",
    "content": "1 PRINT TAB(32);\"FOOTBALL\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n100 REM\n120 DIM A(20),B(20),C(40),H(2),T(2),W(2),X(2),Y(2),Z(2)\n130 DIM M$(2),D(2),P$(20)\n140 PRINT \"PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\"\n145 PRINT:PRINT\n150 INPUT \"DO YOU WANT INSTRUCTIONS\";A$\n160 IF A$=\"NO\" THEN 290\n165 IF A$<>\"YES\" THEN 150\n170 PRINT \"THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST\"\n180 PRINT \"PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,\"\n190 PRINT \"1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20\"\n195 PRINT \"THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS.\"\n200 PRINT\"A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH\"\n210 PRINT \"BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE\"\n220 PRINT \"PLAYS THE LESS YARDAGE GAINED.  SCORES ARE GIVEN\"\n223 PRINT \"WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED\"\n225 PRINT \"BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A\"\n227 PRINT \"FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE\"\n230 PRINT \"ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER\"\n240 PRINT \"YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO\"\n250 PRINT \"BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO\"\n260 PRINT \"TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO.\"\n270 PRINT \"THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C).\"\n280 PRINT \"PLEASE PREPARE A TAPE AND RUN.\": STOP\n290 PRINT:PRINT \"PLEASE INPUT SCORE LIMIT ON GAME\";:INPUT E\n300 FOR I=1 TO 40: READ N: IF I>20 THEN 350\n330 A(N)=I: GOTO 360\n350 B(N)=I-20\n360 C(I)=N: NEXT I\n370 FOR I=1 TO 20: READ P$(I): NEXT I\n380 L=0: T=1\n410 PRINT \"TEAM\";T;\"PLAY CHART\"\n420 PRINT \"NO.      PLAY\"\n430 FOR I=1 TO 20\n440 REM\n450 PRINT C(I+L);TAB(6);P$(I)\n460 NEXT I\n630 L=L+20:T=2\n640 PRINT\n650 PRINT \"TEAR OFF HERE----------------------------------------------\"\n660 FOR X=1 TO 11: PRINT: NEXT X\n670 FOR Z=1 TO 3000: NEXT Z\n680 IF L=20 THEN 410\n690 D(1)=0: D(2)=3: M$(1)=\"--->\": M$(2)=\"<---\"\n700 H(1)=0: H(2)=0: T(1)=2: T(2)=1\n710 W(1)=-1: W(2)=1: X(1)=100: X(2)=0\n720 Y(1)=1: Y(2)=-1: Z(1)=0: Z(2)=100\n725 GOSUB 1910\n730 PRINT \"TEAM 1 DEFENDS 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.\"\n740 T=INT(2*RND(1)+1)\n760 PRINT: PRINT \"THE COIN IS FLIPPED\"\n765 P=X(T)-Y(T)*40\n770 GOSUB 1860: PRINT : PRINT \"TEAM\";T;\"RECEIVES KICK-OFF\"\n780 K=INT(26*RND(1)+40)\n790 P=P-Y(T)*K\n794 IF W(T)*P<Z(T)+10 THEN 810\n795 PRINT: PRINT \"BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--\"\n796 GOTO 870\n810 PRINT \"BALL WENT\";K;\"YARDS.  NOW ON\";P:GOSUB 1900\n830 PRINT \"TEAM\";T;\"DO YOU WANT TO RUNBACK\";:INPUT A$\n840 IF A$=\"YES\" THEN 1430\n845 IF A$<>\"NO\" THEN 830\n850 IF W(T)*P<Z(T) THEN 880\n870 P=Z(T)-W(T)*20\n880 D=1: S=P\n885 FOR I=1 TO 72: PRINT \"=\";: NEXT I\n890 PRINT: PRINT \"TEAM\";T;\"DOWN\";D;\"ON\";P\n893 IF D<>1 THEN 900\n895 IF Y(T)*(P+Y(T)*10)>=X(T) THEN 898\n897 C=4: GOTO 900\n898 C=8\n900 IF C=8 THEN 904\n901 PRINT TAB(27);10-(Y(T)*P-Y(T)*S);\"YARDS TO 1ST DOWN\"\n902 GOTO 910\n904 PRINT TAB(27);X(T)-Y(T)*P;\"YARDS\"\n910 GOSUB 1900: IF D=4 THEN 1180\n920 REM\n930 U=INT(3*RND(0)-1): GOTO 940\n936 PRINT \"ILLEGAL PLAY NUMBER, CHECK AND\"\n940 PRINT \"INPUT OFFENSIVE PLAY, DEFENSIVE PLAY\";\n950 IF T=2 THEN 970\n960 INPUT P1,P2: GOTO 975\n970 INPUT P2,P1\n975 IF P1=77 THEN 1180\n980 IF P1>20 THEN 1800\n985 IF P1<1 THEN 1800\n990 IF P2>20 THEN 1800\n992 IF P2<1 THEN 1800\n995 P1=INT(P1): P2=INT(P2)\n1000 Y=INT(ABS(A(P1)-B(P2))/19*((X(T)-Y(T)*P+25)*RND(1)-15))\n1005 PRINT: IF T=2 THEN 1015\n1010 IF A(P1)<11 THEN 1048\n1012 GOTO 1020\n1015 IF B(P2)<11 THEN 1048\n1020 IF U<>0 THEN 1035\n1025 PRINT \"PASS INCOMPLETE TEAM\";T\n1030 Y=0: GOTO 1050\n1035 G=RND(1): IF G>.025 THEN 1040\n1037 IF Y>2 THEN 1045\n1040 PRINT \"QUARTERBACK SCRAMBLED\": GOTO 1050\n1045 PRINT \"PASS COMPLETED\": GOTO 1050\n1048 PRINT \"THE BALL WAS RUN\"\n1050 P=P-W(T)*Y\n1060 PRINT: PRINT \"NET YARDS GAINED ON DOWN\";D;\"ARE \";Y\n1070 G=RND(1): IF G>.025 THEN 1110\n1080 PRINT: PRINT \"** LOSS OF POSSESSION FROM TEAM\";T;\"TO TEAM\";T(T)\n1100 GOSUB 1850: PRINT: T=T(T): GOTO 830\n1110 IF Y(T)*P>=X(T) THEN 1320\n1120 IF W(T)*P>=Z(T) THEN 1230\n1130 IF Y(T)*P-Y(T)*S>=10 THEN 880\n1140 D=D+1: IF D<>5 THEN 885\n1160 PRINT: PRINT \"CONVERSION UNSUCCESSFUL TEAM\";T:T=T(T)\n1170 GOSUB 1850: GOTO 880\n1180 PRINT \"DOES TEAM\";T;\"WANT TO PUNT\";: INPUT A$\n1185 IF A$=\"NO\" THEN 1200\n1187 IF A$<>\"YES\" THEN 1180\n1190 PRINT:PRINT \"TEAM\";T;\"WILL PUNT\": G=RND(1): IF G<.025 THEN 1080\n1195 GOSUB 1850: K=INT(25*RND(1)+35): T=T(T): GOTO 790\n1200 PRINT \"DOES TEAM\";T;\"WANT TO ATTEMPT A FIELD GOAL\";: INPUT A$\n1210 IF A$=\"YES\" THEN 1640\n1215 IF A$<>\"NO\" THEN 1200\n1217 GOTO 920\n1230 PRINT: PRINT \"SAFETY AGAINST TEAM\";T;\"**********************OH-OH\"\n1240 H(T(T))=H(T(T))+2: GOSUB 1810\n1280 PRINT\"TEAM\";T;\"DO YOU WANT TO PUNT INSTEAD OF A KICKOFF\";:INPUT A$\n1290 P=Z(T)-W(T)*20: IF A$=\"YES\" THEN 1190\n1320 PRINT: PRINT \"TOUCHDOWN BY TEAM\";T;\"*********************YEA TEAM\"\n1340 Q=7: G=RND(1): IF G>.1 THEN 1380\n1360 Q=6: PRINT \"EXTRA POINT NO GOOD\": GOTO 1390\n1380 PRINT \"EXTRA POINT GOOD\"\n1390 H(T)=H(T)+Q: GOSUB 1810\n1420 T=T(T): GOTO 765\n1430 K=INT(9*RND(0)+1)\n1440 R=INT(((X(T)-Y(T)*P+25)*RND(1)-15)/K)\n1460 P=P-W(T)*R\n1480 PRINT:PRINT \"RUNBACK TEAM\";T;R;\"YARDS\"\n1485 G=RND(1): IF G<.025 THEN 1080\n1490 IF Y(T)*P>=X(T) THEN 1320\n1500 IF W(T)*P>=Z(T) THEN 1230\n1510 GOTO 880\n1640 PRINT: PRINT \"TEAM\";T;\"WILL ATTEMPT A FIELD GOAL\"\n1645 G=RND(1): IF G<.025 THEN 1080\n1650 F=INT(35*RND(1)+20)\n1660 PRINT: PRINT \"KICK IS\";F;\"YARDS LONG\"\n1680 P=P-W(T)*F: G=RND(1)\n1690 IF G<.35 THEN 1735\n1700 IF Y(T)*P<X(T) THEN 1740\n1710 PRINT \"FIELD GOAL GOOD FOR TEAM\";T;\"*********************YEA\"\n1720 Q=3: GOTO 1390\n1735 PRINT \"BALL WENT WIDE\"\n1740 PRINT \"FIELD GOAL UNSUCCESFUL TEAM\";T;\"-----------------TOO BAD\"\n1742 GOSUB 1850: IF Y(T)*P<X(T)+10 THEN 1745\n1744 T=T(T): GOTO 794\n1745 PRINT: PRINT \"BALL NOW ON\";P\n1750 T=T(T): GOSUB 1900: GOTO 830\n1770 DATA 17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6\n1780 DATA 20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3\n1790 DATA \"PITCHOUT\",\"TRIPLE REVERSE\",\"DRAW\",\"QB SNEAK\",\"END AROUND\"\n1792 DATA \"DOUBLE REVERSE\",\"LEFT SWEEP\",\"RIGHT SWEEP\",\"OFF TACKLE\"\n1794 DATA \"WISHBONE OPTION\",\"FLARE PASS\",\"SCREEN PASS\"\n1796 DATA \"ROLL OUT OPTION\",\"RIGHT CURL\",\"LEFT CURL\",\"WISHBONE OPTION\"\n1798 DATA \"SIDELINE PASS\",\"HALF-BACK OPTION\",\"RAZZLE-DAZZLE\",\"BOMB!!!!\"\n1800 IF P1<>99 THEN 936\n1810 PRINT: PRINT \"TEAM 1 SCORE IS\";H(1)\n1820 PRINT \"TEAM 2 SCORE IS\";H(2): PRINT\n1825 IF H(T)<E THEN 1830\n1827 PRINT \"TEAM\";T;\"WINS*******************\": GOTO 2000\n1830 IF P1=99 THEN 940\n1835 RETURN\n1850 PRINT\n1860 FOR X=1 TO 72: PRINT \"+\";: NEXT X: PRINT\n1870 RETURN\n1900 PRINT TAB(D(T)+5+P/2);M$(T)\n1910 PRINT \"TEAM 1 [0   10   20   30   40   50   60   70   80   90\";\n1915 PRINT \"   100] TEAM 2\"\n1920 PRINT\n1930 RETURN\n2000 END\n"
  },
  {
    "path": "00_Alternate_Languages/37_Football/ftball.bas",
    "content": "10 PRINT TAB(33);\"FTBALL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT\n220 PRINT \"THIS IS DARTMOUTH CHAMPIONSHIP FOOTBALL.\":PRINT\n230 PRINT \"YOU WILL QUARTERBACK DARTMOUTH. CALL PLAYS AS FOLLOWS:\"\n240 PRINT \"1= SIMPLE RUN; 2= TRICKY RUN; 3= SHORT PASS;\"\n250 PRINT \"4= LONG PASS; 5= PUNT; 6= QUICK KICK; 7= PLACE KICK.\"\n260 PRINT\n270 PRINT \"CHOOSE YOUR OPPONENT\";\n280 INPUT O$(1)\n290 O$(0)=\"DARTMOUTH\"\n300 PRINT\n310 LET S(0)=0: LET S(1)=0\n320 REM\n330 DIM L$(20)\n340 FOR I=1 TO 20: READ L$(I): NEXT I\n350 DATA \"KICK\",\"RECEIVE\",\" YARD \",\"RUN BACK FOR \",\"BALL ON \"\n360 DATA \"YARD LINE\",\" SIMPLE RUN\",\" TRICKY RUN\",\" SHORT PASS\"\n370 DATA \" LONG PASS\",\"PUNT\",\" QUICK KICK \",\" PLACE KICK\",\" LOSS \"\n380 DATA \" NO GAIN\",\"GAIN \",\" TOUCHDOWN \",\" TOUCHBACK \",\"SAFETY***\"\n385 DATA \"JUNK\"\n390 LET P=INT(RND(1)*2)\n400 PRINT O$(P);\" WON THE TOSS\"\n410 DEF FNF(X)=1-2*P\n420 DEF FNG(Z)=P*(X1-X)+(1-P)*(X-X1)\n430 IF P=0 THEN 470\n440 PRINT O$(1);\" ELECTS TO RECEIVE.\"\n450 PRINT\n460 GOTO 580\n470 PRINT \"DO YOU ELECT TO KICK OR RECEIVE\";\n480 INPUT A$\n490 PRINT\n500 FOR E=1 TO 2\n510 IF A$=L$(E) THEN 550\n520 NEXT E\n530 PRINT \"INCORRECT ANSWER.  PLEASE TYPE 'KICK' OR 'RECEIVE'\";\n540 GOTO 480\n550 IF E=2 THEN 580\n560 LET P=1\n580 LET X=40+(1-P)*20\n590 LET Y=INT(200*(RND(1)-.5)^3+55)\n600 PRINT Y;L$(3);\" KICKOFF\"\n610 LET X=X-FNF(1)*Y\n620 IF ABS(X-50)>=50 THEN 700\n630 LET Y=INT(50*RND(1)^2)+(1-P)*INT(50*RND(1)^4)\n640 LET X=X+FNF(1)*Y\n650 IF ABS(X-50)>=50 THEN 655\n651 PRINT Y;L$(3);\" RUNBACK\"\n652 GOTO 720\n655 PRINT L$(4);\n660 GOTO 2600\n700 PRINT \"TOUCHBACK FOR \";O$(P);\".\"\n710 LET X=20+P*60\n720 REM FIRST DOWN\n730 GOSUB 800\n740 LET X1=X\n750 LET D=1\n760 PRINT:PRINT \"FIRST DOWN \";O$(P);\"***\"\n770 PRINT\n780 PRINT\n790 GOTO 860\n800 REM PRINT POSITION\n810 IF X>50 THEN 840\n820 PRINT L$(5);O$(0);X;L$(6)\n830 GOTO 850\n840 PRINT L$(5);O$(1);100-X;L$(6)\n850 RETURN\n860 REM NEW PLAY\n870 LET T=T+1\n880 IF T=30 THEN 1060\n890 IF T<50 THEN 940\n900 IF RND(1)>.2 THEN 940\n910 PRINT \"END OF GAME  ***\"\n920 PRINT \"FINAL SCORE:  \";O$(0);\": \";S(0);\"  \";O$(1);\": \";S(1)\n930 STOP\n940 IF P=1 THEN 1870\n950 PRINT \"NEXT PLAY\";\n960 INPUT Z\n970 IF Z<>INT(Z) THEN 990\n980 IF ABS(Z-4)<=3 THEN 1010\n990 PRINT \"ILLEGAL PLAY NUMBER, RETYPE\";\n1000 GOTO 960\n1010 LET F=0\n1020 PRINT L$(Z+6);\".  \";\n1030 LET R=RND(1)*(.98+FNF(1)*.02)\n1040 LET R1=RND(1)\n1050 ON Z GOTO 1110,1150,1260,1480,1570,1570,1680\n1060 REM  JEAN'S SPECIAL\n1070 IF RND(1)> 1/3 THEN 940\n1080 PRINT \"GAME DELAYED.  DOG ON FIELD.\"\n1090 PRINT\n1100 GOTO 940\n1110 REM  SIMPLE RUN\n1120 LET Y=INT(24*(R-.5)^3+3)\n1130 IF RND(1)<.05 THEN 1180\n1140 GOTO 2190\n1150 REM  TRICKY RUN\n1160 LET Y=INT(20*R-5)\n1170 IF RND(1)>.1 THEN 2190\n1180 LET F=-1\n1190 LET X3=X\n1200 LET X=X+FNF(1)*Y\n1210 IF ABS(X-50)>=50 THEN 1240\n1220 PRINT \"***  FUMBLE AFTER \";\n1230 GOTO 2230\n1240 PRINT \"***  FUMBLE.\"\n1250 GOTO 2450\n1260 REM  SHORT PASS\n1270 LET Y=INT(60*(R1-.5)^3+10)\n1280 IF R<.05 THEN 1330\n1290 IF R<.15 THEN 1390\n1300 IF R<.55 THEN 1420\n1310 PRINT \"COMPLETE.  \";\n1320 GOTO 2190\n1330 IF D=4 THEN 1420\n1340 PRINT \"INTERCEPTED.\"\n1350 LET F=-1\n1360 LET X=X+FNF(1)*Y\n1370 IF ABS(X-50)>=50 THEN 2450\n1380 GOTO 2300\n1390 PRINT \"PASSER TACKLED.  \";\n1400 LET Y=-INT(10*R1)\n1410 GOTO 2190\n1420 LET Y=0\n1430 IF RND(1)<.3 THEN 1460\n1440 PRINT \"INCOMPLETE.  \";\n1450 GOTO 2190\n1460 PRINT \"BATTED DOWN.  \";\n1470 GOTO 2190\n1480 REM  LONG PASS\n1490 LET Y=INT(160*(R1-.5)^3+30)\n1500 IF R<.1 THEN 1330\n1510 IF R<.3 THEN 1540\n1520 IF R<.75 THEN 1420\n1530 GOTO 1310\n1540 PRINT \"PASSER TACKLED.  \";\n1550 LET Y=-INT(15*R1+3)\n1560 GOTO 2190\n1570 REM  PUNT OR KICK\n1580 LET Y=INT(100*(R-.5)^3+35)\n1590 IF D=4 THEN 1610\n1600 LET Y=INT(Y*1.3)\n1610 PRINT Y;L$(3);\" PUNT\"\n1620 IF ABS(X+Y*FNF(1)-50)>=50 THEN 1670\n1630 IF D<4 THEN 1670\n1640 LET Y1=INT(R1^2*20)\n1650 PRINT Y1;L$(3);\" RUN BACK\"\n1660 LET Y=Y-Y1\n1670 GOTO 1350\n1680 REM  PLACE KICK\n1690 LET Y=INT(100*(R-.5)^3+35)\n1700 IF R1>.15 THEN 1750\n1710 PRINT \"KICK IS BLOCKED  ***\"\n1720 LET X=X-5*FNF(1)\n1730 LET P=1-P\n1740 GOTO 720\n1750 LET X=X+FNF(1)*Y\n1760 IF ABS(X-50)>=60 THEN 1810\n1770 PRINT \"KICK IS SHORT.\"\n1780 IF ABS(X-50)>=50 THEN 2710\n1790 P=1-P\n1800 GOTO 630\n1810 IF R1>.5 THEN 1840\n1820 PRINT \"KICK IS OFF TO THE SIDE.\"\n1830 GOTO 2710\n1840 PRINT \"FIELD GOAL ***\"\n1850 LET S(P)=S(P)+3\n1860 GOTO 2640\n1870 REM  OPPONENT'S PLAY\n1880 IF D>1 THEN 1940\n1890 IF RND(1)>1/3 THEN 1920\n1900 LET Z=3\n1910 GOTO 1010\n1920 LET Z=1\n1930 GOTO 1010\n1940 IF D=4 THEN 2090\n1950 IF 10+X-X1<5 THEN 1890\n1960 IF X<5 THEN 1890\n1970 IF X<=10 THEN 2160\n1980 IF X>X1 THEN 2020\n1990 LET A=INT(2*RND(1))\n2000 LET Z=2+A*2\n2010 GOTO 1010\n2020 IF D<3 THEN 1990\n2030 IF X<45 THEN 1990\n2040 IF RND(1)>1/4 THEN 2070\n2050 LET Z=6\n2060 GOTO 1010\n2070 LET Z=4\n2080 GOTO 1010\n2090 IF X>30 THEN 2140\n2100 IF 10+X-X1<3 THEN 1890\n2110 IF X<3 THEN 1890\n2120 LET Z=7\n2130 GOTO 1010\n2140 LET Z=5\n2150 GOTO 1010\n2160 LET A=INT(2*RND(1))\n2170 LET Z=2+A\n2180 GOTO 1010\n2190 REM GAIN OR LOSS\n2200 LET X3=X\n2210 LET X=X+FNF(1)*Y\n2220 IF ABS(X-50)>=50 THEN 2450\n2230 IF Y=0 THEN 2250\n2240 PRINT ABS(Y);L$(3);\n2250 PRINT L$(15+SGN(Y))\n2280 IF ABS(X3-50)>40 THEN 2300\n2290 IF RND(1)<.1 THEN 2860\n2300 GOSUB 800\n2310 IF F=0 THEN 2340\n2320 LET P=1-P\n2330 GOTO 740\n2340 IF FNG(1)>=10 THEN 740\n2350 IF D=4 THEN 2320\n2360 LET D=D+1\n2370 PRINT \"DOWN: \";D;\"     \";\n2380 IF (X1-50)*FNF(1)<40 THEN 2410\n2390 PRINT \"GOAL TO GO\"\n2400 GOTO 2420\n2410 PRINT \"YARDS TO GO: \";10-FNG(1)\n2420 PRINT\n2430 PRINT\n2440 GOTO 860\n2450 REM BALL IN END-ZONE\n2460 IF X>=100 THEN 2490\n2470 LET E=0\n2480 GOTO 2500\n2490 LET E=1\n2500 ON 1+E-F*2+P*4 GOTO 2510,2590,2760,2710,2590,2510,2710,2760\n2510 REM SAFETY\n2520 LET S(1-P)=S(1-P)+2\n2530 PRINT L$(19)\n2540 GOSUB 2800\n2550 PRINT O$(P);\" KICKS OFF FROM ITS 20 YARD LINE.\"\n2560 LET X=20+P*60\n2570 LET P=1-P\n2580 GOTO 590\n2590 REM OFFENSIVE TD\n2600 PRINT L$(17);\"***\"\n2610 IF RND(1)>.8 THEN 2680\n2620 LET S(P)=S(P)+7\n2630 PRINT \"KICK IS GOOD.\"\n2640 GOSUB 2800\n2650 PRINT O$(P);\" KICKS OFF\"\n2660 LET P=1-P\n2670 GOTO 580\n2680 PRINT \"KICK IS OFF TO THE SIDE\"\n2690 LET S(P)=S(P)+6\n2700 GOTO 2640\n2710 REM TOUCHBACK\n2720 PRINT L$(18)\n2730 LET P=1-P\n2740 LET X=20+P*60\n2750 GOTO 720\n2760 REM DEFENSIVE TD\n2770 PRINT L$(17);\"FOR \";O$(1-P);\"***\"\n2780 LET P=1-P\n2790 GOTO 2600\n2800 REM SCORE\n2810 PRINT\n2820 PRINT \"SCORE:  \";S(0);\" TO \";S(1)\n2830 PRINT\n2840 PRINT\n2850 RETURN\n2860 REM PENALTY\n2870 LET P3=INT(2*RND(1))\n2880 PRINT O$(P3);\" OFFSIDES -- PENALTY OF 5 YARDS.\"\n2890 PRINT\n2900 PRINT\n2910 IF P3=0 THEN 2980\n2920 PRINT \"DO YOU ACCEPT THE PENALTY\";\n2930 INPUT A$\n2940 IF A$=\"NO\" THEN 2300\n2950 IF A$=\"YES\" THEN 3110\n2960 PRINT \"TYPE 'YES' OR 'NO'\";\n2970 GOTO 2930\n2980 REM OPPONENT'S STRATEGY ON PENALTY\n2990 IF P=1 THEN 3040\n3000 IF Y<=0 THEN 3080\n3010 IF F<0 THEN 3080\n3020 IF FNG(1)<3*D-2 THEN 3080\n3030 GOTO 3100\n3040 IF Y<=5 THEN 3100\n3050 IF F<0 THEN 3100\n3060 IF D<4 THEN 3080\n3070 IF FNG(1)<10 THEN 3100\n3080 PRINT \"PENALTY REFUSED.\"\n3090 GOTO 2300\n3100 PRINT \"PENALTY ACCEPTED.\"\n3110 LET F=0\n3120 LET D=D-1\n3130 IF P<>P3 THEN 3160\n3140 LET X=X3-FNF(1)*5\n3150 GOTO 2300\n3160 LET X=X3+FNF(1)*5\n3170 GOTO 2300\n3180 END\n"
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript furtrader.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"furtrader\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms",
    "content": "print \" \"*31 + \"Fur Trader\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nfurs = [0,0,0,0]\t// how many of each type of fur you have\nvalue = [0,0,0,0]\t// value of each type of fur\nfurNames = \"mink beaver ermine fox\".split\n\ngetYesNo = function\n\twhile true\n\t\tans = input(\"Answer yes or no: \").upper\n\t\tif not ans then continue\n\t\tif ans[0] == \"Y\" then return \"YES\"\n\t\tif ans[0] == \"N\" then return \"NO\"\n\tend while\nend function\n\nprintInstructions = function\n\tprint \"You are the leader of a French fur trading expedition in \"\n\tprint \"1776 leaving the Lake Ontario area to sell furs and get\"\n\tprint \"supplies for the next year.  You have a choice of three\"\n\tprint \"forts at which you may trade.  The cost of supplies\"\n\tprint \"and the amount you receive for your furs will depend\"\n\tprint \"on the fort that you choose.\"\n\tprint\nend function\n\npickFort = function\n\tprint\n\twhile true\n\t\tprint \"You may trade your furs at fort 1, fort 2,\"\n\t\tprint \"or fort 3.  Fort 1 is Fort Hochelaga (Montreal)\"\n\t\tprint \"and is under the protection of the French army.\"\n\t\tprint \"Fort 2 is Fort Stadacona (Quebec) and is under the\"\n\t\tprint \"protection of the French Army.  However, you must\"\n\t\tprint \"make a portage and cross the Lachine rapids.\"\n\t\tprint \"Fort 3 is Fort New York and is under Dutch control.\"\n\t\tprint \"You must cross through Iroquois land.\"\n\t\tb = input(\"Answer 1, 2, or 3: \").val\n\t\tif b == 1 then\n\t\t\tprint \"You have chosen the easiest route.  However, the fort\"\n\t\t\tprint \"is far from any seaport.  The value\"\n\t\t\tprint \"you receive for your furs will be low and the cost\"\n\t\t\tprint \"of supplies higher than at Forts Stadacona or New York.\"\t\t\n\t\telse if b == 2 then\n\t\t\tprint \"You have chosen a hard route.  It is, in comparsion,\"\n\t\t\tprint \"harder than the route to Hochelaga but easier than\"\n\t\t\tprint \"the route to New York.  You will receive an average value\"\n\t\t\tprint \"for your furs and the cost of your supplies will be average.\"\n\t\telse if b == 3 then\n\t\t\tprint \"You have chosen the most difficult route.  At\"\n\t\t\tprint \"Fort New York you will receive the highest value\"\n\t\t\tprint \"for your furs.  The cost of your supplies\"\n\t\t\tprint \"will be lower than at all the other forts.\"\t\t\n\t\telse\n\t\t\tcontinue\n\t\tend if\n\t\tprint \"Do you want to trade at another fort?\"\n\t\tif getYesNo == \"NO\" then return b\n\tend while\nend function\n\nvisitFort = function(fort)\n\tprint\n\tif fort == 1 then\n\t\tvalue[0] = floor((.2*rnd+.7)*100+.5)/100\n\t\tvalue[2] = floor((.2*rnd+.65)*100+.5)/100\n\t\tvalue[1] = floor((.2*rnd+.75)*100+.5)/100\n\t\tvalue[3] = floor((.2*rnd+.8)*100+.5)/100\n\t\tprint \"Supplies at Fort Hochelaga cost $150.00.\"\n\t\tprint \"Your travel expenses to Hochelaga were $10.00.\"\n\t\tglobals.money -= 150 + 10\n\telse if fort == 2 then\t\n\t\tvalue[0] = floor((.3*rnd+.85)*100+.5)/100\n\t\tvalue[2] = floor((.15*rnd+.8)*100+.5)/100\n\t\tvalue[1] = floor((.2*rnd+.9)*100+.5)/100\n\t\tp = floor(10*rnd)+1\n\t\tif p <= 2 then\n\t\t\tfurs[1] = 0\n\t\t\tprint \"Your beaver were too heavy to carry across\"\n\t\t\tprint \"the portage.  You had to leave the pelts, but found\"\n\t\t\tprint \"them stolen when you returned.\"\n\t\telse if p <= 6 then \n\t\t\tprint \"You arrived safely at Fort Stadacona.\"\n\t\telse if p <= 8 then\n\t\t\tfor j in range(0,3); furs[j] = 0; end for\n\t\t\tprint \"Your canoe upset in the Lachine rapids.  You\"\n\t\t\tprint \"lost all your furs.\"\n\t\telse if furs[3] then\n\t\t\tfurs[3] = 0\n\t\t\tprint \"Your fox pelts were not cured properly.\"\n\t\t\tprint \"No one will buy them.\"\n\t\tend if\n\t\tprint \"Supplies at Fort Stadacona cost $125.00.\"\n\t\tprint \"Your travel expenses to Stadacona were $15.00.\"\n\t\tglobals.money -= 125 + 15\n\telse\n\t\tvalue[0] = floor((.15*rnd+1.05)*100+.5)/100\n\t\tvalue[3] = floor((.25*rnd+1.1)*100+.5)/100\n\t\tp = floor(10*rnd)+1\n\t\tif p <= 2 then\n\t\t\tprint \"You were attacked by a party of Iroquois.\"\n\t\t\tprint \"All people in your trading group were\"\n\t\t\tprint \"killed.  This ends the game.\"\n\t\t\tglobals.gameOver = true\n\t\t\treturn\n\t\telse if p<=6 then\n\t\t\tprint \"You were lucky.  You arrived safely\"\n\t\t\tprint \"at Fort New York.\"\n\t\telse if p<=8 then\n\t\t\tfor j in range(0,3); furs[j] = 0; end for\n\t\t\tprint \"You narrowly escaped an iroquois raiding party.\"\n\t\t\tprint \"However, you had to leave all your furs behind.\"\n\t\telse\n\t\t\tvalue[1] /= 2\n\t\t\tvalue[0] /= 2\n\t\t\tprint \"Your mink and beaver were damaged on your trip.\"\n\t\t\tprint \"You receive only half the current price for these furs.\"\n\t\tend if\n\t\tprint \"Supplies at New York cost $80.00.\"\n\t\tprint \"Your travel expenses to New York were $25.00.\"\n\t\tglobals.money -= 80 + 25\n\tend if\nend function\n\nprintInstructions\n\ngameOver = false\nmoney=600\nwhile not gameOver\n\tprint \"Do you wish to trade furs?\"\n\tif getYesNo == \"NO\" then break\n\n\tvalue[2]=floor((.15*rnd+.95)*100+.5)/100\t\t// ermine value\n\tvalue[1]=floor((.25*rnd+1.00)*100+.5)/100\t\t// beaver value\n\t\n\tprint\n\tprint \"You have $\" + money + \" savings.\"\n\tprint \"And 190 furs to begin the expedition.\"\n\tprint\n\tprint \"Your 190 furs are distributed among the following\"\n\tprint \"kinds of pelts: mink, beaver, ermine and fox.\"\n\tprint\n\tfurs = [0,0,0,0]\n\tfor j in range(0, 3)\n\t\tfurs[j] = input(\"How many \" + furNames[j] + \" do you have? \").val\n\t\tif furs.sum >= 190 then break\n\tend for\n\tif furs.sum > 190 then\n\t\tprint \"You may not have that many furs.\"\n\t\tprint \"Do not try to cheat.  I can add.\"\n\t\tprint \"You must start again.\"\n\t\tcontinue\n\tend if\n\n\tfort = pickFort\n\tvisitFort fort\n\tif gameOver then break\n\n\tprint\n\tfor j in [1, 3, 2, 0]\n\t\tif not furs[j] then continue\n\t\trevenue = value[j] * furs[j]\n\t\tprint \"Your \" + furNames[j] + \" sold for $\" + revenue + \".\"\n\t\tmoney += revenue\n\tend for\n\tprint\n\tprint \"You now have $\" + money + \" including your previous savings.\"\nend while\n\n\n"
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/c/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [ANSI-C](https://en.wikipedia.org/wiki/ANSI_C)\n\n##### Translator Notes:\nI tried to preserve as much of the original layout and flow of the code\nas possible.  However I did use enumerated types for the Fort numbers\nand Fur types.  I think this was certainly a change for the better, and\nmakes the code much easier to read.\n\nI also tried to minimise the use of pointers, and stuck with old-school\nC formatting, because you never know how old the compiler is.\n\nInterestingly the code seems to have a bug around the prices of Fox Furs.\nThe commodity-rate for these is stored in the variable `D1`, however some\npaths through the code do not set this price.  So there was a chance of\nusing this uninitialised, or whatever the previous loop set.  I don't\nthink this was the original authors intent.  So I preserved the original flow\nof the code (using the previous `D1` value), but also catching the\nuninitialised path, and assigning a \"best guess\" value.\n\nkrt@krt.com.au 2020-10-10\n"
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/c/furtrader.c",
    "content": "\n/*\n * Ported from furtrader.bas to ANSI C (C99) by krt@krt.com.au\n *\n * compile with:\n *    gcc -g -Wall -Werror furtrader.c -o furtrader\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n\n/* Constants */\n#define FUR_TYPE_COUNT    4\n#define FUR_MINK          0\n#define FUR_BEAVER        1\n#define FUR_ERMINE        2\n#define FUR_FOX           3\n#define MAX_FURS        190\nconst char *FUR_NAMES[FUR_TYPE_COUNT] = { \"MINK\", \"BEAVER\", \"ERMINE\", \"FOX\" };\n\n#define FORT_TYPE_COUNT 3\n#define FORT_MONTREAL   1\n#define FORT_QUEBEC     2\n#define FORT_NEWYORK    3\nconst char *FORT_NAMES[FORT_TYPE_COUNT] = { \"HOCHELAGA (MONTREAL)\", \"STADACONA (QUEBEC)\", \"NEW YORK\" };\n\n\n\n/* Print the words at the specified column */\nvoid printAtColumn( int column, const char *words )\n{\n    int i;\n    for ( i=0; i<column; i++ )\n        printf( \" \" );\n    printf( \"%s\\n\", words );\n}\n\n/* trivial function to output a line with a \\n */\nvoid print( const char *words )\n{\n    printf( \"%s\\n\", words );\n}\n\n/* Show the player the introductory message */\nvoid showIntroduction()\n{\n    print( \"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \" );\n    print( \"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\" );\n    print( \"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\" );\n    print( \"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\" );\n    print( \"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\" );\n    print( \"ON THE FORT THAT YOU CHOOSE.\" );\n    print( \"\" );\n}\n\n\n/*\n * Prompt the user for input.\n * When input is given, try to conver it to an integer\n * return the integer converted value or 0 on error\n */\nint getNumericInput()\n{\n    int  result = -1;\n    char buffer[64];   /* somewhere to store user input */\n    char *endstr;\n\n    while ( result == -1 )\n    {\n        printf( \">> \" );                                 /* prompt the user */\n        fgets( buffer, sizeof( buffer ), stdin );        /* read from the console into the buffer */\n        result = (int)strtol( buffer, &endstr, 10 );     /* only simple error checking */\n\n        if ( endstr == buffer )                          /* was the string -> integer ok? */\n            result = -1;\n    }\n\n    return result;\n}\n\n\n/*\n * Prompt the user for YES/NO input.\n * When input is given, try to work out if it's YES, Yes, yes, Y, etc.\n * And convert to a single upper-case letter\n * Returns a character of 'Y' or 'N'.\n */\nchar getYesOrNo()\n{\n    char result = '!';\n    char buffer[64];   /* somewhere to store user input */\n\n    while ( !( result == 'Y' || result == 'N' ) )       /* While the answer was not Yes or No */\n    {\n        print( \"ANSWER YES OR NO\" );\n        printf( \">> \" );\n\n        fgets( buffer, sizeof( buffer ), stdin );            /* read from the console into the buffer */\n        if ( buffer[0] == 'Y' || buffer[0] == 'y' )\n            result = 'Y';\n        else if ( buffer[0] == 'N' || buffer[0] == 'n' )\n            result = 'N';\n    }\n\n    return result;\n}\n\n\n\n/*\n * Show the player the choices of Fort, get their input, if the\n * input is a valid choice (1,2,3) return it, otherwise keep\n * prompting the user.\n */\nint getFortChoice()\n{\n    int result = 0;\n\n    while ( result == 0 )\n    {\n        print( \"\" );\n        print( \"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\" );\n        print( \"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\" );\n        print( \"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\" );\n        print( \"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\" );\n        print( \"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\" );\n        print( \"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\" );\n        print( \"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\" );\n        print( \"YOU MUST CROSS THROUGH IROQUOIS LAND.\" );\n        print( \"ANSWER 1, 2, OR 3.\" );\n\n        result = getNumericInput();   /* get input from the player */\n    }\n\n    return result;\n}\n\n\n/*\n * Print the description for the fort\n */\nvoid showFortComment( int which_fort )\n{\n    print( \"\" );\n    if ( which_fort == FORT_MONTREAL )\n    {\n        print( \"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\" );\n        print( \"IS FAR FROM ANY SEAPORT.  THE VALUE\" );\n        print( \"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\" );\n        print( \"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\" );\n    }\n    else if ( which_fort == FORT_QUEBEC )\n    {\n        print( \"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\" );\n        print( \"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\" );\n        print( \"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\" );\n        print( \"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\" );\n    }\n    else if ( which_fort == FORT_NEWYORK )\n    {\n        print( \"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\" );\n        print( \"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\" );\n        print( \"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\" );\n        print( \"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\" );\n    }\n    else\n    {\n        printf( \"Internal error #1, fort %d does not exist\\n\", which_fort );\n        exit( 1 );  /* you have a bug */\n    }\n    print( \"\" );\n}\n\n\n/*\n * Prompt the player for how many of each fur type they want.\n * Accept numeric inputs, re-prompting on incorrect input values\n */\nvoid getFursPurchase( int *furs )\n{\n    int i;\n\n    printf( \"YOUR %d FURS ARE DISTRIBUTED AMONG THE FOLLOWING\\n\", FUR_TYPE_COUNT );\n    print( \"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\" );\n    print( \"\" );\n\n    for ( i=0; i<FUR_TYPE_COUNT; i++ )\n    {\n        printf( \"HOW MANY %s DO YOU HAVE\\n\", FUR_NAMES[i] );\n        furs[i] = getNumericInput();\n    }\n}\n\n\n/*\n * (Re)Set the player's inventory to zero\n */\nvoid zeroInventory( int *player_fur_count )\n{\n    int i;\n    for ( i=0; i<FUR_TYPE_COUNT; i++ )\n    {\n        player_fur_count[i] = 0;\n    }\n}\n\n\n/*\n * Tally the player's inventory\n */\nint sumInventory( int *player_fur_count )\n{\n    int result = 0;\n    int i;\n    for ( i=0; i<FUR_TYPE_COUNT; i++ )\n    {\n        result += player_fur_count[i];\n    }\n\n    return result;\n}\n\n\n/*\n * Return a random number between a & b\n * Ref: https://stackoverflow.com/a/686376/1730895\n */\nfloat randomAB(float a, float b)\n{\n    return ((b - a) * ((float)rand() / (float)RAND_MAX)) + a;\n}\n/* Random floating point number between 0 and 1 */\nfloat randFloat()\n{\n    return randomAB( 0, 1 );\n}\n\n\n/* States to allow switching in main game-loop */\n#define STATE_STARTING      1\n#define STATE_CHOOSING_FORT 2\n#define STATE_TRAVELLING    3\n#define STATE_TRADING       4\n\nint main( void )\n{\n    /* variables for storing player's status */\n    float player_funds = 0;                              /* no money */\n    int   player_furs[FUR_TYPE_COUNT]  = { 0, 0, 0, 0 }; /* no furs */\n\n    /* player input holders */\n    char  yes_or_no;\n    int   event_picker;\n    int   which_fort;\n\n    /* what part of the game is in play */\n    int   game_state = STATE_STARTING;\n\n    /* commodity prices */\n    float mink_price   = -1;\n    float beaver_price = -1;\n    float ermine_price = -1;\n    float fox_price    = -1;  /* sometimes this takes the \"last\" price (probably this was a bug) */\n\n    float mink_value;\n    float beaver_value;\n    float ermine_value;\n    float fox_value;      /* for calculating sales results */\n\n\n    srand( time( NULL ) );  /* seed the random number generator */\n\n    printAtColumn( 31, \"FUR TRADER\" );\n    printAtColumn( 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\" );\n    printAtColumn( 15, \"(Ported to ANSI-C Oct 2012 krt@krt.com.au)\" );\n    print( \"\\n\\n\\n\" );\n\n    /* Loop forever until the player asks to quit */\n    while ( 1 )\n    {\n        if ( game_state == STATE_STARTING )\n        {\n            showIntroduction();\n\n            player_funds = 600;            /* Initial player start money */\n            zeroInventory( player_furs );  /* Player fur inventory */\n\n            print( \"DO YOU WISH TO TRADE FURS?\" );\n            yes_or_no = getYesOrNo();\n            if ( yes_or_no == 'N' )\n                exit( 0 );                 /* STOP */\n            game_state = STATE_TRADING;\n        }\n\n        else if ( game_state == STATE_TRADING )\n        {\n            print( \"\" );\n            printf( \"YOU HAVE $ %1.2f IN SAVINGS\\n\", player_funds );\n            printf( \"AND %d FURS TO BEGIN THE EXPEDITION\\n\", MAX_FURS );\n            getFursPurchase( player_furs );\n\n            if ( sumInventory( player_furs ) > MAX_FURS )\n            {\n                print( \"\" );\n                print( \"YOU MAY NOT HAVE THAT MANY FURS.\" );\n                print( \"DO NOT TRY TO CHEAT.  I CAN ADD.\" );\n                print( \"YOU MUST START AGAIN.\" );\n                print( \"\" );\n                game_state = STATE_STARTING;   /* T/N: Wow, harsh. */\n            }\n            else\n            {\n                game_state = STATE_CHOOSING_FORT;\n            }\n        }\n\n        else if ( game_state == STATE_CHOOSING_FORT )\n        {\n            which_fort = getFortChoice();\n            showFortComment( which_fort );\n            print( \"DO YOU WANT TO TRADE AT ANOTHER FORT?\" );\n            yes_or_no = getYesOrNo();\n            if ( yes_or_no == 'N' )\n                game_state = STATE_TRAVELLING;\n        }\n\n        else if ( game_state == STATE_TRAVELLING )\n        {\n            print( \"\" );\n            if ( which_fort == FORT_MONTREAL )\n            {\n                mink_price   = ( ( 0.2 * randFloat() + 0.70 ) * 100 + 0.5 ) / 100;\n                ermine_price = ( ( 0.2 * randFloat() + 0.65 ) * 100 + 0.5 ) / 100;\n                beaver_price = ( ( 0.2 * randFloat() + 0.75 ) * 100 + 0.5 ) / 100;\n                fox_price    = ( ( 0.2 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;\n\n                print( \"SUPPLIES AT FORT HOCHELAGA COST $150.00.\" );\n                print( \"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\" );\n                player_funds -= 160;\n            }\n\n            else if ( which_fort == FORT_QUEBEC )\n            {\n                mink_price   = ( ( 0.30 * randFloat() + 0.85 ) * 100 + 0.5 ) / 100;\n                ermine_price = ( ( 0.15 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;\n                beaver_price = ( ( 0.20 * randFloat() + 0.90 ) * 100 + 0.5 ) / 100;\n                fox_price    = ( ( 0.25 * randFloat() + 1.10 ) * 100 + 0.5 ) / 100;\n                event_picker = ( 10 * randFloat() ) + 1;\n\n                if ( event_picker <= 2 )\n                {\n                    print( \"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\" );\n                    print( \"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\" );\n                    print( \"THEM STOLEN WHEN YOU RETURNED.\" );\n                    player_furs[ FUR_BEAVER ] = 0;\n                }\n                else if ( event_picker <= 6 )\n                {\n                    print( \"YOU ARRIVED SAFELY AT FORT STADACONA.\" );\n                }\n                else if ( event_picker <= 8 )\n                {\n                    print( \"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\" );\n                    print( \"LOST ALL YOUR FURS.\" );\n                    zeroInventory( player_furs );\n                }\n                else if ( event_picker <= 10 )\n                {\n                    print( \"YOUR FOX PELTS WERE NOT CURED PROPERLY.\" );\n                    print( \"NO ONE WILL BUY THEM.\" );\n                    player_furs[ FUR_FOX ] = 0;\n                }\n                else\n                {\n                    printf( \"Internal Error #3, Out-of-bounds event_picker %d\\n\", event_picker );\n                    exit( 1 );  /* you have a bug */\n                }\n\n                print( \"\" );\n                print( \"SUPPLIES AT FORT STADACONA COST $125.00.\" );\n                print( \"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\" );\n                player_funds -= 140;\n            }\n\n            else if ( which_fort == FORT_NEWYORK )\n            {\n                mink_price   = ( ( 0.15 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100;\n                ermine_price = ( ( 0.15 * randFloat() + 0.95 ) * 100 + 0.5 ) / 100;\n                beaver_price = ( ( 0.25 * randFloat() + 1.00 ) * 100 + 0.5 ) / 100;\n                if ( fox_price < 0 )\n                {\n                    /* Original Bug?  There is no Fox price generated for New York,\n                       it will use any previous \"D1\" price.\n                       So if there was no previous value, make one up */\n                    fox_price = ( ( 0.25 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100; /* not in orginal code */\n                }\n                event_picker = ( 10 * randFloat() ) + 1;\n\n                if ( event_picker <= 2 )\n                {\n                    print( \"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\" );\n                    print( \"ALL PEOPLE IN YOUR TRADING GROUP WERE\" );\n                    print( \"KILLED.  THIS ENDS THE GAME.\" );\n                    exit( 0 );\n                }\n                else if ( event_picker <= 6 )\n                {\n                    print( \"YOU WERE LUCKY.  YOU ARRIVED SAFELY\" );\n                    print( \"AT FORT NEW YORK.\" );\n                }\n                else if ( event_picker <= 8 )\n                {\n                    print( \"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\" );\n                    print( \"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\" );\n                    zeroInventory( player_furs );\n                }\n                else if ( event_picker <= 10 )\n                {\n                    mink_price /= 2;\n                    fox_price  /= 2;\n                    print( \"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\" );\n                    print( \"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\" );\n                }\n                else\n                {\n                    print( \"Internal Error #4, Out-of-bounds event_picker %d\\n\" );\n                    exit( 1 );  /* you have a bug */\n                }\n\n                print( \"\" );\n                print( \"SUPPLIES AT NEW YORK COST $85.00.\" );\n                print( \"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\" );\n                player_funds -= 105;\n            }\n\n            else\n            {\n                printf( \"Internal error #2, fort %d does not exist\\n\", which_fort );\n                exit( 1 );  /* you have a bug */\n            }\n\n            /* Calculate sales */\n            beaver_value = beaver_price * player_furs[ FUR_BEAVER ];\n            fox_value    = fox_price    * player_furs[ FUR_FOX ];\n            ermine_value = ermine_price * player_furs[ FUR_ERMINE ];\n            mink_value   = mink_price   * player_furs[ FUR_MINK ];\n\n            print( \"\" );\n            printf( \"YOUR BEAVER SOLD FOR $%6.2f\\n\", beaver_value );\n            printf( \"YOUR FOX SOLD FOR    $%6.2f\\n\", fox_value );\n            printf( \"YOUR ERMINE SOLD FOR $%6.2f\\n\", ermine_value );\n            printf( \"YOUR MINK SOLD FOR   $%6.2f\\n\", mink_value );\n\n            player_funds += beaver_value + fox_value + ermine_value + mink_value;\n\n            print( \"\" );\n            printf( \"YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS\\n\", player_funds );\n\n            print( \"\" );\n            print( \"DO YOU WANT TO TRADE FURS NEXT YEAR?\" );\n            yes_or_no = getYesOrNo();\n            if ( yes_or_no == 'N' )\n                exit( 0 );             /* STOP */\n            else\n                game_state = STATE_TRADING;\n\n        }\n    }\n\n    return 0; /* exit OK */\n}\n"
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/furtrader.bas",
    "content": "1 DIM F(4)\n2 PRINT TAB(31);\"FUR TRADER\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n15 GOSUB 1091\n16 LET I=600\n17 PRINT \"DO YOU WISH TO TRADE FURS?\"\n18 GOSUB 1402\n19 IF B$=\"YES\" THEN 100\n20 IF B$=\"YES \" THEN 100\n21 STOP\n100 PRINT\n101 PRINT \"YOU HAVE $\";I \" SAVINGS.\"\n102 PRINT \"AND 190 FURS TO BEGIN THE EXPEDITION.\"\n261 LET E1=INT((.15*RND(1)+.95)*10^2+.5)/10^2\n262 LET B1=INT((.25*RND(1)+1.00)*10^2+.5)/10^2\n300 PRINT\n301 PRINT \"YOUR 190 FURS ARE DISTRIBUTED AMONG THE FOLLOWING\"\n302 PRINT \"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\"\n310 GOSUB 1430\n315 RESTORE\n330 FOR J=1 TO 4\n332 READ B$\n333 PRINT\n335 PRINT \"HOW MANY \";B$;\" PELTS DO YOU HAVE\";\n338 INPUT F(J)\n340 LET F(0)=F(1)+F(2)+F(3)+F(4)\n342 IF F(0)=190 THEN 1100\n344 IF F(0)>190 THEN 500\n348 NEXT J\n350 GOTO 1100\n500 PRINT\n501 PRINT \"YOU MAY NOT HAVE THAT MANY FURS.\"\n502 PRINT \"DO NOT TRY TO CHEAT.  I CAN ADD.\"\n503 PRINT \"YOU MUST START AGAIN.\"\n504 GOTO 15\n508 PRINT\n511 PRINT \"DO YOU WANT TO TRADE FURS NEXT YEAR?\"\n513 GOTO 18\n1091 PRINT \"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \"\n1092 PRINT \"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\"\n1093 PRINT \"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\"\n1094 PRINT \"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\"\n1095 PRINT \"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\"\n1096 PRINT \"ON THE FORT THAT YOU CHOOSE.\"\n1099 RETURN\n1100 PRINT \"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\"\n1102 PRINT \"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\"\n1103 PRINT \"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\"\n1104 PRINT \"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\"\n1105 PRINT \"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\"\n1106 PRINT \"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\"\n1108 PRINT \"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\"\n1109 PRINT \"YOU MUST CROSS THROUGH IROQUOIS LAND.\"\n1110 PRINT \"ANSWER 1, 2, OR 3.\"\n1111 INPUT B\n1112 IF B=1 THEN 1120\n1113 IF B=2 THEN 1135\n1115 IF B=3 THEN 1147\n1116 GOTO 1110\n1120 PRINT \"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\"\n1121 PRINT \"IS FAR FROM ANY SEAPORT.  THE VALUE\"\n1122 PRINT \"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\"\n1123 PRINT \"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\"\n1125 GOSUB 1400\n1129 IF B$=\"YES\" THEN 1110\n1130 GOTO 1160\n1135 PRINT \"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\"\n1136 PRINT \"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\"\n1137 PRINT \"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\"\n1138 PRINT \"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\"\n1141 GOSUB 1400\n1144 IF B$=\"YES\" THEN 1110\n1145 GOTO 1198\n1147 PRINT \"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\"\n1148 PRINT \"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\"\n1149 PRINT \"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\"\n1150 PRINT \"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\"\n1152 GOSUB 1400\n1155 IF B$=\"YES\" THEN 1110\n1156 GOTO 1250\n1160 LET I=I-160\n1169 PRINT\n1174 LET M1=INT((.2*RND(1)+.7)*10^2+.5)/10^2\n1175 LET E1=INT((.2*RND(1)+.65)*10^2+.5)/10^2\n1176 LET B1=INT((.2*RND(1)+.75)*10^2+.5)/10^2\n1177 LET D1=INT((.2*RND(1)+.8)*10^2+.5)/10^2\n1180 PRINT \"SUPPLIES AT FORT HOCHELAGA COST $150.00.\"\n1181 PRINT \"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\"\n1190 GOTO 1410\n1198 LET I=I-140\n1201 PRINT\n1205 LET M1=INT((.3*RND(1)+.85)*10^2+.5)/10^2\n1206 LET E1=INT((.15*RND(1)+.8)*10^2+.5)/10^2\n1207 LET B1=INT((.2*RND(1)+.9)*10^2+.5)/10^2\n1209 LET P=INT(10*RND(1))+1\n1210 IF P<=2 THEN 1216\n1212 IF P<=6 THEN 1224\n1213 IF P<=8 THEN 1226\n1215 IF P<=10 THEN 1235\n1216 LET F(2)=0\n1218 PRINT \"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\"\n1219 PRINT \"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\"\n1220 PRINT \"THEM STOLEN WHEN YOU RETURNED.\"\n1221 GOSUB 1244\n1222 GOTO 1414\n1224 PRINT \"YOU ARRIVED SAFELY AT FORT STADACONA.\"\n1225 GOTO 1239\n1226 GOSUB 1430\n1230 PRINT \"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\"\n1231 PRINT \"LOST ALL YOUR FURS.\"\n1232 GOSUB 1244\n1233 GOTO 1418\n1235 LET F(4)=0\n1237 PRINT \"YOUR FOX PELTS WERE NOT CURED PROPERLY.\"\n1238 PRINT \"NO ONE WILL BUY THEM.\"\n1239 GOSUB 1244\n1240 GOTO 1410\n1244 PRINT \"SUPPLIES AT FORT STADACONA COST $125.00.\"\n1246 PRINT \"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\"\n1248 RETURN\n1250 LET I=I-105\n1254 PRINT\n1260 LET M1=INT((.15*RND(1)+1.05)*10^2+.5)/10^2\n1263 LET D1=INT((.25*RND(1)+1.1)*10^2+.5)/10^2\n1270 LET P=INT(10*RND(1))+1\n1271 IF P<=2 THEN 1281\n1272 IF P<=6 THEN 1291\n1273 IF P<=8 THEN 1295\n1274 IF P<=10 THEN 1306\n1281 PRINT \"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\"\n1282 PRINT \"ALL PEOPLE IN YOUR TRADING GROUP WERE\"\n1283 PRINT \"KILLED.  THIS ENDS THE GAME.\"\n1284 STOP\n1291 PRINT \"YOU WERE LUCKY.  YOU ARRIVED SAFELY\"\n1292 PRINT \"AT FORT NEW YORK.\"\n1293 GOTO 1311\n1295 GOSUB 1430\n1300 PRINT \"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\"\n1301 PRINT \"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\"\n1303 GOSUB 1320\n1304 GOTO 1418\n1306 LET B1=B1/2\n1307 LET M1=M1/2\n1308 PRINT \"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\"\n1309 PRINT \"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\"\n1311 GOSUB 1320\n1312 GOTO 1410\n1320 PRINT \"SUPPLIES AT NEW YORK COST $80.00.\"\n1321 PRINT \"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\"\n1322 RETURN\n1400 PRINT \"DO YOU WANT TO TRADE AT ANOTHER FORT?\"\n1402 PRINT \"ANSWER YES OR NO\",\n1403 INPUT B$\n1404 RETURN\n1410 PRINT\n1412 PRINT \"YOUR BEAVER SOLD FOR $\";B1*F(2);\n1414 PRINT \"YOUR FOX SOLD FOR $\";D1*F(4)\n1416 PRINT \"YOUR ERMINE SOLD FOR $\";E1*F(3);\n1417 PRINT \"YOUR MINK SOLD FOR $\";M1*F(1)\n1418 LET I=M1*F(1)+B1*F(2)+E1*F(3)+D1*F(4)+I\n1420 PRINT\n1422 PRINT \"YOU NOW HAVE $\";I;\" INCLUDING YOUR PREVIOUS SAVINGS\"\n1425 GOTO 508\n1430 FOR J=1 TO 4\n1432 LET F(J)=0\n1434 NEXT J\n1436 RETURN\n2000 DATA \"MINK\",\"BEAVER\",\"ERMINE\",\"FOX\"\n2046 END\n"
  },
  {
    "path": "00_Alternate_Languages/38_Fur_Trader/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"log\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nconst (\r\n\tMAXFURS    = 190\r\n\tSTARTFUNDS = 600\r\n)\r\n\r\ntype Fur int8\r\n\r\nconst (\r\n\tFUR_MINK Fur = iota\r\n\tFUR_BEAVER\r\n\tFUR_ERMINE\r\n\tFUR_FOX\r\n)\r\n\r\ntype Fort int8\r\n\r\nconst (\r\n\tFORT_MONTREAL Fort = iota\r\n\tFORT_QUEBEC\r\n\tFORT_NEWYORK\r\n)\r\n\r\ntype GameState int8\r\n\r\nconst (\r\n\tSTARTING GameState = iota\r\n\tTRADING\r\n\tCHOOSINGFORT\r\n\tTRAVELLING\r\n)\r\n\r\nfunc FURS() []string {\r\n\treturn []string{\"MINK\", \"BEAVER\", \"ERMINE\", \"FOX\"}\r\n}\r\n\r\nfunc FORTS() []string {\r\n\treturn []string{\"HOCHELAGA (MONTREAL)\", \"STADACONA (QUEBEC)\", \"NEW YORK\"}\r\n}\r\n\r\ntype Player struct {\r\n\tfunds float32\r\n\tfurs  []int\r\n}\r\n\r\nfunc NewPlayer() Player {\r\n\tp := Player{}\r\n\tp.funds = STARTFUNDS\r\n\tp.furs = make([]int, 4)\r\n\treturn p\r\n}\r\n\r\nfunc (p *Player) totalFurs() int {\r\n\tf := 0\r\n\tfor _, v := range p.furs {\r\n\t\tf += v\r\n\t}\r\n\treturn f\r\n}\r\n\r\nfunc (p *Player) lostFurs() {\r\n\tfor f := 0; f < len(p.furs); f++ {\r\n\t\tp.furs[f] = 0\r\n\t}\r\n}\r\n\r\nfunc printTitle() {\r\n\tfmt.Println(\"                               FUR TRADER\")\r\n\tfmt.Println(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n}\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \")\r\n\tfmt.Println(\"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\")\r\n\tfmt.Println(\"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\")\r\n\tfmt.Println(\"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\")\r\n\tfmt.Println(\"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\")\r\n\tfmt.Println(\"ON THE FORT THAT YOU CHOOSE.\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc getFortChoice() Fort {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println()\r\n\t\tfmt.Println(\"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\")\r\n\t\tfmt.Println(\"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\")\r\n\t\tfmt.Println(\"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\")\r\n\t\tfmt.Println(\"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\")\r\n\t\tfmt.Println(\"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\")\r\n\t\tfmt.Println(\"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\")\r\n\t\tfmt.Println(\"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\")\r\n\t\tfmt.Println(\"YOU MUST CROSS THROUGH IROQUOIS LAND.\")\r\n\t\tfmt.Println(\"ANSWER 1, 2, OR 3.\")\r\n\t\tfmt.Print(\">> \")\r\n\t\tscanner.Scan()\r\n\r\n\t\tf, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil || f < 1 || f > 3 {\r\n\t\t\tfmt.Println(\"Invalid input, Try again ... \")\r\n\t\t\tcontinue\r\n\t\t}\r\n\t\treturn Fort(f)\r\n\t}\r\n}\r\n\r\nfunc printFortComment(f Fort) {\r\n\tfmt.Println()\r\n\tswitch f {\r\n\tcase FORT_MONTREAL:\r\n\t\tfmt.Println(\"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\")\r\n\t\tfmt.Println(\"IS FAR FROM ANY SEAPORT.  THE VALUE\")\r\n\t\tfmt.Println(\"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\")\r\n\t\tfmt.Println(\"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\")\r\n\tcase FORT_QUEBEC:\r\n\t\tfmt.Println(\"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\")\r\n\t\tfmt.Println(\"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\")\r\n\t\tfmt.Println(\"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\")\r\n\t\tfmt.Println(\"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\")\r\n\tcase FORT_NEWYORK:\r\n\t\tfmt.Println(\"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\")\r\n\t\tfmt.Println(\"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\")\r\n\t\tfmt.Println(\"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\")\r\n\t\tfmt.Println(\"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\")\r\n\t}\r\n\tfmt.Println()\r\n}\r\n\r\nfunc getYesOrNo() string {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfor {\r\n\t\tfmt.Println(\"ANSWER YES OR NO\")\r\n\t\tscanner.Scan()\r\n\t\tif strings.ToUpper(scanner.Text())[0:1] == \"Y\" {\r\n\t\t\treturn \"Y\"\r\n\t\t} else if strings.ToUpper(scanner.Text())[0:1] == \"N\" {\r\n\t\t\treturn \"N\"\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc getFursPurchase() []int {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfmt.Printf(\"YOUR %d FURS ARE DISTRIBUTED AMONG THE FOLLOWING\\n\", MAXFURS)\r\n\tfmt.Println(\"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\")\r\n\tfmt.Println()\r\n\r\n\tpurchases := make([]int, 4)\r\n\r\n\tfor i, f := range FURS() {\r\n\tretry:\r\n\t\tfmt.Printf(\"HOW MANY %s DO YOU HAVE: \", f)\r\n\t\tscanner.Scan()\r\n\t\tcount, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"INVALID INPUT, TRY AGAIN ...\")\r\n\t\t\tgoto retry\r\n\t\t}\r\n\t\tpurchases[i] = count\r\n\t}\r\n\r\n\treturn purchases\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\r\n\tprintTitle()\r\n\r\n\tgameState := STARTING\r\n\twhichFort := FORT_NEWYORK\r\n\tvar (\r\n\t\tminkPrice   int\r\n\t\terminePrice int\r\n\t\tbeaverPrice int\r\n\t\tfoxPrice    int\r\n\t)\r\n\tplayer := NewPlayer()\r\n\r\n\tfor {\r\n\t\tswitch gameState {\r\n\t\tcase STARTING:\r\n\t\t\tprintIntro()\r\n\t\t\tfmt.Println(\"DO YOU WISH TO TRADE FURS?\")\r\n\t\t\tif getYesOrNo() == \"N\" {\r\n\t\t\t\tos.Exit(0)\r\n\t\t\t}\r\n\t\t\tgameState = TRADING\r\n\t\tcase TRADING:\r\n\t\t\tfmt.Println()\r\n\t\t\tfmt.Printf(\"YOU HAVE $ %1.2f IN SAVINGS\\n\", player.funds)\r\n\t\t\tfmt.Printf(\"AND %d FURS TO BEGIN THE EXPEDITION\\n\", MAXFURS)\r\n\t\t\tplayer.furs = getFursPurchase()\r\n\r\n\t\t\tif player.totalFurs() > MAXFURS {\r\n\t\t\t\tfmt.Println()\r\n\t\t\t\tfmt.Println(\"YOU MAY NOT HAVE THAT MANY FURS.\")\r\n\t\t\t\tfmt.Println(\"DO NOT TRY TO CHEAT.  I CAN ADD.\")\r\n\t\t\t\tfmt.Println(\"YOU MUST START AGAIN.\")\r\n\t\t\t\tgameState = STARTING\r\n\t\t\t} else {\r\n\t\t\t\tgameState = CHOOSINGFORT\r\n\t\t\t}\r\n\t\tcase CHOOSINGFORT:\r\n\t\t\twhichFort = getFortChoice()\r\n\t\t\tprintFortComment(whichFort)\r\n\t\t\tfmt.Println(\"DO YOU WANT TO TRADE AT ANOTHER FORT?\")\r\n\t\t\tchangeFort := getYesOrNo()\r\n\t\t\tif changeFort == \"N\" {\r\n\t\t\t\tgameState = TRAVELLING\r\n\t\t\t}\r\n\t\tcase TRAVELLING:\r\n\t\t\tswitch whichFort {\r\n\t\t\tcase FORT_MONTREAL:\r\n\t\t\t\tminkPrice = (int((0.2*rand.Float64()+0.70)*100+0.5) / 100)\r\n\t\t\t\terminePrice = (int((0.2*rand.Float64()+0.65)*100+0.5) / 100)\r\n\t\t\t\tbeaverPrice = (int((0.2*rand.Float64()+0.75)*100+0.5) / 100)\r\n\t\t\t\tfoxPrice = (int((0.2*rand.Float64()+0.80)*100+0.5) / 100)\r\n\r\n\t\t\t\tfmt.Println(\"SUPPLIES AT FORT HOCHELAGA COST $150.00.\")\r\n\t\t\t\tfmt.Println(\"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\")\r\n\t\t\t\tplayer.funds -= 160\r\n\t\t\tcase FORT_QUEBEC:\r\n\t\t\t\tminkPrice = (int((0.30*rand.Float64()+0.85)*100+0.5) / 100)\r\n\t\t\t\terminePrice = (int((0.15*rand.Float64()+0.80)*100+0.5) / 100)\r\n\t\t\t\tbeaverPrice = (int((0.20*rand.Float64()+0.90)*100+0.5) / 100)\r\n\t\t\t\tfoxPrice = (int((0.25*rand.Float64()+1.10)*100+0.5) / 100)\r\n\r\n\t\t\t\tevent := int(10*rand.Float64()) + 1\r\n\t\t\t\tif event <= 2 {\r\n\t\t\t\t\tfmt.Println(\"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\")\r\n\t\t\t\t\tfmt.Println(\"THE PORTAGE. YOU HAD TO LEAVE THE PELTS, BUT FOUND\")\r\n\t\t\t\t\tfmt.Println(\"THEM STOLEN WHEN YOU RETURNED.\")\r\n\t\t\t\t\tplayer.furs[FUR_BEAVER] = 0\r\n\t\t\t\t} else if event <= 6 {\r\n\t\t\t\t\tfmt.Println(\"YOU ARRIVED SAFELY AT FORT STADACONA.\")\r\n\t\t\t\t} else if event <= 8 {\r\n\t\t\t\t\tfmt.Println(\"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\")\r\n\t\t\t\t\tfmt.Println(\"LOST ALL YOUR FURS.\")\r\n\t\t\t\t\tplayer.lostFurs()\r\n\t\t\t\t} else if event <= 10 {\r\n\t\t\t\t\tfmt.Println(\"YOUR FOX PELTS WERE NOT CURED PROPERLY.\")\r\n\t\t\t\t\tfmt.Println(\"NO ONE WILL BUY THEM.\")\r\n\t\t\t\t\tplayer.furs[FUR_FOX] = 0\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlog.Fatal(\"Unexpected error\")\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfmt.Println()\r\n\t\t\t\tfmt.Println(\"SUPPLIES AT FORT STADACONA COST $125.00.\")\r\n\t\t\t\tfmt.Println(\"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\")\r\n\t\t\t\tplayer.funds -= 140\r\n\t\t\tcase FORT_NEWYORK:\r\n\t\t\t\tminkPrice = (int((0.15*rand.Float64()+1.05)*100+0.5) / 100)\r\n\t\t\t\terminePrice = (int((0.15*rand.Float64()+0.95)*100+0.5) / 100)\r\n\t\t\t\tbeaverPrice = (int((0.25*rand.Float64()+1.00)*100+0.5) / 100)\r\n\t\t\t\tfoxPrice = (int((0.25*rand.Float64()+1.05)*100+0.5) / 100) // not in original code\r\n\r\n\t\t\t\tevent := int(10*rand.Float64()) + 1\r\n\t\t\t\tif event <= 2 {\r\n\t\t\t\t\tfmt.Println(\"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\")\r\n\t\t\t\t\tfmt.Println(\"ALL PEOPLE IN YOUR TRADING GROUP WERE\")\r\n\t\t\t\t\tfmt.Println(\"KILLED.  THIS ENDS THE GAME.\")\r\n\t\t\t\t\tos.Exit(0)\r\n\t\t\t\t} else if event <= 6 {\r\n\t\t\t\t\tfmt.Println(\"YOU WERE LUCKY.  YOU ARRIVED SAFELY\")\r\n\t\t\t\t\tfmt.Println(\"AT FORT NEW YORK.\")\r\n\t\t\t\t} else if event <= 8 {\r\n\t\t\t\t\tfmt.Println(\"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\")\r\n\t\t\t\t\tfmt.Println(\"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\")\r\n\t\t\t\t\tplayer.lostFurs()\r\n\t\t\t\t} else if event <= 10 {\r\n\t\t\t\t\tminkPrice /= 2\r\n\t\t\t\t\tfoxPrice /= 2\r\n\t\t\t\t\tfmt.Println(\"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\")\r\n\t\t\t\t\tfmt.Println(\"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\")\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlog.Fatal(\"Unexpected error\")\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfmt.Println()\r\n\t\t\t\tfmt.Println(\"SUPPLIES AT NEW YORK COST $85.00.\")\r\n\t\t\t\tfmt.Println(\"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\")\r\n\t\t\t\tplayer.funds -= 110\r\n\t\t\t}\r\n\r\n\t\t\tbeaverValue := beaverPrice * player.furs[FUR_BEAVER]\r\n\t\t\tfoxValue := foxPrice * player.furs[FUR_FOX]\r\n\t\t\termineValue := erminePrice * player.furs[FUR_ERMINE]\r\n\t\t\tminkValue := minkPrice * player.furs[FUR_MINK]\r\n\r\n\t\t\tfmt.Println()\r\n\t\t\tfmt.Printf(\"YOUR BEAVER SOLD FOR $%6.2f\\n\", float64(beaverValue))\r\n\t\t\tfmt.Printf(\"YOUR FOX SOLD FOR    $%6.2f\\n\", float64(foxValue))\r\n\t\t\tfmt.Printf(\"YOUR ERMINE SOLD FOR $%6.2f\\n\", float64(ermineValue))\r\n\t\t\tfmt.Printf(\"YOUR MINK SOLD FOR   $%6.2f\\n\", float64(minkValue))\r\n\r\n\t\t\tplayer.funds += float32(beaverValue + foxValue + ermineValue + minkValue)\r\n\r\n\t\t\tfmt.Println()\r\n\t\t\tfmt.Printf(\"YOU NOW HAVE $%1.2f INCLUDING YOUR PREVIOUS SAVINGS\\n\", player.funds)\r\n\t\t\tfmt.Println(\"\\nDO YOU WANT TO TRADE FURS NEXT YEAR?\")\r\n\t\t\tif getYesOrNo() == \"N\" {\r\n\t\t\t\tos.Exit(0)\r\n\t\t\t} else {\r\n\t\t\t\tgameState = TRADING\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/39_Golf/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript golf.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"golf\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/39_Golf/MiniScript/golf.ms",
    "content": "print \" \"*34 + \"Golf\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\n print \"Welcome to the creative computing country club,\"\n print \"an eighteen hole championship layout located a short\"\n print \"distance from scenic downtown Morristown.  The\"\n print \"commentator will explain the game as you play.\"\n print \"Enjoy your game; see you at the 19th hole...\"\n print;print\n l = [0] * 11\n holesInCourse=18\n totalScore=0\n totalPar=0\n dubChance=.8\n s2=0\n curHole=1\n \n\ngetHoleData = function(hole)\n\t// data for all the holes: distance, par, locOnLeft, and locOnRight for each one\n\tdata = [\n\t 361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2,\n\t 408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4,\n\t 196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2,\n\t 357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2,\n\t 180,3,6,2,550,5,6,6]\n\ti = (hole-1) * 4\n\tglobals.distance = data[i]\n\tglobals.par = data[i+1]\n\tglobals.locOnRight = data[i+2]\nglobals.locOnLeft = data[i+3]\nend function\n\nstartHole = function(hole)\n\tgetHoleData hole\n\tprint\n\tprint \"You are at the tee off hole \" + hole + \" distance \" + distance + \" yards, par \" + par\n\tglobals.totalPar += par\n\tprint \"On your right is \", \"\"\n\tprintLocation locOnRight\n\tprint \"On your left is \", \"\"\n\tprintLocation locOnLeft\nend function\n\n// Get player's handicap\nwhile true\n\thandicap = input(\"What is your handicap? \").val\n\tif 0 <= handicap <= 30 then break\n\tprint \"PGA handicaps range from 0 to 30.\"\nend while\n\n// Get player's weak point\nwhile true\n\tprint \"Difficulties at golf include:\"\n\tprint \"0=hook, 1=slice, 2=poor distance, 3=trap shots, 4=putting\"\n\tweakness = input(\"Which one (only one) is your worst? \").val\n\tif 0 <= weakness <= 4 then break\nend while\n\n// End a sentence by printing the name of the given location\nprintLocation = function(locIdx)\n\tif locIdx < 1 or locIdx > 6 then\n\t\tprint \"out of bounds.\"\n\telse\n\t\tprint [\"fairway.\", \"rough.\", \"trees.\", \"adjacent fairway.\", \n\t\t\t   \"trap.\", \"water.\"][locIdx-1]\n\tend if\nend function\n\n// Print score for one hole (plus total), and some praise or advice.\nprintScore = function(hole, score, par, totalScore, totalPar)\n\tprint \"Your score on hole \" + hole + \" was \" + score\n\tprint \"Total par for \" + hole + \" holes is \" + totalPar + \"  Your total is \" + totalScore\n\tif hole == holesInCourse then return\n\tif score > par+2 then\n\t\tprint \"Keep your head down.\"\n\telse if score == par then\n\t\tprint \"A par.  Nice going.\"\n\telse if score == par-1 then\n\t\tprint \"A birdie.\"\n\telse if score == 1 then\n\t\tprint \"A hole in one.\"\n\telse if score == par-2 then\n\t\tprint \"A great big eagle.\"\n\tend if \nend function\n\n// Print club advice -- but only once.\nclubAdviceGiven = false\nprintClubAdvice = function\n\tif clubAdviceGiven then return\t// (already done)\n\tglobals.clubAdviceGiven = true\n\tprint \"Selection of clubs\"\n\tprint \"yardage desired                       suggested clubs\"\n\tprint \"200 to 280 yards                           1 to 4\"\n\tprint \"100 to 200 yards                          19 to 13\"\n\tprint \"  0 to 100 yards                          29 to 23\"\nend function\t\n\ndoPenalty = function\n \tprint \"Penalty stroke assessed.  Hit from previous location.\"\n \tglobals.score += 1\n \tglobals.j += 1\n \tglobals.curLoc = 1\n \tglobals.distance = prevDistance\nend function\n\n// Try to get out of a trap. Return true if succeeded, false if failed.\ndoTrapShot = function\n\tif weakness == 3 then\n\t\tif rnd <= dubChance then\n\t\t\tglobals.dubChance *= 0.2\n\t\t\tprint \"Shot dubbed, still in trap.\"\n\t\t\treturn false\n\t\tend if\n\t\tglobals.dubChance = 0.8\n\tend if\n\tglobals.distToPin = 1 + (3*floor((80/(40-handicap))*rnd))\n\treturn true\nend function\n\ngetClub = function\n\t//print \"DEBUG: getClub, with curLoc=\" + curLoc\n\twhile true\n\t\tclub = input(\"What club do you choose? \").val\n\t\tprint\n\t\tif club < 1 or club > 29 then continue\n\t\tif club > 4 and club < 12 then\n\t\t\tprint \"That club is not in the bag.\"\n\t\t\tcontinue\n\t\tend if\n\t\tif club >= 12 then club -= 6\n\t\tif curLoc <= 5 or club == 14 or club == 23 then break\n\t\tprint \"That club is not in the bag.\"\n\t\tprint\n\t\tcontinue\n\tend while\n\treturn club\nend function\n\ngetSwing = function(club)\n\tif club <= 13 then return 1 // (full swing)\n\twhile true\n\t\tprint \"Now gauge your distance by a percentage (1 to 100)\"\n\t\tswing = input(\"of a full swing? \").val / 100\n\t\tprint\n\t\tif 0 <= swing <= 1 then return swing\n\t\t// Given an invalid swing input, the original BASIC code would \n\t\t// print \"That club is not in the bag\" and go back to choosing a club.\n\t\t// But that is convoluted spaghetti, and I'm not doing it.\n\tend while\nend function\n\nplayOneHole = function\n\tq = 0\t\t// counts certain kinds of shots on every third hole (?)\n\tdistanceHit = 0\n\toffLine = 0\n\t\n\t// shot loop -- take as many shots as you need for this hole\n\twhile true\n\t\tif curLoc < 1 then curLoc = 1\n\t\tif curLoc > 6 then\n\t\t\tprint \"Your shot went out of bounds.\"\n\t\t\tdoPenalty\n\t\t\tdistanceHit = 0\n\t\telse if curLoc > 5 then\n\t\t\tprint \"Your shot went into the water.\"\n\t\t\tdoPenalty\n\t\t\tdistanceHit = 0\n\t\tend if\n\t\n\t\tif score > 0 and distanceHit then\n\t\t\tprint \"Shot went \" + distanceHit + \" yards.  It's \" + distToPin + \" yards from the cup.\"\n\t\t\tprint \"Ball is \" + floor(offLine) + \" yards off line... in \", \"\"\n\t\t\tprintLocation curLoc\n\t\tend if\n \n\t\tprintClubAdvice\n\t\n\t\tclub = getClub\n\t\tswing = getSwing(club)\n\t\tglobals.score += 1\n\t\tif curLoc == 5 and not doTrapShot then continue\n\t\tif club > 14 then club -= 10\n\n\t\t//print \"DEBUG Club:\"+club + \" Swing:\"+swing + \" Weakness:\"+weakness\n\n\t\tif curHole % 3 == 0 then\n\t\t\tif s2 + q + (10*(curHole-1)/18) < (curHole-1)*(72+((handicap+1)/.85))/18 then\n\t\t\t\tq += 1\n\t\t\t\tif score % 2 and distance >= 95 then\n\t\t\t\t\tglobals.distance -= 75\n\t\t\t\t\tdistanceHit = 0\n\t\t\t\t\tprint \"Ball hit tree - bounced into rough \" + distance + \" yards from hole.\"\n\t\t\t\t\tcontinue\n\t\t\t\tend if\n\t\t\tend if\t\t\n\t\tend if\n\t\t\n\t\tif club >= 4 and curLoc == 2 then\n\t\t\tprint \"You dubbed it.\"\n\t\t\tdistanceHit = 35\n\t\telse if score > 7 and distance < 200 then\n\t\t\t// user is really sucking, let's cut them a break\n\t\t\tputt 1 + (3 * floor((80/(40-handicap))*rnd))\n\t\t\treturn\n\t\telse\n\t\t\t//print \"DEBUG: SWING with handicap:\" + handicap + \" club:\" + club\n\t\t\tdistanceHit = floor(((30-handicap)*2.5+187-((30-handicap)*.25+15)*club/2)+25*rnd)\n\t\t\tdistanceHit = floor(distanceHit*swing)\n\t\t\tif weakness == 2 then distanceHit = floor(.85*distanceHit)\n\t\tend if\n\t\toffLine = (rnd/.8)*(2*handicap+16)*abs(tan(distanceHit*.0035))\n\t\tdistToPin = floor(sqrt(offLine^2+abs(distance-distanceHit)^2))\n\t\t//print \"DEBUG distance:\"+distance+\"; distanceHit:\"+distanceHit+\"; distToPin:\"+distToPin+\"; offLine:\"+offLine\n\t\tif distanceHit > distance and distToPin >= 20 then print \"Too much club. You're past the hole.\"\n\n\t\tglobals.prevDistance = distance\n\t\tglobals.distance = distToPin\n\t\tif distToPin > 27 then\n\t\t\tif offLine < 30 or j > 0 then\n\t\t\t\tcurLoc = 1\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\t// hook or slice\n\t\t\ts9 = (s2+1)/15\n\t\t\tif weakness == 0 then\n\t\t\t\tisSlice = floor(s9) == s9\n\t\t\telse\n\t\t\t\tisSlice = not floor(s9) == s9\n\t\t\tend if\n\t\t\tif isSlice then\n\t\t\t\tprint \"You sliced- \"\n\t\t\t\tcurLoc = locOnRight\n\t\t\telse\n\t\t\t\tprint \"You hooked- \"\n\t\t\t\tcurLoc = locOnLeft\n\t\t\tend if\n\t\t\tif offLine > 45 then print \"badly.\"\n\n\t\telse if distToPin > 20 then\n\t\t\tcurLoc = 5\n\t\telse if distToPin > .5 then\n\t\t\tglobals.curLoc = 8\t\t// on the green!\n\t\t\tputt distToPin * 3\t\t// (convert yards to feet, and putt)\n\t\t\treturn\n\t\telse\n\t\t\tcurLoc = 9\n\t\t\tprint \"You holed it.\"\n\t\t\tprint\n\t\t\tglobals.curHole += 1\n\t\t\treturn\n\t\tend if\n\tend while\nend function\n\nputt = function(distToPin)\n\tputtAttempts = 0\n\twhile true\n\t\tdistToPin = abs(floor(distToPin))\n\t\tprint \"On green, \" + distToPin + \" feet from the pin.\"\n\t\ti = input(\"Choose your putt potency (1 to 13): \").val\n\t\tglobals.score += 1\n\t\tif score+1 - par > handicap*0.072 + 2 or puttAttempts > 2 then break\n\t\tputtAttempts += 1\n\t\tif weakness == 4 then\n\t\t\tdistToPin -= i*(4+1*rnd)+1\n\t\telse\n\t\t\tdistToPin -= i*(4+2*rnd)+1.5\n\t\tend if\n\t\tif -2 <= distToPin <= 2 then break\n\t\tif distToPin < 0 then\n\t\t\tprint \"Passed by cup.\"\n\t\telse\n\t\t\tprint \"Putt short.\"\n\t\tend if\n\tend while\n\tprint \"You holed it.\"\n\tprint\n\treturn\nend function\n\n// main loop\nwhile true\n\tcurLoc = 0\n\tj = 0\n\ts2 += 1\n\tif curHole > 1 then\n\tend if\n\n\tprint\n\n\tscore = 0\n\tstartHole curHole\n\tplayOneHole\n\n\ttotalScore += score\n\tprintScore curHole, score, par, totalScore, totalPar\n\tif curHole == holesInCourse then break\n\n\tcurHole += 1\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/39_Golf/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/39_Golf/golf.bas",
    "content": "1 PRINT TAB(34);\"GOLF\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,\"\n5 PRINT \"AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT\"\n6 PRINT \"DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN.  THE\"\n7 PRINT \"COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY.\"\n8 PRINT \"ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE...\"\n9 PRINT:PRINT: DIM L(10)\n10 G1=18\n20 G2=0\n30 G3=0\n40 A=0\n50 N=.8\n60 S2=0\n70 F=1\n80 PRINT \"WHAT IS YOUR HANDICAP\";\n90 INPUT H:PRINT\n100 IF H>30 THEN 470\n110 IF H<0 THEN 470\n120 PRINT \"DIFFICULTIES AT GOLF INCLUDE:\"\n130 PRINT \"0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING\"\n140 PRINT \"WHICH ONE (ONLY ONE) IS YOUR WORST\";\n150 INPUT T:PRINT\n160 IF T>5 THEN 120\n170 S1=0\n210 REM\n230 L(0)=0\n240 J=0\n245 Q=0\n250 S2=S2+1\n260 K=0\n270 IF F=1 THEN 310\n290 PRINT \"YOUR SCORE ON HOLE\";F-1;\"WAS\";S1\n291 GOTO 1750\n292 IF S1>P+2 THEN 297\n293 IF S1=P THEN 299\n294 IF S1=P-1 THEN 301\n295 IF S1=P-2 THEN 303\n296 GOTO 310\n297 PRINT \"KEEP YOUR HEAD DOWN.\"\n298 GOTO 310\n299 PRINT \"A PAR.  NICE GOING.\"\n300 GOTO 310\n301 PRINT \"A BIRDIE.\"\n302 GOTO 310\n303 IF P=3 THEN 306\n304 PRINT \"A GREAT BIG EAGLE.\"\n305 GOTO 310\n306 PRINT \"A HOLE IN ONE.\"\n310 IF F=19 THEN 1710\n315 S1=0\n316 PRINT\n320 IF S1=0 THEN 1590\n330 IF L(0)<1 THEN 1150\n340 X=0\n350 IF L(0)>5 THEN 1190\n360 PRINT \"SHOT WENT\";D1;\"YARDS.  IT'S\";D2;\"YARDS FROM THE CUP.\"\n362 PRINT \"BALL IS\";INT(O);\"YARDS OFF LINE... IN \";\n380 GOSUB 400\n390 GOTO 620\n400 IF L(X)=1 THEN 480\n410 IF L(X)=2 THEN 500\n420 IF L(X)=3 THEN 520\n430 IF L(X)=4 THEN 540\n440 IF L(X)=5 THEN 560\n450 IF L(X)=6 THEN 580\n460 PRINT \"OUT OF BOUNDS.\"\n465 GOTO 1690\n470 PRINT \"PGA HANDICAPS RANGE FROM 0 TO 30.\"\n472 GOTO 80\n480 PRINT \"FAIRWAY.\"\n490 GOTO 1690\n500 PRINT \"ROUGH.\"\n510 GOTO 1690\n520 PRINT \"TREES.\"\n530 GOTO 1690\n540 PRINT \"ADJACENT FAIRWAY.\"\n550 GOTO 1690\n560 PRINT \"TRAP.\"\n570 GOTO 1690\n580 PRINT \"WATER.\"\n590 GOTO 1690\n620 IF A=1 THEN 629\n621 PRINT \"SELECTION OF CLUBS\"\n622 PRINT \"YARDAGE DESIRED                       SUGGESTED CLUBS\"\n623 PRINT \"200 TO 280 YARDS                           1 TO 4\"\n624 PRINT \"100 TO 200 YARDS                          19 TO 13\"\n625 PRINT \"  0 TO 100 YARDS                          29 TO 23\"\n626 A=1\n629 PRINT \"WHAT CLUB DO YOU CHOOSE\";\n630 INPUT C\n632 PRINT\n635 IF C<1 THEN 690\n637 IF C>29 THEN 690\n640 IF C>4 THEN 710\n650 IF L(0)<=5 THEN 740\n660 IF C=14 THEN 740\n665 IF C=23 THEN 740\n670 GOTO 690\n680 S1=S1-1\n690 PRINT \"THAT CLUB IS NOT IN THE BAG.\"\n693 PRINT\n700 GOTO 620\n710 IF C<12 THEN 690\n720 C=C-6\n730 GOTO 650\n740 S1=S1+1\n741 W=1\n742 IF C>13 THEN 960\n746 IF INT(F/3)=F/3 THEN 952\n752 IF C<4 THEN 756\n754 GOTO 760\n756 IF L(0)=2 THEN 862\n760 IF S1>7 THEN 867\n770 D1=INT(((30-H)*2.5+187-((30-H)*.25+15)*C/2)+25*RND(1))\n780 D1=INT(D1*W)\n800 IF T=2 THEN 1170\n830 O=(RND(1)/.8)*(2*H+16)*ABS(TAN(D1*.0035))\n840 D2=INT(SQR(O^2+ABS(D-D1)^2))\n850 IF D-D1<0 THEN 870\n860 GOTO 890\n862 PRINT \"YOU DUBBED IT.\"\n864 D1=35\n866 GOTO 830\n867 IF D<200 THEN 1300\n868 GOTO 770\n870 IF D2<20 THEN 890\n880 PRINT \"TOO MUCH CLUB. YOU'RE PAST THE HOLE.\"\n890 B=D\n900 D=D2\n910 IF D2>27 THEN 1020\n920 IF D2>20 THEN 1100\n930 IF D2>.5 THEN 1120\n940 L(0)=9\n950 GOTO 1470\n952 IF S2+Q+(10*(F-1)/18)<(F-1)*(72+((H+1)/.85))/18 THEN 956\n954 GOTO 752\n956 Q=Q+1\n957 IF S1/2<>INT(S1/2) THEN 1011\n958 GOTO 862\n960 PRINT \"NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)\"\n961 PRINT \"OF A FULL SWING\";\n970 INPUT W: W=W/100\n972 PRINT\n980 IF W>1 THEN 680\n985 IF L(0)=5 THEN 1280\n990 IF C=14 THEN 760\n1000 C=C-10\n1010 GOTO 760\n1011 IF D<95 THEN 862\n1012 PRINT \"BALL HIT TREE - BOUNCED INTO ROUGH\";D-75;\"YARDS FROM HOLE.\"\n1014 D=D-75\n1018 GOTO 620\n1020 IF O<30 THEN 1150\n1022 IF J>0 THEN 1150\n1030 IF T>0 THEN 1070\n1035 S9=(S2+1)/15\n1036 IF INT(S9)=S9 THEN 1075\n1040 PRINT \"YOU HOOKED- \";\n1050 L(0)=L(2)\n1055 IF O>45 THEN 1092\n1060 GOTO 320\n1070 S9=(S2+1)/15\n1071 IF INT(S9)=S9 THEN 1040\n1075 PRINT \"YOU SLICED- \";\n1080 L(0)=L(1)\n1090 GOTO 1055\n1092 PRINT \"BADLY.\"\n1094 GOTO 320\n1100 L(0)=5\n1110 GOTO 320\n1120 L(0)=8\n1130 D2=INT(D2*3)\n1140 GOTO 1380\n1150 L(0)=1\n1160 GOTO 320\n1170 D1=INT(.85*D1)\n1180 GOTO 830\n1190 IF L(0)>6 THEN 1260\n1200 PRINT \"YOUR SHOT WENT INTO THE WATER.\"\n1210 S1=S1+1\n1220 PRINT \"PENALTY STROKE ASSESSED.  HIT FROM PREVIOUS LOCATION.\"\n1230 J=J+1\n1240 L(0)=1\n1242 D=B\n1250 GOTO 620\n1260 PRINT \"YOUR SHOT WENT OUT OF BOUNDS.\"\n1270 GOTO 1210\n1280 IF T=3 THEN 1320\n1300 D2=1+(3*INT((80/(40-H))*RND(1)))\n1310 GOTO 1380\n1320 IF RND(1)>N THEN 1360\n1330 N=N*.2\n1340 PRINT \"SHOT DUBBED, STILL IN TRAP.\"\n1350 GOTO 620\n1360 N=.8\n1370 GOTO 1300\n1380 PRINT \"ON GREEN,\";D2;\"FEET FROM THE PIN.\"\n1381 PRINT \"CHOOSE YOUR PUTT POTENCY (1 TO 13):\";\n1400 INPUT I\n1410 S1=S1+1\n1420 IF S1+1-P>(H*.072)+2 THEN 1470\n1425 IF K>2 THEN 1470\n1428 K=K+1\n1430 IF T=4 THEN 1530\n1440 D2=D2-I*(4+2*RND(1))+1.5\n1450 IF D2<-2 THEN 1560\n1460 IF D2>2 THEN 1500\n1470 PRINT \"YOU HOLED IT.\"\n1472 PRINT\n1480 F=F+1\n1490 GOTO 230\n1500 PRINT \"PUTT SHORT.\"\n1505 D2=INT(D2)\n1510 GOTO 1380\n1530 D2=D2-I*(4+1*RND(1))+1\n1550 GOTO 1450\n1560 PRINT \"PASSED BY CUP.\"\n1570 D2=-D2\n1580 GOTO 1505\n1590 READ D,P,L(1),L(2)\n1595 PRINT\n1600 PRINT \"YOU ARE AT THE TEE OFF HOLE\";F;\"DISTANCE\";D;\"YARDS, PAR\";P\n1605 G3=G3+P\n1620 PRINT \"ON YOUR RIGHT IS \";\n1630 X=1\n1640 GOSUB 400\n1650 PRINT \"ON YOUR LEFT IS \";\n1660 X=2\n1670 GOSUB 400\n1680 GOTO 620\n1690 RETURN\n1700 DATA 361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2\n1702 DATA 408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4\n1704 DATA 196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2\n1706 DATA 357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2\n1708 DATA 180,3,6,2,550,5,6,6\n1710 PRINT\n1750 G2=G2+S1\n1760 PRINT \"TOTAL PAR FOR\";F-1;\"HOLES IS\";G3;\"  YOUR TOTAL IS\";G2\n1761 IF G1=F-1 THEN 1770\n1765 GOTO 292\n1770 END\n"
  },
  {
    "path": "00_Alternate_Languages/40_Gomoko/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript gomoko.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"gomoko\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms",
    "content": "print \" \"*33 + \"Gomoku\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Welcome to the Oriental game of Gomoko.\"\nprint; print \"The game is played on an N by N grid of a size\"\nprint \"that you specify  During your play, you may cover one grid\"\nprint \"intersection with a marker. The object of the game is to get\"\nprint \"5 adjacent markers in a row -- horizontally, vertically, or\"\nprint \"diagonally.  On the board diagram, your moves are marked\"\nprint \"with a '1' and the computer moves with a '2'.\"\nprint; print \"The computer does not keep track of who has won.\"\nprint \"To end the game, type -1,-1 for your move.\"; print\n\ninBounds = function(x,y)\n    return 0 < x <= n and 0 < y <= n\nend function\n\nempty = function(x,y)\n    return A[x][y] == 0\nend function\n\nprintBoard = function\n    for y in range(1,n)\n        print A[y][1:n+1].join\n    end for\n    print\nend function\n\ndoPlayerMove = function\n    while true\n        inp = input(\"Your play (i,j)? \").replace(\" \", \"\").split(\",\")\n        print\n        if inp.len != 2 then continue\n        x = inp[0].val; y = inp[1].val\n        if x == -1 then return false\n        if not inBounds(x,y) then\n            print \"Illegal move.  Try again...\"\n        else if not empty(x,y) then\n            print \"Square occupied.  Try again...\"\n        else\n            break\n        end if\n    end while\n    A[x][y] = 1\n    globals.lastPlayerMove = [x,y]\n    return true\nend function\n\ndoComputerMove = function\n\t// Computer tries a move near the player's last move\n\tfor e in range(-1,1)\n\t\tfor f in range(-1,1)\n\t\t\tif e==0 and f==0 then continue\n\t\t\tx = lastPlayerMove[0] + e; y = lastPlayerMove[1] + f\n\t\t\tif inBounds(x,y) and empty(x,y) then\n\t\t\t\tA[x][y] = 2\n\t\t\t\treturn\n\t\t\tend if\n\t\tend for\n\tend for\n\t\n\t// Computer tries a random move\n\twhile true\n\t\tx = floor(n * rnd + 1); y = floor(n * rnd + 1)\n\t\tif empty(x,y) then break\n\tend while\n\tA[x][y] = 2\nend function\n\nplayGame = function\n    while true\n        globals.n = input(\"What is your board size (min 7/ max 19)? \").val\n        if 7 <= n <= 19 then break\n        print \"I said, the minimum is 7, the maximum is 19.\"\n    end while\n    globals.A = []\n    for i in range(0,19)\n        A.push [0]*20\n    end for\n    print; print \"We alternate moves.  You go first...\"; print\n    while true\n        if not doPlayerMove then return\n        doComputerMove\n        printBoard\n    end while\nend function\n\n// Main loop\nwhile true\n    playGame\n    print; print \"Thanks for the game!!\"\n    q = input(\"Play again (1 for Yes, 0 for No)? \").val\n    if q != 1 then break\nend while"
  },
  {
    "path": "00_Alternate_Languages/40_Gomoko/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/40_Gomoko/gomoko.bas",
    "content": "2 PRINT TAB(33);\"GOMOKO\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n8 DIM A(19,19)\n10 PRINT \"WELCOME TO THE ORIENTAL GAME OF GOMOKO.\"\n20 PRINT: PRINT \"THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\"\n30 PRINT \"THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID\"\n40 PRINT \"INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\"\n50 PRINT \"5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\"\n60 PRINT \"DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\"\n70 PRINT \"WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\"\n80 PRINT: PRINT \"THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\"\n90 PRINT \"TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\": PRINT\n110 PRINT \"WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)\";: INPUT N\n115 IF N>6 THEN 117\n116 GOTO 120\n117 IF N<20 THEN 210\n120 PRINT \"I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\": GOTO 110\n210 FOR I=1 TO N:FOR J=1 TO N: A(I,J)=0: NEXT J: NEXT I\n300 PRINT: PRINT \"WE ALTERNATE MOVES.  YOU GO FIRST...\": PRINT\n310 PRINT \"YOUR PLAY (I,J)\";: INPUT I,J\n315 PRINT\n320 IF I=-1 THEN 980\n330 X=I: Y=J: GOSUB 910: IF L=1 THEN 410\n340 PRINT \"ILLEGAL MOVE.  TRY AGAIN...\": GOTO 310\n410 IF A(I,J)=0 THEN 440\n420 PRINT \"SQUARE OCCUPIED.  TRY AGAIN...\": GOTO 310\n440 A(I,J)=1\n500 REM *** COMPUTER TRIES AN INTELLIGENT MOVE ***\n510 FOR E=-1 TO 1: FOR F=-1 TO 1: IF E+F-E*F=0 THEN 590\n540 X=I+F: Y=J+F: GOSUB 910\n570 IF L=0 THEN 590\n580 IF A(X,Y)=1 THEN 710\n590 NEXT F: NEXT E\n600 REM *** COMPUTER TRIES A RANDOM MOVE ***\n610 X=INT(N*RND(1)+1): Y=INT(N*RND(1)+1): GOSUB 910: IF L=0 THEN 610\n650 IF A(X,Y)<>0 THEN 610\n660 A(X,Y)=2: GOSUB 810: GOTO 310\n710 X=I-E: Y=J-F: GOSUB 910\n750 IF L=0 THEN 610\n760 GOTO 650\n800 REM *** PRINT THE BOARD ***\n810 FOR I=1 TO N: FOR J=1 TO N: PRINT A(I,J);\n840 NEXT J: PRINT: NEXT I: PRINT: RETURN\n910 L=1: IF X<1 THEN 970\n920 IF X>N THEN 970\n930 IF Y<1 THEN 970\n940 IF Y>N THEN 970\n950 RETURN\n970 L=0: RETURN\n980 PRINT: PRINT \"THANKS FOR THE GAME!!\"\n985 PRINT \"PLAY AGAIN (1 FOR YES, 0 FOR NO)\";: INPUT Q\n990 IF Q=1 THEN 110\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/41_Guess/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript guess.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"guess\"\n\trun\n```\n3. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of guess.ms, and click the \"Run Script\" button.\n"
  },
  {
    "path": "00_Alternate_Languages/41_Guess/MiniScript/guess.ms",
    "content": "setup = function\n\tprint \" \"*33 + \"GUESS\"\n\tprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n\tprint; print; print\n\tprint \"This is a number guessing game. I'll think\"\n\tprint \"of a number between 1 and any limit you want.\"\n\tprint \"Then you have to guess what it is.\"\n\tprint\n\twhile true\n\t\tglobals.limit = input(\"What limit do you want? \").val\n\t\tif limit > 1 then break\n\t\tprint \"Please enter a number greater than 1.\"\n\tend while\n\tglobals.par = floor(log(limit, 2)) + 1\nend function\n\nprintGap = function\n\tfor i in range(1, 5)\n\t\tprint\n\tend for\nend function\n\ndoOneGame = function\n\trightAnswer = ceil(rnd * limit)\n\tprint \"I'm thinking of a number between 1 and \" + limit\n\tprint \"Now you try to guess what it is.\"\n\tguess = 0\n\twhile true\n\t\tguess = guess + 1\n\t\tnum = input(\"Your guess: \").val\n\t\tif num <= 0 then\n\t\t\tprintGap\n\t\t\tsetup\n\t\t\treturn\n\t\tend if\n\t\tif num == rightAnswer then\n\t\t\tprint \"That's it! You got it in \" + guess + \" tries.\"\n\t\t\tif guess < par then\n\t\t\t\tprint \"Very good.\"\n\t\t\telse if guess == par then\n\t\t\t\tprint \"Good.\"\n\t\t\telse\n\t\t\t\tprint \"You should have been able to get it in only \" + par + \".\"\n\t\t\tend if\n\t\t\tprintGap\n\t\t\treturn\n\t\tend if\n\t\tif num > rightAnswer then\n\t\t\tprint \"Too high. Try a smaller answer.\"\n\t\telse\n\t\t\tprint \"Too low. Try a bigger answer.\"\n\t\tend if\n\tend while\nend function\n\nsetup\nwhile true\n\tdoOneGame\nend while"
  },
  {
    "path": "00_Alternate_Languages/41_Guess/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/41_Guess/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"time\"\r\n)\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"                   Guess\")\r\n\tfmt.Println(\"Creative Computing  Morristown, New Jersey\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n\tfmt.Println(\"This is a number guessing game. I'll think\")\r\n\tfmt.Println(\"of a number between 1 and any limit you want.\")\r\n\tfmt.Println(\"Then you have to guess what it is\")\r\n}\r\n\r\nfunc getLimit() (int, int) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tfor {\r\n\t\tfmt.Println(\"What limit do you want?\")\r\n\t\tscanner.Scan()\r\n\r\n\t\tlimit, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil || limit < 0 {\r\n\t\t\tfmt.Println(\"Please enter a number greater or equal to 1\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tlimitGoal := int((math.Log(float64(limit)) / math.Log(2)) + 1)\r\n\t\treturn limit, limitGoal\r\n\t}\r\n\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\tprintIntro()\r\n\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tlimit, limitGoal := getLimit()\r\n\r\n\tguessCount := 1\r\n\tstillGuessing := true\r\n\twon := false\r\n\tmyGuess := int(float64(limit)*rand.Float64() + 1)\r\n\r\n\tfmt.Printf(\"I'm thinking of a number between 1 and %d\\n\", limit)\r\n\tfmt.Println(\"Now you try to guess what it is.\")\r\n\r\n\tfor stillGuessing {\r\n\t\tscanner.Scan()\r\n\t\tn, err := strconv.Atoi(scanner.Text())\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"Please enter a number greater or equal to 1\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tif n < 0 {\r\n\t\t\tbreak\r\n\t\t}\r\n\r\n\t\tfmt.Print(\"\\n\\n\\n\")\r\n\t\tif n < myGuess {\r\n\t\t\tfmt.Println(\"Too low. Try a bigger answer\")\r\n\t\t\tguessCount += 1\r\n\t\t} else if n > myGuess {\r\n\t\t\tfmt.Println(\"Too high. Try a smaller answer\")\r\n\t\t\tguessCount += 1\r\n\t\t} else {\r\n\t\t\tfmt.Printf(\"That's it! You got it in %d tries\\n\", guessCount)\r\n\t\t\twon = true\r\n\t\t\tstillGuessing = false\r\n\t\t}\r\n\t}\r\n\r\n\tif won {\r\n\t\tif guessCount < limitGoal {\r\n\t\t\tfmt.Println(\"Very good.\")\r\n\t\t} else if guessCount == limitGoal {\r\n\t\t\tfmt.Println(\"Good.\")\r\n\t\t} else {\r\n\t\t\tfmt.Printf(\"You should have been able to get it in only %d guesses.\\n\", limitGoal)\r\n\t\t}\r\n\t\tfmt.Print(\"\\n\\n\\n\")\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/41_Guess/guess.bas",
    "content": "1 PRINT TAB(33);\"GUESS\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"THIS IS A NUMBER GUESSING GAME. I'LL THINK\"\n5 PRINT \"OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\"\n6 PRINT \"THEN YOU HAVE TO GUESS WHAT IT IS.\"\n7 PRINT\n8 PRINT \"WHAT LIMIT DO YOU WANT\";\n9 INPUT L\n10 PRINT\n11 L1=INT(LOG(L)/LOG(2))+1\n12 PRINT \"I'M THINKING OF A NUMBER BETWEEN 1 AND\";L\n13 G=1\n14 PRINT \"NOW YOU TRY TO GUESS WHAT IT IS.\"\n15 M=INT(L*RND(1)+1)\n20 INPUT N\n21 IF N>0 THEN 25\n22 GOSUB 70\n23 GOTO 1\n25 IF N=M THEN 50\n30 G=G+1\n31 IF N>M THEN 40\n32 PRINT \"TOO LOW. TRY A BIGGER ANSWER.\"\n33 GOTO 20\n40 PRINT \"TOO HIGH. TRY A SMALLER ANSWER.\"\n42 GOTO 20\n50 PRINT \"THAT'S IT! YOU GOT IT IN\";G;\"TRIES.\"\n52 IF G<L1 THEN 58\n54 IF G=L1 THEN 60\n56 PRINT \"YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY\";L1\n57 GOTO 65\n58 PRINT \"VERY \";\n60 PRINT \"GOOD.\"\n65 GOSUB 70\n66 GOTO 12\n70 FOR H=1 TO 5\n71 PRINT\n72 NEXT H\n73 RETURN\n99 END\n"
  },
  {
    "path": "00_Alternate_Languages/42_Gunner/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript gunner.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"gunner\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms",
    "content": "print \" \"*30 + \"Gunner\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"You are the officer-in-charge, giving orders to a gun\"\nprint \"crew, telling them the degrees of elevation you estimate\"\nprint \"will place a projectile on target.  A hit within 100 yards\"\nprint \"of the target will destroy it.\"; print\n\n// Select a target and give the player up to 5 tries to hit it.\n// Return the number of shots taken, or set globals.gameOver to true.\nplayOneTarget = function(maxRange)\n\tglobals.gameOver = false\n\ttargetDist = floor(maxRange * (.1 + .8 * rnd))\n\tshot = 0\n\tprint \"Distance to the target is \" + targetDist + \" yards.\"\n\tprint\n\twhile true\n\t\tprint\n\t\tdegrees = input(\"Elevation? \").val\n\t\tif degrees > 89 then\n\t\t\tprint \"Maximum elevation is 89 degrees.\"\n\t\t\tcontinue\n\t\telse if degrees < 1 then\n\t\t\tprint \"Minimum elevation is one degree.\"\n\t\t\tcontinue\n\t\tend if\n\t\tshot += 1\n\t\tif shot >= 6 then\n\t\t\tglobals.gameOver = true\n\t\t\treturn\n\t\tend if\n\t\tradiansX2 = 2 * degrees * pi/180\n\t\tthrow = maxRange * sin(radiansX2)\n\t\tdiff = floor(targetDist - throw)\n\t\tif abs(diff) < 100 then\n\t\t\tprint \"*** TARGET DESTROYED ***  \" + shot + \" rounds of ammunition expended.\"\n\t\t\treturn shot\n\t\tend if\n\t\tif diff > 0 then\n\t\t\tprint \"Short of target by \" + diff + \" yards.\"\n\t\telse\n\t\t\tprint \"Over target by \" + abs(diff) + \" yards.\"\n\t\tend if\n\tend while\nend function\n\nplayOneGame = function\n\tmaxRange = floor(40000*rnd + 20000)\n\tprint \"Maximum range of your gun is \" + maxRange + \" yards.\"\n\tshots = 0\n\tfor targetNum in range(1,4)\n\t\tshots += playOneTarget(maxRange)\n\t\tif gameOver then break\n\t\tif targetNum < 4 then\n\t\t\tprint\n\t\t\tprint \"The forward observer has sighted more enemy activity...\"\n\t\tend if\n\tend for\n\tif gameOver then\n\t\tprint; print \"Boom !!!!   You have just been destroyed\"\n\t\tprint \"by the enemy.\"; print; print; print\n\telse\n\t\tprint; print; print \"Total rounds expended were: \" + shots\n\tend if\n\tif shots > 18 or gameOver then\n\t\tprint \"Better go back to font sill for refresher training!\"\n\telse\n\t\tprint \"Nice shooting !!\"\n\tend if\nend function\n\n// Main loop\nwhile true\n\tplayOneGame\n\tprint; yn = input(\"Try again (Y or N)? \").upper\n\tif not yn or yn[0] != \"Y\" then break\nend while\nprint; print \"OK.  Return to base camp.\"\n"
  },
  {
    "path": "00_Alternate_Languages/42_Gunner/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/42_Gunner/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"                                 GUNNER\")\r\n\tfmt.Println(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Print(\"\\n\\n\\n\")\r\n\tfmt.Println(\"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\")\r\n\tfmt.Println(\"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\")\r\n\tfmt.Println(\"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\")\r\n\tfmt.Println(\"OF THE TARGET WILL DESTROY IT.\")\r\n\tfmt.Println()\r\n}\r\n\r\nfunc getFloat() float64 {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfor {\r\n\t\tscanner.Scan()\r\n\t\tfl, err := strconv.ParseFloat(scanner.Text(), 64)\r\n\r\n\t\tif err != nil {\r\n\t\t\tfmt.Println(\"Invalid input\")\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\treturn fl\r\n\t}\r\n}\r\n\r\nfunc play() {\r\n\tgunRange := int(40000*rand.Float64() + 20000)\r\n\tfmt.Printf(\"\\nMAXIMUM RANGE OF YOUR GUN IS %d YARDS\\n\", gunRange)\r\n\r\n\tkilledEnemies := 0\r\n\tS1 := 0\r\n\r\n\tfor {\r\n\t\ttargetDistance := int(float64(gunRange) * (0.1 + 0.8*rand.Float64()))\r\n\t\tshots := 0\r\n\r\n\t\tfmt.Printf(\"\\nDISTANCE TO THE TARGET IS %d YARDS\\n\", targetDistance)\r\n\r\n\t\tfor {\r\n\t\t\tfmt.Print(\"\\n\\nELEVATION? \")\r\n\t\t\televation := getFloat()\r\n\r\n\t\t\tif elevation > 89 {\r\n\t\t\t\tfmt.Println(\"MAXIMUM ELEVATION IS 89 DEGREES\")\r\n\t\t\t\tcontinue\r\n\t\t\t}\r\n\r\n\t\t\tif elevation < 1 {\r\n\t\t\t\tfmt.Println(\"MINIMUM ELEVATION IS 1 DEGREE\")\r\n\t\t\t\tcontinue\r\n\t\t\t}\r\n\r\n\t\t\tshots += 1\r\n\r\n\t\t\tif shots < 6 {\r\n\t\t\t\tB2 := 2 * elevation / 57.3\r\n\t\t\t\tshotImpact := int(float64(gunRange) * math.Sin(B2))\r\n\t\t\t\tshotProximity := int(targetDistance - shotImpact)\r\n\r\n\t\t\t\tif math.Abs(float64(shotProximity)) < 100 { // hit\r\n\t\t\t\t\tfmt.Printf(\"*** TARGET DESTROYED *** %d ROUNDS OF AMMUNITION EXPENDED.\\n\", shots)\r\n\t\t\t\t\tS1 += shots\r\n\r\n\t\t\t\t\tif killedEnemies == 4 {\r\n\t\t\t\t\t\tfmt.Printf(\"\\n\\nTOTAL ROUNDS EXPENDED WERE: %d\\n\", S1)\r\n\t\t\t\t\t\tif S1 > 18 {\r\n\t\t\t\t\t\t\tprint(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\")\r\n\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tprint(\"NICE SHOOTING !!\")\r\n\t\t\t\t\t\t\treturn\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tkilledEnemies += 1\r\n\t\t\t\t\t\tfmt.Println(\"\\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\")\r\n\t\t\t\t\t\tbreak\r\n\t\t\t\t\t}\r\n\t\t\t\t} else { // missed\r\n\t\t\t\t\tif shotProximity > 100 {\r\n\t\t\t\t\t\tfmt.Printf(\"SHORT OF TARGET BY %d YARDS.\\n\", int(math.Abs(float64(shotProximity))))\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tfmt.Printf(\"OVER TARGET BY %d YARDS.\\n\", int(math.Abs(float64(shotProximity))))\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Print(\"\\nBOOM !!!!   YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\\n\\n\\n\")\r\n\t\t\t\tfmt.Println(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\")\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tprintIntro()\r\n\r\n\tfor {\r\n\t\tplay()\r\n\r\n\t\tfmt.Print(\"TRY AGAIN (Y OR N)? \")\r\n\t\tscanner.Scan()\r\n\r\n\t\tif strings.ToUpper(scanner.Text())[0:1] != \"Y\" {\r\n\t\t\tfmt.Println(\"\\nOK. RETURN TO BASE CAMP.\")\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/42_Gunner/gunner.bas",
    "content": "10 PRINT TAB(30);\"GUNNER\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n130 PRINT \"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\"\n140 PRINT \"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\"\n150 PRINT \"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\"\n160 PRINT \"OF THE TARGET WILL DESTROY IT.\" : PRINT\n170 R=INT(40000*RND(1)+20000)\n180 PRINT \"MAXIMUM RANGE OF YOUR GUN IS\";R;\" YARDS.\"\n185 Z=0\n190 PRINT\n195 S1=0\n200 T=INT(R*(.1+.8*RND(1)))\n210 S=0\n220 GOTO 370\n230 PRINT \"MINIMUM ELEVATION IS ONE DEGREE.\"\n240 GOTO 390\n250 PRINT \"MAXIMUM ELEVATION IS 89 DEGREES.\"\n260 GOTO 390\n270 PRINT \"OVER TARGET BY \";ABS(E);\"YARDS.\"\n280 GOTO 390\n290 PRINT \"SHORT OF TARGET BY \"ABS(E);\"YARDS.\"\n300 GOTO 390\n320 PRINT \"*** TARGET DESTROYED ***  \";S;\"ROUNDS OF AMMUNITION EXPENDED.\"\n325 S1=S1+S\n330 IF Z=4 THEN 490\n340 Z=Z+1\n345 PRINT\n350 PRINT \"THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\"\n360 GOTO 200\n370 PRINT \"DISTANCE TO THE TARGET IS \"T;\" YARDS.\"\n380 PRINT\n390 PRINT\n400 INPUT \"ELEVATION\";B\n420 IF B>89 THEN 250\n430 IF B<1 THEN 230\n440 S=S+1\n442 IF S<6 THEN 450\n444 PRINT:PRINT \"BOOM !!!!   YOU HAVE JUST BEEN DESTROYED \";\n446 PRINT \"BY THE ENEMY.\" : PRINT : PRINT : PRINT : GOTO 495\n450 B2=2*B/57.3 : I=R*SIN(B2) : X=T-I : E=INT(X)\n460 IF ABS(E)<100 THEN 320\n470 IF E>100 THEN 290\n480 GOTO 270\n490 PRINT : PRINT : PRINT \"TOTAL ROUNDS EXPENDED WERE:\";S1\n492 IF S1>18 THEN 495\n493 PRINT \"NICE SHOOTING !!\" : GOTO 500\n495 PRINT \"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\"\n500 PRINT : INPUT \"TRY AGAIN (Y OR N)\";Z$\n510 IF Z$=\"Y\" THEN 170\n520 PRINT:PRINT \"OK.  RETURN TO BASE CAMP.\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/43_Hammurabi/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hammurabi.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hammurabi\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms",
    "content": "print \" \"*32 + \"Hamurabi\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Try your hand at governing ancient Sumeria\"\nprint \"for a ten-year term of office.\"; print\n\neol = char(10)\n\ngame = {}\ngame.z = 0\t// year\ngame.p = 95\ngame.s = 2800\t// bushels in store\ngame.h = 3000\ngame.e = game.h - game.s\t// bushels eaten by rats\ngame.food = 0\t// bushels given to people to eat\ngame.y = 3\t\t// value (in bushels) per acre\ngame.a = game.h / game.y\t// acres owned\ngame.i = 5\t// immigration/births\ngame.d = 0\t// how many starved this year\ngame.d1 = 0\t// total starved over the whole game\ngame.p1 = 0\t// average % of population starved per year\ngame.q = 1\t// if negative, then a plague strikes\n\nstartYear = function\n\tprint; print; print \"Hamurabi:  I beg to report to you,\"\n\tgame.z += 1\n\tprint \"In year \" + game.z + \", \" +\n\t  game.d + \" people starved, \" +\n\t  game.i + \" came to the city,\"\n\tgame.p += game.i\n\tif game.q < 0 then\n\t\tgame.p = floor(game.p / 2)\n\t\tprint \"A horrible plague struck!  Half the people died.\"\n\tend if\n\tprint \"Population is now \" + game.p + \".\"\n\tprint \"The city now owns \" + game.a + \" acres.\"\n\tprint \"You harvested \" + game.y + \" bushels per acre.\"\n\tprint \"The rats ate \" + game.e + \" bushels.\"\n\tprint \"You now have \" + game.s + \" bushels in store.\"; print\nend function\n\nexitGame = function\n\tprint; print char(7)*10\n\tprint \"So long for now.\"; print\n\texit\nend function\n\nimpeach = function\n\tprint \"Due to this extreme mismanagement you have not only\"\n\tprint \"been impeached and thrown out of office but you have\"\n\tprint \"also been declared national fink!!!!\"\n\texitGame\nend function\n\ngetNumber = function(prompt, max, maxMsg)\n\twhile true\n\t\tvalue = input(prompt + \"? \").val\n\t\tif value < 0 then\n\t\t\tprint; print \"Hamurabi:  I cannot do what you wish.\"\n\t\t\tprint \"Get yourself another steward!\"\n\t\t\texitGame\n\t\tend if\n\t\tif value <= max then return value\n\t\tprint \"Hamurabi:  Think again.  \" + maxMsg + \"  Now then,\"\n\tend while\nend function\n\nhint = function(msg)\n\t// This was not in the original program.  But if you want to make\n\t// the game easier, uncomment this line:\n\t//print msg\nend function\n\nmin = function(a, b, c)\n\tm = [a, b, c]\n\tm.sort\n\treturn m[0]\nend function\n\ngetDecisions = function\n\t// buy/sell land\n\tc = floor(10 * rnd); game.y = c + 17\n\tprint \"Land is trading at \" + game.y + \" bushels per acre.\"\n\tqty = getNumber(\"How many acres do you wish to buy\",\n\t\tfloor(game.s / game.y), \"You have only\" + eol + game.s + \" bushels of grain.\")\n\tif qty > 0 then\n\t\tgame.a += qty\n\t\tgame.s -= game.y * qty\n\telse\n\t\tqty = getNumber(\"How many acres do you wish to sell\",\n\t\t\tgame.a, \"You own only\" + eol + game.a + \" acres.\")\n\t\tgame.a -= qty\n\t\tgame.s += game.y * qty\n\tend if\t\n\t\n\t// feed the people\n\thint \"Your people want \" + (game.p * 20) + \" bushels of food.\"\n\tgame.food = getNumber(\"How many bushels do you wish to feed your people\",\n\t\tgame.s, \"You have only\" + eol + game.s + \" bushels of grain.\")\n\tgame.s -= game.food\n\t\n\t// planting (a little more complicate because there are THREE limits)\n\thint \"You can plant up to \" + \n\t   min(game.a, floor(game.s * 2), floor(game.p*10-1)) + \" acres.\"\n\tgame.d = 0\n\twhile game.a > 0 and game.s > 2\n\t\tgame.d = getNumber(\"How many acres do you wish to plant with seed\",\n\t\t\tgame.a, \"You own only \" + game.a + \" acres.\")\n\t\t// enough grain for seed?  (each bushel can plant 2 acres)\n\t\tif floor(game.d / 2) > game.s then\n\t\t\tprint \"Hamurabi:  Think again.  You have only\" + eol + game.s +\n\t\t\t  \" bushels of grain.  Now then,\"\n\t\t\tcontinue\n\t\tend if\n\t\t// enough people to tend the crops?  (each person can tend 10 acres)\n\t\tif game.d >= game.p * 10 then\n\t\t\tprint \"But you have only \" + game.p + \" people to tend the fields!  Now then,\"\n\t\t\tcontinue\n\t\tend if\n\t\tbreak\n\tend while\n\tgame.s -= floor(game.d / 2)\nend function\n\nsimulateYear = function\n\t// A bountiful harvest!\n\tc = floor(rnd * 5) + 1\n\tgame.y = c; game.h = game.d * game.y; game.e = 0\t\n\tc = floor(rnd * 5) + 1\n\tif c % 2 == 0 then\n\t\t// rats are running wild!!\n\t\tgame.e = floor(game.s / c)\n\tend if\n\tgame.s += game.h - game.e\n\t\n\t// Let's have some babies\n\tc = floor(rnd * 5) + 1\n\tgame.i = floor(c * (20 * game.a + game.s) / game.p / 100 + 1)\n\t// How many people had full tummies?\n\tc = floor(game.food / 20)\n\t// Horros, a 15% chance of plague\n\tgame.q = floor(10 * (2 * rnd - 0.3))\n\t\n\tif game.p < c then\n\t\tgame.d = 0\n\telse\n\t\t// starve enough for impeachment?\n\t\tgame.d = game.p - c\n\t\tif game.d > 0.45 * game.p then\n\t\t\tprint; print \"You starved \" + game.d + \" people in one year!!!\"\n\t\t\timpeach\n\t\tend if\n\t\tgame.p1 = ((game.z - 1) * game.p1 + game.d * 100 / game.p) / game.z\n\t\tgame.p = c\n\t\tgame.d1 += game.d\n\tend if\nend function\n\nprintFinalResult = function\n\tprint \"In your 10-year term of office, \" + game.p1 + \" percent of the\"\n\tprint \"population starved per year on the average, i.e., a total of\"\n\tprint game.d1 + \" people died!!\"\n\tacresPer = game.a / game.p\n\tprint \"You started with 10 acres per person and ended with\"\n\tprint acresPer + \" acres per person.\"; print\n\tif game.p1 > 33 or acresPer < 7 then impeach\n\tif game.p1 > 10 or acresPer < 9 then\n\t\tprint \"Your heavy-handed performance smacks of Nero and Ivan IV.\"\n\t\tprint \"The people (remaining) find you an unpleasant ruler, and,\"\n\t\tprint \"frankly, hate your guts!!\"\n\telse if game.p1 > 3 or acresPer < 10 then\n\t\tprint \"Your performance could have been somewhat better, but\"\n\t\tprint \"really wasn't too bad at all.  \" + floor(game.p * 0.8 * rnd) + \" people\"\n\t\tprint \"would dearly like to see you assassinated but we all have our\"\n\t\tprint \"trivial problems.\"\n\telse\n\t\tprint \"A fantastic performance!!  Charlemange, Disraeli, and\"\n\t\tprint \"Jefferson combined could not have done better!\"\n\tend if\nend function\n\n// Main loop\nwhile true\n\tstartYear\n\tif game.z == 11 then break\n\tgetDecisions\n\tsimulateYear\nend while\nprintFinalResult\nexitGame\n"
  },
  {
    "path": "00_Alternate_Languages/43_Hammurabi/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/43_Hammurabi/hammurabi.bas",
    "content": "10 PRINT TAB(32); \"HAMURABI\"\n20 PRINT TAB(15); \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT : PRINT : PRINT \n80 PRINT \"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\"\n90 PRINT \"FOR A TEN-YEAR TERM OF OFFICE.\" : PRINT \n95 D1 = 0 : P1 = 0\n100 Z = 0 : P = 95 : S = 2800 : H = 3000 : E = H - S\n110 Y = 3 : A = H / Y : I = 5 : Q = 1\n210 D = 0\n215 PRINT : PRINT : PRINT \"HAMURABI:  I BEG TO REPORT TO YOU,\" : Z = Z + 1\n217 PRINT \"IN YEAR \"; Z; \",\"; D; \" PEOPLE STARVED, \"; I; \" CAME TO THE CITY,\"\n218 P = P + I\n227 IF Q > 0 THEN 230\n228 P = INT(P / 2)\n229 PRINT \"A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\"\n230 PRINT \"POPULATION IS NOW \"; P\n232 PRINT \"THE CITY NOW OWNS \"; A; \" ACRES.\"\n235 PRINT \"YOU HARVESTED \"; Y; \" BUSHELS PER ACRE.\"\n250 PRINT \"THE RATS ATE \"; E; \" BUSHELS.\"\n260 PRINT \"YOU NOW HAVE \"; S; \" BUSHELS IN STORE.\" : PRINT \n270 IF Z = 11 THEN 860\n310 C = INT(10 * RND(1)) : Y = C + 17\n312 PRINT \"LAND IS TRADING AT \"; Y; \" BUSHELS PER ACRE.\"\n320 PRINT \"HOW MANY ACRES DO YOU WISH TO BUY\";\n321 INPUT Q : IF Q < 0 THEN 850\n322 IF Y * Q <= S THEN 330\n323 GOSUB 710\n324 GOTO 320\n330 IF Q = 0 THEN 340\n331 A = A + Q : S = S - Y * Q : C = 0\n334 GOTO 400\n340 PRINT \"HOW MANY ACRES DO YOU WISH TO SELL\";\n341 INPUT Q : IF Q < 0 THEN 850\n342 IF Q < A THEN 350\n343 GOSUB 720\n344 GOTO 340\n350 A = A - Q : S = S + Y * Q : C = 0\n400 PRINT \n410 PRINT \"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE\";\n411 INPUT Q\n412 IF Q < 0 THEN 850\n418 REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?\n420 IF Q <= S THEN 430\n421 GOSUB 710\n422 GOTO 410\n430 S = S - Q : C = 1 : PRINT \n440 PRINT \"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED\";\n441 INPUT D : IF D = 0 THEN 511\n442 IF D < 0 THEN 850\n444 REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?\n445 IF D <= A THEN 450\n446 GOSUB 720\n447 GOTO 440\n449 REM *** ENOUGH GRAIN FOR SEED?\n450 IF INT(D / 2) <= S THEN 455\n452 GOSUB 710\n453 GOTO 440\n454 REM *** ENOUGH PEOPLE TO TEND THE CROPS?\n455 IF D < 10 * P THEN 510\n460 PRINT \"BUT YOU HAVE ONLY \"; P; \" PEOPLE TO TEND THE FIELDS!  NOW THEN,\"\n470 GOTO 440\n510 S = S - INT(D / 2)\n511 GOSUB 800\n512 REM *** A BOUNTIFUL HARVEST!\n515 Y = C : H = D * Y : E = 0\n521 GOSUB 800\n522 IF INT(C / 2) <> C / 2 THEN 530\n523 REM *** RATS ARE RUNNING WILD!!\n525 E = INT(S / C)\n530 S = S - E + H\n531 GOSUB 800\n532 REM *** LET'S HAVE SOME BABIES\n533 I = INT(C *(20 * A + S) / P / 100 + 1)\n539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES?\n540 C = INT(Q / 20)\n541 REM *** HORROS, A 15% CHANCE OF PLAGUE\n542 Q = INT(10 *(2 * RND(1) - 0.3))\n550 IF P < C THEN 210\n551 REM *** STARVE ENOUGH FOR IMPEACHMENT?\n552 D = P - C : IF D > 0.45 * P THEN 560\n553 P1 =((Z - 1) * P1 + D * 100 / P) / Z\n555 P = C : D1 = D1 + D : GOTO 215\n560 PRINT : PRINT \"YOU STARVED \"; D; \" PEOPLE IN ONE YEAR!!!\"\n565 PRINT \"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\"\n566 PRINT \"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\"\n567 PRINT \"ALSO BEEN DECLARED NATIONAL FINK!!!!\" : GOTO 990\n710 PRINT \"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\"\n711 PRINT S; \"BUSHELS OF GRAIN.  NOW THEN,\"\n712 RETURN \n720 PRINT \"HAMURABI:  THINK AGAIN.  YOU OWN ONLY \"; A; \" ACRES.  NOW THEN,\"\n730 RETURN \n800 C = INT(RND(1) * 5) + 1\n801 RETURN \n850 PRINT : PRINT \"HAMURABI:  I CANNOT DO WHAT YOU WISH.\"\n855 PRINT \"GET YOURSELF ANOTHER STEWARD!!!!!\"\n857 GOTO 990\n860 PRINT \"IN YOUR 10-YEAR TERM OF OFFICE,\"; P1; \"PERCENT OF THE\"\n862 PRINT \"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\"\n865 PRINT D1; \"PEOPLE DIED!!\" : L = A / P\n870 PRINT \"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\"\n875 PRINT L; \"ACRES PER PERSON.\" : PRINT \n880 IF P1 > 33 THEN 565\n885 IF L < 7 THEN 565\n890 IF P1 > 10 THEN 940\n892 IF L < 9 THEN 940\n895 IF P1 > 3 THEN 960\n896 IF L < 10 THEN 960\n900 PRINT \"A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\"\n905 PRINT \"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\" : GOTO 990\n940 PRINT \"YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\"\n945 PRINT \"THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,\"\n950 PRINT \"FRANKLY, HATE YOUR GUTS!!\" : GOTO 990\n960 PRINT \"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\"\n965 PRINT \"REALLY WASN'T TOO BAD AT ALL. \"; INT(P * 0.8 * RND(1)); \"PEOPLE\"\n970 PRINT \"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\"\n975 PRINT \"TRIVIAL PROBLEMS.\"\n990 PRINT : FOR N = 1 TO 10 : PRINT CHR$(7); : NEXT N\n995 PRINT \"SO LONG FOR NOW.\" : PRINT \n999 END "
  },
  {
    "path": "00_Alternate_Languages/44_Hangman/C/dictionary.txt",
    "content": "harm\nretire\nprinciple\ntile\nbiology\nshow\nreporter\nprofound\nprestige\nhardship\nsupplementary\nabundant\nfirm\npreparation\nmother\nwelfare\nbroadcast\nvirgin\nbloody\nshaft\nbird\nbuy\npassion\nsouth\nslant\nhesitate\nleak\nride\ncontempt\nbanner\nhurt\ndisaster\nranch\ndamage\nconceive\nenvironmental\noutside\napathy\ntemple\narrange\nhour\ntone\nintelligence\nsoup\nbishop\nfool\nchase\nsnub\ndevelop\ndomination\ncry\ndistant\npoem\nimplication\nrally\nassertive\nanxiety\nhome\nbear\nexecute\ncentury\nsolo\ncathedral\nterminal\nintegration\nmastermind\npen\nX-ray\nmatch\nceremony\nstop\nlinger\nslow\ndesert\nsuperior\ntender\ndebt\ncriticism\nrehabilitation\nfinish\njest\nscream\npiece\nmask\napproach\nsequence\nnegotiation\nto\ntraffic\nmidnight\naspect\ndull\nconcession\ncitizen\nconception\ninstrument\ncompartment\nresponsibility\nresist\nwithdraw"
  },
  {
    "path": "00_Alternate_Languages/44_Hangman/C/main.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#define MAX_WORDS 100\n\n//check if windows or linux for the clear screen\n#ifdef _WIN32\n#define CLEAR \"cls\"\n#else\n#define CLEAR \"clear\"\n#endif\n\n/**\n * @brief Prints the stage of the hangman based on the number of wrong guesses.\n * \n * @param stage Hangman stage.\n */\nvoid print_hangman(int stage){\n    switch (stage){\n        case 0:\n            printf(\"----------\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|\\n\");\n            printf(\"|\\n\");\n            printf(\"|\\n\");\n            printf(\"|\\n\");\n            break;\n        case 1:\n            printf(\"----------\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|        O\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|\\n\");\n            printf(\"|\\n\");\n            break;\n        case 2:\n            printf(\"----------\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|        o\\n\");\n            printf(\"|       /|\\n\");\n            printf(\"|\\n\");\n            printf(\"|\\n\");\n            break;\n        case 3:\n            printf(\"----------\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|        o\\n\");\n            printf(\"|       /|\\\\\\n\");\n            printf(\"|\\n\");\n            printf(\"|\\n\");\n            break; \n        case 4:\n            printf(\"----------\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|        o\\n\");\n            printf(\"|       /|\\\\\\n\");\n            printf(\"|       /\\n\");\n            printf(\"|\\n\");\n            break; \n        case 5:\n            printf(\"----------\\n\");\n            printf(\"|        |\\n\");\n            printf(\"|        o\\n\");\n            printf(\"|       /|\\\\\\n\");\n            printf(\"|       / \\\\\\n\");\n            printf(\"|\\n\");\n            break;         \n        default:\n            break;\n    }\n}\n\n/**\n * @brief Picks and return a random word from the dictionary.\n * \n * @return Random word \n */\nchar* random_word_picker(){\n    //generate a random english word\n    char* word = malloc(sizeof(char) * 100);\n    FILE* fp = fopen(\"dictionary.txt\", \"r\");\n    srand(time(NULL));\n    if (fp == NULL){\n        printf(\"Error opening dictionary.txt\\n\");\n        exit(1);\n    }\n    int random_number = rand() % MAX_WORDS;\n    for (int j = 0; j < random_number; j++){\n        fscanf(fp, \"%s\", word);\n    }\n    fclose(fp);\n    return word;\n}\n\n\n\n\nvoid main(void){\n    char* word = malloc(sizeof(char) * 100);\n    word = random_word_picker();\n    char* hidden_word = malloc(sizeof(char) * 100);\n    for (int i = 0; i < strlen(word); i++){\n        hidden_word[i] = '_';\n    }\n    hidden_word[strlen(word)] = '\\0';\n    int stage = 0;\n    int wrong_guesses = 0;\n    int correct_guesses = 0;\n    char* guess = malloc(sizeof(char) * 100);\n    while (wrong_guesses < 6 && correct_guesses < strlen(word)){\n        CLEAR;\n        print_hangman(stage);\n        printf(\"%s\\n\", hidden_word);\n        printf(\"Enter a guess: \");\n        scanf(\"%s\", guess);\n        for (int i = 0; i < strlen(word); i++){\n            if (strcmp(guess,word) == 0){\n                correct_guesses = strlen(word);\n            }\n            else if (guess[0] == word[i]){\n                hidden_word[i] = guess[0];\n                correct_guesses++;\n            }\n        }\n        if (strchr(word, guess[0]) == NULL){\n            wrong_guesses++;\n        }\n        stage = wrong_guesses;\n    }\n    if (wrong_guesses == 6){\n        printf(\"You lose! The word was %s\\n\", word);\n    }\n    else {\n        printf(\"You win!\\n\");\n    }\n}"
  },
  {
    "path": "00_Alternate_Languages/44_Hangman/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hangman.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hangman\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms",
    "content": "print \" \"*32 + \"Hangman\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nwords = []\nwords += [\"gum\",\"sin\",\"for\",\"cry\",\"lug\",\"bye\",\"fly\"]\nwords += [\"ugly\",\"each\",\"from\",\"work\",\"talk\",\"with\",\"self\"]\nwords += [\"pizza\",\"thing\",\"feign\",\"fiend\",\"elbow\",\"fault\",\"dirty\"]\nwords += [\"budget\",\"spirit\",\"quaint\",\"maiden\",\"escort\",\"pickax\"]\nwords += [\"example\",\"tension\",\"quinine\",\"kidney\",\"replica\",\"sleeper\"]\nwords += [\"triangle\",\"kangaroo\",\"mahogany\",\"sergeant\",\"sequence\"]\nwords += [\"moustache\",\"dangerous\",\"scientist\",\"different\",\"quiescent\"]\nwords += [\"magistrate\",\"erroneously\",\"loudspeaker\",\"phytotoxic\"]\nwords += [\"matrimonial\",\"parasympathomimetic\",\"thigmotropism\"]\n// Note: on Mini Micro, you could instead do:\n// words = file.readLines(\"/sys/data/englishWords.txt\")\n\nwords.shuffle\n\naddToPic = function(guessCount)\n\tif guessCount == 1 then\n\t\tprint \"First, we draw a head\"\n\t\tps[3][6]=\"-\"; ps[3][7]=\"-\"; ps[3][8]=\"-\"; ps[4][5]=\"(\"; ps[4][6]=\".\"\n\t\tps[4][8]=\".\"; ps[4][9]=\")\"; ps[5][6]=\"-\"; ps[5][7]=\"-\"; ps[5][8]=\"-\"\n\telse if guessCount == 2 then\n\t\tprint \"Now we draw a body.\"\n\t\tfor i in range(6, 9); ps[i][7]=\"x\"; end for\n\telse if guessCount == 3 then\n\t\tprint \"Next we draw an arm.\"\n\t\tfor i in range(4, 7); ps[i][i-1]=\"\\\"; end for\n\telse if guessCount == 4 then\n\t\tprint \"This time it's the other arm.\"\n\t\tps[4][11]=\"/\"; ps[5][10]=\"/\"; ps[6][9]=\"/\"; ps[7][8]=\"/\"\n\telse if guessCount == 5 then\n\t\tprint \"Now, let's draw the right leg.\"\n\t\tps[10][6]=\"/\"; ps[11][5]=\"/\"\n\telse if guessCount == 6 then\n\t\tprint \"This time we draw the left leg.\"\n\t\tps[10][8]=\"\\\"; ps[11][9]=\"\\\"\n\telse if guessCount == 7 then\n\t\tprint \"Now we put up a hand.\"\n\t\tps[3][11]=\"\\\"\n\telse if guessCount == 8 then\n\t\tprint \"Next the other hand.\"\n\t\tps[3][3]=\"/\"\n\telse if guessCount == 9 then\n\t\tprint \"Now we draw one foot\"\n\t\tps[12][10]=\"\\\"; ps[12][11]=\"-\"\n\telse if guessCount == 10 then\n\t\tprint \"Here's the other foot -- you're hung!!\"\n\t\tps[12][3]=\"-\"; ps[12][4]=\"/\"\n\tend if\n\tfor i in range(1, 12)\n\t\tprint ps[i].join(\"\")\n\tend for\n\tprint\nend function\n\ndoOneGame = function\n\tusedLetters = []\n\tglobals.ps = []\n\tfor i in range(0, 12); ps.push [\" \"]*12; end for\n\tfor i in range(1,12); ps[i][1] = \"X\"; end for\n\tfor i in range(1, 7); ps[1][i] = \"X\"; end for; ps[2][7] = \"X\"\n\tsecretWord = words.pull.upper\n\t//print \"(Secret word: \" + secretWord + \")\"\n\tvisibleWord = [\"-\"] * secretWord.len\n\twrongGuesses = 0\n\twhile true\n\t\tprint \"Here are the letters you used:\"\n\t\tprint usedLetters.join(\",\")\n\t\tprint\n\t\tprint visibleWord.join(\"\")\n\t\tprint\n\t\tguess = input(\"What is your guess? \").upper\n\t\tguess = (guess + \" \")[0]\n\t\tif guess < \"A\" or guess > \"Z\" then continue\n\t\tif usedLetters.indexOf(guess) != null then\n\t\t\tprint \"You guessed that letter before!\"\n\t\t\tcontinue\n\t\tend if\n\t\tusedLetters.push guess\n\t\tfor i in visibleWord.indexes\n\t\t\tif secretWord[i] == guess then visibleWord[i] = guess\n\t\tend for\n\t\tif visibleWord.indexOf(\"-\") == null then\n\t\t\tprint \"You found the word!\"\n\t\t\treturn true\n\t\telse if secretWord.indexOf(guess) != null then\n\t\t\tprint\n\t\t\tprint visibleWord.join(\"\")\n\t\t\tprint\n\t\t\tguess = input(\"What is your guess for the word? \").upper\n\t\t\tif guess == secretWord then\n\t\t\t\tprint \"Right!! It took you \" + usedLetters.len + \" guesses!\"\n\t\t\t\treturn true\n\t\t\telse\n\t\t\t\tprint \"Wrong.  Try another letter.\"\n\t\t\tend if\n\t\t\tprint\n\t\telse\n\t\t\tprint \"Sorry, that letter isn't in the word.\"\n\t\t\twrongGuesses += 1\n\t\t\taddToPic wrongGuesses\n\t\t\tif wrongGuesses > 9 then\n\t\t\t\tprint \"Sorry, you lose.  The word was \" + secretWord\n\t\t\t\treturn false\n\t\t\tend if\n\t\tend if\n\tend while\nend function\n\nwhile true\n\tif not words then\n\t\tprint \"You did all the words!!\"\n\t\tbreak\n\tend if\n\twon = doOneGame\n\tif won then\n\t\tyn = input(\"Want another word? \").upper\n\telse\n\t\tyn = input(\"You missed that one.  Do you want another word? \").upper\n\tend if\n\tif not yn or yn[0] != \"Y\" then break\nend while\nprint\nprint \"It's been fun!  Bye for now.\"\n"
  },
  {
    "path": "00_Alternate_Languages/44_Hangman/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/44_Hangman/hangman.bas",
    "content": "10 PRINT TAB(32);\"HANGMAN\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n25 PRINT:PRINT:PRINT\n30 DIM P$(12,12),L$(20),D$(20),N$(26),U(50)\n40 C=1: N=50\n50 FOR I=1 TO 20: D$(I)=\"-\": NEXT I: M=0\n60 FOR I=1 TO 26: N$(I)=\"\": NEXT I\n70 FOR I=1 TO 12: FOR J=1 TO 12: P$(I,J)=\" \": NEXT J: NEXT I\n80 FOR I=1 TO 12: P$(I,1)=\"X\": NEXT I\n90 FOR I=1 TO 7: P$(1,I)=\"X\": NEXT: P$(2,7)=\"X\"\n95 IF C<N THEN 100\n97 PRINT \"YOU DID ALL THE WORDS!!\": STOP\n100 Q=INT(N*RND(1))+1\n110 IF U(Q)=1 THEN 100\n115 U(Q)=1: C=C+1: RESTORE: T1=0\n150 FOR I=1 TO Q: READ A$: NEXT I\n160 L=LEN(A$): FOR I=1 TO LEN(A$): L$(I)=MID$(A$,I,1): NEXT I\n170 PRINT \"HERE ARE THE LETTERS YOU USED:\"\n180 FOR I=1 TO 26: PRINT N$(I);: IF N$(I+1)=\"\" THEN 200\n190 PRINT \",\";: NEXT I\n200 PRINT: PRINT: FOR I=1 TO L: PRINT D$(I);: NEXT I: PRINT: PRINT\n210 INPUT \"WHAT IS YOUR GUESS\";G$: R=0\n220 FOR I=1 TO 26: IF N$(I)=\"\" THEN 250\n230 IF G$=N$(I) THEN PRINT \"YOU GUESSED THAT LETTER BEFORE!\": GOTO 170\n240 NEXT I: PRINT \"PROGRAM ERROR.  RUN AGAIN.\": STOP\n250 N$(I)=G$: T1=T1+1\n260 FOR I=1 TO L: IF L$(I)=G$ THEN 280\n270 NEXT I: IF R=0 THEN 290\n275 GOTO 300\n280 D$(I)=G$: R=R+1: GOTO 270\n290 M=M+1: GOTO 400\n300 FOR I=1 TO L: IF D$(I)=\"-\" THEN 320\n310 NEXT I: GOTO 390\n320 PRINT: FOR I=1 TO L: PRINT D$(I);: NEXT I: PRINT: PRINT\n330 INPUT \"WHAT IS YOUR GUESS FOR THE WORD\";B$\n340 IF A$=B$ THEN 360\n350 PRINT \"WRONG.  TRY ANOTHER LETTER.\": PRINT: GOTO 170\n360 PRINT \"RIGHT!!  IT TOOK YOU\";T1;\"GUESSES!\"\n370 INPUT \"WANT ANOTHER WORD\";W$: IF W$=\"YES\" THEN 50\n380 PRINT: PRINT \"IT'S BEEN FUN!  BYE FOR NOW.\": GOTO 999\n390 PRINT \"YOU FOUND THE WORD!\": GOTO 370\n400 PRINT: PRINT: PRINT\"SORRY, THAT LETTER ISN'T IN THE WORD.\"\n410 ON M GOTO 415,420,425,430,435,440,445,450,455,460\n415 PRINT \"FIRST, WE DRAW A HEAD\": GOTO 470\n420 PRINT \"NOW WE DRAW A BODY.\": GOTO 470\n425 PRINT \"NEXT WE DRAW AN ARM.\": GOTO 470\n430 PRINT \"THIS TIME IT'S THE OTHER ARM.\": GOTO 470\n435 PRINT \"NOW, LET'S DRAW THE RIGHT LEG.\": GOTO 470\n440 PRINT \"THIS TIME WE DRAW THE LEFT LEG.\": GOTO 470\n445 PRINT \"NOW WE PUT UP A HAND.\": GOTO 470\n450 PRINT \"NEXT THE OTHER HAND.\": GOTO 470\n455 PRINT \"NOW WE DRAW ONE FOOT\": GOTO 470\n460 PRINT \"HERE'S THE OTHER FOOT -- YOU'RE HUNG!!\"\n470 ON M GOTO 480,490,500,510,520,530,540,550,560,570\n480 P$(3,6)=\"-\": P$(3,7)=\"-\": P$(3,8)=\"-\": P$(4,5)=\"(\": P$(4,6)=\".\"\n481 P$(4,8)=\".\":P$(4,9)=\")\":P$(5,6)=\"-\":P$(5,7)=\"-\":P$(5,8)=\"-\":GOTO 580\n490 FOR I=6 TO 9: P$(I,7)=\"X\": NEXT I: GOTO 580\n500 FOR I=4 TO 7: P$(I,I-1)=\"\\\": NEXT I: GOTO 580\n510 P$(4,11)=\"/\": P$(5,10)=\"/\": P$(6,9)=\"/\": P$(7,8)=\"/\": GOTO 580\n520 P$(10,6)=\"/\": P$(11,5)=\"/\": GOTO 580\n530 P$(10,8)=\"\\\": P$(11,9)=\"\\\": GOTO 580\n540 P$(3,11)=\"\\\": GOTO 580\n550 P$(3,3)=\"/\": GOTO 580\n560 P$(12,10)=\"\\\": P$(12,11)=\"-\": GOTO 580\n570 P$(12,3)=\"-\": P$(12,4)=\"/\"\n580 FOR I=1 TO 12: FOR J=1 TO 12: PRINT P$(I,J);: NEXT J\n590 PRINT: NEXT I: PRINT: PRINT: IF M<>10 THEN 170\n600 PRINT \"SORRY, YOU LOSE.  THE WORD WAS \";A$\n610 PRINT \"YOU MISSED THAT ONE.  DO YOU \";: GOTO 370\n620 INPUT \"TYPE YES OR NO\";Y$: IF LEFT$(Y$,1)=\"Y\" THEN 50\n700 DATA \"GUM\",\"SIN\",\"FOR\",\"CRY\",\"LUG\",\"BYE\",\"FLY\"\n710 DATA \"UGLY\",\"EACH\",\"FROM\",\"WORK\",\"TALK\",\"WITH\",\"SELF\"\n720 DATA \"PIZZA\",\"THING\",\"FEIGN\",\"FIEND\",\"ELBOW\",\"FAULT\",\"DIRTY\"\n730 DATA \"BUDGET\",\"SPIRIT\",\"QUAINT\",\"MAIDEN\",\"ESCORT\",\"PICKAX\"\n740 DATA \"EXAMPLE\",\"TENSION\",\"QUININE\",\"KIDNEY\",\"REPLICA\",\"SLEEPER\"\n750 DATA \"TRIANGLE\",\"KANGAROO\",\"MAHOGANY\",\"SERGEANT\",\"SEQUENCE\"\n760 DATA \"MOUSTACHE\",\"DANGEROUS\",\"SCIENTIST\",\"DIFFERENT\",\"QUIESCENT\"\n770 DATA \"MAGISTRATE\",\"ERRONEOUSLY\",\"LOUDSPEAKER\",\"PHYTOTOXIC\"\n780 DATA \"MATRIMONIAL\",\"PARASYMPATHOMIMETIC\",\"THIGMOTROPISM\"\n990 PRINT \"BYE NOW\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/ANSI_C/hello.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\n#define TRUE 1\n#define FALSE 0\n#define MAX_INPUT_LENGTH 80\n\nvoid tab(int number_of_spaces);\nvoid get_input(char *input_buffer);\nint strings_match(char *string1, char *string2);\n\nint main() {\n    int done = FALSE;\n    int paid = FALSE;\n    int maybe_more, sure;\n    \n    char name[MAX_INPUT_LENGTH];\n    char reply[MAX_INPUT_LENGTH];\n    \n    tab(33);\n    printf(\"HELLO\\n\");\n    tab(15);\n    printf(\"CREATIVE COMPUTING   MORRISTOWN, NEW JERSEY\\n\");\n    printf(\"\\n\\n\\n\");\n    printf(\"HELLO.   MY NAME IS CREATIVE COMPUTER.\\n\");\n    printf(\"\\n\\nWHAT'S YOUR NAME \");\n    get_input(name);\n    printf(\"\\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE \", name);\n\n    get_input(reply);\n    while (!strings_match(reply, \"YES\") && !strings_match(reply, \"NO\")) {\n        printf(\"%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\\n\", name, reply);\n        printf(\"PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE \");\n        get_input(reply);    \n    }\n    \n    if (strings_match(reply, \"YES\")) {\n        printf(\"I'M GLAD TO HEAR THAT, %s.\\n\", name);\n    }\n    else {\n        printf(\"OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN \"\n            \"BRIGHTEN UP YOUR VISIT A BIT.\\n\", name);\n    }\n\n    printf(\"\\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT \"\n        \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO \"\n        \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) \", name);\n\n    while (!done) {\n        get_input(reply);\n        \n        if (strings_match(reply, \"JOB\")) {\n            printf(\"I CAN SYMPATHIZE WITH YOU %s.   I HAVE TO WORK \"\n                \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES \"\n                \"REALLY BEAT ON MY KEYBOARD.    MY ADVICE TO YOU, %s, IS TO \"\n                \"OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\\n\\n\", name, name);\n        }\n\n        else if (strings_match(reply, \"MONEY\")) {\n            printf(\"SORRY, %s, I'M BROKE TOO.  WHY DON'T YOU SELL \"\n                \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING \"\n                \"SO YOU WON'T NEED SO MUCH MONEY?\\n\\n\", name);\n        }\n        \n        else if (strings_match(reply, \"HEALTH\")) {\n            printf(\"MY ADVICE TO YOU %s IS:\\n\", name);\n            printf(\"         1.  TAKE TWO ASPRIN\\n\");\n            printf(\"         2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\\n\");\n            printf(\"         3.  GO TO BED (ALONE)\\n\\n\");\n        }\n        \n        else if (strings_match(reply, \"SEX\")) {\n            printf(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE \");\n            \n            sure = FALSE;\n            while (!sure) {\n                get_input(reply);\n                if (strings_match(reply, \"TOO MUCH\")) {\n                    printf(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\\n\");\n                    printf(\"IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\\n\\n\", name);\n                    sure = TRUE;\n                }\n                else if (strings_match(reply, \"TOO LITTLE\")) {\n                    printf(\"WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE \"\n                        \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME \"\n                        \"REAL ACTION.\\n\\n\", name);\n                    sure = TRUE;\n                }\n                else {\n                    printf(\"DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION \"\n                        \"WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT \", name);\n                }\n            }\n        }\n        \n        else {  // not one of the prescribed categories\n            printf(\"OH, %s, YOUR ANSWER OF '%s' IS GREEK TO ME.\\n\\n\", name, reply);\n        }\n        \n        printf(\"ANY MORE PROBLEMS YOU WANT SOLVED, %s \", name);\n        \n        maybe_more = TRUE;\n        while (maybe_more) {\n            get_input(reply);\n            if (strings_match(reply, \"NO\")) {\n                done = TRUE;\n                maybe_more = FALSE;\n            }\n            else if (strings_match(reply, \"YES\")) {\n                printf(\"WHAT KIND (SEX, MONEY, HEALTH, JOB) \");\n                maybe_more = FALSE;\n            }\n            else {\n                printf(\"JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s. \", name);\n            }\n        } // no further questions\n    } // end of 'not done' loop\n    \n    printf(\"\\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\\n\", name);\n    printf(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\\n\");\n    // pause a few seconds\n    printf(\"\\n\\n\\nDID YOU LEAVE THE MONEY \");\n    get_input(reply);\n    while (!paid) {\n        if (strings_match(reply, \"YES\")) {\n            printf(\"HEY, %s??? YOU LEFT NO MONEY AT ALL!\\n\", name);\n            printf(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\\n\");\n            printf(\"\\nWHAT A RIP OFF, %s!!!\\n\", name);\n            printf(\"TAKE A WALK, %s.\\n\\n\", name);\n            paid = TRUE;\n        }\n        else if (strings_match(reply, \"NO\")) {\n            printf(\"THAT'S HONEST, %s, BUT HOW DO YOU EXPECT \"\n                \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS \"\n                \"DON'T PAY THEIR BILLS?\\n\\n\", name);\n            printf(\"NICE MEETING YOU, %s, HAVE A NICE DAY.\\n\", name);\n                paid = TRUE;\n        }\n        else {\n            printf(\"YOUR ANSWER OF '%s' CONFUSES ME, %s.\\n\", reply, name);\n            printf(\"PLEASE RESPOND WITH 'YES' OR 'NO'.\\n\");\n        }\n    }\n}\n\n\nvoid tab(int number_of_spaces) {\n    for (int i=0; i < number_of_spaces; i++)\n        putchar(' ');\n}\n\n\nvoid get_input(char *input_buffer) {\n    fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin);\n    input_buffer[strcspn(input_buffer, \"\\n\")] = '\\0';     // trim the trailing line break\n}\n\n\nint strings_match(char *string1, char *string2) {\n    if (strncasecmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0)\n        return FALSE;\n    else // strings match, at least within maximum input line length\n        return TRUE;\n}\n\n\n"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hello.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hello\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/MiniScript/hello.ms",
    "content": "print \" \"*33 + \"Hello\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"Hello.  My name is Creative Computer.\"\nprint\nprint\nns = input(\"What's your name? \")\nprint\nprint \"Hi there, \" + ns + \", are you enjoying yourself here?\"\nwhile true\n\tbs = input.lower\n\tprint\n\tif bs == \"yes\" then\n\t\tprint \"I'm glad to hear that, \" + ns + \".\"\n\t\tprint\n\t\tbreak\n\telse if bs == \"no\" then\n\t\tprint \"Oh, I'm sorry to hear that, \" + ns + \". Maybe we can\"\n\t\tprint \"brighten up your visit a bit.\"\n\t\tbreak\n\telse\n\t\tprint \"Please answer 'yes' or 'no'.  Do you like it here?\"\n\tend if\nend while\nprint\nprint \"Say, \" + ns + \", I can solve all kinds of problems except\"\nprint \"those dealing with Greece.  What kind of problems do\"\nprint \"you have (answer sex, health, money, or job)?\"\nwhile true\n\tcs = input\n\tprint\n\tif cs != \"sex\" and cs != \"health\" and cs != \"money\" and cs != \"job\" then\n\t\tprint \"Oh, \" + ns + \", your answer of \" + cs + \" is Greek to me.\"\n\telse if cs == \"job\" then\n\t\tprint \"I can sympathize with you \" + ns + \".  I have to work\"\n\t\tprint \"very long hours for no pay -- and some of my bosses\"\n\t\tprint \"really beat on my keyboard.  My advice to you, \" + ns + \",\"\n\t\tprint \"is to open a retail computer store.  It's great fun.\"\n\telse if cs == \"money\" then\n\t\tprint \"Sorry, \" + ns + \", I'm broke too.  Why don't you sell\"\n\t\tprint \"encyclopeadias or marry someone rich or stop eating\"\n\t\tprint \"so you won't need so much money?\"\n\telse if cs == \"health\" then\n\t\tprint \"My advice to you \" + ns + \" is:\"\n\t\tprint \"     1.  Take two asprin\"\n\t\tprint \"     2.  Drink plenty of fluids (orange juice, not beer!)\"\n\t\tprint \"     3.  Go to bed (alone)\"\n\telse\n\t\tprint \"Is your problem too much or too little?\"\n\t\twhile true\n\t\t\tds = input.lower\n\t\t\tprint\n\t\t\tif ds == \"too much\" then\n\t\t\t\tprint \"You call that a problem?!!  I should have such problems!\"\n\t\t\t\tprint \"If it bothers you, \" + ns + \", take a cold shower.\"\n\t\t\t\tbreak\n\t\t\telse if ds == \"too little\" then\n\t\t\t\tprint \"Why are you here in suffern, \" + ns + \"?  You should be\"\n\t\t\t\tprint \"in Tokyo or New York or Amsterdam or someplace with some\"\n\t\t\t\tprint \"real action.\"\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tprint \"Don't get all shook, \" + ns + \", just answer the question\"\n\t\t\t\tprint \"with 'too much' or 'too little'.  Which is it?\"\n\t\t\tend if\n\t\tend while\n\tend if\n\tprint\n\tprint \"Any more problems you want solved, \" + ns + \"?\"\n\tes = input.lower\n\tprint\n\tif es == \"yes\" then\n\t\tprint \"What kind (sex, money, health, job)?\"\n\telse if es == \"no\" then\n\t\tprint \"That will be $5.00 for the advice, \" + ns + \".\"\n\t\tprint \"Please leave the money on the terminal.\"\n\t\tprint\n\t\twait 2\n\t\tprint\n\t\tprint\n\t\twhile true\n\t\t\tgs = input(\"Did you leave the money? \").lower\n\t\t\tprint\n\t\t\tif gs == \"yes\" then\n\t\t\t\tprint \"Hey, \" + ns + \"??? You left no money at all!\"\n\t\t\t\tprint \"You are cheating me out of my hard-earned living.\"\n\t\t\t\tprint\n\t\t\t\tprint \"What a rip off, \" + ns + \"!!!\"\n\t\t\t\tprint\n\t\t\t\tbreak\n\t\t\telse if gs == \"no\" then\n\t\t\t\tprint \"That's honest, \" + ns + \", but how do you expect\"\n\t\t\t\tprint \"me to go on with my psychology studies if my patient\"\n\t\t\t\tprint \"don't pay their bills?\"\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tprint \"Your answer of '\" + gs + \"' confuses me, \" + ns + \".\"\n\t\t\t\tprint \"Please respond with 'yes' or 'no'.\"\n\t\t\tend if\n\t\tend while\n\t\tbreak\n\tend if\nend while\nprint\nprint \"Take a walk, \" + ns + \".\"\nprint\nprint\n"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/45_Hello/Swift/hello.swift",
    "content": "\nfunc tab(_ number_Of_Spaces: Int) {\n    var spaces = \"\"\n    \n    for _ in 1...number_Of_Spaces {\n        spaces += \" \"\n    }\n    print(spaces, terminator:\"\")\n}\n\n\nfunc get_Input() -> String {\n    let input = readLine()\n    return (input == nil ? \"\" : input!.uppercased())\n}\n\n\nfunc main()\n{\n    var done = false,\n        answered = false,\n        maybe_More = false,\n        paid = false\n    var reply = \"\"\n    var name = \"STRANGER\"\n    \n    tab (33)\n    print(\"HELLO\")\n    tab (15)\n    print(\"CREATIVE COMPUTING   MORRISTOWN, NEW JERSEY\\n\")\n    \n    print(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\")\n    print(\"WHAT'S YOUR NAME? \")\n    let input = readLine()\n    if (input != nil && input != \"\") {\n        name = input!.uppercased()\n    }\n    \n    print(\"\\nHI THERE, \\(name), ARE YOU ENJOYING YOURSELF HERE?\")\n\n    reply = get_Input()\n    while (reply != \"YES\" && reply != \"NO\") {\n        print(\"\\(name), I DON'T UNDERSTAND YOUR ANSWER OF '\\(reply)'.\")\n        print(\"PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE?\")\n        reply = get_Input()\n    }\n    \n    if (reply == \"YES\") {\n        print(\"\\nI'M GLAD TO HEAR THAT, \\(name).\\n\")\n    }\n    else {\n        print(\"\\nOH, I'M SORRY TO HEAR THAT, \\(name). MAYBE WE CAN \"\n            + \"BRIGHTEN UP YOUR VISIT A BIT.\\n\")\n    }\n\n    print(\"SAY, \\(name), I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT \"\n        + \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO \"\n        + \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)?\")\n\n    while (!done) {\n        reply = get_Input()\n        \n        if (reply == \"JOB\") {\n            print(\"\\nI CAN SYMPATHIZE WITH YOU \\(name).   I HAVE TO WORK \"\n                + \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES \"\n                + \"REALLY BEAT ON MY KEYBOARD.    MY ADVICE TO YOU, \\(name), IS TO \"\n                + \"OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\\n\")\n        }\n\n        else if (reply == \"MONEY\") {\n            print(\"\\nSORRY, \\(name), I'M BROKE TOO.  WHY DON'T YOU SELL \"\n                + \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING \"\n                + \"SO YOU WON'T NEED SO MUCH MONEY?\\n\")\n        }\n        \n        else if (reply == \"HEALTH\") {\n            print(\"\\nMY ADVICE TO YOU \\(name) IS:\")\n            print(\"         1.  TAKE TWO ASPRIN\")\n            print(\"         2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\")\n            print(\"         3.  GO TO BED (ALONE)\\n\")\n        }\n        \n        else if (reply == \"SEX\") {\n            print(\"\\nIS YOUR PROBLEM TOO MUCH OR TOO LITTLE?\")\n            \n            answered = false\n            while (!answered) {\n                reply = get_Input()\n                if (reply == \"TOO MUCH\") {\n                    print(\"\\nYOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\")\n                    print(\"IF IT BOTHERS YOU, \\(name), TAKE A COLD SHOWER.\\n\")\n                    answered = true\n                }\n                else if (reply == \"TOO LITTLE\") {\n                    print(\"\\nWHY ARE YOU HERE IN SUFFERN, \\(name)? YOU SHOULD BE \"\n                        + \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME \"\n                        + \"REAL ACTION.\\n\")\n                    answered = true\n                }\n                else {\n                    print(\"\\nDON'T GET ALL SHOOK, \\(name), JUST ANSWER THE QUESTION \"\n                        + \"WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT?\")\n                }\n            }\n        }\n        \n        else {  // not one of the prescribed categories\n            print(\"\\nOH, \\(name), YOUR ANSWER OF '\\(reply)' IS GREEK TO ME.\\n\")\n        }\n        \n        print(\"\\nANY MORE PROBLEMS YOU WANT SOLVED, \\(name)? \")\n        \n        maybe_More = true\n        while (maybe_More) {\n            reply = get_Input()\n            if (reply == \"NO\") {\n                done = true\n                maybe_More = false\n            }\n            else if (reply == \"YES\") {\n                print(\"\\nWHAT KIND (SEX, MONEY, HEALTH, JOB) \")\n                maybe_More = false\n            }\n            else {\n                print(\"\\nJUST A SIMPLE 'YES' OR 'NO' PLEASE, \\(name). \")\n            }\n        } // no further questions\n    } // end of 'not done' loop\n    \n    print(\"\\nTHAT WILL BE $5.00 FOR THE ADVICE, \\(name).\")\n    print(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\")\n    // pause a few seconds\n    print(\"\\n\\n\\nDID YOU LEAVE THE MONEY? \")\n    reply = get_Input()\n    while (!paid) {\n        if (reply == \"YES\") {\n            print(\"\\nHEY, \\(name)??? YOU LEFT NO MONEY AT ALL!\")\n            print(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\\n\")\n            print(\"WHAT A RIP OFF, \\(name)!!!\\n\")\n            print(\"TAKE A WALK, \\(name).\")\n            paid = true\n        }\n        else if (reply == \"NO\") {\n            print(\"THAT'S HONEST, \\(name), BUT HOW DO YOU EXPECT \"\n                + \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS \"\n                + \"DON'T PAY THEIR BILLS?\\n\")\n            print(\"NICE MEETING YOU, \\(name), HAVE A NICE DAY.\")\n                paid = true\n        }\n        else {\n            print(\"YOUR ANSWER OF '\\(reply)' CONFUSES ME, \\(name).\")\n            print(\"PLEASE RESPOND WITH 'YES' OR 'NO'.\")\n        }\n    }\n}\n\nmain()\n"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"os\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\ntype PROBLEM_TYPE int8\r\n\r\nconst (\r\n\tSEX PROBLEM_TYPE = iota\r\n\tHEALTH\r\n\tMONEY\r\n\tJOB\r\n\tUKNOWN\r\n)\r\n\r\nfunc getYesOrNo() (bool, bool, string) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tscanner.Scan()\r\n\r\n\tif strings.ToUpper(scanner.Text()) == \"YES\" {\r\n\t\treturn true, true, scanner.Text()\r\n\t} else if strings.ToUpper(scanner.Text()) == \"NO\" {\r\n\t\treturn true, false, scanner.Text()\r\n\t} else {\r\n\t\treturn false, false, scanner.Text()\r\n\t}\r\n}\r\n\r\nfunc printTntro() {\r\n\tfmt.Println(\"                              HELLO\")\r\n\tfmt.Println(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Print(\"\\n\\n\\n\")\r\n\tfmt.Println(\"HELLO. MY NAME IS CREATIVE COMPUTER.\")\r\n\tfmt.Println(\"\\nWHAT'S YOUR NAME?\")\r\n}\r\n\r\nfunc askEnjoyQuestion(user string) {\r\n\tfmt.Printf(\"HI THERE %s, ARE YOU ENJOYING YOURSELF HERE?\\n\", user)\r\n\r\n\tfor {\r\n\t\tvalid, value, msg := getYesOrNo()\r\n\r\n\t\tif valid {\r\n\t\t\tif value {\r\n\t\t\t\tfmt.Printf(\"I'M GLAD TO HEAR THAT, %s.\\n\", user)\r\n\t\t\t\tfmt.Println()\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Printf(\"OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN\\n\", user)\r\n\t\t\t\tfmt.Println(\"BRIGHTEN UP YOUR VISIT A BIT.\")\r\n\t\t\t}\r\n\t\t\tbreak\r\n\t\t} else {\r\n\t\t\tfmt.Printf(\"%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\\n\", user, msg)\r\n\t\t\tfmt.Println(\"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE?\")\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc promptForProblems(user string) PROBLEM_TYPE {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\tfmt.Println()\r\n\tfmt.Printf(\"SAY %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\\n\", user)\r\n\tfmt.Println(\"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\")\r\n\tfmt.Println(\"YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB)\")\r\n\tfor {\r\n\t\tscanner.Scan()\r\n\r\n\t\tswitch strings.ToUpper(scanner.Text()) {\r\n\t\tcase \"SEX\":\r\n\t\t\treturn SEX\r\n\t\tcase \"HEALTH\":\r\n\t\t\treturn HEALTH\r\n\t\tcase \"MONEY\":\r\n\t\t\treturn MONEY\r\n\t\tcase \"JOB\":\r\n\t\t\treturn JOB\r\n\t\tdefault:\r\n\t\t\treturn UKNOWN\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc promptTooMuchOrTooLittle() (bool, bool) {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tscanner.Scan()\r\n\r\n\tif strings.ToUpper(scanner.Text()) == \"TOO MUCH\" {\r\n\t\treturn true, true\r\n\t} else if strings.ToUpper(scanner.Text()) == \"TOO LITTLE\" {\r\n\t\treturn true, false\r\n\t} else {\r\n\t\treturn false, false\r\n\t}\r\n}\r\n\r\nfunc solveSexProblem(user string) {\r\n\tfmt.Println(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?\")\r\n\tfor {\r\n\t\tvalid, tooMuch := promptTooMuchOrTooLittle()\r\n\t\tif valid {\r\n\t\t\tif tooMuch {\r\n\t\t\t\tfmt.Println(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\")\r\n\t\t\t\tfmt.Printf(\"IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\\n\", user)\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Printf(\"WHY ARE YOU HERE IN SUFFERN, %s?  YOU SHOULD BE\\n\", user)\r\n\t\t\t\tfmt.Println(\"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\")\r\n\t\t\t\tfmt.Println(\"REAL ACTION.\")\r\n\t\t\t}\r\n\t\t\treturn\r\n\t\t} else {\r\n\t\t\tfmt.Printf(\"DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION\\n\", user)\r\n\t\t\tfmt.Println(\"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT?\")\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc solveHealthProblem(user string) {\r\n\tfmt.Printf(\"MY ADVICE TO YOU %s IS:\\n\", user)\r\n\tfmt.Println(\"     1.  TAKE TWO ASPRIN\")\r\n\tfmt.Println(\"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\")\r\n\tfmt.Println(\"     3.  GO TO BED (ALONE)\")\r\n}\r\n\r\nfunc solveMoneyProblem(user string) {\r\n\tfmt.Printf(\"SORRY, %s, I'M BROKE TOO.  WHY DON'T YOU SELL\\n\", user)\r\n\tfmt.Println(\"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\")\r\n\tfmt.Println(\"SO YOU WON'T NEED SO MUCH MONEY?\")\r\n}\r\n\r\nfunc solveJobProblem(user string) {\r\n\tfmt.Printf(\"I CAN SYMPATHIZE WITH YOU %s.  I HAVE TO WORK\\n\", user)\r\n\tfmt.Println(\"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\")\r\n\tfmt.Printf(\"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, %s,\\n\", user)\r\n\tfmt.Println(\"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\")\r\n}\r\n\r\nfunc askQuestionLoop(user string) {\r\n\tfor {\r\n\t\tproblem := promptForProblems(user)\r\n\r\n\t\tswitch problem {\r\n\t\tcase SEX:\r\n\t\t\tsolveSexProblem(user)\r\n\t\tcase HEALTH:\r\n\t\t\tsolveHealthProblem(user)\r\n\t\tcase MONEY:\r\n\t\t\tsolveMoneyProblem(user)\r\n\t\tcase JOB:\r\n\t\t\tsolveJobProblem(user)\r\n\t\tcase UKNOWN:\r\n\t\t\tfmt.Printf(\"OH %s, YOUR ANSWER IS GREEK TO ME.\\n\", user)\r\n\t\t}\r\n\r\n\t\tfor {\r\n\t\t\tfmt.Println()\r\n\t\t\tfmt.Printf(\"ANY MORE PROBLEMS YOU WANT SOLVED, %s?\\n\", user)\r\n\r\n\t\t\tvalid, value, _ := getYesOrNo()\r\n\t\t\tif valid {\r\n\t\t\t\tif value {\r\n\t\t\t\t\tfmt.Println(\"WHAT KIND (SEX, MONEY, HEALTH, JOB)\")\r\n\t\t\t\t\tbreak\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfmt.Printf(\"JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s\\n\", user)\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc goodbyeUnhappy(user string) {\r\n\tfmt.Println()\r\n\tfmt.Printf(\"TAKE A WALK, %s.\\n\", user)\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n}\r\n\r\nfunc goodbyeHappy(user string) {\r\n\tfmt.Printf(\"NICE MEETING YOU %s, HAVE A NICE DAY.\\n\", user)\r\n}\r\n\r\nfunc askForFee(user string) {\r\n\tfmt.Println()\r\n\tfmt.Printf(\"THAT WILL BE $5.00 FOR THE ADVICE, %s.\\n\", user)\r\n\tfmt.Println(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\")\r\n\ttime.Sleep(4 * time.Second)\r\n\tfmt.Print(\"\\n\\n\\n\")\r\n\tfmt.Println(\"DID YOU LEAVE THE MONEY?\")\r\n\r\n\tfor {\r\n\t\tvalid, value, msg := getYesOrNo()\r\n\t\tif valid {\r\n\t\t\tif value {\r\n\t\t\t\tfmt.Printf(\"HEY, %s, YOU LEFT NO MONEY AT ALL!\\n\", user)\r\n\t\t\t\tfmt.Println(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\")\r\n\t\t\t\tfmt.Println()\r\n\t\t\t\tfmt.Printf(\"WHAT A RIP OFF, %s!!!\\n\", user)\r\n\t\t\t\tfmt.Println()\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Printf(\"THAT'S HONEST, %s, BUT HOW DO YOU EXPECT\\n\", user)\r\n\t\t\t\tfmt.Println(\"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\")\r\n\t\t\t\tfmt.Println(\"DON'T PAY THEIR BILLS?\")\r\n\t\t\t}\r\n\t\t\treturn\r\n\t\t} else {\r\n\t\t\tfmt.Printf(\"YOUR ANSWER OF '%s' CONFUSES ME, %s.\\n\", msg, user)\r\n\t\t\tfmt.Println(\"PLEASE RESPOND WITH 'YES' or 'NO'.\")\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunc main() {\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tprintTntro()\r\n\tscanner.Scan()\r\n\tuserName := scanner.Text()\r\n\tfmt.Println()\r\n\r\n\taskEnjoyQuestion(userName)\r\n\r\n\taskQuestionLoop(userName)\r\n\r\n\taskForFee(userName)\r\n\r\n\tif false {\r\n\t\tgoodbyeHappy(userName) // unreachable\r\n\t} else {\r\n\t\tgoodbyeUnhappy(userName)\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/hello.bas",
    "content": "2 PRINT TAB(33);\"HELLO\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 PRINT \"HELLO.  MY NAME IS CREATIVE COMPUTER.\"\n20 PRINT: PRINT: INPUT \"WHAT'S YOUR NAME\";N$: PRINT\n30 PRINT \"HI THERE, \";N$;\", ARE YOU ENJOYING YOURSELF HERE\";\n40 INPUT B$: PRINT\n50 IF B$=\"YES\" THEN 70\n55 IF B$=\"NO\" THEN 80\n60 PRINT N$;\", I DON'T UNDERSTAND YOUR ANSWER OF '\";B$;\"'.\"\n65 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE\";: GOTO 40\n70 PRINT \"I'M GLAD TO HEAR THAT, \";N$;\".\": PRINT\n75 GOTO 100\n80 PRINT \"OH, I'M SORRY TO HEAR THAT, \";N$;\". MAYBE WE CAN\"\n85 PRINT \"BRIGHTEN UP YOUR VISIT A BIT.\"\n100 PRINT\n105 PRINT \"SAY, \";N$;\", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\"\n110 PRINT \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\"\n120 PRINT \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)\";\n125 INPUT C$\n126 PRINT\n130 IF C$=\"SEX\" THEN 200\n132 IF C$=\"HEALTH\" THEN 180\n134 IF C$=\"MONEY\" THEN 160\n136 IF C$=\"JOB\" THEN 145\n138 PRINT \"OH, \";N$;\", YOUR ANSWER OF \";C$;\" IS GREEK TO ME.\"\n140 GOTO 250\n145 PRINT \"I CAN SYMPATHIZE WITH YOU \";N$;\".  I HAVE TO WORK\"\n148 PRINT \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\"\n150 PRINT \"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, \";N$;\",\"\n153 PRINT \"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\"\n155 GOTO 250\n160 PRINT \"SORRY, \";N$;\", I'M BROKE TOO.  WHY DON'T YOU SELL\"\n162 PRINT \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\"\n164 PRINT \"SO YOU WON'T NEED SO MUCH MONEY?\"\n170 GOTO 250\n180 PRINT \"MY ADVICE TO YOU \";N$;\" IS:\"\n185 PRINT \"     1.  TAKE TWO ASPRIN\"\n188 PRINT \"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\"\n190 PRINT \"     3.  GO TO BED (ALONE)\"\n195 GOTO 250\n200 INPUT \"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE\";D$: PRINT\n210 IF D$=\"TOO MUCH\" THEN 220\n212 IF D$=\"TOO LITTLE\" THEN 230\n215 PRINT \"DON'T GET ALL SHOOK, \";N$;\", JUST ANSWER THE QUESTION\"\n217 INPUT \"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT\";D$:GOTO 210\n220 PRINT \"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\"\n225 PRINT \"IF IT BOTHERS YOU, \";N$;\", TAKE A COLD SHOWER.\"\n228 GOTO 250\n230 PRINT \"WHY ARE YOU HERE IN SUFFERN, \";N$;\"?  YOU SHOULD BE\"\n235 PRINT \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\"\n240 PRINT \"REAL ACTION.\"\n250 PRINT\n255 PRINT \"ANY MORE PROBLEMS YOU WANT SOLVED, \";N$;\n260 INPUT E$: PRINT\n270 IF E$=\"YES\" THEN 280\n273 IF E$=\"NO\" THEN 300\n275 PRINT \"JUST A SIMPLE 'YES' OR 'NO' PLEASE, \";N$;\".\"\n277 GOTO 255\n280 PRINT \"WHAT KIND (SEX, MONEY, HEALTH, JOB)\";\n282 GOTO 125\n300 PRINT\n302 PRINT \"THAT WILL BE $5.00 FOR THE ADVICE, \";N$;\".\"\n305 PRINT \"PLEASE LEAVE THE MONEY ON THE TERMINAL.\"\n307 FOR I=1 TO 2000: NEXT I\n310 PRINT: PRINT: PRINT\n315 PRINT \"DID YOU LEAVE THE MONEY\";\n320 INPUT G$: PRINT\n325 IF G$=\"YES\" THEN 350\n330 IF G$=\"NO\" THEN 370\n335 PRINT \"YOUR ANSWER OF '\";G$;\"' CONFUSES ME, \";N$;\".\"\n340 PRINT \"PLEASE RESPOND WITH 'YES' OR 'NO'.\": GOTO 315\n350 PRINT \"HEY, \";N$;\"??? YOU LEFT NO MONEY AT ALL!\"\n355 PRINT \"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\"\n360 PRINT:PRINT \"WHAT A RIP OFF, \";N$;\"!!!\":PRINT\n365 GOTO 385\n370 PRINT \"THAT'S HONEST, \";N$;\", BUT HOW DO YOU EXPECT\"\n375 PRINT \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\"\n380 PRINT \"DON'T PAY THEIR BILLS?\"\n385 PRINT:PRINT \"TAKE A WALK, \";N$;\".\":PRINT:PRINT:GOTO 999\n390 PRINT \"NICE MEETING YOU, \";N$;\", HAVE A NICE DAY.\"\n400 REM\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/45_Hello/hello.c",
    "content": "#include <stdio.h>\n#include <string.h>\n\n#define TRUE 1\n#define FALSE 0\n#define MAX_INPUT_LENGTH 80\n\nvoid tab(int number_of_spaces);\nvoid get_input(char *input_buffer);\nint strings_match(char *string1, char *string2);\n\nint main() {\n   int done = FALSE;\n   int paid = FALSE;\n   int maybe_more, sure;\n   \n   char name[MAX_INPUT_LENGTH];\n   char reply[MAX_INPUT_LENGTH];\n   \n   tab(33);\n   printf(\"HELLO\\n\");\n   tab(15);\n   printf(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n   printf(\"\\n\\n\\n\");\n   printf(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\");\n   printf(\"\\n\\nWHAT'S YOUR NAME \");\n   get_input(name);\n   printf(\"\\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE \", name);\n\n   get_input(reply);\n   while (!strings_match(reply, \"YES\") && !strings_match(reply, \"NO\")) {\n      printf(\"%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\\n\", name, reply);\n      printf(\"PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE \");\n      get_input(reply);  \n   }\n   \n   if (strings_match(reply, \"YES\")) {\n      printf(\"I'M GLAD TO HEAR THAT, %s.\\n\", name);\n   }\n   else {\n      printf(\"OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN \"\n         \"BRIGHTEN UP YOUR VISIT A BIT.\\n\", name);\n   }\n\n   printf(\"\\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT \"\n      \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO \"\n      \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) \", name);\n\n   while (!done) {\n      get_input(reply);\n      \n      if (strings_match(reply, \"JOB\")) {\n         printf(\"I CAN SYMPATHIZE WITH YOU %s.  I HAVE TO WORK \"\n            \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES \"\n            \"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, %s, IS TO \"\n            \"OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\\n\\n\", name, name);\n      }\n\n      else if (strings_match(reply, \"MONEY\")) {\n         printf(\"SORRY, %s, I'M BROKE TOO.  WHY DON'T YOU SELL \"\n            \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING \"\n            \"SO YOU WON'T NEED SO MUCH MONEY?\\n\\n\", name);\n      }\n      \n      else if (strings_match(reply, \"HEALTH\")) {\n         printf(\"MY ADVICE TO YOU %s IS:\\n\", name);\n         printf(\"     1.  TAKE TWO ASPRIN\\n\");\n         printf(\"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\\n\");\n         printf(\"     3.  GO TO BED (ALONE)\\n\\n\");\n      }\n      \n      else if (strings_match(reply, \"SEX\")) {\n         printf(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE \");\n         \n         sure = FALSE;\n         while (!sure) {\n\t\t\t get_input(reply);\n\t\t\t if (strings_match(reply, \"TOO MUCH\")) {\n\t\t\t\tprintf(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\\n\");\n\t\t\t\tprintf(\"IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\\n\\n\", name);\n\t\t\t\tsure = TRUE;\n\t\t\t }\n\t\t\t else if (strings_match(reply, \"TOO LITTLE\")) {\n\t\t\t\tprintf(\"WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE \"\n\t\t\t\t   \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME \"\n\t\t\t\t   \"REAL ACTION.\\n\\n\", name);\n\t\t\t\tsure = TRUE;\n\t\t\t }\n\t\t\t else {\n\t\t\t\tprintf(\"DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION \"\n\t\t\t\t\"WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT \", name);\n\t\t\t }\n\t\t  }\n      }\n      \n      else {  // not one of the prescribed categories\n         printf(\"OH, %s, YOUR ANSWER OF '%s' IS GREEK TO ME.\\n\\n\", name, reply);\n      }\n      \n      printf(\"ANY MORE PROBLEMS YOU WANT SOLVED, %s \", name);\n      \n      maybe_more = TRUE;\n      while (maybe_more) {\n         get_input(reply);\n         if (strings_match(reply, \"NO\")) {\n            done = TRUE;\n            maybe_more = FALSE;\n         }\n         else if (strings_match(reply, \"YES\")) {\n            printf(\"WHAT KIND (SEX, MONEY, HEALTH, JOB) \");\n            maybe_more = FALSE;\n         }\n         else {\n            printf(\"JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s. \", name);\n         }\n      } // no further questions\n   } // end of 'not done' loop\n   \n   printf(\"\\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\\n\", name);\n   printf(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\\n\");\n   // pause a few seconds\n   printf(\"\\n\\n\\nDID YOU LEAVE THE MONEY \");\n   get_input(reply);\n   while (!paid) {\n      if (strings_match(reply, \"YES\")) {\n         printf(\"HEY, %s??? YOU LEFT NO MONEY AT ALL!\\n\", name);\n         printf(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\\n\");\n         printf(\"\\nWHAT A RIP OFF, %s!!!\\n\", name);\n         printf(\"TAKE A WALK, %s.\\n\\n\", name);\n         paid = TRUE;\n      }\n      else if (strings_match(reply, \"NO\")) {\n         printf(\"THAT'S HONEST, %s, BUT HOW DO YOU EXPECT \"\n            \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS \"\n            \"DON'T PAY THEIR BILLS?\\n\\n\", name);\n         printf(\"NICE MEETING YOU, %s, HAVE A NICE DAY.\\n\", name);\n            paid = TRUE;\n      }\n      else {\n         printf(\"YOUR ANSWER OF '%s' CONFUSES ME, %s.\\n\", reply, name);\n         printf(\"PLEASE RESPOND WITH 'YES' OR 'NO'.\\n\");\n      }\n   }\n}\n\n\nvoid tab(int number_of_spaces) {\n   for (int i=0; i < number_of_spaces; i++)\n      putchar(' ');\n}\n\n\nvoid get_input(char *input_buffer) {\n   fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin);\n   input_buffer[strcspn(input_buffer, \"\\n\")] = '\\0';    // trim the trailing line break\n}\n\n\nint strings_match(char *string1, char *string2) {\n\tif (strncmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0)\n\t   return FALSE;\n\telse // strings do not match within maximum input line length\n\t   return TRUE;\n}\n"
  },
  {
    "path": "00_Alternate_Languages/46_Hexapawn/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hexapawn.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hexapawn\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms",
    "content": "print \" \"*32 + \"Hexapawn\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\n//  Hexapawn:  interpretation of hexapawn game as presented in\n//  Martin Gardner's \"The Unexpected Hanging and Other Mathematic-\n//  al Diversions\", chapter eight:  A Matchbox Game-Learning Machine\n//  Original version for H-P timeshare system by reversed.A. Kaapke 5/5/76\n//  Instructions by jeff dalton\n//  Conversion to MITS BASIC by Steve North\n//\tConversion to MiniScript by Joe Strout\n\n// All 19 possible board positions:\nba = [null,\n          [null,-1,-1,-1,1,0,0,0,1,1],\n          [null,-1,-1,-1,0,1,0,1,0,1],\n          [null,-1,0,-1,-1,1,0,0,0,1],\n          [null,0,-1,-1,1,-1,0,0,0,1],\n          [null,-1,0,-1,1,1,0,0,1,0],\n          [null,-1,-1,0,1,0,1,0,0,1],\n          [null,0,-1,-1,0,-1,1,1,0,0],\n          [null,0,-1,-1,-1,1,1,1,0,0],\n          [null,-1,0,-1,-1,0,1,0,1,0],\n          [null,0,-1,-1,0,1,0,0,0,1],\n          [null,0,-1,-1,0,1,0,1,0,0],\n          [null,-1,0,-1,1,0,0,0,0,1],\n          [null,0,0,-1,-1,-1,1,0,0,0],\n          [null,-1,0,0,1,1,1,0,0,0],\n          [null,0,-1,0,-1,1,1,0,0,0],\n          [null,-1,0,0,-1,-1,1,0,0,0],\n          [null,0,0,-1,-1,1,0,0,0,0],\n          [null,0,-1,0,1,-1,0,0,0,0],\n          [null,-1,0,0,-1,1,0,0,0,0]]\n          \n// Possible responses for each board position (move from x to y,\n// represented as x*10 + y):\nma = [null,\n          [null,24,25,36,0],\n          [null,14,15,36,0],\n          [null,15,35,36,47],\n          [null,36,58,59,0],\n          [null,15,35,36,0],\n          [null,24,25,26,0],\n          [null,26,57,58,0],\n          [null,26,35,0,0],\n          [null,47,48,0,0],\n          [null,35,36,0,0],\n          [null,35,36,0,0],\n          [null,36,0,0,0],\n          [null,47,58,0,0],\n          [null,15,0,0,0],\n          [null,26,47,0,0],\n          [null,47,58,0,0],\n          [null,35,36,47,0],\n          [null,28,58,0,0],\n          [null,15,47,0,0]]\ns = [0]*10\nt = [0]*10\n\nshowBoard = function\n    print\n    for i in [1,2,3]\n        print \" \"*10, \"\"\n        for j in [1,2,3]\n            print \"X.O\"[s[(i - 1) * 3 + j] + 1], \"\"\n        end for\n        print\n    end for\nend function\n\nmirror = function(x)\n\treturn [null, 3,2,1, 6,5,4, 9,8,7][x]\nend function\n\nmirrorBoard = function(b)\n\treturn [null, b[3],b[2],b[1], b[6],b[5],b[4], b[9],b[8],b[7]]\nend function\n\nintro = function\n\twhile true\n\t\ts = input(\"Instructions (Y-N)? \").lower\n\t\tif s then s = s[0]\n\t\tif s == \"n\" then return\n\t\tif s == \"y\" then break\n\tend while\n\tprint\n\tprint \"This program plays the game of Hexapawn.\"\n\tprint \"Hexapawn is played with Chess pawns on a 3 by 3 board.\"\n\tprint \"The pawns are moved as in Chess - one space forward to\"\n\tprint \"an empty space or one space forward and diagonally to\"\n\tprint \"capture an opposing man.  On the board, your pawns\"\n\tprint \"are 'O', the computer's pawns are 'X', and empty \"\n\tprint \"squares are '.'.  To enter a move, type the number of\"\n\tprint \"the square you are moving from, followed by the number\"\n\tprint \"of the square you will move to.  The numbers must be\"\n\tprint \"seperated by a comma.\"\n\tprint\n\tinput \"(Press Return.)\"\n\tprint\n\tprint \"The computer starts a series of games knowing only when\"\n\tprint \"the game is won (a draw is impossible) and how to move.\"\n\tprint \"It has no strategy at first and just moves randomly.\"\n\tprint \"However, it learns from each game.  Thus, winning becomes\"\n\tprint \"more and more difficult.  Also, to help offset your\"\n\tprint \"initial advantage, you will not be told how to win the\"\n\tprint \"game but must learn this by playing.\"\n\tprint\n\tprint \"The numbering of the board is as follows:\"\n\tprint \" \"*10 + \"123\"\n\tprint \" \"*10 + \"456\"\n\tprint \" \"*10 + \"789\"\n\tprint\n\tprint \"For example, to move your rightmost pawn forward,\"\n\tprint \"you would type 9,6 in response to the question\"\n\tprint \"'Your move?'.  Since I'm a good sport, you'll always\"\n\tprint \"go first.\"\n\tprint\nend function\t\n\ngetMove = function\n\twhile true\n\t\tinp = input(\"Your move? \").replace(\",\", \" \").split\n\t\tif inp.len > 1 then\n\t\t\tm1 = inp[0].val\n\t\t\tm2 = inp[-1].val\n\t\t\tif 0 < m1 < 10 and 0 < m2 < 10 then\n\t\t\t\tif s[m1] != 1 or s[m2] == 1 or \n\t\t\t\t  (m2 - m1 != -3 and s[m2] != -1) or \n\t\t\t\t  (m2 > m1) or (m2 - m1 == -3 and s[m2] != 0) or \n\t\t\t\t  (m2 - m1 < -4) or (m1 == 7 and m2 == 3) then\n\t\t\t\t\tprint \"Illegal move.\"\n\t\t\t\t\tcontinue\n\t\t\t\tend if\n\t\t\t\treturn [m1, m2]\n\t\t\tend if\n\t\tend if\n\t\tprint \"Illegal co-ordinates.\"\n\tend while\nend function\n\n// Find the current board number (1-19) and whether it is mirrored.\nfindBoardNum = function\n\tidx = ba.indexOf(s)\n\tif idx != null then return [idx, false]\n\tidx = ba.indexOf(mirrorBoard(s))\n\tif idx != null then return [idx, true]\n\treturn null\nend function\n\n// Main program\nintro\nwins = 0\nlosses = 0\nwhile true\n\ts = [null, -1,-1,-1, 0,0,0, 1,1,1]\n\tcomputerWins = false\n\tshowBoard\n\twhile true\n\t\t// Input player's move\n\t\tuserMove = getMove\n\t\tm1 = userMove[0]; m2 = userMove[1]\n\n\t\t// Move player's pawn\n\t\ts[m1] = 0\n\t\ts[m2] = 1\n\t\tshowBoard\n\n\t\t// If no computer pawns, or player reached top, then computer loses\n\t\tif s.indexOf(-1) == null or s[1] == 1 or s[2] == 1 or s[3] == 1 then\n\t\t\tbreak\n\t\tend if\n\t\t// Ensure at least one computer pawn with valid move.\n\t\t// (Note: original BASIC code for this had several bugs; the code\n\t\t// below should be more correct.)\n\t\tanyValidMove = false\n\t\tfor i in range(1, 6)\t// (no sense checking position 7-9)\n\t\t\tif s[i] != -1 then continue\n\t\t\t// check for a straight-ahead move\n\t\t\tif s[i + 3] == 0 then anyValidMove = true\n\t\t\t// check for a capture\n\t\t\tif i == 2 or i == 5 then\n\t\t\t\tif s[i+2] == 1 or s[i+4] == 1 then anyValidMove = true\n\t\t\telse if i == 1 or i == 4 then\n\t\t\t\tif s[i+4] == 1 then anyValidMove = true\n\t\t\telse\n\t\t\t\tif s[i+2] == 1 then anyValidMove = true\n\t\t\tend if\n\t\tend for\n\t\tif not anyValidMove then break\n\t\t\n\t\tboardAndReversed = findBoardNum\n\t\tif boardAndReversed == null then\n\t\t\tprint \"Illegal board pattern\"\t// (should never happen in normal play)\n\t\t\tbreak\n\t\tend if\n\t\tx = boardAndReversed[0]; reversed = boardAndReversed[1]\n\n\t\t// Select a random move for board X, as permitted by our memory\n\t\tpossibilities = []\n\t\tfor i in range(1, 4)\n\t\t\tif ma[x][i] != 0 then possibilities.push i\n\t\tend for\n\n\t\t// For more insight into how the computer learns, uncomment this line:\n\t\t//print \"Considering for board \" + x + \": \" + possibilities + \" (reversed=\" + reversed + \")\"\n\t\tif not possibilities then\n\t\t\tprint \"I resign.\"\n\t\t\tbreak\n\t\tend if\n\t\tpossibilities.shuffle\n\t\ty = possibilities[0]\n\t\t\n\t\tm1 = floor(ma[x][y] / 10)\n\t\tm2 = ma[x][y] % 10\n\t\tif reversed then\n\t\t\tm1 = mirror(m1)\n\t\t\tm2 = mirror(m2)\n\t\tend if\n\t\t\n\t\t// Announce move\n\t\tprint \"I move from \" + m1 + \" to \" + m2\n\t\ts[m1] = 0\n\t\ts[m2] = -1\n\t\tshowBoard\n\t\t\n\t\t// Finish if computer reaches bottom, or no player pawns are left\n\t\tif s[7] == -1 or s[8] == -1 or s[9] == -1 or s.indexOf(1) == null then\n\t\t\tcomputerWins = true\n\t\t\tbreak\n\t\tend if\n\t\t\n\t\t// Finish if player cannot move\n\t\tplayerCanMove = false\n\t\tfor i in range(1, 9)\n\t\t\tif s[i] != 1 then continue\n\t\t\tif i > 3 and s[i - 3] == 0 then playerCanMove = true\n\t\t\tif mirror(i) != i then\n\t\t\t\tif i >= 7 then\n\t\t\t\t\tif s[5] == -1 then playerCanMove = true\n\t\t\t\telse\n\t\t\t\t\tif s[2] == -1 then playerCanMove = true\n\t\t\t\tend if\n\t\t\telse\n\t\t\t\tif s[i - 2] == -1 or s[i - 4] == -1 then playerCanMove = true\n\t\t\tend if\n\t\tend for\n\t\tif not playerCanMove then\n\t\t\tprint \"You can't move, so \", \"\"\n\t\t\tcomputerWins = true\n\t\t\tbreak\n\t\tend if\n\tend while\n\tif computerWins then\n\t\tprint \"I win.\"\n\t\twins += 1\n\telse \n\t\tprint \"You win\"\n\t\t// Because we lost, clear out the last response used, so that we don't\n\t\t// make the same mistake again.  This is how the computer learns!\n\t\tma[x][y] = 0\n\t\tlosses += 1\n\tend if\n\tprint \"I have won \" + wins + \" and you \" + losses + \" out of \" + (losses + wins) + \" games.\"\n\tprint\n\twait 2\nend while"
  },
  {
    "path": "00_Alternate_Languages/46_Hexapawn/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/46_Hexapawn/hexapawn.bas",
    "content": "1 PRINT TAB(32);\"HEXAPAWN\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 REM  HEXAPAWN:  INTERPRETATION OF HEXAPAWN GAME AS PRESENTED IN\n5 REM  MARTIN GARDNER'S \"THE UNEXPECTED HANGING AND OTHER MATHEMATIC-\n6 REM  AL DIVERSIONS\", CHAPTER EIGHT:  A MATCHBOX GAME-LEARNING MACHINE\n7 REM  ORIGINAL VERSION FOR H-P TIMESHARE SYSTEM BY R.A. KAAPKE 5/5/76\n8 REM  INSTRUCTIONS BY JEFF DALTON\n9 REM  CONVERSION TO MITS BASIC BY STEVE NORTH\n10 DIM B(19,9),M(19,4),S(9),P$(3)\n15 W=0: L=0\n20 DEF FNR(X)=-3*(X=1)-(X=3)-4*(X=6)-6*(X=4)-7*(X=9)-9*(X=7)+FNS(X)\n25 DEF FNS(X)=-X*(X=2 OR X=5 OR X=8)\n30 DEF FNM(Y)=Y-INT(Y/10)*10\n35 P$=\"X.O\"\n40 FOR I=1 TO 19: FOR J=1 TO 9: READ B(I,J): NEXT J: NEXT I\n45 FOR I=1 TO 19: FOR J=1 TO 4: READ M(I,J): NEXT J: NEXT I\n50 PRINT \"INSTRUCTIONS (Y-N)\";\n60 INPUT A$\n70 A$=LEFT$(A$,1)\n80 IF A$=\"Y\" THEN 2000\n90 IF A$<>\"N\" THEN 50\n100 X=0: Y=0\n111 S(4)=0: S(5)=0: S(6)=0\n112 S(1)=-1: S(2)=-1: S(3)=-1\n113 S(7)=1: S(8)=1: S(9)=1\n115 GOSUB 1000\n120 PRINT \"YOUR MOVE\";\n121 INPUT M1,M2\n122 IF M1=INT(M1)AND M2=INT(M2)AND M1>0 AND M1<10 AND M2>0 AND M2<10 THEN 130\n123 PRINT \"ILLEGAL CO-ORDINATES.\"\n124 GOTO 120\n130 IF S(M1)=1 THEN 150\n140 PRINT \"ILLEGAL MOVE.\": GOTO 120\n150 IF S(M2)=1 THEN 140\n160 IF M2-M1<>-3 AND S(M2)<>-1 THEN 140\n170 IF M2>M1 THEN 140\n180 IF M2-M1=-3 AND (S(M2)<>0) THEN 140\n185 IF M2-M1<-4 THEN 140\n186 IF M1=7 AND M2=3 THEN 140\n190 S(M1)=0\n200 S(M2)=1\n205 GOSUB 1000\n210 IF S(1)=1 OR S(2)=1 OR S(3)=1 THEN 820\n220 FOR I=1 TO 9\n221 IF S(I)=-1 THEN 230\n222 NEXT I\n223 GOTO 820\n230 FOR I=1 TO 9\n240 IF S(I)<>-1 THEN 330\n250 IF S(I+3)=0 THEN 350\n260 IF FNR(I)=I THEN 320\n270 IF I>3 THEN 300\n280 IF S(5)=1 THEN 350\n290 GOTO 330\n300 IF S(8)=1 THEN 350\n310 GOTO 330\n320 IF S(I+2)=1 OR S(I+4)=1 THEN 350\n330 NEXT I\n340 GOTO 820\n350 FOR I=1 TO 19\n360 FOR J=1 TO 3\n370 FOR K=3 TO 1 STEP -1\n380 T((J-1)*3+K)=B(I,(J-1)*3+4-K)\n390 NEXT K\n400 NEXT J\n410 FOR J=1 TO 9\n420 IF S(J)<>B(I,J) THEN 460\n430 NEXT J\n440 R=0\n450 GOTO 540\n460 FOR J=1 TO 9\n470 IF S(J)<>T(J) THEN 510\n480 NEXT J\n490 R=1\n500 GOTO 540\n510 NEXT I\n511 REMEMBER THE TERMINATION OF THIS LOOP IS IMPOSSIBLE\n512 PRINT \"ILLEGAL BOARD PATTERN.\"\n530 STOP\n540 X=I\n550 FOR I=1 TO 4\n560 IF M(X,I)<>0 THEN 600\n570 NEXT I\n580 PRINT \"I RESIGN.\"\n590 GOTO 820\n600 Y=INT(RND(1)*4+1)\n601 IF M(X,Y)=0 THEN 600\n610 IF R<>0 THEN 630\n620 PRINT \"I MOVE FROM \";STR$(INT(M(X,Y)/10));\" TO \";STR$(FNM(M(X,Y)))\n622 S(INT(M(X,Y)/10))=0\n623 S(FNM(M(X,Y)))=-1\n624 GOTO 640\n630 PRINT \"I MOVE FROM \";STR$(FNR(INT(M(X,Y)/10)));\" TO \";\n631 PRINT STR$(FNR(FNM(M(X,Y))))\n632 S(FNR(INT(M(X,Y)/10)))=0\n633 S(FNR(FNM(M(X,Y))))=-1\n640 GOSUB 1000\n641 IF S(7)=-1 OR S(8)=-1 OR S(9)=-1 THEN 870\n650 FOR I=1 TO 9\n660 IF S(I)=1 THEN 690\n670 NEXT I\n680 GOTO 870\n690 FOR I=1 TO 9\n700 IF S(I)<>1 THEN 790\n710 IF S(I-3)=0 THEN 120\n720 IF FNR(I)=I THEN 780\n730 IF I<7 THEN 760\n740 IF S(5)=-1 THEN 120\n750 GOTO 790\n760 IF S(2)=-1 THEN 120\n770 GOTO 790\n780 IF S(I-2)=-1 OR S(I-4)=-1 THEN 120\n790 NEXT I\n800 PRINT \"YOU CAN'T MOVE, SO \";\n810 GOTO 870\n820 PRINT \"YOU WIN.\"\n830 M(X,Y)=0\n840 L=L+1\n850 PRINT \"I HAVE WON\";W;\"AND YOU\";L;\"OUT OF\";L+W;\"GAMES.\"\n851 PRINT\n860 GOTO 100\n870 PRINT \"I WIN.\"\n880 W=W+1\n890 GOTO 850\n900 DATA -1,-1,-1,1,0,0,0,1,1,-1,-1,-1,0,1,0,1,0,1\n905 DATA -1,0,-1,-1,1,0,0,0,1,0,-1,-1,1,-1,0,0,0,1\n910 DATA -1,0,-1,1,1,0,0,1,0,-1,-1,0,1,0,1,0,0,1\n915 DATA 0,-1,-1,0,-1,1,1,0,0,0,-1,-1,-1,1,1,1,0,0\n920 DATA -1,0,-1,-1,0,1,0,1,0,0,-1,-1,0,1,0,0,0,1\n925 DATA 0,-1,-1,0,1,0,1,0,0,-1,0,-1,1,0,0,0,0,1\n930 DATA 0,0,-1,-1,-1,1,0,0,0,-1,0,0,1,1,1,0,0,0\n935 DATA 0,-1,0,-1,1,1,0,0,0,-1,0,0,-1,-1,1,0,0,0\n940 DATA 0,0,-1,-1,1,0,0,0,0,0,-1,0,1,-1,0,0,0,0\n945 DATA -1,0,0,-1,1,0,0,0,0\n950 DATA 24,25,36,0,14,15,36,0,15,35,36,47,36,58,59,0\n955 DATA 15,35,36,0,24,25,26,0,26,57,58,0\n960 DATA 26,35,0,0,47,48,0,0,35,36,0,0,35,36,0,0\n965 DATA 36,0,0,0,47,58,0,0,15,0,0,0\n970 DATA 26,47,0,0,47,58,0,0,35,36,47,0,28,58,0,0,15,47,0,0\n1000 PRINT\n1010 FOR I=1 TO 3\n1020 FOR J=1 TO 3\n1030 PRINT TAB(10);MID$(P$,S((I-1)*3+J)+2,1);\n1040 NEXT J\n1050 PRINT\n1060 NEXT I\n1070 PRINT\n1080 RETURN\n2000 PRINT: PRINT \"THIS PROGRAM PLAYS THE GAME OF HEXAPAWN.\"\n2010 PRINT \"HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.\"\n2020 PRINT \"THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO\"\n2030 PRINT \"AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO\"\n2040 PRINT \"CAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS\"\n2050 PRINT \"ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY \"\n2060 PRINT \"SQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF\"\n2070 PRINT \"THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER\"\n2080 PRINT \"OF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE\"\n2090 PRINT \"SEPERATED BY A COMMA.\": PRINT\n2100 PRINT \"THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN\"\n2105 PRINT \"THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE.\"\n2110 PRINT \"IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY.\"\n2120 PRINT \"HOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES\"\n2130 PRINT \"MORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR\"\n2140 PRINT \"INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE\"\n2150 PRINT \"GAME BUT MUST LEARN THIS BY PLAYING.\"\n2160 PRINT: PRINT \"THE NUMBERING OF THE BOARD IS AS FOLLOWS:\"\n2170 PRINT TAB(10);\"123\": PRINT TAB(10);\"456\": PRINT TAB(10);\"789\"\n2180 PRINT: PRINT \"FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,\"\n2190 PRINT \"YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION\"\n2200 PRINT \"'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS\"\n2210 PRINT \"GO FIRST.\": PRINT\n2220 GOTO 100\n9999 END\n"
  },
  {
    "path": "00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of hi-lo.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hi-lo.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hi-lo\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms",
    "content": "print \" \"*34 + \"Hi Lo\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"This is the game of hi lo.\"; print\nprint \"You will have 6 tries to guess the amount of money in the\"\nprint \"hi lo jackpot, which is between 1 and 100 dollars.  If you\"\nprint \"guess the amount, you win all the money in the jackpot!\"\nprint \"Then you get another chance to win more money.  However,\"\nprint \"if you do not guess the amount, the game ends.\"; print\ntotal = 0\nwhile true\n\tguesses=0\n\tprint\n\tnumber=floor(100*rnd)\n\twhile true\n\t\tguess = input(\"Your guess? \").val\n\t\tguesses += 1\n\t\tif guess < number then\n\t\t\tprint \"Your guess is too low.\"\n\t\telse if guess > number then\n\t\t\tprint \"Your guess is too high.\"\n\t\telse\n\t\t\tprint \"Got it!!!!!!!!!!   You win \" + number + \" dollars.\"\n\t\t\ttotal += number\n\t\t\tprint \"Your total winnings are now \" + total + \" dollars.\"\n\t\t\tbreak\n\t\tend if\n\t\tif guesses >= 6 then\n\t\t\tprint \"You blew it...too bad...the number was \" + number\n\t\t\ttotal = 0\n\t\t\tbreak\n\t\tend if\n\tend while\n\n\tprint\n\tyn = input(\"Play again (yes or no)?\").lower\n\tif not yn or yn[0] != \"y\" then break\nend while\n\nprint\nprint \"So long.  Hope you enjoyed yourself!!!\"\n"
  },
  {
    "path": "00_Alternate_Languages/47_Hi-Lo/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/47_Hi-Lo/go/main.go",
    "content": "package main\r\n\r\nimport (\r\n\t\"bufio\"\r\n\t\"fmt\"\r\n\t\"math/rand\"\r\n\t\"os\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\nconst MAX_ATTEMPTS = 6\r\n\r\nfunc printIntro() {\r\n\tfmt.Println(\"HI LO\")\r\n\tfmt.Println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n\tfmt.Println(\"\\n\\n\\nTHIS IS THE GAME OF HI LO.\")\r\n\tfmt.Println(\"\\nYOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\")\r\n\tfmt.Println(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\")\r\n\tfmt.Println(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\")\r\n\tfmt.Println(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\")\r\n\tfmt.Println(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\")\r\n\tfmt.Println()\r\n\tfmt.Println()\r\n}\r\n\r\nfunc main() {\r\n\trand.Seed(time.Now().UnixNano())\r\n\tscanner := bufio.NewScanner(os.Stdin)\r\n\r\n\tprintIntro()\r\n\r\n\ttotalWinnings := 0\r\n\r\n\tfor {\r\n\t\tfmt.Println()\r\n\t\tsecret := rand.Intn(1000) + 1\r\n\r\n\t\tguessedCorrectly := false\r\n\r\n\t\tfor attempt := 0; attempt < MAX_ATTEMPTS; attempt++ {\r\n\t\t\tfmt.Println(\"YOUR GUESS?\")\r\n\t\t\tscanner.Scan()\r\n\t\t\tguess, err := strconv.Atoi(scanner.Text())\r\n\t\t\tif err != nil {\r\n\t\t\t\tfmt.Println(\"INVALID INPUT\")\r\n\t\t\t}\r\n\r\n\t\t\tif guess == secret {\r\n\t\t\t\tfmt.Printf(\"GOT IT!!!!!!!!!!   YOU WIN %d DOLLARS.\\n\", secret)\r\n\t\t\t\tguessedCorrectly = true\r\n\t\t\t\tbreak\r\n\t\t\t} else if guess > secret {\r\n\t\t\t\tfmt.Println(\"YOUR GUESS IS TOO HIGH.\")\r\n\t\t\t} else {\r\n\t\t\t\tfmt.Println(\"YOUR GUESS IS TOO LOW.\")\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif guessedCorrectly {\r\n\t\t\ttotalWinnings += secret\r\n\t\t\tfmt.Printf(\"YOUR TOTAL WINNINGS ARE NOW $%d.\\n\", totalWinnings)\r\n\t\t} else {\r\n\t\t\tfmt.Printf(\"YOU BLEW IT...TOO BAD...THE NUMBER WAS %d\\n\", secret)\r\n\t\t}\r\n\r\n\t\tfmt.Println()\r\n\t\tfmt.Println(\"PLAYAGAIN (YES OR NO)?\")\r\n\t\tscanner.Scan()\r\n\r\n\t\tif strings.ToUpper(scanner.Text())[0:1] != \"Y\" {\r\n\t\t\tbreak\r\n\t\t}\r\n\t}\r\n\tfmt.Println(\"\\nSO LONG.  HOPE YOU ENJOYED YOURSELF!!!\")\r\n}\r\n"
  },
  {
    "path": "00_Alternate_Languages/47_Hi-Lo/hi-lo.bas",
    "content": "10 PRINT TAB(34);\"HI LO\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"THIS IS THE GAME OF HI LO.\":PRINT\n110 PRINT \"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\"\n120 PRINT \"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\"\n130 PRINT \"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\"\n140 PRINT \"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\"\n150 PRINT \"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\":PRINT\n160 R=0\n170 B=0:PRINT\n180 Y=INT(100*RND(1))\n200 PRINT \"YOUR GUESS\";\n210 INPUT A\n220 B=B+1\n230 IF A=Y THEN 300\n240 IF A>Y THEN 270\n250 PRINT \"YOUR GUESS IS TOO LOW.\":GOTO 280\n270 PRINT \"YOUR GUESS IS TOO HIGH.\"\n280 PRINT:IF B<6 THEN 200\n290 PRINT \"YOU BLEW IT...TOO BAD...THE NUMBER WAS\";Y\n295 R=0:GOTO 350\n300 PRINT \"GOT IT!!!!!!!!!!   YOU WIN\";Y;\"DOLLARS.\"\n310 R=R+Y\n320 PRINT \"YOUR TOTAL WINNINGS ARE NOW\";R;\"DOLLARS.\"\n350 PRINT:PRINT \"PLAY AGAIN (YES OR NO)\";\n360 INPUT A$:IF A$=\"YES\" THEN 170\n380 PRINT:PRINT \"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\"\n390 END\n"
  },
  {
    "path": "00_Alternate_Languages/48_High_IQ/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript highiq.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"highiq\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms",
    "content": "print \" \"*33 + \"H-I-Q\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Here is the board:\"; print\n\nprint \"          !    !    !\"\nprint \"         13   14   15\"; print\nprint \"          !    !    !\"\nprint \"         22   23   24\"; print\nprint \"!    !    !    !    !    !    !\"\nprint \"29   30   31   32   33   34   35\"; print\nprint \"!    !    !    !    !    !    !\"\nprint \"38   39   40   41   42   43   44\"; print\nprint \"!    !    !    !    !    !    !\"\nprint \"47   48   49   50   51   52   53\"; print\nprint \"          !    !    !\"\nprint \"         58   59   60\"; print\nprint \"          !    !    !\"\nprint \"         67   68   69\"; print\nprint \"To save typing time, a compressed version of the game board\"\nprint \"will be used during play.  Refer to the above one for peg\"\ninput \"numbers.  Press Return to begin.\"\nprint\n\n// Prepare the board (t): a 9x9 2D array, with 5 for pins,\n// -5 for invalid (no hole) positions, and 0 for empty holes.\n// Also prepare the pinToPos map, which maps pin numbers to\n// [row, column] positions.\nsetupBoard = function\n\tglobals.t = [[-5]*10]\n\tglobals.pinToPos = {}\n\tpinNums = [13,14,15,22,23,24,29,30,31,32,33,34,35,38,39,40,41,\n\t  42,43,44,47,48,49,50,51,52,53,58,59,60,67,68,69]\n\tfor row in range(1,9)\n\t\tt.push [-5]*10\n\t\tfor col in range(1,9)\n\t\t\tif row < 2 or row > 8 or col < 2 or col > 8 or\n\t\t\t  ((row < 4 or row > 6) and (col < 4 or col > 6)) then\n\t\t\t\tt[row][col] = -5\n\t\t\telse\n\t\t\t\tt[row][col] = 5\n\t\t\t\tpinToPos[pinNums.pull] = [row,col]\n\t\t\tend if\n\t\tend for\n\tend for\n\tt[5][5] = 0\nend function\n\nprintBoard = function\n\tfor x in range(1,9)\n\t\ts = \"\"\n\t\tfor y in range(1,9)\n\t\t\tif t[x][y] < 0 then\n\t\t\t\ts += \"  \"\n\t\t\telse if t[x][y] == 0 then\n\t\t\t\ts += \" o\"\n\t\t\telse\n\t\t\t\ts += \" !\"\n\t\t\tend if\n\t\tend for\n\t\tprint s\n\tend for\nend function\n\nisPin = function(pinNum)\n\tif not pinToPos.hasIndex(pinNum) then return false\n\tpos = pinToPos[pinNum]\n\treturn t[pos[0]][pos[1]] == 5\nend function\n\nisHole = function(pinNum)\n\tif not pinToPos.hasIndex(pinNum) then return false\n\tpos = pinToPos[pinNum]\n\treturn t[pos[0]][pos[1]] == 0\nend function\n\nisValidJump = function(pinFrom, pinTo)\n\tif not pinToPos.hasIndex(pinFrom) then return false\n\tposFrom = pinToPos[pinFrom]\n\tif not isHole(pinTo) then return false\n\tposTo = pinToPos[pinTo]\n\t// check that the Manhattan distance is exactly 2\n\tdist = abs(posFrom[0] - posTo[0]) + abs(posFrom[1] - posTo[1])\n\tif dist != 2 then return false\n\t// and check that the intervening position contains a pin\n\tif t[(posFrom[0]+posTo[0])/2][(posFrom[1]+posTo[1])/2] != 5 then return false\n\treturn true\nend function\n\n// Check if the game is over (player has no legal moves).\n// Return true if over, false if there are legal moves yet.\ncheckGameOver = function\n\tfor row in range(2,8)\n\t\tfor col in range(2,8)\n\t\t\tfromPin = pinToPos.indexOf([row,col])\n\t\t\tif fromPin == null or not isPin(fromPin) then continue\n\t\t\tfor r2 in [row-2, row+2]\n\t\t\t\ttoPin = pinToPos.indexOf([r2,col])\n\t\t\t\tif toPin == null then continue\n\t\t\t\tif isValidJump(fromPin, toPin) then return false\n\t\t\tend for\n\t\t\tfor c2 in [col-2, col+2]\n\t\t\t\ttoPin = pinToPos.indexOf([row,c2])\n\t\t\t\tif toPin == null then continue\n\t\t\t\tif isValidJump(fromPin, toPin) then return false\n\t\t\tend for\n\t\tend for\n\tend for\n\treturn true // no legal moves found, so game over\nend function\n\n// Get the user's move, returning [[fromRow,fromCol], [toRow,toCol]].\n// (Check legality and return only legal moves.)\ngetMove = function\n\tprint\n\twhile true\n\t\tfromNum = input(\"Move which piece? \").val\n\t\tif isPin(fromNum) then toNum = input(\"To where? \").val else toNum = 0\n\t\tif isHole(toNum) and isValidJump(fromNum, toNum) then break\n\t\tprint \"Illegal move, try again...\"\n\tend while\n\treturn [pinToPos[fromNum], pinToPos[toNum]]\t\nend function\n\n// Get the user's move, and update the board accordingly.\ndoOneMove = function\n\tmove = getMove\n\tfromRow = move[0][0]; fromCol = move[0][1]\n\ttoRow = move[1][0];   toCol = move[1][1]\n\tt[fromRow][fromCol] = 0\n\tt[toRow][toCol] = 5\n\tt[(fromRow+toRow)/2][(fromCol+toCol)/2] = 0\nend function\n\n// Main program\nwhile true\n\tsetupBoard\n\tprintBoard\n\twhile true\n\t\tdoOneMove\n\t\tprint\n\t\tprintBoard\n\t\tif checkGameOver then break\n\tend while\n\tprint; print \"The game is over.\"\n\tpinsLeft = 0\n\tfor a in t\n\t\tfor b in a\n\t\t\tif b == 5 then pinsLeft += 1\n\t\tend for\n\tend for\n\tprint \"You had \" + pinsLeft + \" pieces remaining.\"\n\tif pinsLeft == 1 then\n\t\tprint \"Bravo!  You made a perfect score!\"\n\t\tprint \"Save this paper as a record of your accomplishment!\"\n\tend if\n\tprint\n\tyn = input(\"Play again (yes or no)? \").lower\n\tif yn and yn[0] == \"n\" then break\nend while\nprint; print \"So long for now.\"; print\n\n\t"
  },
  {
    "path": "00_Alternate_Languages/48_High_IQ/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/48_High_IQ/highiq.bas",
    "content": "1 PRINT TAB(33);\"H-I-Q\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 DIM B(70),T(9,9)\n5 PRINT \"HERE IS THE BOARD:\": PRINT\n6 PRINT \"          !    !    !\"\n7 PRINT \"         13   14   15\": PRINT\n8 PRINT \"          !    !    !\"\n9 PRINT \"         22   23   24\": PRINT\n10 PRINT \"!    !    !    !    !    !    !\"\n11 PRINT \"29   30   31   32   33   34   35\": PRINT\n12 PRINT \"!    !    !    !    !    !    !\"\n13 PRINT \"38   39   40   41   42   43   44\": PRINT\n14 PRINT \"!    !    !    !    !    !    !\"\n15 PRINT \"47   48   49   50   51   52   53\": PRINT\n16 PRINT \"          !    !    !\"\n17 PRINT \"         58   59   60\": PRINT\n18 PRINT \"          !    !    !\"\n19 PRINT \"         67   68   69\": PRINT\n20 PRINT \"TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\"\n22 PRINT \"WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG\"\n24 PRINT \"NUMBERS.  OK, LET'S BEGIN.\"\n28 REM *** SET UP BOARD\n29 FOR R=1 TO 9\n30 FOR C=1 TO 9\n31 IF (R-4)*(R-5)*(R-6)=0 THEN 40\n32 IF (C-4)*(C-5)*(C-6)=0 THEN 40\n35 T(R,C)=-5\n36 GOTO 50\n40 IF (R-1)*(C-1)*(R-9)*(C-9)=0 THEN 35\n42 T(R,C)=5\n50 NEXT C\n60 NEXT R\n65 T(5,5)=0: GOSUB 500\n70 REM *** INPUT MOVE AND CHECK ON LEGALITY\n75 FOR W=1 TO 33\n77 READ M\n79 DATA 13,14,15,22,23,24,29,30,31,32,33,34,35,38,39,40,41\n81 DATA 42,43,44,47,48,49,50,51,52,53,58,59,60,67,68,69\n83 B(M)=-7: NEXT W\n86 B(41)=-3\n100 INPUT \"MOVE WHICH PIECE\";Z\n110 IF B(Z)=-7 THEN 140\n120 PRINT \"ILLEGAL MOVE, TRY AGAIN...\": GOTO 100\n140 INPUT \"TO WHERE\";P\n150 IF B(P)=0 THEN 120\n153 IF B(P)=-7 THEN 120\n156 IF Z=P THEN 100\n160 IF ((Z+P)/2)=INT((Z+P)/2) THEN 180\n170 GOTO 120\n180 IF (ABS(Z-P)-2)*(ABS(Z-P)-18)<>0 THEN 120\n190 GOSUB 1000\n200 GOSUB 500\n210 GOSUB 1500\n220 GOTO 100\n500 REM *** PRINT BOARD\n510 FOR X=1 TO 9\n520 FOR Y=1 TO 9\n525 IF (X-1)*(X-9)*(Y-1)*(Y-9)=0 THEN 550\n530 IF (X-4)*(X-5)*(X-6)=0 THEN 570\n540 IF (Y-4)*(Y-5)*(Y-6)=0 THEN 570\n550 REM\n560 GOTO 610\n570 IF T(X,Y)<>5 THEN 600\n580 PRINT TAB(Y*2);\"!\";\n590 GOTO 610\n600 PRINT TAB(Y*2);\"O\";\n610 REM\n615 NEXT Y\n620 PRINT\n630 NEXT X\n640 RETURN\n1000 REM *** UPDATE BOARD\n1005 C=1: FOR X=1 TO 9\n1020 FOR Y=1 TO 9\n1030 IF C<>Z THEN 1220\n1040 IF C+2<>P THEN 1080\n1045 IF T(X,Y+1)=0 THEN 120\n1050 T(X,Y+2)=5\n1060 T(X,Y+1)=0: B(C+1)=-3\n1070 GOTO 1200\n1080 IF C+18<>P THEN 1130\n1085 IF T(X+1,Y)=0 THEN 120\n1090 T(X+2,Y)=5: T(X+1,Y)=0: B(C+9)=-3\n1120 GOTO 1200\n1130 IF C-2<>P THEN 1170\n1135 IF T(X,Y-1)=0 THEN 120\n1140 T(X,Y-2)=5: T(X,Y-1)=0: B(C-1)=-3\n1160 GOTO 1200\n1170 IF C-18<>P THEN 1220\n1175 IF T(X-1,Y)=0 THEN 120\n1180 T(X-2,Y)=5: T(X-1,Y)=0: B(C-9)=-3\n1200 B(Z)=-3: B(P)=-7\n1210 T(X,Y)=0: GOTO 1240\n1220 C=C+1\n1225 NEXT Y\n1230 NEXT X\n1240 RETURN\n1500 REM*** CHECK IF GAME IS OVER\n1505 F=0\n1510 FOR R=2 TO 8\n1520 FOR C=2 TO 8\n1530 IF T(R,C)<>5 THEN 1580\n1535 F=F+1\n1540 FOR A=R-1 TO R+1\n1545 T=0\n1550 FOR B=C-1 TO C+1\n1560 T=T+T(A,B)\n1561 NEXT B\n1564 IF T<>10 THEN 1567\n1565 IF T(A,C)<>0 THEN 1630\n1567 NEXT A\n1568 FOR X=C-1 TO C+1\n1569 T=0\n1570 FOR Y=R-1 TO R+1\n1571 T=T+T(Y,X)\n1572 NEXT Y\n1573 IF T<>10 THEN 1575\n1574 IF T(R,X)<>0 THEN 1630\n1575 NEXT X\n1580 NEXT C\n1590 NEXT R\n1600 REM *** GAME IS OVER\n1605 PRINT \"THE GAME IS OVER.\"\n1610 PRINT \"YOU HAD\";F;\"PIECES REMAINING.\"\n1611 IF F<>1 THEN 1615\n1612 PRINT \"BRAVO!  YOU MADE A PERFECT SCORE!\"\n1613 PRINT \"SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!\"\n1615 PRINT: INPUT \"PLAY AGAIN (YES OR NO)\";A$\n1617 IF A$=\"NO\" THEN 2000\n1618 RESTORE: GOTO 28\n1620 STOP\n1630 RETURN\n2000 PRINT: PRINT \"SO LONG FOR NOW.\": PRINT\n2010 END\n"
  },
  {
    "path": "00_Alternate_Languages/49_Hockey/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hockey.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hockey\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms",
    "content": "print \" \"*33 + \"Hockey\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n// ROBERT PUOPOLO ALG. 1 140 MCCOWAN 6/7/73 HOCKEY\n\ngetYesNo = function(prompt)\n\twhile true\n\t\tyn = input(prompt + \"? \").lower\n\t\tif yn and yn[0] == \"y\" then return \"yes\"\n\t\tif yn and yn[0] == \"n\" then return \"no\"\n\t\tprint \"Answer yes or no!!\"\n\tend while\nend function\n\ngetTwoStrings = function(prompt)\n\ts = input(prompt + \"? \").replace(\", \", \",\").split(\",\")\n\tanswer1 = s[0]\n\tif s.len < 2 then\n\t\tanswer2 = input(\"?? \")\n\telse\n\t\tanswer2 = s[1]\n\tend if\n\treturn [answer1, answer2]\nend function\n\ngetNumber = function(prompt, minVal = 1, maxVal = 999)\n\twhile true\n\t\tnum = input(prompt + \"? \").val\n\t\tif minVal <= num <= maxVal then return num\n\tend while\nend function\n\nprintWithTab = function(s)\n\tprint s.replace(\"\\t\", char(9))\nend function\n\nha = [0] * 21\nta = [0] * 6\nt1 = [0] * 6\nt2 = [0] * 6\nt3 = [0] * 6\naNames = [\"\"] * 8\t// Team 1 player names and team name\nbNames = [\"\"] * 8\t// Team 2 player names and team name\nx = 1\nprint; print; print\nif getYesNo(\"Would you like the instructions\") == \"yes\" then\n\tprint\n\tprint \"This is a simulated hockey game.\"\n\tprint \"Question     Response\"\n\tprint \"pass         Type in the number of passes you would\"\n\tprint \"             like to make, from 0 to 3.\"\n\tprint \"shot         Type the number corresponding to the shot\"\n\tprint \"             you want to make.  Enter:\"\n\tprint \"             1 for a slapshot\"\n\tprint \"             2 for a wristshot\"\n\tprint \"             3 for a backhand\"\n\tprint \"             4 for a snap shot\"\n\tprint \"area         Type in the number corresponding to\"\n\tprint \"             the area you are aiming at.  Enter:\"\n\tprint \"             1 for upper left hand corner\"\n\tprint \"             2 for upper right hand corner\"\n\tprint \"             3 for lower left hand corner\"\n\tprint \"             4 for lower right hand corner\"\n\tprint\n\tprint \"At the start of the game, you will be asked for the names\"\n\tprint \"of your players.  They are entered in the order: \"\n\tprint \"left wing, center, right wing, left defense,\"\n\tprint \"right defense, goalkeeper.  Any other input required will\"\n\tprint \"have explanatory instructions.\"\nend if\n\nsetup = function\n\tteamNames = getTwoStrings(\"Enter the two teams\")\n\taNames[7] = teamNames[0]\n\tbNames[7] = teamNames[1]\n\tprint\n\tglobals.roundsInGame = getNumber(\"Enter the number of minutes in a game\")\n\tprint\n\tprint \"Would the \" + aNames[7] + \" coach enter his team\"\n\tprint\n\tfor i in range(1, 6)\n\t\taNames[i] = input(\"Player \" + i + \"? \")\n\tend for\n\tprint\n\tprint \"Would the \" + bNames[7] + \" coach do the same\"\n\tprint\n\tfor t in range(1, 6)\n\t\tbNames[t] = input(\"Player \" + t + \"? \")\n\tend for\n\tprint\n\trs = input(\"Input the referee for this game? \")\n\tprint\n\tprint \" \"*10 + aNames[7] + \" starting lineup\"\n\tfor t in range(1, 6)\n\t\tprint aNames[t]\n\tend for\n\tprint\n\tprint \" \"*10 + bNames[7] + \" starting lineup\"\n\tfor t in range(1, 6)\n\t\tprint bNames[t]\n\tend for\n\tprint\n\tprint \"We're ready for tonights opening face-off.\"\n\tprint rs + \" will drop the puck between \" + aNames[2] + \" and \" + bNames[2]\nend function\n\nshootAndScore = function(shootingTeam, shooter, asst1, asst2, z)\n\twhile true\n\t\tha[20] = floor(100 * rnd) + 1\n\t\tif ha[20] % z != 0 then break\n\t\ta2 = floor(100 * rnd) + 1\n\t\tif a2 % 4 == 0 then\n\t\t\tif shootingTeam == 1 then\n\t\t\t\tprint \"Save \" + bNames[6] + \"  -= 1  rebound\"\n\t\t\telse\n\t\t\t\tprint \"Save \" + aNames[6] + \"  -= 1  follow up\"\n\t\t\tend if\n\t\t\tcontinue\n\t\tend if\n\tend while\n\n\tif shootingTeam == 1 then\n\t\tprint \"Goal \" + aNames[7]\n\t\tha[9] += 1\n\telse\n\t\tprint \"Score \" + bNames[7]\n\t\tha[8] += 1\n\tend if\n\tprint char(7) * 25\n\tprint \"Score: \"\n\tif ha[8] <= ha[9] then\n\t\tprintWithTab aNames[7] + \": \" + ha[9] + \"\\t\" + bNames[7] + \": \" + ha[8]\n\telse\n\t\tprintWithTab bNames[7] + \": \" + ha[8] + \"\\t\" + aNames[7] + \": \" + ha[9]\n\tend if\n\tif shootingTeam == 1 then\n\t\tprint \"Goal scored by: \" + aNames[shooter]\n\t\tif asst1 then\n\t\t\tif asst2 then\n\t\t\t\tprint \" assisted by: \" + aNames[asst1] + \" and \" + aNames[asst2]\n\t\t\telse\n\t\t\t\tprint \" assisted by: \" + aNames[asst1]\n\t\t\tend if\n\t\telse\n\t\t\tprint \" unassisted.\"\n\t\tend if\n\t\tta[shooter] += 1\n\t\tt1[asst1] += 1\n\t\tt1[asst2] += 1\n\telse\n\t\tprint \"Goal scored by: \" + bNames[shooter]\n\t\tif asst1 then\n\t\t\tif asst2 then\n\t\t\t\tprint \" assisted by: \" + bNames[asst1] + \" and \" + bNames[asst2]\n\t\t\telse\n\t\t\t\tprint \" assisted by: \" + bNames[asst1]\n\t\t\tend if\n\t\telse\n\t\t\tprint \" unassisted.\"\n\t\tend if\n\t\tt2[shooter] += 1\n\t\tt3[asst1] += 1\n\t\tt3[asst2] += 1\n\tend if\nend function\n\nshootBlocked = function(shootingTeam, shooter)\n\ts1 = floor(6 * rnd) + 1\n\tif shootingTeam == 1 then\n\t\tif s1 == 1 then\n\t\t\tprint \"Kick save and a beauty by \" + bNames[6]\n\t\t\tprint \"cleared out by \" + bNames[3]\n\t\t\treturn false\n\t\telse if s1 == 2 then\n\t\t\tprint \"what a spectacular glove save by \" + bNames[6]\n\t\t\tprint \"and \" + bNames[6] + \" golfs it into the crowd\"\n\t\telse if s1 == 3 then\n\t\t\tprint \"skate save on a low steamer by \" + bNames[6]\n\t\t\treturn false\n\t\telse if s1 == 4 then\n\t\t\tprint \"pad save by \" + bNames[6] + \" off the stick\"\n\t\t\tprint \"of \" + aNames[shooter] + \" and \" + bNames[6] + \" covers up\"\n\t\telse if s1 == 5 then\n\t\t\tprint \"whistles one over the head of \" + bNames[6]\n\t\t\treturn false\n\t\telse if s1 == 6 then\n\t\t\tprint bNames[6] + \" makes a face save!! and he is hurt\"\n\t\t\tprint \"the defenseman \" + bNames[5] + \" covers up for him\"\n\t\tend if\n\telse\n\t\tif s1 == 1 then\n\t\t\tprint \"stick save by \" + aNames[6] +\"\"\n\t\t\tprint \"and cleared out by \" + aNames[4]\n\t\t\treturn false\n\t\telse if s1 == 2 then\n\t\t\tprint \"Oh my god!! \" + bNames[shooter] + \" rattles one off the post\"\n\t\t\tprint \"to the right of \" + aNames[6] + \" and \" + aNames[6] + \" covers \"\n\t\t\tprint \"on the loose puck!\"\n\t\telse if s1 == 3 then\n\t\t\tprint \"Skate save by \" + aNames[6]\n\t\t\tprint aNames[6] + \" whacks the loose puck into the stands\"\n\t\telse if s1 == 4 then\n\t\t\tprint \"Stick save by \" + aNames[6] + \" and he clears it out himself\"\n\t\t\treturn false\n\t\telse if s1 == 5 then\n\t\t\tprint \"Kicked out by \" + aNames[6]\n\t\t\tprint \"and it rebounds all the way to center ice\"\n\t\t\treturn false\n\t\telse if s1 == 6 then\n\t\t\tprint \"Glove save \" + aNames[6] + \" and he hangs on\"\n\t\tend if\n\tend if\nend function\n\ndoOneRound = function\n\tcontrol = floor(2 * rnd) + 1\n\tif control == 1 then\n\t\tprint aNames[7] + \" has control of the puck\"\n\telse\n\t\tprint bNames[7] + \" has control.\"\n\tend if\n\tp = getNumber(\"Pass\", 0, 3)\n\tfor n in range(1, 3)\n\t\tha[n] = 0\n\tend for\n\twhile true\n\t\tfor j in range(1, p + 2)\n\t\t\tha[j] = floor(5 * rnd) + 1\n\t\tend for\n\t\tif not (ha[j - 1] == ha[j - 2] or (p + 2 >= 3 and (ha[j - 1] == ha[j - 3] or ha[j - 2] == ha[j - 3]))) then break\n\tend while\n\n\tif p == 0 then\n\t\ts = getNumber(\"Shot\", 1, 4)\n\t\tif control == 1 then\n\t\t\tprint aNames[ha[j - 1]], \"\"\n\t\t\tg = ha[j - 1]\n\t\t\tg1 = 0\n\t\t\tg2 = 0\n\t\telse\n\t\t\tprint bNames[ha[j - 1]], \"\"\n\t\t\tg2 = 0\n\t\t\tg2 = 0\n\t\t\tg = ha[j - 1]\n\t\tend if\n\t\tif s == 1 then\n\t\t\tprint \" lets a boomer go from the red line!!\"\n\t\t\tz = 10\n\t\telse if s == 2 then\n\t\t\tprint \" flips a wristshot down the ice\"\n\t\t\t// BUG: missing line 430 in the original caused it to fall through\n\t\t\t// to the s == 3 case.  We'll instead just do:\n\t\t\tz = 2\n\t\telse if s == 3 then\n\t\t\tprint \" backhands one in on the goaltender\"\n\t\t\tz = 25\n\t\telse\n\t\t\tprint \" snaps a long flip shot\"\n\t\t\tz = 17\n\t\tend if\n\telse\n\t\tif control == 1 then\n\t\t\tif p == 1 then\n\t\t\t\tprint aNames[ha[j - 2]] + \" leads \" + aNames[ha[j - 1]] + \" with a perfect pass.\"\n\t\t\t\tprint aNames[ha[j - 1]] + \" cutting in!!!\"\n\t\t\t\tg = ha[j - 1]\n\t\t\t\tg1 = ha[j - 2]\n\t\t\t\tg2 = 0\n\t\t\t\tz1 = 3\n\t\t\telse if p == 2 then\n\t\t\t\tprint aNames[ha[j - 2]] + \" gives to a streaking \" + aNames[ha[j - 1]]\n\t\t\t\tprint aNames[ha[j - 3]] + \" comes down on \" + bNames[5] + \" and \" + bNames[4]\n\t\t\t\tg = ha[j - 3]\n\t\t\t\tg1 = ha[j - 1]\n\t\t\t\tg2 = ha[j - 2]\n\t\t\t\tz1 = 2\n\t\t\telse if p == 3 then\n\t\t\t\tprint \"oh my god!! a ' 4 on 2 ' situation\"\n\t\t\t\tprint aNames[ha[j - 3]] + \" leads \" + aNames[ha[j - 2]]\n\t\t\t\tprint aNames[ha[j - 2]] + \" is wheeling through center.\"\n\t\t\t\tprint aNames[ha[j - 2]] + \" gives and goest with \" + aNames[ha[j - 1]]\n\t\t\t\tprint \"pretty passing!\"\n\t\t\t\tprint aNames[ha[j - 1]] + \" drops it to \" + aNames[ha[j - 4]]\n\t\t\t\tg = ha[j - 4]\n\t\t\t\tg1 = ha[j - 1]\n\t\t\t\tg2 = ha[j - 2]\n\t\t\t\tz1 = 1\n\t\t\tend if\n\t\telse\n\t\t\tif p == 1 then\n\t\t\t\tprint bNames[ha[j - 1]] + \" hits \" + bNames[ha[j - 2]] + \" flying down the left side\"\n\t\t\t\tg = ha[j - 2]\n\t\t\t\tg1 = ha[j - 1]\n\t\t\t\tg2 = 0\n\t\t\t\tz1 = 3\n\t\t\telse if p == 2 then\n\t\t\t\tprint \"it's a ' 3 on 2 '!\"\n\t\t\t\tprint \"only \" + aNames[4] + \" and \" + aNames[5] + \" are back.\"\n\t\t\t\tprint bNames[ha[j - 2]] + \" gives off to \" + bNames[ha[j - 1]]\n\t\t\t\tprint bNames[ha[j - 1]] + \" drops to \" + bNames[ha[j - 3]]\n\t\t\t\tg = ha[j - 3]\n\t\t\t\tg1 = ha[j - 1]\n\t\t\t\tg2 = ha[j - 2]\n\t\t\t\tz1 = 2\n\t\t\telse if p == 3 then\n\t\t\t\tprint \" a '3 on 2 ' with a ' trailer '!\"\n\t\t\t\tprint bNames[ha[j - 4]] + \" gives to \" + bNames[ha[j - 2]] + \" who shuffles it off to\"\n\t\t\t\tprint bNames[ha[j - 1]] + \" who fires a wing to wing pass to \"\n\t\t\t\tprint bNames[ha[j - 3]] + \" aNames he cuts in alone!!\"\n\t\t\t\tg = ha[j - 3]\n\t\t\t\tg1 = ha[j - 1]\n\t\t\t\tg2 = ha[j - 2]\n\t\t\t\tz1 = 1\n\t\t\tend if\n\t\tend if\n\t\ts = getNumber(\"Shot\", 1, 4)\n\t\tif control == 1 then\n\t\t\tprint aNames[g], \"\"\n\t\telse\n\t\t\tprint bNames[g], \"\"\n\t\tend if\n\t\tif s == 1 then\n\t\t\tprint \" lets a big slap shot go!!\"\n\t\t\tz = 4\n\t\t\tz += z1\n\t\telse if s == 2 then\n\t\t\tprint \" rips a wrist shot off\"\n\t\t\tz = 2\n\t\t\tz += z1\n\t\telse if s == 3 then\n\t\t\tprint \" gets a backhand off\"\n\t\t\tz = 3\n\t\t\tz += z1\n\t\telse\n\t\t\tprint \" snaps off a snap shot\"\n\t\t\tz = 2\n\t\t\tz += z1\n\t\tend if\n\tend if\n\t\n\ta = getNumber(\"Area\", 1, 4)\t// area shot in\n\ta1 = floor(4 * rnd) + 1\t\t// area vulnerable\n\t\n\tif control == 1 then\n\t\tglobals.teamAShotsOnNet += 1\n\telse\n\t\tglobals.teamBShotsOnNet += 1\n\tend if\n\tif a == a1 then\n\t\tshootAndScore control, g, g1, g2\n\telse\n\t\tshootBlocked control, g\n\tend if\n\treturn true\nend function\n\n// Main program\nsetup\nteamAShotsOnNet = 0\nteamBShotsOnNet = 0\nfor l in range(1, roundsInGame)\n\twhile not doOneRound; end while\t// (repeat until it returns true)\n\tif l < roundsInGame then print \"And we're ready for the face-off\"\nend for\n\n\n\nprint char(7)*30\nprint \"That's the Siren\"\nprint\nprint \" \"*15 + \"Final Score:\"\nif ha[8] <= ha[9] then\n\tprintWithTab aNames[7] + \": \" + ha[9] + \"\\t\" + bNames[7] + \": \" + ha[8]\nelse\n\tprintWithTab bNames[7] + \": \" + ha[8] + \"\\t\" + aNames[7] + \": \" + ha[9]\nend if\nprint\nprint \" \"*10 + \"Scoring Summary\"\nprint\nprint \" \"*25 + aNames[7]\nprintWithTab \"\\tName\\tGoals\\tAssists\"\nprintWithTab \"\\t -= 1 -= 1\\t -= 1 -= 1-\\t -= 1 -= 1 -= 1-\"\nfor i in range(1, 5)\n\tprintWithTab \"\\t\" + aNames[i] + \"\\t\" + ta[i] + \"\\t\" + t1[i]\nend for\nprint\nprint \" \"*25 + bNames[7]\nprintWithTab \"\\tName\\tGoals\\tAssists\"\nprintWithTab \"\\t -= 1 -= 1\\t -= 1 -= 1-\\t -= 1 -= 1 -= 1-\"\nfor t in range(1, 5)\n\tprintWithTab \"\\t\" + bNames[t] + \"\\t\" + t2[t] + \"\\t\" + t3[t]\nend for\nprint\nprint \"Shots on net\"\nprint aNames[7] + \": \" + teamAShotsOnNet\nprint bNames[7] + \": \" + teamBShotsOnNet\n"
  },
  {
    "path": "00_Alternate_Languages/49_Hockey/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/49_Hockey/hockey.bas",
    "content": "2 PRINT TAB(33);\"HOCKEY\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 REM ROBERT PUOPOLO ALG. 1 140 MCCOWAN 6/7/73 HOCKEY\n30 LET X=1\n40 PRINT:PRINT:PRINT\n50 PRINT \"WOULD YOU LIKE THE INSTRUCTIONS\";:INPUT C$\n55 PRINT\n60 IF C$=\"NO\" THEN 90\n65 IF C$=\"YES\" THEN 80\n70 PRINT \"ANSWER YES OR NO!!\":GOTO 50\n80 GOTO 1720\n90 DIM A$(7),B$(7),H(20),T(5),T1(5),T2(5),T3(5)\n100 PRINT \"ENTER THE TWO TEAMS\";:INPUT A$(7),B$(7)\n105 PRINT\n110 PRINT \"ENTER THE NUMBER OF MINUTES IN A GAME\";:INPUT T6\n115 PRINT\n120 IF T6<1 THEN 110:PRINT\n130 PRINT \"WOULD THE \" A$(7) \" COACH ENTER HIS TEAM\"\n135 PRINT\n140 FOR I=1 TO 6:PRINT \"PLAYER\"I;:INPUT A$(I):NEXT I:PRINT\n150 PRINT \"WOULD THE \" B$(7) \" COACH DO THE SAME\"\n155 PRINT\n160 FOR T=1 TO 6:PRINT \"PLAYER\"T;:INPUT B$(T):NEXT T:PRINT\n170 PRINT \"INPUT THE REFEREE FOR THIS GAME\";:INPUT R$\n180 PRINT:PRINT TAB(10);A$(7) \" STARTING LINEUP\"\n190 FOR T=1 TO 6:PRINT A$(T):NEXT T\n200 PRINT:PRINT TAB(10);B$(7)\" STARTING LINEUP\"\n210 FOR T=1 TO 6:PRINT B$(T):NEXT T:PRINT\n220 PRINT \"WE'RE READY FOR TONIGHTS OPENING FACE-OFF.\"\n230 PRINT R$ \" WILL DROP THE PUCK BETWEEN \" A$(2) \" AND \" B$(2)\n240 FOR L=1 TO T6:IF L=1 THEN 260\n250 PRINT \"AND WE'RE READY FOR THE FACE-OFF\"\n260 C=INT(2*RND(X))+1:ON C GOTO 270,280\n270 PRINT A$(7) \" HAS CONTROL OF THE PUCK\":GOTO 290\n280 PRINT B$(7) \" HAS CONTROL.\"\n290 PRINT \"PASS\";:INPUT P:FOR N=1 TO 3:H(N)=0:NEXT N\n300 IF P<0 THEN 290\n305 IF P>3 THEN 290\n310 FOR J=1 TO (P+2)\n320 H(J)=INT(5*RND(X))+1\n330 NEXT J:IF H(J-1)=H(J-2) THEN 310\n331 IF P+2<3 THEN 350\n335 IF H(J-1)=H(J-3) THEN 310\n340 IF H(J-2)=H(J-3) THEN 310\n350 IF P=0 THEN 360\n355 GOTO 490\n360 INPUT \"SHOT\";S:IF S<1 THEN 360\n365 IF S>4 THEN 360\n370 ON C GOTO 380,480\n380 PRINT A$(H(J-1));:G=H(J-1):G1=0:G2=0\n390 ON S GOTO 400,420,440,460\n400 PRINT \" LET'S A BOOMER GO FROM THE RED LINE!!\"\n410 Z=10:GOTO 890\n420 PRINT \" FLIPS A WRISTSHOT DOWN THE ICE\"\n440 PRINT \" BACKHANDS ONE IN ON THE GOALTENDER\"\n450 Z=25:GOTO 890\n460 PRINT \" SNAPS A LONG FLIP SHOT\"\n470 Z=17:GOTO 890\n480 PRINT B$(H(J-1));:G1=0:G2=0:G=H(J-1):GOTO 390\n490 ON C GOTO 500,640\n500 ON P GOTO 510,540,570\n510 PRINT A$(H(J-2)) \" LEADS \" A$(H(J-1)) \" WITH A PERFECT PASS.\"\n520 PRINT A$(H(J-1)) \" CUTTING IN!!!\"\n530 G=H(J-1):G1=H(J-2):G2=0:Z1=3:GOTO 770\n540 PRINT A$(H(J-2)) \" GIVES TO A STREAKING \" A$(H(J-1))\n550 PRINT A$(H(J-3)) \" COMES DOWN ON \" B$(5) \" AND \" B$(4)\n560 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=2:GOTO 770\n570 PRINT \"OH MY GOD!! A ' 4 ON 2 ' SITUATION\"\n580 PRINT A$(H(J-3)) \" LEADS \" A$(H(J-2))\n590 PRINT A$(H(J-2)) \" IS WHEEELING THROUGH CENTER.\"\n600 PRINT A$(H(J-2)) \" GIVES AND GOES WITH \" A$(H(J-1))\n610 PRINT \"PRETTY PASSING!\"\n620 PRINT A$(H(J-1)) \" DROPS IT TO \" A$(H(J-4))\n630 G=H(J-4):G1=H(J-1):G2=H(J-2):Z1=1:GOTO 770\n640 ON P GOTO 650,670,720\n650 PRINT B$(H(J-1)) \" HITS \" B$(H(J-2)) \" FLYING DOWN THE LEFT SIDE\"\n660 G=H(J-2):G1=H(J-1):G2=0:Z1=3:GOTO 770\n670 PRINT \"IT'S A ' 3 ON 2 '!\"\n680 PRINT \"ONLY \" A$(4) \" AND \" A$(5) \" ARE BACK.\"\n690 PRINT B$(H(J-2)) \" GIVES OFF TO \" B$(H(J-1))\n700 PRINT B$(H(J-1)) \" DROPS TO \" B$(H(J-3))\n710 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=2:GOTO 770\n720 PRINT \" A ' 3 ON 2 ' WITH A ' TRAILER '!\"\n730 PRINT B$(H(J-4)) \" GIVES TO \" B$(H(J-2)) \" WHO SHUFFLES IT OFF TO\"\n740 PRINT B$(H(J-1)) \" WHO FIRES A WING TO WING PASS TO \"\n750 PRINT B$(H(J-3)) \" AS HE CUTS IN ALONE!!\"\n760 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=1:GOTO 770\n770 PRINT \"SHOT\";:INPUT S:IF S>4 THEN 770:IF S<1 THEN 770\n780 ON C GOTO 790,880\n790 PRINT A$(G);:ON S GOTO 800,820,840,860\n800 PRINT \" LET'S A BIG SLAP SHOT GO!!\"\n810 Z=4:Z=Z+Z1:GOTO 890\n820 PRINT \" RIPS A WRIST SHOT OFF\"\n830 Z=2:Z=Z+Z1:GOTO 890\n840 PRINT \" GETS A BACKHAND OFF\"\n850 Z=3:Z=Z+Z1:GOTO 890\n860 PRINT \" SNAPS OFF A SNAP SHOT\"\n870 Z=2:Z=Z+Z1:GOTO 890\n880 PRINT B$(G);:ON S GOTO 800,820,840,860\n890 PRINT \"AREA\";:INPUT A:IF A<1 THEN 890\n895 IF A>4 THEN 890\n900 ON C GOTO 910,920\n910 S2=S2+1:GOTO 930\n920 S3=S3+1\n930 A1=INT(4*RND(X))+1:IF A<>A1 THEN 1200\n940 H(20)=INT(100*RND(X))+1\n950 IF INT(H(20)/Z)=H(20)/Z THEN 1160\n960 ON C GOTO 970,980\n970 PRINT \"GOAL \" A$(7):H(9)=H(9)+1:GOTO 990\n980 PRINT \"SCORE \" B$(7):H(8)=H(8)+1\n990 FOR B1=1 TO 25:PRINT CHR$(7);:NEXT B1:PRINT\n1000 PRINT \"SCORE: \";:IF H(8)>H(9) THEN 1020\n1010 PRINT A$(7)\":\";H(9),B$(7)\":\";H(8):GOTO 1030\n1020 PRINT B$(7)\":\";H(8),A$(7)\":\";H(9)\n1030 ON C GOTO 1040,1100\n1040 PRINT \"GOAL SCORED BY: \" A$(G):IF G1=0 THEN 1070\n1050 IF G2=0 THEN 1080\n1060 PRINT \" ASSISTED BY: \" A$(G1) \" AND \" A$(G2):GOTO 1090\n1070 PRINT \" UNASSISTED.\":GOTO 1090\n1080 PRINT \" ASSISTED BY: \" A$(G1)\n1090 T(G)=T(G)+1:T1(G1)=T1(G1)+1:T1(G2)=T1(G2)+1:GOTO 1540\n1100 PRINT \"GOAL SCORED BY: \" B$(G);\n1110 IF G1=0 THEN 1130\n1115 IF G2=0 THEN 1140\n1120 PRINT \" ASSISTED BY: \" B$(G1) \" AND \" B$(G2):GOTO 1150\n1130 PRINT \" UNASSISTED\":GOTO 1150\n1140 PRINT \" ASSISTED BY: \" B$(G1):GOTO 1150\n1150 T2(G)=T2(G)+1:T3(G1)=T3(G1)+1:T3(G2)=T3(G2)+1:GOTO 1540\n1160 A2=INT(100*RND(X))+1:IF INT(A2/4)=A2/4 THEN 1170\n1165 GOTO 1200\n1170 ON C GOTO 1180,1190\n1180 PRINT \"SAVE \" B$(6) \" --  REBOUND\":GOTO 940\n1190 PRINT \"SAVE \" A$(6) \" --  FOLLOW UP\":GOTO 940\n1200 S1=INT(6*RND(X))+1\n1210 ON C GOTO 1220,1380\n1220 ON S1 GOTO 1230,1260,1290,1300,1330,1350\n1230 PRINT \"KICK SAVE AND A BEAUTY BY \" B$(6)\n1240 PRINT \"CLEARED OUT BY \" B$(3)\n1250 GOTO 260\n1260 PRINT \"WHAT A SPECTACULAR GLOVE SAVE BY \" B$(6)\n1270 PRINT \"AND \" B$(6) \" GOLFS IT INTO THE CROWD\"\n1280 GOTO 1540\n1290 PRINT \"SKATE SAVE ON A LOW STEAMER BY \" B$(6):GOTO 260\n1300 PRINT \"PAD SAVE BY \" B$(6) \" OFF THE STICK\"\n1310 PRINT \"OF \"A$(G) \" AND \" B$(6) \" COVERS UP\"\n1320 GOTO 1540\n1330 PRINT \"WHISTLES ONE OVER THE HEAD OF \" B$(6)\n1340 GOTO 260\n1350 PRINT B$(6) \" MAKES A FACE SAVE!! AND HE IS HURT\"\n1360 PRINT \"THE DEFENSEMAN \" B$(5) \" COVERS UP FOR HIM\"\n1370 GOTO 1540\n1380 ON S1 GOTO 1390,1410,1440,1470,1490,1520\n1390 PRINT \"STICK SAVE BY \" A$(6)\n1400 PRINT \"AND CLEARED OUT BY \" A$(4):GOTO 260\n1410 PRINT \"OH MY GOD!! \" B$(G) \" RATTLES ONE OFF THE POST\"\n1420 PRINT \"TO THE RIGHT OF \" A$(6) \" AND \" A$(6) \" COVERS \";\n1430 PRINT \"ON THE LOOSE PUCK!\":GOTO 1540\n1440 PRINT \"SKATE SAVE BY \" A$(6)\n1450 PRINT A$(6) \" WHACKS THE LOOSE PUCK INTO THE STANDS\"\n1460 GOTO 1540\n1470 PRINT \"STICK SAVE BY \" A$(6) \" AND HE CLEARS IT OUT HIMSELF\"\n1480 GOTO 260\n1490 PRINT \"KICKED OUT BY \" A$(6)\n1500 PRINT \"AND IT REBOUNDS ALL THE WAY TO CENTER ICE\"\n1510 GOTO 260\n1520 PRINT \"GLOVE SAVE \" A$(6) \" AND HE HANGS ON\"\n1530 GOTO 1540\n1540 NEXT L:FOR N=1 TO 30:PRINT CHR$(7);:NEXT N:PRINT \"THAT'S THE SIREN\"\n1550 PRINT:PRINT TAB(15);\"FINAL SCORE:\"\n1560 IF H(8)>H(9) THEN 1580\n1570 PRINT A$(7)\":\";H(9),B$(7)\":\";H(8):GOTO 1590\n1580 PRINT B$(7)\":\";H(8),A$(7)\":\";H(9)\n1590 PRINT: PRINT TAB(10);\"SCORING SUMMARY\":PRINT\n1600 PRINT TAB(25);A$(7)\n1610 PRINT TAB(5);\"NAME\";TAB(20);\"GOALS\";TAB(35);\"ASSISTS\"\n1620 PRINT TAB(5);\"----\";TAB(20);\"-----\";TAB(35);\"-------\"\n1630 FOR I=1 TO 5:PRINT TAB(5);A$(I);TAB(21);T(I);TAB(36);T1(I)\n1640 NEXT I:PRINT\n1650 PRINT TAB(25);B$(7)\n1660 PRINT TAB(5);\"NAME\";TAB(20);\"GOALS\";TAB(35);\"ASSISTS\"\n1670 PRINT TAB(5);\"----\";TAB(20);\"-----\";TAB(35);\"-------\"\n1680 FOR T=1 TO 5:PRINT TAB(5);B$(T);TAB(21);T2(T);TAB(36);T3(T)\n1690 NEXT T:PRINT\n1700 PRINT \"SHOTS ON NET\":PRINT A$(7)\":\";S2:PRINT B$(7)\":\";S3\n1710 END\n1720 PRINT: PRINT \"THIS IS A SIMULATED HOCKEY GAME.\"\n1730 PRINT \"QUESTION     RESPONSE\"\n1740 PRINT \"PASS         TYPE IN THE NUMBER OF PASSES YOU WOULD\"\n1750 PRINT \"             LIKE TO MAKE, FROM 0 TO 3.\"\n1760 PRINT \"SHOT         TYPE THE NUMBER CORRESPONDING TO THE SHOT\"\n1770 PRINT \"             YOU WANT TO MAKE.  ENTER:\"\n1780 PRINT \"             1 FOR A SLAPSHOT\"\n1790 PRINT \"             2 FOR A WRISTSHOT\"\n1800 PRINT \"             3 FOR A BACKHAND\"\n1810 PRINT \"             4 FOR A SNAP SHOT\"\n1820 PRINT \"AREA         TYPE IN THE NUMBER CORRESPONDING TO\"\n1830 PRINT \"             THE AREA YOU ARE AIMING AT.  ENTER:\"\n1840 PRINT \"             1 FOR UPPER LEFT HAND CORNER\"\n1850 PRINT \"             2 FOR UPPER RIGHT HAND CORNER\"\n1860 PRINT \"             3 FOR LOWER LEFT HAND CORNER\"\n1870 PRINT \"             4 FOR LOWER RIGHT HAND CORNER\"\n1880 PRINT\n1890 PRINT \"AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES\"\n1900 PRINT \"OF YOUR PLAYERS.  THEY ARE ENTERED IN THE ORDER: \"\n1910 PRINT \"LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,\"\n1920 PRINT \"RIGHT DEFENSE, GOALKEEPER.  ANY OTHER INPUT REQUIRED WILL\"\n1930 PRINT \"HAVE EXPLANATORY INSTRUCTIONS.\"\n1940 GOTO 90\n1950 END\n"
  },
  {
    "path": "00_Alternate_Languages/50_Horserace/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript horserace.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"horserace\"\n\trun\n```\n\n## Porting Notes\n\n- The original program, designed to be played directly on a printer, drew a track 27 rows long.  To fit better on modern screens, I've shortened the track to 23 rows.  This is adjustable via the \"trackLen\" value assigned on line 72.\n\n- Also because we're playing on a screen instead of a printer, I'm clearing the screen and pausing briefly before each new update of the track.  This is done via the `clear` API when running in Mini Micro, or by using a VT100 escape sequence in other contexts.\n"
  },
  {
    "path": "00_Alternate_Languages/50_Horserace/MiniScript/horserace.ms",
    "content": "print \" \"*31 + \"Horserace\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"Welcome to South Portland High Racetrack\"\nprint \"                      ...owned by Laurie Chevalier\"\n\n// show directions, if wanted\nx = input(\"Do you want directions? \").lower\nif not x or x[0] != \"n\" then\n\tprint \"Up to 10 may play.  A table of odds will be printed.  You\"\n\tprint \"may bet any + amount under 100000 on one horse.\"\n\tprint \"During the race, a horse will be shown by its\"\n\tprint \"number.  The horses race down the paper!\"\n\tprint\nend if\n\n// get player names\nqtyPlayers = input(\"How many want to bet? \").val\nif qtyPlayers < 1 then exit\nprint \"When ? appears, type name\"\nplayerNames = [null]\nfor i in range(1, qtyPlayers)\n\tplayerNames.push input(\"?\")\nend for\nprint\npick = [null] + [0]*qtyPlayers\nbet = [null] + [0]*qtyPlayers\n\nd = [0] * 9\t\t// odds denominator\nr = 0\t\t\t// odds numerator\n\nprintInColumns = function(col0, col1, col2)\n\tprint (col0+\" \"*16)[16] + (col1+\" \"*10)[:10] + (col2+\" \"*10)[:10]\nend function\n\nsetup = function\n\t// initialize the horses\n\tglobals.names = [null] +\n\t  \"Joe Maw,L.B.J.,Mr.Washburn,Miss Karen,Jolly,Horse,Jelly Do Not,Midnight\".split(\",\")\n\tfor i in range(1,8)\n\t\td[i] = floor(10*rnd+1)\n\tend for\n\tglobals.r = d.sum\n\n\t// print odds table\n\tprintInColumns \"Horse\", \"Number\", \"Odds\"\n\tfor i in range(1,8)\n\t\tprintInColumns names[i], i, round(r/d[i],2) + \":1\"\n\tend for\n\n\t// get the players' bets\n\tprint \"--------------------------------------------------\"\n\tprint \"Place your bets...Horse # then Amount\"\n\tfor j in range(1, qtyPlayers)\n\t\twhile true\n\t\t\ts = input(playerNames[j] + \"? \").replace(\",\", \" \").split\n\t\t\tif s.len < 2 then s.push -1\n\t\t\tpick[j] = s[0].val\n\t\t\tbet[j] = s[-1].val\n\t\t\tif pick[j] < 1 or pick[j] > 8 or bet[j] < 1 or bet[j] >=100000 then\n\t\t\t\tprint \"You can't do that!\"\n\t\t\telse\n\t\t\t\tbreak\n\t\t\tend if\n\t\tend while\n\tend for\nend function\n\n// Draw a racetrack, with each horse the given number\n// of lines down from START to FINISH.\ntrackLen = 23\ndrawTrack = function(horsePositions)\n\tprint\n\tif version.hostName == \"Mini Micro\" then clear else print char(27)+\"c\"\n\tif horsePositions[1] == 0 then print \"1 2 3 4 5 6 7 8\" else print\n\tprint \"XXXXSTARTXXXX\"\n\tfor row in range(1, trackLen)\n\t\tfor h in range(1,8)\n\t\t\tp = horsePositions[h]\n\t\t\tif p > trackLen then p = trackLen\n\t\t\tif p == row then print h, \" \"\n\t\tend for\n\t\tprint\n\tend for\n\tprint \"XXXXFINISHXXXX\", \"\"\n\tif version.hostName != \"Mini Micro\" then print\nend function\n\nrunRace = function\n\tpos = [0]*9\n\tmaxPos = 0\n\twhile true\n\t\tdrawTrack pos\n\t\twait 1\n\t\tif maxPos >= trackLen then break\n\t\tfor i in range(1,8)\n\t\t\tq = floor(100*rnd+1)\n\t\t\tx = floor(r/d[i]+0.5)\n\t\t\tif q < 10 then\n\t\t\t\tspeed = 1\n\t\t\telse if q < x+17 then\n\t\t\t\tspeed = 2\n\t\t\telse if q < x+37 then\n\t\t\t\tspeed = 3\n\t\t\telse if q < x+57 then\n\t\t\t\tspeed = 4\n\t\t\telse if q < x+77 then\n\t\t\t\tspeed = 5\n\t\t\telse if q < x+92 then\n\t\t\t\tspeed = 6\n\t\t\telse\n\t\t\t\tspeed = 7\n\t\t\tend if\n\t\t\tpos[i] += speed\n\t\t\tif pos[i] > maxPos then maxPos = pos[i]\n\t\tend for\n\tend while\n\n\tprint\n\tprint \"---------------------------------------------\"\n\tprint\n\tprint \"The race results are:\"\n\tresults = []\n\tfor i in range(1,8)\n\t\tresults.push {\"num\":i, \"pos\":pos[i]}\n\tend for\n\tresults.sort \"pos\", false\n\tfor place in range(1, 8)\n\t\th = results[place-1].num\n\t\tprint \" \" + place + \" Place Horse No. \" + h + \"   at \" + round(r/d[h],2) + \":1\"\n\t\tprint\n\tend for\n\tfor p in range(1, qtyPlayers)\n\t\tif pick[p] == results[0].num then\n\t\t\tprint playerNames[p] + \" wins $\" + round((r/d[pick[p]])*bet[p], 2)\n\t\tend if\n\tend for\nend function\n\n// Main loop\nwhile true\n\tsetup\n\trunRace\n\tprint \"Do you want to bet on the next race ?\"\n\tyn = input(\"Yes or no? \").lower\n\tif not yn or yn[0] != \"y\" then break\nend while\n\n"
  },
  {
    "path": "00_Alternate_Languages/50_Horserace/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/50_Horserace/horserace.bas",
    "content": "100 PRINT TAB(31);\"HORSERACE\"\n110 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n120 PRINT:PRINT:PRINT\n210 DIM S(8)\n220 PRINT \"WELCOME TO SOUTH PORTLAND HIGH RACETRACK\"\n230 PRINT \"                      ...OWNED BY LAURIE CHEVALIER\"\n240 PRINT \"DO YOU WANT DIRECTIONS\";\n250 INPUT X$\n260 IF X$=\"NO\" THEN 320\n270 PRINT\"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\"\n280 PRINT\"MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.\"\n290 PRINT \"DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\"\n300 PRINT\"NUMBER.  THE HORSES RACE DOWN THE PAPER!\"\n310 PRINT\n320 PRINT \"HOW MANY WANT TO BET\";\n330 INPUT C\n340 PRINT \"WHEN ? APPEARS,TYPE NAME\"\n350 FOR A=1 TO C\n360 INPUT W$(A)\n370 NEXT A\n380 PRINT\n390 PRINT\"HORSE\",,\"NUMBER\",\"ODDS\"\n400 PRINT\n410 FOR I=1 TO 8: S(I)=0: NEXT I\n420 LET R=0\n430 FOR A=1 TO 8\n440 LET D(A)=INT(10*RND(1)+1)\n450 NEXT A\n460 FOR A=1 TO 8\n470 LET R=R+D(A)\n480 NEXT A\n490 LET V$(1)=\"JOE MAW\"\n500 LET V$(2)=\"L.B.J.\"\n510 LET V$(3)=\"MR.WASHBURN\"\n520 LET V$(4)=\"MISS KAREN\"\n530 LET V$(5)=\"JOLLY\"\n540 LET V$(6)=\"HORSE\"\n550 LET V$(7)=\"JELLY DO NOT\"\n560 LET V$(8)=\"MIDNIGHT\"\n570 FOR N=1 TO 8\n580 PRINT V$(N),,N,R/D(N);\":1\"\n590 NEXT N\n600 PRINT\"--------------------------------------------------\"\n610 PRINT \"PLACE YOUR BETS...HORSE # THEN AMOUNT\"\n620 FOR J=1 TO C\n630 PRINT W$(J);\n640 INPUT Q(J),P(J)\n650 IF P(J)<1 THEN 670\n660 IF P(J)<100000 THEN 690\n670 PRINT\"  YOU CAN'T DO THAT!\"\n680 GOTO 630\n690 NEXT J\n700 PRINT\n710 PRINT\"1 2 3 4 5 6 7 8\"\n720 PRINT\"XXXXSTARTXXXX\"\n730 FOR I=1 TO 8\n740 LET M=I\n750 LET M(I)=M\n760 LET Y(M(I))=INT(100*RND(1)+1)\n770 IF Y(M(I))<10 THEN 860\n780 LET S=INT(R/D(I)+.5)\n790 IF Y(M(I))<S+17 THEN 880\n800 IF Y(M(I))<S+37 THEN 900\n810 IF Y(M(I))<S+57 THEN 920\n820 IF Y(M(I))<77+S THEN 940\n830 IF Y(M(I))<S+92 THEN 960\n840 LET Y(M(I))=7\n850 GOTO 970\n860 LET Y(M(I))=1\n870 GOTO 970\n880 LET Y(M(I))=2\n890 GOTO 970\n900 LET Y(M(I))=3\n910 GOTO 970\n920 LET Y(M(I))=4\n930 GOTO 970\n940 LET Y(M(I))=5\n950 GOTO 970\n960 LET Y(M(I))=6\n970 NEXT I\n980 LET M=I\n990 FOR I=1 TO 8\n1000 LET S(M(I))=S(M(I))+Y(M(I))\n1010 NEXT I\n1020 LET I=1\n1030 FOR L=1 TO 8\n1040 FOR I=1 TO 8-L\n1050 IF S(M(I))<S(M(I+1))THEN 1090\n1060 LET H=M(I)\n1070 LET M(I)=M(I+1)\n1080 LET M(I+1)=H\n1090 NEXT I\n1100 NEXT L\n1110 LET T=S(M(8))\n1120 FOR I=1 TO 8\n1130 LET B=S(M(I))-S(M(I-1))\n1140 IF B=0 THEN 1190\n1150 FOR A=1 TO B\n1160 PRINT\n1170 IF S(M(I))>27 THEN 1240\n1180 NEXT A\n1190 PRINT M(I);\n1200 NEXT I\n1210 FOR A=1 TO 28-T\n1220 PRINT\n1230 NEXT A\n1240 PRINT \"XXXXFINISHXXXX\";\n1242 PRINT\n1243 PRINT\n1244 PRINT \"---------------------------------------------\"\n1245 PRINT\n1250 IF T<28 THEN 720\n1270 PRINT \"THE RACE RESULTS ARE:\"\n1272 LET Z9=1\n1280 FOR I=8 TO 1 STEP-1\n1290 LET F=M(I)\n1300 PRINT\n1310 PRINT Z9;\"PLACE HORSE NO.\";F,\"AT \";R/D(F);\":1\"\n1312 LET Z9=Z9+1\n1320  NEXT I\n1330 FOR J=1 TO C\n1340 IF Q(J)<>M(8) THEN 1370\n1350 LET N=Q(J)\n1355 PRINT\n1360 PRINT W$(J);\" WINS $\";(R/D(N))*P(J)\n1370 NEXT J\n1372 PRINT \"DO YOU WANT TO BET ON THE NEXT RACE ?\"\n1374 INPUT \"YES OR NO\"; O$\n1376 IF O$=\"YES\" THEN 380\n1380 END\n"
  },
  {
    "path": "00_Alternate_Languages/51_Hurkle/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of hurkle.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript hurkle.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"hurkle\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms",
    "content": "print \" \"*33 + \"Hurcle\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nn = 5\t// number of guesses allowed\ng = 10\t// grid size\nprint\nprint \"A hurkle is hiding on a \" + g + \" by \" + g + \" grid. Homebase\"\nprint \"on the grid is point 0,0 in the southwest corner,\"\nprint \"and any point on the grid is designated by a\"\nprint \"pair of whole numbers seperated by a comma. The first\"\nprint \"number is the horizontal position and the second number\"\nprint \"is the vertical position. You must try to\"\nprint \"guess the hurkle's gridpoint. You get \" + n + \"tries.\"\nprint \"After each try, I will tell you the approximate\"\nprint \"direction to go to look for the hurkle.\"\nprint\n\nplayOneGame = function\n    a = floor(g*rnd)\n    b = floor(g*rnd)\n    for k in range(1, n)\n        s = input(\"Guess #\" + k + \"? \").replace(\",\", \" \").split\n        x = s[0].val\n        y = s[-1].val\n        if x == a and y == b then\n            print \n            print \"You found him in \" + k + \" guesses!\"\n            return\n        end if\n        if y == b then\n            if x == a then\n                print\n                print \"You found him in \" + k + \" guesses!\"\n                return\n            else if x < a then\n                dir = \"east\"\n            else\n                dir = \"west\"\n            end if\n        else if y < b then\n            dir = \"north\"\n        else\n            dir = \"south\"\n        end if\n        print \"Go \" + dir\n    end for\n    print \"Sorry, that's \" + n + \" guesses.\"\n    print \"The hurkle is at \" + a + \",\" + b\nend function\n\nwhile true\n    playOneGame\n    print\n    print \"Let's play again, hurkle is hiding.\"\n    print\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/51_Hurkle/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/51_Hurkle/hurkle.bas",
    "content": "10 PRINT TAB(33);\"HURKLE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n110 N=5\n120 G=10\n210 PRINT\n220 PRINT \"A HURKLE IS HIDING ON A\";G;\"BY\";G;\"GRID. HOMEBASE\"\n230 PRINT \"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\"\n235 PRINT \"AND ANY POINT ON THE GRID IS DESIGNATED BY A\"\n240 PRINT \"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\"\n245 PRINT \"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\"\n246 PRINT \"IS THE VERTICAL POSITION. YOU MUST TRY TO\"\n250 PRINT \"GUESS THE HURKLE'S GRIDPOINT. YOU GET\";N;\"TRIES.\"\n260 PRINT \"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\"\n270 PRINT \"DIRECTION TO GO TO LOOK FOR THE HURKLE.\"\n280 PRINT\n285 A=INT(G*RND(1))\n286 B=INT(G*RND(1))\n310 FOR K=1 TO N\n320 PRINT \"GUESS #\";K;\n330 INPUT X,Y\n340 IF ABS(X-A)+ABS(Y-B)=0 THEN 500\n350 REM PRINT INFO\n360 GOSUB 610\n370 PRINT\n380 NEXT K\n410 PRINT\n420 PRINT \"SORRY, THAT'S\";N;\"GUESSES.\"\n430 PRINT \"THE HURKLE IS AT \";A;\",\";B\n440 PRINT\n450 PRINT \"LET'S PLAY AGAIN, HURKLE IS HIDING.\"\n460 PRINT\n470 GOTO 285\n500 REM\n510 PRINT\n520 PRINT \"YOU FOUND HIM IN\";K;\"GUESSES!\"\n540 GOTO 440\n610 PRINT \"GO \";\n620 IF Y=B THEN 670\n630 IF Y<B THEN 660\n640 PRINT \"SOUTH\";\n650 GOTO 670\n660 PRINT \"NORTH\";\n670 IF X=A THEN 720\n680 IF X<A THEN 710\n690 PRINT \"WEST\";\n700 GOTO 720\n710 PRINT \"EAST\";\n720 PRINT\n730 RETURN\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/52_Kinema/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript kinema.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"kinema\"\n\trun\n```\n3. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of kinema.ms, and click the \"Run Script\" button.\n"
  },
  {
    "path": "00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms",
    "content": "// Kinema\n//\n// Ported from BASIC to MiniScript by Joe Strout\n\nprint \" \"*33 + \"KINEMA\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\n\ncheckAnswer = function(prompt, correctValue)\n\tanswer = input(prompt).val\n\tright = abs((answer - correctValue)/answer) < 0.15\n\tif right then\n\t\tprint \"Close enough!\"\n\telse\n\t\tprint \"Not even close....\"\n\tend if\n\tprint \"Correct answer is \" + correctValue\n\treturn right\nend function\n\ndoOneRun = function\n\tprint; print\n\trightCount = 0\n\tV = 5 + floor(35*rnd)\n\tprint \"A ball is thrown upwards at \" + V + \" meters per second.\"\n\tprint\n\trightCount += checkAnswer(\"How high will it go (in meters)? \", 0.05 * V^2)\n\trightCount += checkAnswer(\"How long until it returns (in seconds)? \", V/5)\n\tt = 1 + floor(2*V*rnd)/10\n\trightCount += checkAnswer(\"What will its velocity be after \" + t +\n\t     \" seconds? \", V-10*t)\n\tprint\n\tprint rightCount + \" right out of 3.\"\n\tif rightCount >= 2 then print \"  Not bad.\"\nend function\n\n// main loop (press control-C to break out)\nwhile true\n\tdoOneRun\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/52_Kinema/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/52_Kinema/kinema.bas",
    "content": "10 PRINT TAB(33);\"KINEMA\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 PRINT\n105 PRINT\n106 Q=0\n110 V=5+INT(35*RND(1))\n111 PRINT \"A BALL IS THROWN UPWARDS AT\";V;\"METERS PER SECOND.\"\n112 PRINT\n115 A=.05*V^2\n116 PRINT \"HOW HIGH WILL IT GO (IN METERS)\";\n117 GOSUB 500\n120 A=V/5\n122 PRINT \"HOW LONG UNTIL IT RETURNS (IN SECONDS)\";\n124 GOSUB 500\n130 T=1+INT(2*V*RND(1))/10\n132 A=V-10*T\n134 PRINT \"WHAT WILL ITS VELOCITY BE AFTER\";T;\"SECONDS\";\n136 GOSUB 500\n140 PRINT\n150 PRINT Q;\"RIGHT OUT OF 3.\";\n160 IF Q<2 THEN 100\n170 PRINT \"  NOT BAD.\"\n180 GOTO 100\n500 INPUT G\n502 IF ABS((G-A)/A)<.15 THEN 510\n504 PRINT \"NOT EVEN CLOSE....\"\n506 GOTO 512\n510 PRINT \"CLOSE ENOUGH.\"\n511 Q=Q+1\n512 PRINT \"CORRECT ANSWER IS \";A\n520 PRINT\n530 RETURN\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/53_King/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript king.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"king\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/53_King/MiniScript/king.ms",
    "content": "print \" \"*34 + \"KING\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nyearsRequired = 8\nrallods = floor(60000+(1000*rnd)-(1000*rnd))\ncountrymen = floor(500+(10*rnd)-(10*rnd))\nlandArea = 2000\nforeignWorkers = 0\nsellableLandExplained = false\ntourism = 0\nyear = 0\n\nzs = input(\"Do you want instructions? \").lower\nif zs == \"again\" then\n\twhile true\n\t\tyear = input(\"How many years had you been in office when interrupted? \").val\n\t\tif 0 <= year < yearsRequired then break\n\t\tprint \"   Come on, your term in office is only \" + yearsRequired + \" years.\"\n\tend while\n\trallods = input(\"How much did you have in the treasury? \").val\n\tcountrymen = input(\"How many countrymen? \").val\n\tforeignWorkers = input(\"How many foreign workers? \").val\n\twhile true\n\t\tlandArea = input(\"How many square miles of land? \").val\n\t\tif 1000 <= landArea <= 2000 then break\n\t\tprint \"   Come on, you started with 1000 sq. miles of farm land\"\n\t\tprint \"   and 1000 sq. miles of forest land.\"\n\tend while\nelse if not zs or zs[0] != \"n\" then\n\tprint; print; print\n\tprint \"Congratulations! You've just been elected premier of Setats\"\n\tprint \"Detinu, a small communist island 30 by 70 miles long. Your\"\n\tprint \"job is to decide upon the contry's budget and distribute\"\n\tprint \"money to your countrymen from the communal treasury.\"\n\tprint \"The money system is rallods, and each person needs 100\"\n\tprint \"rallods per year to survive. Your country's income comes\"\n\tprint \"from farm produce and tourists visiting your magnificent\"\n\tprint \"forests, hunting, fishing, etc. Half your land is farm land\"\n\tprint \"which also has an excellent mineral content and may be sold\"\n\tprint \"to foreign industry (strip mining) who import and support\"\n\tprint \"their own workers. Crops cost between 10 and 15 rallods per\"\n\tprint \"square mile to plant.\"\n\tprint \"Your goal is to complete your \" + yearsRequired + \" year term of office.\"\n\tprint \"Good luck!\"\nend if\n\nprint\n\n\n// Bonus little feature when running in Mini Micro: display a status bar with\n// key game stats at the top of the screen.\nupdateStatusBar = function\n\tif version.hostName != \"Mini Micro\" then return\n\tdisplay(2).mode = displayMode.text; td = display(2)\n\ts = \" Rallods: \" + (rallods + \" \"*8)[:8]\n\ts += \" Land: \" + (landArea + \" \"*6)[:6]\n\ts += \" Countrymen: \" + (countrymen + \" \"*6)[:6]\n\ts += \" Foreigners: \" + (foreignWorkers + \" \"*5)[:5]\n\ttd.color = color.black; td.backColor = text.color\n\ttd.row = 25; td.column = 0;\ttd.print s\nend function\n\nmin0 = function(x)\n\tif x < 0 then return 0 else return x\nend function\nfloorMin0 = function(x)\n\treturn min0(floor(x))\nend function\nstop = function\n\tupdateStatusBar\n\tprint; print; exit\nend function\n\nwhile true\n\tlandPrice = floor(10*rnd+95)\n\tplantingArea = 0\n\tpollutionControl = 0\n\tdeaths = 0\n\t\n\tprint\n\tprint \"You now have \" + rallods + \" rallods in the treasury.\"\n\tprint floor(countrymen) + \" countrymen, \", \"\"\n\tcostToPlant = floor(((rnd/2)*10+10))\n\tif foreignWorkers != 0 then\n\t\tprint floor(foreignWorkers) + \" foreign workers, \", \"\"\n\tend if\n\tprint \"and \" + floor(landArea) + \" sq. miles of land.\"\n\tprint \"This year industry will buy land for \" + landPrice, \"\"\n\tprint \" rallods per square mile.\"\n\tprint \"Land currently costs \" + costToPlant + \" rallods per square mile to plant.\"\n\tprint\n\t\n\tupdateStatusBar\n\twhile true\n\t\tsellToIndustry = input(\"How many square miles do you wish to sell to industry? \").val\n\t\tif sellToIndustry < 0 then continue\n\t\tif sellToIndustry <= landArea-1000 then break\n\t\tprint \"***  Think again. You only have \" + (landArea-1000) + \" square miles of farm land.\"\n\t\tif not sellableLandExplained then\n\t\t\tprint;print \"(Foreign industry will only buy farm land because\"\n\t\t\tprint \"forest land is uneconomical to strip mine due to trees,\"\n\t\t\tprint \"thicker top soil, etc.)\"\n\t\t\tsellableLandExplained = true\n\t\tend if\n\tend while\n\tlandArea = floor(landArea-sellToIndustry)\n\trallods = floor(rallods+(sellToIndustry*landPrice))\n\t\n\tupdateStatusBar\n\twhile true\n\t\twelfare = input(\"How many rallods will you distribute among your countrymen? \").val\n\t\tif welfare < 0 then continue\n\t\tif welfare <= rallods then break\n\t\tprint \"   Think again. You've only \" + rallods + \" rallods in the treasury\"\n\tend while\n\trallods = floor(rallods-welfare)\n\t\n\tupdateStatusBar\n\twhile rallods > 0\n\t\tplantingArea = input(\"How many square miles do you wish to plant? \").val\n\t\tif plantingArea < 0 then continue\n\t\tif plantingArea > countrymen*2 then\n\t\t\tprint \"   Sorry, but each countryman can only plant 2 sq. miles.\"\n\t\t\tcontinue\n\t\tend if\n\t\tif plantingArea > landArea-1000 then\n\t\t\tprint \"   Sorry, but you've only \" + (landArea-1000) + \" sq. miles of farm land.\"\n\t\t\tcontinue\n\t\tend if\n\t\tplantingCost = floor(plantingArea * costToPlant)\n\t\tif plantingCost <= rallods then break\n\t\tprint \"   Think again. You've only \" + rallods + \" rallods left in the treasury.\"\n\tend while\n\trallods -= plantingCost\n\t\n\tupdateStatusBar\n\twhile rallods > 0\n\t\tpollutionControl = input(\"How many rallods do you wish to spend on pollution control? \").val\n\t\tif pollutionControl < 0 then continue\n\t\tif pollutionControl <= rallods then break\n\t\tprint \"   Think again. You only have \" + rallods + \" rallods remaining.\"\n\tend while\n\t\n\tif sellToIndustry == 0 and welfare == 0 and plantingArea == 0 and pollutionControl == 0 then\n\t\tprint\n\t\tprint \"Goodbye.\"\n\t\tprint \"(If you wish to continue this game at a later date, answer\"\n\t\tprint \"'again' when asked if you want instructions at the start\"\n\t\tprint \"of the game.)\"\n\t\texit\n\tend if\n\t\n\tprint\n\tprint\n\t\n\trallods = floor(rallods-pollutionControl)\n\tupdateStatusBar\n\t\n\toriginal_rallods = rallods\n\t\n\tstarvationDeaths = floorMin0(countrymen - welfare/100)\n\tif starvationDeaths then\n\t\tif welfare/100 < 50 then\n\t\t\tprint\n\t\t\tprint\n\t\t\tprint \"Over one third of the popultation has died since you\"\n\t\t\tprint \"were elected to office. The people (remaining)\"\n\t\t\tprint \"hate your guts.\"\n\t\t\tif rnd > .5 then\n\t\t\t\tprint \"You have been thrown out of office and are now\"\n\t\t\t\tprint \"residing in prison.\"\n\t\t\telse\n\t\t\t\tprint \"You have been assassinated.\"\n\t\t\tend if\n\t\t\tcountrymen -= starvationDeaths\n\t\t\tstop\t\t\n\t\tend if\n\t\tprint starvationDeaths + \" countrymen died of starvation\"\n\tend if\n\t\n\tpollutionDeaths = floorMin0(rnd*(2000-landArea))\n\tif pollutionControl >= 25 then\n\t\tpollutionDeaths = floor(pollutionDeaths/(pollutionControl/25))\n\tend if\n\tif pollutionDeaths > 0 then\n\t\tprint pollutionDeaths + \" countrymen died of carbon-monoxide and dust inhalation\"\n\tend if\n\t\n\tdeaths = starvationDeaths + pollutionDeaths\n\tif deaths then\n\t\tprint \"   You were forced to spend \" + floor(deaths*9), \"\"\n\t\tprint \" rallods on funeral expenses\"\n\t\trallods -= deaths * 9\n\tend if\n\t\n\tif rallods < 0 then\n\t\tprint \"   Insufficient reserves to cover cost - land was sold\"\n\t\tlandArea = floorMin0(landArea+(rallods/landPrice))\n\t\trallods = 0\n\tend if\n\t\n\tcountrymen = min0(countrymen - deaths)\n\t\n\tif sellToIndustry then\n\t\tnewForeigners = floor(sellToIndustry+(rnd*10)-(rnd*20))\n\t\tif foreignWorkers == 0 then newForeigners += 20\n\t\tforeignWorkers += newForeigners\n\t\tprint newForeigners + \" workers came to the country and \", \"\"\n\tend if\n\t\n\timmigration = floor(((welfare/100-countrymen)/10)+(pollutionControl/25)-((2000-landArea)/50)-(pollutionDeaths/2))\n\tprint abs(immigration) + \" countrymen \", \"\"\n\tif immigration < 0 then print \"came to\", \"\" else print \"left\", \"\"\n\tprint \" the island.\"\n\tcountrymen = floorMin0(countrymen + immigration)\n\t\n\tcropLoss = floor(((2000-landArea)*((rnd+1.5)/2)))\n\tif cropLoss > plantingArea then cropLoss = plantingArea\n\tif foreignWorkers > 0 then print \"Of \" + floor(plantingArea) + \" sq. miles planted,\", \"\"\n\tprint \" you harvested \" + floor(plantingArea-cropLoss) + \" sq. miles of crops.\"\n\tif cropLoss then\n\t\tprint \"   (Due to air and water pollution from foreign industry.)\"\n\tend if\n\tagriculturalIncome = floor((plantingArea-cropLoss)*(landPrice/2))\n\tprint \"Making \" + agriculturalIncome + \" rallods.\"\n\trallods += agriculturalIncome\n\t\n\tv1 = floor(((countrymen-immigration)*22)+(rnd*500))\n\tv2 = floor((2000-landArea)*15)\n\tprevTourism = tourism\n\ttourism = abs(floor(v1-v2))\n\tprint \" You made \" + tourism + \" rallods from tourist trade.\"\n\tif v2 > 2 and tourism < prevTourism then\n\t\tprint \"   Decrease because \", \"\"\n\t\tg1 = 10*rnd\n\t\tif g1 <= 2 then\n\t\t\tprint \"fish population has dwindled due to water pollution.\"\n\t\telse if g1 <= 4 then\n\t\t\tprint \"air pollution is killing game bird population.\"\n\t\telse if g1 <= 6 then\n\t\t\tprint \"mineral baths are being ruined by water pollution.\"\n\t\telse if g1 <= 8 then\n\t\t\tprint \"unpleasant smog is discouraging sun bathers.\"\n\t\telse\n\t\t\tprint \"hotels are looking shabby due to smog grit.\"\n\t\tend if\n\tend if\n\trallods += tourism\n\tupdateStatusBar\n\t\n\tif deaths > 200 then\n\t\tprint\n\t\tprint\n\t\tprint deaths + \"countrymen died in one year!!!!!\"\n\t\tprint \"due to this extreme mismanagement, you have not only\"\n\t\tprint \"been impeached and thrown out of office, but you\"\n\t\tm6 = floor(rnd*10)\n\t\tif m6 <= 3 then 1670\n\t\tif m6 <= 6 then 1680\n\t\tif m6 <= 10 then 1690\n\t\tprint \"also had your left eye gouged out!\"\n\t\tgoto 1590\n\t\tprint \"have also gained a very bad reputation.\"\n\t\tgoto 1590\n\t\tprint \"have also been declared national fink.\"\n\t\tstop\n\telse if countrymen < 343 then\n\t\tprint\n\t\tprint\n\t\tprint \"Over one third of the popultation has died since you\"\n\t\tprint \"were elected to office. The people (remaining)\"\n\t\tprint \"hate your guts.\"\n\t\tif rnd > .5 then\n\t\t\tprint \"You have been thrown out of office and are now\"\n\t\t\tprint \"residing in prison.\"\n\t\telse\n\t\t\tprint \"You have been assassinated.\"\n\t\tend if\n\t\tstop\n\telse if (original_rallods/100) > 5 and deaths - pollutionDeaths >= 2 then\n\t\tprint\n\t\tprint \"Money was left over in the treasury which you did\"\n\t\tprint \"not spend. As a result, some of your countrymen died\"\n\t\tprint \"of starvation. The public is enraged and you have\"\n\t\tprint \"been forced to either resign or commit suicide.\"\n\t\tprint \"The choice is yours.\"\n\t\tprint \"If you choose the latter, please turn off your computer\"\n\t\tprint \"before proceeding.\"\n\t\tstop\n\telse if foreignWorkers > countrymen then\n\t\tprint\n\t\tprint\n\t\tprint \"The number of foreign workers has exceeded the number\"\n\t\tprint \"of countrymen. As a minority, they have revolted and\"\n\t\tprint \"taken over the country.\"\n\t\tif rnd > .5 then\n\t\t\tprint \"You have been thrown out of office and are now\"\n\t\t\tprint \"residing in prison.\"\n\t\telse\n\t\t\tprint \"You have been assassinated.\"\n\t\tend if\n\t\tstop\n\telse if year == yearsRequired-1 then\n\t\tprint\n\t\tprint\n\t\tprint \"Congratulations!!!!!!!!!!!!!!!!!!\"\n\t\tprint \"You have succesfully completed your \" + yearsRequired + \" year term\"\n\t\tprint \"of office. You were, of course, extremely lucky, but\"\n\t\tprint \"nevertheless, it's quite an achievement. Goodbye and good\"\n\t\tprint \"luck - you'll probably need it if you're the type that\"\n\t\tprint \"plays this game.\"\n\t\tstop\n\tend if\n\t\n\tupdateStatusBar\n\twait\n\tyear += 1\nend while\n\n//print\n//print\n//print \"the number of foreign workers has exceeded the number\"\n//print \"of countrymen. as a minority, they have revolted and\"\n//print \"taken over the country.\"\n//if rnd<=.5 then 1580\n//print \"you have been thrown out of office and are now\"\n//print \"residing in prison.\"\n//goto 1590\n//print \"you have been assassinated.\"\n//print\n//print\n//exit\n//print\n//print\n//print deaths + \"countrymen died in one year!!!!!\"\n//print \"due to this extreme mismanagement, you have not only\"\n//print \"been impeached and thrown out of office, but you\"\n//m6 = floor(rnd*10)\n//if m6 <= 3 then 1670\n//if m6 <= 6 then 1680\n//if m6 <= 10 then 1690\n//print \"also had your left eye gouged out!\"\n//goto 1590\n//print \"have also gained a very bad reputation.\"\n//goto 1590\n//print \"have also been declared national fink.\"\n//goto 1590\n//\n//print\n//print\n//print \"over one third of the popultation has died since you\"\n//print \"were elected to office. the people (remaining)\"\n//print \"hate your guts.\"\n//goto 1570\n//if deaths-pollutionDeaths < 2 then 1515\n//print\n//print \"money was left over in the treasury which you did\"\n//print \"not spend. as a result, some of your countrymen died\"\n//print \"of starvation. the public is enraged and you have\"\n//print \"been forced to either resign or commit suicide.\"\n//print \"the choice is yours.\"\n//print \"if you choose the latter, please turn off your computer\"\n//print \"before proceeding.\"\n//goto 1590\n//print\n//print\n//print \"congratulations!!!!!!!!!!!!!!!!!!\"\n//print \"you have succesfully completed your\" + yearsRequired + \"year term\"\n//print \"of office. you were, of course, extremely lucky, but\"\n//print \"nevertheless, it's quite an achievement. goodbye and good\"\n//print \"luck - you'll probably need it if you're the type that\"\n//print \"plays this game.\"\n//goto 1590\n//\n//print \"how many years had you been in office when interrupted\";\n//input year\n//if year < 0 then 1590\n//if year < 8 then 1969\n//print \"   come on, your term in office is only\" + yearsRequired + \"years.\"\n//goto 1960\n//print \"how much did you have in the treasury\";\n//input rallods\n//if rallods < 0 then 1590\n//print \"how many countrymen\";\n//input countrymen\n//if countrymen < 0 then 1590\n//print \"how many workers\";\n//input foreignWorkers\n//if foreignWorkers < 0 then 1590\n//print \"how many square miles of land\";\n//input landArea\n//if landArea < 0 then 1590\n//if landArea > 2000 then 1996\n//if landArea > 1000 then 100\n//print \"   come on, you started with 1000 sq. miles of farm land\"\n//print \"   and 10,000 sq. miles of forest land.\"\n//goto 1990\n//\n//year = year+1\n//deaths = 0\n//goto 100\n//end\n"
  },
  {
    "path": "00_Alternate_Languages/53_King/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/53_King/king.bas",
    "content": "1 PRINT TAB(34);\"KING\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"DO YOU WANT INSTRUCTIONS\";\n5 INPUT Z$\n6 N5=8\n10 IF LEFT$(Z$,1)=\"N\" THEN 47\n11 IF Z$=\"AGAIN\" THEN 1960\n12 PRINT:PRINT:PRINT\n20 PRINT \"CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\"\n22 PRINT \"DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\"\n24 PRINT \"JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\"\n26 PRINT \"MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\"\n28 PRINT \"THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\"\n30 PRINT \"RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\"\n32 PRINT \"FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\"\n34 PRINT \"FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\"\n36 PRINT \"WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\"\n38 PRINT \"TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\"\n40 PRINT \"THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\"\n42 PRINT \"SQUARE MILE TO PLANT.\"\n44 PRINT \"YOUR GOAL IS TO COMPLETE YOUR\";N5;\"YEAR TERM OF OFFICE.\"\n46 PRINT \"GOOD LUCK!\"\n47 PRINT\n50 A=INT(60000+(1000*RND(1))-(1000*RND(1)))\n55 B=INT(500+(10*RND(1))-(10*RND(1)))\n65 D=2000\n100 W=INT(10*RND(1)+95)\n102 PRINT\n105 PRINT \"YOU NOW HAVE \";A;\" RALLODS IN THE TREASURY.\"\n110 PRINT INT(B);:PRINT \"COUNTRYMEN, \";\n115 V9=INT(((RND(1)/2)*10+10))\n120 IF C=0 THEN 140\n130 PRINT INT(C);\"FOREIGN WORKERS, \";\n140 PRINT \"AND\";INT(D);\"SQ. MILES OF LAND.\"\n150 PRINT \"THIS YEAR INDUSTRY WILL BUY LAND FOR\";W;\n152 PRINT \"RALLODS PER SQUARE MILE.\"\n155 PRINT \"LAND CURRENTLY COSTS\";V9;\"RALLODS PER SQUARE MILE TO PLANT.\"\n162 PRINT\n200 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY\";\n210 INPUT H\n215 IF H<0 THEN 200\n220 IF H<=D-1000 THEN 300\n230 PRINT \"***  THINK AGAIN. YOU ONLY HAVE\";D-1000;\"SQUARE MILES OF FARM LAND.\"\n240 IF X<>0 THEN 200\n250 PRINT:PRINT \"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\"\n260 PRINT \"FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\"\n270 PRINT \"THICKER TOP SOIL, ETC.)\"\n280 X=1\n299 GOTO 200\n300 D=INT(D-H)\n310 A=INT(A+(H*W))\n320 PRINT \"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN\";\n340 INPUT I\n342 IF I<0 THEN 320\n350 IF I<A THEN 400\n360 IF I=A THEN 380\n370 PRINT \"   THINK AGAIN. YOU'VE ONLY\";A;\" RALLODS IN THE TREASURY\"\n375 GOTO 320\n380 J=0\n390 K=0\n395 A=0\n399 GOTO 1000\n400 A=INT(A-I)\n410 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO PLANT\";\n420 INPUT J\n421 IF J<0 THEN 410\n422 IF J<=B*2 THEN 426\n423 PRINT \"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\"\n424 GOTO 410\n426 IF J<=D-1000 THEN 430\n427 PRINT \"   SORRY, BUT YOU'VE ONLY\";D-1000;\"SQ. MILES OF FARM LAND.\"\n428 GOTO 410\n430 U1=INT(J*V9)\n435 IF U1<A THEN 500\n440 IF U1=A THEN 490\n450 PRINT \"   THINK AGAIN. YOU'VE ONLY\";A;\" RALLODS LEFT IN THE TREASURY.\"\n460 GOTO 410\n490 K=0\n495 A=0\n499 GOTO 1000\n500 A=A-U1\n510 PRINT \"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL\";\n520 INPUT K\n522 IF K<0 THEN 510\n530 IF K<=A THEN 1000\n540 PRINT \"   THINK AGAIN. YOU ONLY HAVE \";A;\" RALLODS REMAINING.\"\n550 GOTO 510\n600 IF H<>0 THEN 1002\n602 IF I<>0 THEN 1002\n604 IF J<>0 THEN 1002\n606 IF K<>0 THEN 1002\n609 PRINT\n612 PRINT \"GOODBYE.\"\n614 PRINT \"(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\"\n616 PRINT \"'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\"\n617 PRINT \"OF THE GAME).\"\n618 STOP\n1000 GOTO 600\n1002 PRINT\n1003 PRINT\n1010 A=INT(A-K)\n1020 A4=A\n1100 IF INT(I/100-B)>=0 THEN 1120\n1105 IF I/100<50 THEN 1700\n1110 PRINT INT(B-(I/100));\"COUNTRYMEN DIED OF STARVATION\"\n1120 F1=INT(RND(1)*(2000-D))\n1122 IF K<25 THEN 1130\n1125 F1=INT(F1/(K/25))\n1130 IF F1<=0 THEN 1150\n1140 PRINT F1;\"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\"\n1150 IF INT((I/100)-B)<0 THEN 1170\n1160 IF F1>0 THEN 1180\n1165 GOTO 1200\n1170 PRINT \"   YOU WERE FORCED TO SPEND\";INT((F1+(B-(I/100)))*9);\n1172 PRINT \"RALLODS ON FUNERAL EXPENSES\"\n1174 B5=INT(F1+(B-(I/100)))\n1175 A=INT(A-((F1+(B-(I/100)))*9))\n1176 GOTO 1185\n1180 PRINT \"   YOU WERE FORCED TO SPEND \";INT(F1*9);\"RALLODS ON \";\n1181 PRINT \"FUNERAL EXPENSES.\"\n1182 B5=F1\n1183 A=INT(A-(F1*9))\n1185 IF A>=0 THEN 1194\n1187 PRINT \"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\"\n1189 D=INT(D+(A/W))\n1190 A=0\n1194 B=INT(B-B5)\n1200 IF H=0 THEN 1250\n1220 C1=INT(H+(RND(1)*10)-(RND(1)*20))\n1224 IF C>0 THEN 1230\n1226 C1=C1+20\n1230 PRINT C1;\"WORKERS CAME TO THE COUNTRY AND\";\n1250 P1=INT(((I/100-B)/10)+(K/25)-((2000-D)/50)-(F1/2))\n1255 PRINT ABS(P1);\"COUNTRYMEN \";\n1260 IF P1<0 THEN 1275\n1265 PRINT \"CAME TO\";\n1270 GOTO 1280\n1275 PRINT \"LEFT\";\n1280 PRINT \" THE ISLAND.\"\n1290 B=INT(B+P1)\n1292 C=INT(C+C1)\n1305 U2=INT(((2000-D)*((RND(1)+1.5)/2)))\n1310 IF C=0 THEN 1324\n1320 PRINT \"OF \";INT(J);\"SQ. MILES PLANTED,\";\n1324 IF J>U2 THEN 1330\n1326 U2=J\n1330 PRINT \" YOU HARVESTED \";INT(J-U2);\"SQ. MILES OF CROPS.\"\n1340 IF U2=0 THEN 1370\n1344 IF T1>=2 THEN 1370\n1350 PRINT \"   (DUE TO \";\n1355 IF T1=0 THEN 1365\n1360 PRINT \"INCREASED \";\n1365 PRINT \"AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\"\n1370 Q=INT((J-U2)*(W/2))\n1380 PRINT \"MAKING\";INT(Q);\"RALLODS.\"\n1390 A=INT(A+Q)\n1400 V1=INT(((B-P1)*22)+(RND(1)*500))\n1405 V2=INT((2000-D)*15)\n1410 PRINT \" YOU MADE\";ABS(INT(V1-V2));\"RALLODS FROM TOURIST TRADE.\"\n1420 IF V2=0 THEN 1450\n1425 IF V1-V2>=V3 THEN 1450\n1430 PRINT \"   DECREASE BECAUSE \";\n1435 G1=10*RND(1)\n1440 IF G1<=2 THEN 1460\n1442 IF G1<=4 THEN 1465\n1444 IF G1<=6 THEN 1470\n1446 IF G1<=8 THEN 1475\n1448 IF G1<=10 THEN 1480\n1450 V3=INT(A+V3)\n1451 A=INT(A+V3)\n1452 GOTO 1500\n1460 PRINT \"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\"\n1462 GOTO 1450\n1465 PRINT \"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\"\n1467 GOTO 1450\n1470 PRINT \"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\"\n1472 GOTO 1450\n1475 PRINT \"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\"\n1477 GOTO 1450\n1480 PRINT \"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\"\n1482 GOTO 1450\n1500 IF B5>200 THEN 1600\n1505 IF B<343 THEN 1700\n1510 IF (A4/100)>5 THEN 1800\n1515 IF C>B THEN 1550\n1520 IF N5-1=X5 THEN 1900\n1545 GOTO 2000\n1550 PRINT\n1552 PRINT\n1560 PRINT \"THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\"\n1562 PRINT \"OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\"\n1564 PRINT \"TAKEN OVER THE COUNTRY.\"\n1570 IF RND(1)<=.5 THEN 1580\n1574 PRINT \"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\"\n1576 PRINT \"RESIDING IN PRISON.\"\n1578 GOTO 1590\n1580 PRINT \"YOU HAVE BEEN ASSASSINATED.\"\n1590 PRINT\n1592 PRINT\n1596 STOP\n1600 PRINT\n1602 PRINT\n1610 PRINT B5;\"COUNTRYMEN DIED IN ONE YEAR!!!!!\"\n1615 PRINT \"DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\"\n1620 PRINT \"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\"\n1622 M6=INT(RND(1)*10)\n1625 IF M6<=3 THEN 1670\n1630 IF M6<=6 THEN 1680\n1635 IF M6<=10 THEN 1690\n1670 PRINT \"ALSO HAD YOUR LEFT EYE GOUGED OUT!\"\n1672 GOTO 1590\n1680 PRINT \"HAVE ALSO GAINED A VERY BAD REPUTATION.\"\n1682 GOTO 1590\n1690 PRINT \"HAVE ALSO BEEN DECLARED NATIONAL FINK.\"\n1692 GOTO 1590\n1700 PRINT\n1702 PRINT\n1710 PRINT \"OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\"\n1715 PRINT \"WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\"\n1720 PRINT \"HATE YOUR GUTS.\"\n1730 GOTO 1570\n1800 IF B5-F1<2 THEN 1515\n1807 PRINT\n1815 PRINT \"MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\"\n1820 PRINT \"NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\"\n1825 PRINT \"OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\"\n1830 PRINT \"BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\"\n1835 PRINT \"THE CHOICE IS YOURS.\"\n1840 PRINT \"IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\"\n1845 PRINT \"BEFORE PROCEEDING.\"\n1850 GOTO 1590\n1900 PRINT\n1902 PRINT\n1920 PRINT \"CONGRATULATIONS!!!!!!!!!!!!!!!!!!\"\n1925 PRINT \"YOU HAVE SUCCESFULLY COMPLETED YOUR\";N5;\"YEAR TERM\"\n1930 PRINT \"OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\"\n1935 PRINT \"NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\"\n1940 PRINT \"LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\"\n1945 PRINT \"PLAYS THIS GAME.\"\n1950 GOTO 1590\n1960 PRINT \"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED\";\n1961 INPUT X5\n1962 IF X5<0 THEN 1590\n1963 IF X5<8 THEN 1969\n1965 PRINT \"   COME ON, YOUR TERM IN OFFICE IS ONLY\";N5;\"YEARS.\"\n1967 GOTO 1960\n1969 PRINT \"HOW MUCH DID YOU HAVE IN THE TREASURY\";\n1970 INPUT A\n1971 IF A<0 THEN 1590\n1975 PRINT \"HOW MANY COUNTRYMEN\";\n1976 INPUT B\n1977 IF B<0 THEN 1590\n1980 PRINT \"HOW MANY WORKERS\";\n1981 INPUT C\n1982 IF C<0 THEN 1590\n1990 PRINT \"HOW MANY SQUARE MILES OF LAND\";\n1991 INPUT D\n1992 IF D<0 THEN 1590\n1993 IF D>2000 THEN 1996\n1994 IF D>1000 THEN 100\n1996 PRINT \"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\"\n1997 PRINT \"   AND 10,000 SQ. MILES OF FOREST LAND.\"\n1998 GOTO 1990\n2000 X5=X5+1\n2020 B5=0\n2040 GOTO 100\n2046 END\n"
  },
  {
    "path": "00_Alternate_Languages/53_King/king_variable_update.bas",
    "content": "1 PRINT TAB(34);\"KING\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"DO YOU WANT INSTRUCTIONS\";\n5 INPUT Z$\n6 YEARS_REQUIRED=8\n10 IF LEFT$(Z$,1)=\"N\" THEN 47\n    11 IF Z$=\"AGAIN\" THEN 1960\n    12 PRINT:PRINT:PRINT\n    20 PRINT \"CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\"\n    22 PRINT \"DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\"\n    24 PRINT \"JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\"\n    26 PRINT \"MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\"\n    28 PRINT \"THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\"\n    30 PRINT \"RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\"\n    32 PRINT \"FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\"\n    34 PRINT \"FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\"\n    36 PRINT \"WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\"\n    38 PRINT \"TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\"\n    40 PRINT \"THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\"\n    42 PRINT \"SQUARE MILE TO PLANT.\"\n    44 PRINT \"YOUR GOAL IS TO COMPLETE YOUR\";YEARS_REQUIRED;\"YEAR TERM OF OFFICE.\"\n    46 PRINT \"GOOD LUCK!\"\n\n47 PRINT\n\n50 RALLODS=INT(60000+(1000*RND(1))-(1000*RND(1)))\n55 COUNTRYMEN=INT(500+(10*RND(1))-(10*RND(1)))\n65 LANDAREA=2000\n100 LANDPRICE=INT(10*RND(1)+95)\n102 PRINT\n105 PRINT \"YOU NOW HAVE \";RALLODS;\" RALLODS IN THE TREASURY.\"\n110 PRINT INT(COUNTRYMEN);:PRINT \"COUNTRYMEN, \";\n115 COST_TO_PLANT=INT(((RND(1)/2)*10+10))\n120 IF FOREIGN_WORKERS=0 THEN 140\n130 PRINT INT(FOREIGN_WORKERS);\"FOREIGN WORKERS, \";\n140 PRINT \"AND\";INT(LANDAREA);\"SQ. MILES OF LAND.\"\n150 PRINT \"THIS YEAR INDUSTRY WILL BUY LAND FOR\";LANDPRICE;\n152 PRINT \"RALLODS PER SQUARE MILE.\"\n155 PRINT \"LAND CURRENTLY COSTS\";COST_TO_PLANT;\"RALLODS PER SQUARE MILE TO PLANT.\"\n162 PRINT\n\n200 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY\";\n210 INPUT SELL_TO_INDUSTRY\n215 IF SELL_TO_INDUSTRY<0 THEN 200\n220 IF SELL_TO_INDUSTRY<=LANDAREA-1000 THEN 300\n230 PRINT \"***  THINK AGAIN. YOU ONLY HAVE\";LANDAREA-1000;\"SQUARE MILES OF FARM LAND.\"\n\n240 IF EXPLANATION_GIVEN THEN 200\n    250 PRINT:PRINT \"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\"\n    260 PRINT \"FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\"\n    270 PRINT \"THICKER TOP SOIL, ETC.)\"\n    280 EXPLANATION_GIVEN=TRUE\n299 GOTO 200\n\n300 LANDAREA=INT(LANDAREA-SELL_TO_INDUSTRY)\n310 RALLODS=INT(RALLODS+(SELL_TO_INDUSTRY*LANDPRICE))\n320 PRINT \"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN\";\n340 INPUT WELFARE\n342 IF WELFARE<0 THEN 320\n350 IF WELFARE<RALLODS THEN 400\n360 IF WELFARE=RALLODS THEN 380\n370 PRINT \"   THINK AGAIN. YOU'VE ONLY\";RALLODS;\" RALLODS IN THE TREASURY\"\n375 GOTO 320\n\n380 PLANTING_AREA=0\n390 MONEY_SPENT_ON_POLLUTION_CONTROL=0\n395 RALLODS=0\n399 GOTO 1000\n400 RALLODS=INT(RALLODS-WELFARE)\n\n410 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO PLANT\";\n420 INPUT PLANTING_AREA\n421 IF PLANTING_AREA<0 THEN 410\n422 IF PLANTING_AREA<=COUNTRYMEN*2 THEN 426\n423 PRINT \"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\"\n424 GOTO 410\n\n426 IF PLANTING_AREA<=LANDAREA-1000 THEN 430\n427 PRINT \"   SORRY, BUT YOU'VE ONLY\";LANDAREA-1000;\"SQ. MILES OF FARM LAND.\"\n428 GOTO 410\n\n430 MONEY_SPENT_ON_PLANTING=INT(PLANTING_AREA*COST_TO_PLANT)\n435 IF MONEY_SPENT_ON_PLANTING<RALLODS THEN 500\n440 IF MONEY_SPENT_ON_PLANTING=RALLODS THEN 490\n450 PRINT \"   THINK AGAIN. YOU'VE ONLY\";RALLODS;\" RALLODS LEFT IN THE TREASURY.\"\n460 GOTO 410\n\n490 MONEY_SPENT_ON_POLLUTION_CONTROL=0\n495 RALLODS=0\n499 GOTO 1000\n\n500 RALLODS=RALLODS-MONEY_SPENT_ON_PLANTING\n\n510 PRINT \"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL\";\n520 INPUT MONEY_SPENT_ON_POLLUTION_CONTROL\n\n522 IF MONEY_SPENT_ON_POLLUTION_CONTROL<0 THEN 510\n530 IF MONEY_SPENT_ON_POLLUTION_CONTROL<=RALLODS THEN 1000\n540 PRINT \"   THINK AGAIN. YOU ONLY HAVE \";RALLODS;\" RALLODS REMAINING.\"\n550 GOTO 510\n\n600 IF SELL_TO_INDUSTRY<>0 THEN 1002\n602 IF WELFARE<>0 THEN 1002\n604 IF PLANTING_AREA<>0 THEN 1002\n606 IF MONEY_SPENT_ON_POLLUTION_CONTROL<>0 THEN 1002\n\n609 PRINT\n612 PRINT \"GOODBYE.\"\n614 PRINT \"(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\"\n616 PRINT \"'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\"\n617 PRINT \"OF THE GAME).\"\n618 STOP\n\n1000 GOTO 600\n\n1002 PRINT\n1003 PRINT\n\n1010 RALLODS=INT(RALLODS-MONEY_SPENT_ON_POLLUTION_CONTROL)\n1020 ORIGINAL_RALLODS=RALLODS\n\n1100 IF INT(WELFARE/100-COUNTRYMEN)>=0 THEN 1120\n1105 IF WELFARE/100<50 THEN 1700\n1110 PRINT INT(COUNTRYMEN-(WELFARE/100));\"COUNTRYMEN DIED OF STARVATION\"\n\n1120 POLLUTION_DEATHS=INT(RND(1)*(2000-LANDAREA))\n1122 IF MONEY_SPENT_ON_POLLUTION_CONTROL<25 THEN 1130\n1125 POLLUTION_DEATHS=INT(POLLUTION_DEATHS/(MONEY_SPENT_ON_POLLUTION_CONTROL/25))\n\n1130 IF POLLUTION_DEATHS<=0 THEN 1150\n1140 PRINT POLLUTION_DEATHS;\"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\"\n\n1150 IF INT((WELFARE/100)-COUNTRYMEN)<0 THEN 1170\n1160 IF POLLUTION_DEATHS>0 THEN 1180\n1165 GOTO 1200\n\n1170 PRINT \"   YOU WERE FORCED TO SPEND\";INT((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9);\n1172 PRINT \"RALLODS ON FUNERAL EXPENSES\"\n1174 DEATHS=INT(POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))\n1175 RALLODS=INT(RALLODS-((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9))\n1176 GOTO 1185\n\n1180 PRINT \"   YOU WERE FORCED TO SPEND \";INT(POLLUTION_DEATHS*9);\"RALLODS ON \";\n1181 PRINT \"FUNERAL EXPENSES.\"\n1182 DEATHS=POLLUTION_DEATHS\n1183 RALLODS=INT(RALLODS-(POLLUTION_DEATHS*9))\n\n1185 IF RALLODS>=0 THEN 1194\n1187 PRINT \"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\"\n1189 LANDAREA=INT(LANDAREA+(RALLODS/LANDPRICE))\n1190 RALLODS=0\n\n1194 COUNTRYMEN=INT(COUNTRYMEN-DEATHS)\n\n1200 IF SELL_TO_INDUSTRY=0 THEN 1250\n1220 NEW_FOREIGNERS=INT(SELL_TO_INDUSTRY+(RND(1)*10)-(RND(1)*20))\n1224 IF FOREIGN_WORKERS>0 THEN 1230\n1226 NEW_FOREIGNERS=NEW_FOREIGNERS+20\n\n1230 PRINT NEW_FOREIGNERS;\"WORKERS CAME TO THE COUNTRY AND\";\n\n1250 IMMIGRATION=INT(((WELFARE/100-COUNTRYMEN)/10)+(MONEY_SPENT_ON_POLLUTION_CONTROL/25)-((2000-LANDAREA)/50)-(POLLUTION_DEATHS/2))\n1255 PRINT ABS(IMMIGRATION);\"COUNTRYMEN \";\n1260 IF IMMIGRATION<0 THEN 1275\n1265 PRINT \"CAME TO\";\n1270 GOTO 1280\n1275 PRINT \"LEFT\";\n1280 PRINT \" THE ISLAND.\"\n1290 COUNTRYMEN=INT(COUNTRYMEN+IMMIGRATION)\n\n\n1292 FOREIGN_WORKERS=INT(FOREIGN_WORKERS+NEW_FOREIGNERS)\n\n1305 CROP_LOSS=INT(((2000-LANDAREA)*((RND(1)+1.5)/2)))\n1310 IF FOREIGN_WORKERS=0 THEN 1324\n1320 PRINT \"OF \";INT(PLANTING_AREA);\"SQ. MILES PLANTED,\";\n1324 IF PLANTING_AREA>CROP_LOSS THEN 1330\n1326 CROP_LOSS=PLANTING_AREA\n1330 PRINT \" YOU HARVESTED \";INT(PLANTING_AREA-CROP_LOSS);\"SQ. MILES OF CROPS.\"\n1340 IF CROP_LOSS=0 THEN 1370\n1344 IF T1>=2 THEN 1370\n1350 PRINT \"   (DUE TO \";\n1355 IF T1=0 THEN 1365\n1360 PRINT \"INCREASED \";\n1365 PRINT \"AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\"\n1370 AGRICULTURAL_INCOME=INT((PLANTING_AREA-CROP_LOSS)*(LANDPRICE/2))\n1380 PRINT \"MAKING\";INT(AGRICULTURAL_INCOME);\"RALLODS.\"\n1390 RALLODS=INT(RALLODS+AGRICULTURAL_INCOME)\n\nREM I think tourism calculations are actually wrong in the original code!\n\n1400 V1=INT(((COUNTRYMEN-IMMIGRATION)*22)+(RND(1)*500))\n1405 V2=INT((2000-LANDAREA)*15)\n1410 PRINT \" YOU MADE\";ABS(INT(V1-V2));\"RALLODS FROM TOURIST TRADE.\"\n1420 IF V2=0 THEN 1450\n1425 IF V1-V2>=V3 THEN 1450\n1430 PRINT \"   DECREASE BECAUSE \";\n1435 G1=10*RND(1)\n1440 IF G1<=2 THEN 1460\n1442 IF G1<=4 THEN 1465\n1444 IF G1<=6 THEN 1470\n1446 IF G1<=8 THEN 1475\n1448 IF G1<=10 THEN 1480\n1450 V3=INT(RALLODS+V3)\n1451 RALLODS=INT(RALLODS+V3)\n1452 GOTO 1500\n1460 PRINT \"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\"\n1462 GOTO 1450\n1465 PRINT \"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\"\n1467 GOTO 1450\n1470 PRINT \"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\"\n1472 GOTO 1450\n1475 PRINT \"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\"\n1477 GOTO 1450\n1480 PRINT \"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\"\n1482 GOTO 1450\n1500 IF DEATHS>200 THEN 1600\n1505 IF COUNTRYMEN<343 THEN 1700\n1510 IF (ORIGINAL_RALLODS/100)>5 THEN 1800\n1515 IF FOREIGN_WORKERS>COUNTRYMEN THEN 1550\n1520 IF YEARS_REQUIRED-1=YEAR THEN 1900\n1545 GOTO 2000\n1550 PRINT\n1552 PRINT\n1560 PRINT \"THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\"\n1562 PRINT \"OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\"\n1564 PRINT \"TAKEN OVER THE COUNTRY.\"\n1570 IF RND(1)<=.5 THEN 1580\n1574 PRINT \"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\"\n1576 PRINT \"RESIDING IN PRISON.\"\n1578 GOTO 1590\n1580 PRINT \"YOU HAVE BEEN ASSASSINATED.\"\n1590 PRINT\n1592 PRINT\n1596 STOP\n1600 PRINT\n1602 PRINT\n1610 PRINT DEATHS;\"COUNTRYMEN DIED IN ONE YEAR!!!!!\"\n1615 PRINT \"DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\"\n1620 PRINT \"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\"\n1622 M6=INT(RND(1)*10)\n1625 IF M6<=3 THEN 1670\n1630 IF M6<=6 THEN 1680\n1635 IF M6<=10 THEN 1690\n1670 PRINT \"ALSO HAD YOUR LEFT EYE GOUGED OUT!\"\n1672 GOTO 1590\n1680 PRINT \"HAVE ALSO GAINED A VERY BAD REPUTATION.\"\n1682 GOTO 1590\n1690 PRINT \"HAVE ALSO BEEN DECLARED NATIONAL FINK.\"\n1692 GOTO 1590\n\n1700 PRINT\n1702 PRINT\n1710 PRINT \"OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\"\n1715 PRINT \"WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\"\n1720 PRINT \"HATE YOUR GUTS.\"\n1730 GOTO 1570\n1800 IF DEATHS-POLLUTION_DEATHS<2 THEN 1515\n1807 PRINT\n1815 PRINT \"MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\"\n1820 PRINT \"NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\"\n1825 PRINT \"OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\"\n1830 PRINT \"BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\"\n1835 PRINT \"THE CHOICE IS YOURS.\"\n1840 PRINT \"IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\"\n1845 PRINT \"BEFORE PROCEEDING.\"\n1850 GOTO 1590\n1900 PRINT\n1902 PRINT\n1920 PRINT \"CONGRATULATIONS!!!!!!!!!!!!!!!!!!\"\n1925 PRINT \"YOU HAVE SUCCESFULLY COMPLETED YOUR\";YEARS_REQUIRED;\"YEAR TERM\"\n1930 PRINT \"OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\"\n1935 PRINT \"NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\"\n1940 PRINT \"LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\"\n1945 PRINT \"PLAYS THIS GAME.\"\n1950 GOTO 1590\n\n1960 PRINT \"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED\";\n1961 INPUT YEAR\n1962 IF YEAR<0 THEN 1590\n1963 IF YEAR<8 THEN 1969\n1965 PRINT \"   COME ON, YOUR TERM IN OFFICE IS ONLY\";YEARS_REQUIRED;\"YEARS.\"\n1967 GOTO 1960\n1969 PRINT \"HOW MUCH DID YOU HAVE IN THE TREASURY\";\n1970 INPUT RALLODS\n1971 IF RALLODS<0 THEN 1590\n1975 PRINT \"HOW MANY COUNTRYMEN\";\n1976 INPUT COUNTRYMEN\n1977 IF COUNTRYMEN<0 THEN 1590\n1980 PRINT \"HOW MANY WORKERS\";\n1981 INPUT FOREIGN_WORKERS\n1982 IF FOREIGN_WORKERS<0 THEN 1590\n1990 PRINT \"HOW MANY SQUARE MILES OF LAND\";\n1991 INPUT LANDAREA\n1992 IF LANDAREA<0 THEN 1590\n1993 IF LANDAREA>2000 THEN 1996\n1994 IF LANDAREA>1000 THEN 100\n1996 PRINT \"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\"\n1997 PRINT \"   AND 10,000 SQ. MILES OF FOREST LAND.\"\n1998 GOTO 1990\n\n2000 YEAR=YEAR+1\n2020 DEATHS=0\n2040 GOTO 100\n2046 END\n"
  },
  {
    "path": "00_Alternate_Languages/54_Letter/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript letter.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"letter\"\n\trun\n```\n3. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of letter.ms, and click the \"Run Script\" button.\n"
  },
  {
    "path": "00_Alternate_Languages/54_Letter/MiniScript/letter.ms",
    "content": "// Letter Guessing Game\n// Ported to MiniScript by Joe Strout, 2023\n\nprint \" \"*33 + \"LETTER\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\n\nprint \"Letter Guessing Game\"; print\nprint \"I'll think of a letter of the alphabet, A to Z.\"\nprint \"Try to guess my letter and I'll give you clues\"\nprint \"as to how close you're getting to my letter.\"\n\n// Function to play one round of the game\nplayOneGame = function\n\tletter = char(65 + floor(rnd * 26))\n\tguesses = 0\n\tprint; print \"OK, I have a letter.  Start guessing.\"\n\twhile true\n\t\tprint; guess = input(\"What is your guess? \")[:1].upper\n\t\tguesses = guesses + 1\n\t\tif guess == letter then\n\t\t\tprint; print \"You got it in \" + guesses + \" guesses!!\"\n\t\t\tif guesses > 5 then\n\t\t\t\tprint \"But it shouldn't take more than 5 guesses!\"\n\t\t\telse\n\t\t\t\tprint \"Good job !!!!!\"\n\t\t\t\tprint char(7) * 15\n\t\t\tend if\n\t\t\treturn\n\t\telse if guess < letter then\n\t\t\tprint \"Too low.  Try a higher letter.\"\n\t\telse\n\t\t\tprint \"Too high.  Try a lower letter.\"\n\t\tend if\n\tend while\nend function\n\n// main loop -- press Control-C to exit\nwhile true\n\tprint\n\tplayOneGame\n\tprint\n\tprint \"Let's play again.....\"\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/54_Letter/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/54_Letter/letter.bas",
    "content": "10 PRINT TAB(33);\"LETTER\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"LETTER GUESSING GAME\": PRINT\n210 PRINT \"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\"\n220 PRINT \"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\"\n230 PRINT \"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\"\n310 L=65+INT(RND(1)*26)\n320 G=0\n340 PRINT: PRINT \"O.K., I HAVE A LETTER.  START GUESSING.\"\n410 PRINT: PRINT \"WHAT IS YOUR GUESS\";\n420 G=G+1\n430 INPUT A$: A=ASC(A$): PRINT\n440 IF A=L THEN 500\n450 IF A>L THEN 480\n460 PRINT \"TOO LOW.  TRY A HIGHER LETTER.\": GOTO 410\n480 PRINT \"TOO HIGH.  TRY A LOWER LETTER.\": GOTO 410\n500 PRINT: PRINT \"YOU GOT IT IN\";G;\"GUESSES!!\"\n504 IF G<=5 THEN 508\n506 PRINT \"BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\": GOTO 515\n508 PRINT \"GOOD JOB !!!!!\"\n510 FOR N=1 TO 15: PRINT CHR$(7);: NEXT N\n515 PRINT\n520 PRINT \"LET'S PLAY AGAIN.....\"\n530 GOTO 310\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/55_Life/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript life.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"life\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/55_Life/MiniScript/life.ms",
    "content": "print \" \"*34 + \"LIFE\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nimport \"listUtil\"\t\t// (needed for list.init2d)\n\nmaxx = 66\t\t// (size adjusted for Mini Micro display)\nmaxy = 23\nA = list.init2d(maxx+1, maxy+1, 0)\n\n// Stuff the given pattern into the center of the cell array.\n// Return the number of live cells.\nstuffIntoCenter = function(pattern)\n\tmaxLen = 0\n\tfor p in pattern\n\t\tif p.len > maxLen then maxLen = p.len\n\tend for\n\n\tpopulation = 0\n\ty = floor(maxy/2 - pattern.len/2)\n\tfor row in pattern\n\t\tx = floor(maxx/2 - maxLen/2)\n\t\tfor c in row\n\t\t\tif c != \" \" then\n\t\t\t\tA[x][y] = 1\n\t\t\t\tpopulation += 1\n\t\t\tend if\n\t\t\tx += 1\n\t\tend for\n\t\ty += 1\n\tend for\n\treturn population\nend function\n\n// Get the initial pattern from the user\ninitToUserPattern = function\n\tprint \"Enter your pattern (enter DONE when done):\"\n\tuserPattern = []\n\twhile true\n\t\tp = input(\"?\")\n\t\tif p.upper == \"DONE\" then break\n\t\tif p and p[0] == \".\" then p = \" \" + p[1:]\n\t\tuserPattern.push p\n\tend while\n\treturn stuffIntoCenter(userPattern)\nend function\n\n// For testing purposes, skip asking the user and just use a hard-coded pattern.\ninitToStandardPattern = function\n\tpattern = [\n\t\t\"   **\",\n\t\t\"  * *\",\n\t\t\"    *\"]\n\treturn stuffIntoCenter(pattern)\nend function\n\n// Or, just for fun, initialize to a random pattern of junk in the center.\ninitRandom = function\n\tfor x in range(ceil(maxx*0.3), floor(maxx*0.7))\n\t\tfor y in range(ceil(maxy*0.3), floor(maxy*0.7))\n\t\t\tA[x][y] = rnd > 0.5\n\t\tend for\n\tend for\nend function\n\n// Define a function to draw the current game state.\n// This also changes 2 (dying) to 0 (dead), and 3 (being born) to 1 (alive).\ndrawGameState = function(generation=0, population=0, invalid=false)\n\tif version.hostName == \"Mini Micro\" then text.row = 26 else print\n\tprint \"Generation: \" + generation + \"    Population: \" + population +\n\t  \"    \" + \"INVALID!\" * invalid\n\tfor y in range(0, maxy)\n\t\ts = \"\"\n\t\tfor x in range(0, maxx)\n\t\t\tif A[x][y] == 2 then\n\t\t\t\tA[x][y] = 0\n\t\t\telse if A[x][y] == 3 then\n\t\t\t\tA[x][y] = 1\n\t\t\tend if\n\t\t\tif A[x][y] then s += \"*\" else s += \" \"\n\t\tend for\n\t\tprint s\n\tend for\nend function\n\n// Update the game state, setting cells that should be born to 3 and \n// cells that should die to 2.  Return the number of cells that will\n// be alive after this update.  Also, set globals.invalid if any live\n// cells are found on the edge of the map.\nupdateGameState = function\n\tpopulation = 0\n\tfor x in range(0, maxx)\n\t\tfor y in range(0, maxy)\n\t\t\tc = A[x][y] == 1 or A[x][y] == 2\t// center state\n\t\t\tn = -c\t// number of neighbors\n\t\t\tfor nx in range(x-1, x+1)\n\t\t\t\tif nx < 0 or nx > maxx then continue\n\t\t\t\tfor ny in range(y-1, y+1)\n\t\t\t\t\tif ny < 0 or ny > maxy then continue\n\t\t\t\t\tn += A[nx][ny] == 1 or A[nx][ny] == 2\n\t\t\t\tend for\n\t\t\tend for\n\t\t\tif c and n != 2 and n != 3 then\t// live cell with < 2 or > 3 neighbors...\n\t\t\t\tA[x][y] = 2\t\t\t\t\t// dies\n\t\t\telse if not c and n == 3 then\t// dead cell with 3 neighbors...\n\t\t\t\tA[x][y] = 3 \t\t\t\t// comes to life\n\t\t\t\tif x == 0 or x == maxx or y == 0 or y == maxy then\n\t\t\t\t\tglobals.invalid = true\n\t\t\t\tend if\n\t\t\tend if\n\t\t\tpopulation += (A[x][y] == 1 or A[x][y] == 3)\n\t\tend for\n\tend for\n\treturn population\nend function\n\t\n\n// Initialize the game state (uncomment one of the following three lines)\npopulation = initToUserPattern\n//population = initToStandardPattern\n//population = initRandom\n\n// Main loop\nif version.hostName == \"Mini Micro\" then clear\ninvalid = false\ngeneration = 0\nwhile population > 0\n\tdrawGameState generation, population, invalid\n\tpopulation = updateGameState\n\tgeneration += 1\n\t//key.get\t\t// <-- Uncomment this to single-step with each keypress!\nend while\ndrawGameState generation, population, invalid\n"
  },
  {
    "path": "00_Alternate_Languages/55_Life/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/55_Life/life.bas",
    "content": "2 PRINT TAB(34);\"LIFE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n8 PRINT \"ENTER YOUR PATTERN:\"\n9 X1=1: Y1=1: X2=24: Y2=70\n10 DIM A(24,70),B$(24)\n20 C=1\n30 INPUT B$(C)\n40 IF B$(C)=\"DONE\" THEN B$(C)=\"\": GOTO 80\n50 IF LEFT$(B$(C),1)=\".\" THEN B$(C)=\" \"+RIGHT$(B$(C),LEN(B$(C))-1)\n60 C=C+1\n70 GOTO 30\n80 C=C-1: L=0\n90 FOR X=1 TO C-1\n100 IF LEN(B$(X))>L THEN L=LEN(B$(X))\n110 NEXT X\n120 X1=11-C/2\n130 Y1=33-L/2\n140 FOR X=1 TO C\n150 FOR Y=1 TO LEN(B$(X))\n160 IF MID$(B$(X),Y,1)<>\" \" THEN A(X1+X,Y1+Y)=1:P=P+1\n170 NEXT Y\n180 NEXT X\n200 PRINT:PRINT:PRINT\n210 PRINT \"GENERATION:\";G,\"POPULATION:\";P;: IF I9 THEN PRINT \"INVALID!\";\n215 X3=24:Y3=70:X4=1: Y4=1: P=0\n220 G=G+1\n225 FOR X=1 TO X1-1: PRINT: NEXT X\n230 FOR X=X1 TO X2\n240 PRINT\n250 FOR Y=Y1 TO Y2\n253 IF A(X,Y)=2 THEN A(X,Y)=0:GOTO 270\n256 IF A(X,Y)=3 THEN A(X,Y)=1:GOTO 261\n260 IF A(X,Y)<>1 THEN 270\n261 PRINT TAB(Y);\"*\";\n262 IF X<X3 THEN X3=X\n264 IF X>X4 THEN X4=X\n266 IF Y<Y3 THEN Y3=Y\n268 IF Y>Y4 THEN Y4=Y\n270 NEXT Y\n290 NEXT X\n295 FOR X=X2+1 TO 24: PRINT: NEXT X\n299 X1=X3: X2=X4: Y1=Y3: Y2=Y4\n301 IF X1<3 THEN X1=3:I9=-1\n303 IF X2>22 THEN X2=22:I9=-1\n305 IF Y1<3 THEN Y1=3:I9=-1\n307 IF Y2>68 THEN Y2=68:I9=-1\n309 P=0\n500 FOR X=X1-1 TO X2+1\n510 FOR Y=Y1-1 TO Y2+1\n520 C=0\n530 FOR I=X-1 TO X+1\n540 FOR J=Y-1 TO Y+1\n550 IF A(I,J)=1 OR A(I,J)=2 THEN C=C+1\n560 NEXT J\n570 NEXT I\n580 IF A(X,Y)=0 THEN 610\n590 IF C<3 OR C>4 THEN A(X,Y)=2: GOTO 600\n595 P=P+1\n600 GOTO 620\n610 IF C=3 THEN A(X,Y)=3:P=P+1\n620 NEXT Y\n630 NEXT X\n635 X1=X1-1:Y1=Y1-1:X2=X2+1:Y2=Y2+1\n640 GOTO 210\n650 END\n"
  },
  {
    "path": "00_Alternate_Languages/56_Life_for_Two/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).  The only liberty I took with the original design is that, when prompting each player for their turn, I include a reminder of what symbol (* or #) represents their pieces on the board.\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript lifefortwo.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"lifefortwo\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/56_Life_for_Two/MiniScript/lifefortwo.ms",
    "content": "print \" \"*33 + \"LIFE2\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \" \"*10 + \"U.B. LIFE GAME\"\n\n// N: counts neighbors and game state, as follows:\n//    1's digit: player 1 neighbors\n//   10's digit: player 2 neighbors\n//  100's digit: player 1 current live cell\n// 1000's digit: player 2 current live cell\nN = []\nfor i in range(0,6); N.push [0]*7; end for\n\n// K: encodes the rule for what cells come to life, based on\n// the value in N.  The first 9 entries mean new life for Player 1;\n// the second 9 entries mean new life for Player 2.\nK = [3,102,103,120,130,121,112,111,12,\n\t 21,30,1020,1030,1011,1021,1003,1002,1012]\n\n// population: how many live cells each player (1-2) has\npopulation = [null, 0, 0]\n\n// Function to get input coordinates from the player, for any empty space.\n// Where possible, hide the input so the other player can't see it.\ngetCoords = function\n\twhile true\n\t\tprint \"X,Y\"\n\t\tinp = input.replace(\",\", \" \").replace(\"  \",\" \")\n\t\tif version.hostName == \"Mini Micro\" then\n\t\t\ttext.row = text.row + 1; print \" \"*60\n\t\tend if\n\t\tparts = inp.split\n\t\tif parts.len == 2 then\n\t\t\tx = parts[0].val\n\t\t\ty = parts[1].val\n\t\t\tif 0 < x <= 5 and 0 < y <= 5 and N[x][y] == 0 then break\n\t\tend if\n\t\tprint \"Illegal coords. Retype\"\n\tend while\n\treturn [x, y]\nend function\n\n// Function to print the board.  At the same time, it replaces\n// any player 1 value (as judged by list K) with 100, and any\n// player 2 value with 1000.  Also update population[] with the\n// number of pieces of each player.\nprintBoard = function\n\tpopulation[1] = 0\n\tpopulation[2] = 0\n\tfor y in range(0, 6)\n\t\tif y == 0 or y == 6 then\n\t\t\tprint \" 0  1  2  3  4  5  0\"\n\t\telse\n\t\t\tprint \" \" + y, \"  \"\n\t\t\tfor x in range(1, 5)\n\t\t\t\tkIndex = K.indexOf(N[x][y])\n\t\t\t\tif kIndex == null then\n\t\t\t\t\tprint \" \", \"  \"\n\t\t\t\t\tN[x][y] = 0\n\t\t\t\telse if kIndex < 9 then\n\t\t\t\t\tprint \"*\", \"  \"\n\t\t\t\t\tN[x][y] = 100\n\t\t\t\t\tpopulation[1] += 1\n\t\t\t\telse\n\t\t\t\t\tprint \"#\", \"  \"\n\t\t\t\t\tN[x][y] = 1000\n\t\t\t\t\tpopulation[2] += 1\n\t\t\t\tend if\n\t\t\tend for\n\t\t\tprint y\n\t\tend if\n\tend for\n\tprint\nend function\n\n// Function to update the board (N).\nupdateBoard = function\n\tfor j in range(1,5)\n\t\tfor k in range(1,5)\n\t\t\tif N[j][k] < 100 then continue  // not a live cell\n\t\t\tif N[j][k] > 999 then value = 10 else value = 1\n\t\t\tfor x in range(j-1, j+1)\n\t\t\t\tfor y in range(k-1, k+1)\n\t\t\t\t\tif x == j and y == k then continue\n\t\t\t\t\tN[x][y] += value\n\t\t\t\t\t//if [x,y] == [2,1] then print \"adding \" + value + \" from \" + j+\",\"+k + \" to \" + x+\",\"+y + \", --> \" + N[x][y]\n\t\t\t\tend for\n\t\t\tend for\n\t\tend for\n\tend for\nend function\n\n\n// Get initial player positions.\nfor player in [1,2]\n\tprint; print \"Player \" + player + \" - 3 live pieces.\"\n\tif player == 2 then value = 30 else value = 3\n\tfor k in range(1,3)\n\t\tpos = getCoords\n\t\tN[pos[0]][pos[1]] = value\n\tend for\nend for\n\nprintBoard\nwhile true\n\tupdateBoard\n\tprintBoard\n\tif population[1] == 0 and population[2] == 0 then\n\t\tprint \"A DRAW\"\n\t\tbreak\n\telse if population[1] == 0 then\n\t\tprint \"PLAYER 2 IS THE WINNER\"\n\t\tbreak\n\telse if population[2] == 0 then\n\t\tprint \"PLAYER 1 IS THE WINNER\"\n\t\tbreak\n\tend if\n\t\n\tprint; print \"Player 1 (*)\"\n\tp1pos = getCoords\n\tprint; print \"Player 2 (#)\"\n\tp2pos = getCoords\n\tif p1pos == p2pos then\n\t\tprint \"Same coord.  Set to 0\"\n\telse\n\t\tN[p1pos[0]][p1pos[1]] = 100\n\t\tN[p2pos[0]][p2pos[1]] = 1000\n\tend if\nend while"
  },
  {
    "path": "00_Alternate_Languages/56_Life_for_Two/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/56_Life_for_Two/lifefortwo.bas",
    "content": "2 PRINT TAB(33);\"LIFE2\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n7 DIM N(6,6),K(18),A(16),X(2),Y(2)\n8 DATA 3,102,103,120,130,121,112,111,12\n9 DATA 21,30,1020,1030,1011,1021,1003,1002,1012\n10 FOR M=1 TO 18: READ K(M): NEXT M\n13 DATA -1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1\n14 FOR O1= 1 TO 16: READ A(O1): NEXT O1\n20 GOTO 500\n50 FOR J=1 TO 5\n51 FOR K=1 TO 5\n55 IF N(J,K)>99 THEN GOSUB 200\n60 NEXT K\n65 NEXT J\n90 K=0: M2=0: M3=0\n99 FOR J=0 TO 6: PRINT\n100 FOR K=0 TO 6\n101 IF J<>0 THEN IF J<>6 THEN 105\n102 IF K=6 THEN PRINT 0;: GOTO 125\n103 PRINT K;: GOTO 120\n105 IF K<>0 THEN IF K<>6 THEN 110\n106 IF J=6 THEN PRINT 0: GOTO 126\n107 PRINT J;: GOTO 120\n110 GOSUB 300\n120 NEXT K\n125 NEXT J\n126 RETURN\n200 B=1: IF N(J,K)>999 THEN B=10\n220 FOR O1= 1 TO 15 STEP 2\n230 N(J+A(O1),K+A(O1+1))=N(J+A(O1),K+A(O1+1))+B\n231 NEXT O1\n239 RETURN\n300 IF N(J,K)<3 THEN 399\n305 FOR O1=1 TO 18\n310 IF N(J,K)=K(O1) THEN 350\n315 NEXT O1\n320 GOTO 399\n350 IF O1>9 THEN 360\n351 N(J,K)=100: M2=M2+1: PRINT \" * \";\n355 RETURN\n360 N(J,K)=1000: M3=M3+1: PRINT \" # \";\n365 RETURN\n399 N(J,K)=0: PRINT \"   \";: RETURN\n500 PRINT TAB(10);\"U.B. LIFE GAME\"\n505 M2=0: M3=0\n510 FOR J=1 TO 5\n511 FOR K=1 TO 5\n515 N(J,K)=0\n516 NEXT K\n517 NEXT J\n519 FOR B=1 TO 2: P1=3: IF B=2 THEN P1=30\n520 PRINT:PRINT \"PLAYER\";B;\" - 3 LIVE PIECES.\"\n535 FOR K1=1 TO 3: GOSUB 700\n540 N(X(B),Y(B))=P1: NEXT K1\n542 NEXT B\n559 GOSUB 90\n560 PRINT: GOSUB 50\n570 IF M2=0 THEN IF M3=0 THEN 574\n571 IF M3=0 THEN B=1: GOTO 575\n572 IF M2=0 THEN B=2: GOTO 575\n573 GOTO 580\n574 PRINT: PRINT \"A DRAW\":GOTO 800\n575 PRINT: PRINT \"PLAYER\";B;\"IS THE WINNER\":GOTO 800\n580 FOR B=1 TO 2: PRINT: PRINT: PRINT \"PLAYER\";B;: GOSUB 700\n581 IF B=99 THEN 560\n582 NEXT B\n586 N(X(1),Y(1))=100: N(X(2),Y(2))=1000\n596 GOTO 560\n700 PRINT \"X,Y\":PRINT\"XXXXXX\";CHR$(13);\"$$$$$$\";CHR$(13);\"&&&&&&\";\n701 PRINT CHR$(13);: INPUT Y(B),X(B)\n705 IF X(B)<=5 THEN IF X(B)>0 THEN 708\n706 GOTO 750\n708 IF Y(B)<=5 THEN IF Y(B)>0 THEN 715\n710 GOTO 750\n715 IF N(X(B),Y(B))<>0 THEN 750\n720 IF B=1 THEN RETURN\n725 IF X(1)=X(2) THEN IF Y(1)=Y(2) THEN 740\n730 RETURN\n740 PRINT \"SAME COORD.  SET TO 0\"\n741 N(X(B)+1,Y(B)+1)=0: B=99: RETURN\n750 PRINT \"ILLEGAL COORDS. RETYPE\": GOTO 700\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of litquiz.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript litquiz.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"litquiz\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/57_Literature_Quiz/MiniScript/litquiz.ms",
    "content": "print \" \"*24 + \"Literature Quiz\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nr=0\nprint \"Test your knowledge of children's literature.\"\nprint; print \"This is a multiple-choice quiz.\"\nprint \"Type a 1, 2, 3, or 4 after the question mark.\"\nprint; print \"Good luck!\"; \n\nprint; print\nprint \"In pinocchio, what was the name of the cat?\"\nprint \"1)Tigger, 2)Cicero, 3)Figaro, 4)Fuipetto\";\na = input(\"?\").val\nif a!=3 then\n\tprint \"Sorry...Figaro was his name.\"\nelse\n\tprint \"Very good!  Here's another.\"\n\tr += 1\nend if\n\nprint; print\nprint \"From whose garden did Bugs Bunny steal the carrots?\"\nprint \"1)Mr. Nixon's, 2)Elmer Fudd's, 3)Clem Judd's, 4)Stromboli's\";\na = input(\"?\").val\nif a != 2 then\n\tprint \"Too bad...it was elmer fudd's garden.\"\nelse\n\tprint \"Pretty good!\"\n\tr += 1\nend if\n\nprint; print\nprint \"In the Wizard of Oz, Dorothy's dog was named\"\nprint \"1)Cicero, 2)Trixia, 3)King, 4)Toto\";\na = input(\"?\").val\nif a != 4 then\n\tprint \"Back to the books,...Toto was his name.\"\nelse\n\tprint \"Yea!  You're a real literature giant.\"\n\tr += 1\nend if\n\nprint;print\nprint \"Who was the fair maiden who ate the poison apple?\"\nprint \"1)Sleeping Beauty, 2)Cinderella, 3)Snow White, 4)Wendy\";\na = input(\"?\").val\nif a != 3 then\n\tprint \"Oh, come on now...it was Snow White.\"\nelse\n\tprint \"Good memory!\"\n\tr += 1\nend if\n\nprint;print\nif r == 4 then\n\tprint \"Wow!  That's super!  You really know your nursery\"\n\tprint \"Your next quiz will be on 2nd century Chinese\"\n\tprint \"literature (ha, ha, ha)\"\nelse if r<2 then\n\tprint \"Ugh.  That was definitely not too swift.  Back to\"\n\tprint \"nursery school for you, my friend.\"\nelse\n\tprint \"Not bad, but you might spend a little more time\"\n\tprint \"reading the nursery greats.\"\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/57_Literature_Quiz/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/57_Literature_Quiz/litquiz.bas",
    "content": "1 PRINT TAB(25);\"LITERATURE QUIZ\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n5 R=0\n10 PRINT \"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\"\n12 PRINT: PRINT \"THIS IS A MULTIPLE-CHOICE QUIZ.\"\n13 PRINT \"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\"\n15 PRINT: PRINT \"GOOD LUCK!\": PRINT: PRINT\n40 PRINT \"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\"\n42 PRINT \"1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO\";\n43 INPUT A: IF A=3 THEN 46\n44 PRINT \"SORRY...FIGARO WAS HIS NAME.\": GOTO 50\n46 PRINT \"VERY GOOD!  HERE'S ANOTHER.\"\n47 R=R+1\n50 PRINT: PRINT\n51 PRINT \"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\"\n52 PRINT \"1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S\";\n53 INPUT A: IF A=2 THEN 56\n54 PRINT \"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\": GOTO 60\n56 PRINT \"PRETTY GOOD!\"\n57 R=R+1\n60 PRINT: PRINT\n61 PRINT \"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\"\n62 PRINT \"1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO\";\n63 INPUT A: IF A=4 THEN 66\n64 PRINT \"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\": GOTO 70\n66 PRINT \"YEA!  YOU'RE A REAL LITERATURE GIANT.\"\n67 R=R+1\n70 PRINT:PRINT\n71 PRINT \"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\"\n72 PRINT \"1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY\";\n73 INPUT A: IF A=3 THEN 76\n74 PRINT \"OH, COME ON NOW...IT WAS SNOW WHITE.\"\n75 GOTO 80\n76 PRINT \"GOOD MEMORY!\"\n77 R=R+1\n80 PRINT:PRINT\n85 IF R=4 THEN 100\n90 IF R<2 THEN 200\n92 PRINT \"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\"\n94 PRINT \"READING THE NURSERY GREATS.\"\n96 STOP\n100 PRINT \"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\"\n110 PRINT \"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\"\n120 PRINT \"LITERATURE (HA, HA, HA)\"\n130 STOP\n200 PRINT \"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\"\n205 PRINT \"NURSERY SCHOOL FOR YOU, MY FRIEND.\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/58_Love/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of love.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript love.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"love\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/58_Love/MiniScript/love.ms",
    "content": "print \" \"*33 + \"LOVE\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"A tribute to the great american artist, Robert Indiana.\"\nprint \"His greatest work will be reproduced with a message of\"\nprint \"your choice up to 60 characters.  If you can't think of\"\nprint \"a message, simple type the word 'LOVE'\"; print\nmsg = input(\"Your message, please? \")\nfor i in range(1, 10); print; end for\n\nrepeatedMsg = msg * ceil(60 / msg.len)\n\ndata = []\ndata += [60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5]\ndata += [4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4]\ndata += [4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4]\ndata += [4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4]\ndata += [4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8]\ndata += [1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1]\ndata += [5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1]\ndata += [6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10]\ndata += [7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10]\ndata += [8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1]\ndata += [9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1]\ndata += [11,8,13,27,1,11,8,13,27,1,60]\n\nfor row in range(0, 35)\n\ts = []\n\ta1 = 0; p = true\n\twhile a1 < 60\n\t\ta = data.pull\n\t\ta1 += a\n\t\tfor i in range(a1-a, a1-1)\n\t\t\ts.push repeatedMsg[i] * p + \" \" * (not p)\n\t\tend for\n\t\tp = not p\n\tend while\n\tprint s.join(\"\")\n\twait 0.1\t// OPTIONAL; slows printing down so you can see it all\nend for\n"
  },
  {
    "path": "00_Alternate_Languages/58_Love/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/58_Love/love.bas",
    "content": "2 PRINT TAB(33);\"LOVE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n20 PRINT \"A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\"\n30 PRINT \"HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\"\n40 PRINT \"YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\"\n50 PRINT \"A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\": PRINT\n60 INPUT \"YOUR MESSAGE, PLEASE\";A$: L=LEN(A$)\n70 DIM T$(120): FOR I=1 TO 10: PRINT: NEXT I\n100 FOR J=0 TO INT(60/L)\n110 FOR I=1 TO L\n120 T$(J*L+I)=MID$(A$,I,1)\n130 NEXT I: NEXT J\n140 C=0\n200 A1=1: P=1: C=C+1: IF C=37 THEN 999\n205 PRINT\n210 READ A: A1=A1+A: IF P=1 THEN 300\n240 FOR I=1 TO A: PRINT \" \";: NEXT I: P=1: GOTO 400\n300 FOR I=A1-A TO A1-1: PRINT T$(I);: NEXT I: P=0\n400 IF A1>60 THEN 200\n410 GOTO 210\n600 DATA 60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5\n610 DATA 4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4\n620 DATA 4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4\n630 DATA 4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4\n640 DATA 4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8\n650 DATA 1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1\n660 DATA 5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1\n670 DATA 6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10\n680 DATA 7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10\n690 DATA 8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1\n700 DATA 9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1\n710 DATA 11,8,13,27,1,11,8,13,27,1,60\n999 FOR I=1 TO 10: PRINT: NEXT I: END\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).  Note that there are three different programs in this folder, all variations on the \"land the LEM on the Moon\" idea.\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the desired program with a command such as:\n\n```\n\tminiscript lem.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"lem\"\t// (or \"lunar\" or \"rocket\")\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lem.ms",
    "content": "print \" \"*34 + \"LEM\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\n// rockt2 is an interactive game that simulates a lunar\n// landing is similar to that of the apollo program.\n// There is absolutely no chance involved\n\n\nprintIntro = function\n\tprint\n\tprint \"  You are on a lunar landing mission.  as the pilot of\"\n\tprint \"the lunar excursion module, you will be expected to\"\n\tprint \"give certain commands to the module navigation system.\"\n\tprint \"The on-board computer will give a running account\"\n\tprint \"of information needed to navigate the ship.\"\n\tprint\n\tinput \"(Press Return.)\"\n\tprint\n\tprint \"The attitude angle called for is described as follows.\"\n\tprint \"+ or -180 degrees is directly away from the moon\"\n\tprint \"-90 degrees is on a tangent in the direction of orbit\"\n\tprint \"+90 degrees is on a tangent from the direction of orbit\"\n\tprint \"0 (zero) degrees is directly toward the moon\"\n\tprint\n\tprint \" \"*30 + \"-180|+180\"\n\tprint \" \"*34 + \"^\"\n\tprint \" \"*27 + \"-90 < -+- > +90\"\n\tprint \" \"*34 + \"!\"\n\tprint \" \"*34 + \"0\"\n\tprint \" \"*21 + \"<<<< direction of orbit <<<<\"\n\tprint\n\tprint \" \"*20 + \"------ surface of moon ------\"\n\tprint\n\tinput\n\tprint\n\tprint \"All angles between -180 and +180 degrees are accepted.\"\n\tprint\n\tprint \"1 fuel unit = 1 sec. at max thrust\"\n\tprint \"Any discrepancies are accounted for in the use of fuel\"\n\tprint \"for an attitude change.\"\n\tprint \"Available engine power: 0 (zero) and any value between\"\n\tprint \"10 and 100 percent.\"\n\tprint\n\tprint \"Negative thrust or time is prohibited.\"\n\tprint\n\tinput\nend function\n\nprintInOutInfo = function(withExample = true)\n\tprint\n\tprint \"Input: time interval in seconds ------ (T)\"\n\tprint \"       percentage of thrust ---------- (P)\"\n\tprint \"       attitude angle in degrees ----- (A)\"\n\tprint\n\tif withExample then\n\t\tprint \"For example:\"\n\t\tprint \"T,P,A? 10,65,-60\"\n\t\tprint \"To abort the mission at any time, enter 0,0,0\"\n\t\tprint\n\tend if\n\tprint \"Output: total time in elapsed seconds\"\n\tprint \"        height in \" + ms\n\tprint \"        distance from landing site in \" + ms\n\tprint \"        vertical velocity in \" + ms + \"/second\"\n\tprint \"        horizontal velocity in \" + ms + \"/second\"\n\tprint \"        fuel units remaining\"\n\tprint\nend function\n\ninitState = function\n\tglobals.m = 17.95\n\tglobals.f1 = 5.25\n\tglobals.n = 7.5\n\tglobals.r0 = 926\n\tglobals.v0 = 1.29\n\tglobals.t = 0\n\tglobals.h0 = 60\n\tglobals.r = r0+h0\n\tglobals.a = -3.425\n\tglobals.r1 = 0\n\tglobals.a1 = 8.84361e-04\n\tglobals.r3 = 0\n\tglobals.a3 = 0\n\tglobals.m1 = 7.45\n\tglobals.m0 = m1\n\tglobals.b = 750\n\tglobals.t1 = 0\n\tglobals.f = 0\n\tglobals.p = 0\n\tglobals.n = 1\n\tglobals.m2 = 0\n\tglobals.s = 0\n\tglobals.c = 0\nend function\n\ngetUnits = function(moreHelp=true)\n\tprint\n\twhile true\n\t\tprint \"Input measurement option number? \", \"\"\n\t\tif moreHelp then\n\t\t\tprint\n\t\t\tprint \"Which system of measurement do you prefer?\"\n\t\t\tprint \" 1 = metric     0 = english\"\n\t\t\tprint \"Enter the appropriate number? \", \"\"\n\t\tend if\n\t\tk = input.val\n\t\tif k == 0 then\n\t\t\tglobals.z = 6080\n\t\t\tglobals.ms = \"feet\"\n\t\t\tglobals.g3 = .592\n\t\t\tglobals.ns = \"n.miles\"\n\t\t\tglobals.g5 = z\n\t\t\tbreak\n\t\telse if k == 1 then\n\t\t\tglobals.z = 1852.8\n\t\t\tglobals.ms=\"meters\"\n\t\t\tglobals.g3 = 3.6\n\t\t\tglobals.ns=\" kilometers\"\n\t\t\tglobals.g5 = 1000\n\t\t\tbreak\n\t\tend if\n\t\tmoreHelp = true\n\tend while\nend function\n\nstartFirstGame = function\n\tinitState\n\tprint\n\tprint \"Lunar Landing Simulation\"\n\tprint\n\tprint \"Have you flown an Apollo/LEM mission before\", \"\"\n\twhile true\n\t\tqs = input(\" (yes or no)? \").lower\n\t\tif qs and (qs[0] == \"y\" or qs[0] == \"n\") then break\n\t\tprint \"Just answer the question, please, \", \"\"\n\tend while\n\tgetUnits (qs[0] == \"n\")\n\tif qs[0] == \"n\" then printIntro\n\tprintInOutInfo\nend function\n\nstartSubsequentGame = function\n\tinitState\n\tprint\n\tprint \"OK, do you want the complete instructions or the input -\"\n\tprint \"output statements?\"\n\twhile true\n\t\tprint \"1 = complete instructions\"\n\t\tprint \"2 = input-output statements\"\n\t\tprint \"3 = neither\"\n\t\tb1 = input.val\n\t\tif 1 <= b1 <= 3 then break\n\tend while\n\tif b1 == 1 then printIntro\n\tif b1 < 3 then printInOutInfo\nend function\n\ngetTurnInputs = function\n\twhile true\n\t\tprint\n\t\tinp = input(\"T,P,A? \").replace(\",\", \" \").replace(\"  \", \" \").split\n\t\tif inp.len != 3 then continue\n\t\tglobals.t1 = inp[0].val\t// NOTE: though we prompt for T, P, A,\n\t\tglobals.f = inp[1].val\t// internally these are t1, f, and p respectively.\n\t\tglobals.p = inp[2].val\n\t\tglobals.f = f/100\n\t\tif t1 < 0 then\n\t\t\tprint\n\t\t\tprint \"This spacecraft is not able to violate the space-\";\n\t\t\tprint \"time continuum.\"\n\t\t\tcontinue\n\t\telse if t1 == 0 then\n\t\t\treturn\t\t// abort mission\n\t\tend if\n\t\tif f < 0 or f > 1.05 or abs(f-.05) < .05 then\n\t\t\tprint\n\t\t\tprint \"Impossible thrust value: \", \"\"\n\t\t\tif f < 0 then\n\t\t\t\tprint \"negative\"\n\t\t\telse if f < 0.5 then\n\t\t\t\tprint \"too small\"\n\t\t\telse\n\t\t\t\tprint \"too large\"\n\t\t\tend if\n\t\t\tcontinue\n\t\tend if\n\t\tif abs(p) > 180 then\n\t\t\tprint\n\t\t\tprint \"If you want to spin around, go outside the module\"\n\t\t\tprint \"for an E.V.A.\"\n\t\t\tcontinue\n\t\tend if\n\t\treturn\n\tend while\nend function\n\npad = function(num, width=10)\n\tanum = abs(num)\n\tif anum >= 10000 then\n\t\ts = round(num)\n\telse if anum >= 10000 then\n\t\ts = round(num, 1)\n\telse if anum > 100 then\n\t\ts = round(num, 2)\n\telse\n\t\ts = round(num, 3)\n\tend if\n\treturn (s + \" \" * width)[:width]\nend function\n\nintegrate = function\n\tn = 20\n\tif t1 >= 400 then n = t1/20\n\tglobals.t1 = t1/n\n\tglobals.p = p*3.14159/180\n\ts = sin(p)\n\tc = cos(p)\n\tglobals.m2 = m0*t1*f/b\n\tglobals.r3 = -.5*r0*((v0/r)^2)+r*a1*a1\n\tglobals.a3 = -2*r1*a1/r\n\n\tfor i in range(1, n)\n\t\tif m1 != 0 then\n\t\t\tglobals.m1 = m1-m2\n\t\t\tif m1<=0 then\n\t\t\t\tglobals.f = f*(1+m1/m2)\n\t\t\t\tglobals.m2 = m1+m2\n\t\t\t\tprint \"You are out of fuel.\"\n\t\t\t\tglobals.m1 = 0\n\t\t\tend if\n\t\telse\n\t\t\tglobals.f = 0\n\t\t\tglobals.m2 = 0\n\t\tend if\n\t\tglobals.m = m-.5*m2\n\t\tglobals.r4 = r3\n\t\tglobals.r3 = -.5*r0*((v0/r)^2)+r*a1*a1\n\t\tglobals.r2 = (3*r3-r4)/2+.00526*f1*f*c/m\n\t\tglobals.a4 = a3\n\t\tglobals.a3 = -2*r1*a1/r\n\t\tglobals.a2 = (3*a3-a4)/2+.0056*f1*f*s/(m*r)\n\t\tglobals.x = r1*t1+.5*r2*t1*t1\n\t\tglobals.r = r+x\n\t\tglobals.h0 = h0+x\n\t\tglobals.r1 = r1+r2*t1\n\t\tglobals.a = a+a1*t1+.5*a2*t1*t1\n\t\tglobals.a1 = a1+a2*t1\n\t\tglobals.m = m-.5*m2\n\t\tglobals.t = t+t1\n\t\tif h0<3.287828e-04 then break\n\tend for\n\n\tglobals.h = h0*z\n\tglobals.h1 = r1*z\n\tglobals.d = r0*a*z\n\tglobals.d1 = r*a1*z\n\tglobals.t2 = m1*b/m0\n\n\tprint \" \" + [pad(t, 10), pad(h, 10), pad(d, 10), pad(h1, 10), pad(d1, 10), pad(t2, 10)].join\nend function\n\n// Do one turn of the game.  Return true if game still in progress,\n// or false when game is over (aborted, crashed, or landed).\ndoOneTurn = function\n\tif m1 == 0 then\n\t\t// out of fuel!\n\t\tglobals.t1 = 20\n\t\tglobals.f = 0\n\t\tglobals.p = 0\n\telse\n\t\tgetTurnInputs\n\tend if\n\tif t1 == 0 then\n\t\tprint \"Mission abended\"\n\t\treturn false\n\tend if\n\tintegrate\n\t\n\tif h0 < 3.287828e-04 then\n\t\tif r1 < -8.21957e-04 or abs(r*a1) > 4.93174e-04 or h0 < -3.287828e-04 then\n\t\t\tprint\n\t\t\tprint \"Crash !!!!!!!!!!!!!!!!\"\n\t\t\tprint \"Your impact created a crater \" + abs(h) + \" \" + ms + \" deep.\"\n\t\t\tx1 = sqr(d1*d1+h1*h1)*g3\n\t\t\tprint \"At contact you were traveling \" + x1 + \" \" + ns + \"/hr\"\n\t\telse if abs(d)>10*z then\n\t\t\tprint \"You are down safely - \"\n\t\t\tprint\n\t\t\tprint \"But missed the landing site by\" + abs(d/g5) + \" \" + ns + \".\"\n\t\telse\n\t\t\tprint\n\t\t\tprint \"Tranquility Base here -- the Eagle has landed.\"\n\t\t\tprint \"Congratulations -- there was no spacecraft damage.\"\n\t\t\tprint \"You may now proceed with surface exploration.\"\t\t\n\t\tend if\n\t\treturn false\n\tend if\n\t\n\tif r0*a>164.474 then\n\t\tprint\n\t\tprint \"You have been lost in space with no hope of recovery.\"\n\t\treturn false\n\tend if\n\treturn true\nend function\n\nstartFirstGame\nwhile true\n\tt1 = 0; f = 0; p = 0\n\tintegrate\n\twhile doOneTurn\n\tend while\n\tprint\n\twhile true\n\t\tqs = input(\"Do you want to try it again (yes/no)? \").lower\n\t\tif qs and (qs[0] == \"y\" or qs[0] == \"n\") then break\n\tend while\n\tif qs[0] == \"n\" then\n\t\tprint\n\t\tprint \"Too bad, the space program hates to lose experienced\"\n\t\tprint \"astronauts.\"\n\t\tbreak\n\tend if\n\tstartSubsequentGame\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms",
    "content": "print \" \"*33 + \"Lunar\"\nprint \" \"*15 + \"Creative Computing Morristown, New Jersey\"\nprint; print; print\nprint \"This is a computer simulation of an Apollo lunar\"\nprint \"landing capsule.\"; print; print\nprint \"The on-board computer has failed (it was made by\"\nprint \"Xerox) so you have to land the capsule manually.\"\n\nprintCols = function(fields, delimiter=null)\n\tif delimiter == null then delimiter = text.delimiter\n\tline = \"\"\n\tfor s in fields\n\t\tline += (s + \" \"*12)[:12]\n\tend for\n\tprint line, delimiter\nend function\n\ndoOneGame = function\n\tprint; print \"Set burn rate of retro rockets to any value between\"\n\tprint \"0 (free fall) and 200 (maximum burn) pounds per second.\"\n\tprint \"Set new burn rate every 10 seconds.\"; print\n\tprint \"Capsule weight 32,500 lbs; fuel weight 16,500 lbs.\"\n\tprint; print; print; print \"Good luck\"\n\tl = 0\n\n\tprint\n\tprintCols [\"sec\",\"mi + ft\",\"mph\",\"lb fuel\",\"burn rate\"]\n\tprint\n\ta=120; v = 1; m=33000; n=16500; g=1e-03; z = 1.8\n\n\tformulaSet1 = function\t\t// (subroutine 330)\n\t\touter.l += s\n\t\touter.t -= s\n\t\touter.m -= s * k\n\t\touter.a = i\n\t\touter.v = j\n\tend function\n\t\n\tformulaSet2 = function\t\t// (subroutine 420)\n\t\touter.q = s * k / m\n\t\touter.j = v + g*s + z*(-q-q*q/2-q^3/3-q^4/4-q^5/5)\n\t\touter.i = a - g*s*s/2 - v*s+z*s*(q/2+q^2/6+q^3/12+q^4/20+q^5/30)\n\tend function\n\n\tformulaSet3 = function\t\t// (loop 340-360)\n\t\twhile s >= 5e-3\n\t\t\touter.d = v + sqrt(v * v + 2 * a * (g - z * k / m))\n\t\t\touter.s = 2 * a / d\n\t\t\tformulaSet2\n\t\t\tformulaSet1\n\t\tend while\n\tend function\n\n\twhile true\n\t\tprintCols [l, floor(a) + \" \" + floor(5280*(a-floor(a))), 3600*v, m-n], \"\"\n\t\tk = input.val\n\t\tt=10\n\t\tshouldExit = false\n\t\t\n\t\twhile true\n\t\t\tif m-n < 1e-03 then break\n\t\t\tif t < 1e-03 then break\n\t\t\ts = t; if m < n+s*k then s = (m-n)/k\n\t\t\tformulaSet2\n\t\t\tif i <= 0 then\n\t\t\t\tformulaSet3\n\t\t\t\tshouldExit = true\n\t\t\t\tbreak\n\t\t\tend if\n\t\t\tif v > 0 and j < 0 then\n\t\t\t\twhile v > 0 and j <= 0\n\t\t\t\t\tw = (1 - m*g/(z*k))/2\n\t\t\t\t\ts = m*v / (z*k*(w + sqrt(w*w + v/z))) + 0.05\n\t\t\t\t\tformulaSet2\n\t\t\t\t\tif i <= 0 then\n\t\t\t\t\t\tformulaSet3\n\t\t\t\t\t\tshouldExit = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\tend if\n\t\t\t\t\tformulaSet1\n\t\t\t\tend while\n\t\t\t\tif shouldExit then break\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\tformulaSet1\n\t\tend while\n\t\tif shouldExit then break\n\t\tif m-n < 1e-03 then\n\t\t\tprint \"Fuel out at \" + round(l) + \" seconds\"\n\t\t\ts = (-v+sqrt(v*v+2*a*g))/g\n\t\t\tv = v+g*s; l = l+s\n\t\t\tbreak\n\t\tend if\n\tend while\n\t\t\n\tw = 3600*v\n\tprint \"On moon at \" + l + \" seconds - impact velocity \" + round(w,1) + \" mph\"\n\tif w <= 1.2 then\n\t\tprint \"Perfect landing!\"\n\telse if w <= 10 then\n\t\tprint \"Good landing (could be better)\"\n\telse if w <= 60 then\n\t\tprint \"Craft damage... you're stranded here until a rescue\"\n\t\tprint \"party arrives. Hope you have enough oxygen!\"\n\telse\n\t\tprint \"Sorry there were no survivors. You blew it!\"\n\t\tprint \"In fact, you blasted a new lunar crater \" + round(w*.227,1) + \" feet deep!\"\n\tend if\nend function\n\nwhile true\n\tdoOneGame\n\tprint; print; print; print \"Try again??\"\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms",
    "content": "if version.hostName == \"Mini Micro\" then clear\nprint \" \"*30 + \"Rocket\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Lunar Landing Simulation\"\nprint \"----- ------- ----------\";  print\nyn = input(\"Do you want instructions (yes or no)? \").lower\nif not yn or yn[0] != \"n\" then\n\tprint\n\tprint \"You are landing on the moon and and have taken over manual\"\n\tprint \"control 1000 feet above a good landing spot. You have a down-\"\n\tprint \"ward velocity of 50 feet/sec. 150 units of fuel remain.\"\n\tprint\n\tprint \"Here are the rules that govern your Apollo space-craft\"\n\tprint \"(Press Return after each one):\"; print\n\tprint \"(1) After each second the height, velocity, and remaining fuel\"\n\tprint \"    will be reported via Digby your on-board computer.\"\n\tinput\n\tprint \"(2) After the report a '?' will appear. Enter the number\"\n\tprint \"    of units of fuel you wish to burn during the next\"\n\tprint \"    second. Each unit of fuel will slow your descent by\"\n\tprint \"    1 foot/sec.\"\n\tinput\n\tprint \"(3) The maximum thrust of your engine is 30 feet/sec/sec\"\n\tprint \"    or 30 units of fuel per second.\"\n\tinput\n\tprint \"(4) When you contact the lunar surface, your descent engine\"\n\tprint \"    will automatically shut down and you will be given a\"\n\tprint \"    report of your landing speed and remaining fuel.\"\n\tinput\n\tprint \"(5) If you run out of fuel the '?' will no longer appear\"\n\tprint \"    but your second by second report will continue until\"\n\tprint \"    you contact the lunar surface.\"; print\n\tinput\nend if\n\npad = function(s, width=10)\n\treturn (s + \" \"*width)[:width]\nend function\n\n// Bonus little feature when running in Mini Micro: display a header bar\n// always at the top of the screen.\ndrawHeaders = function\n\tif version.hostName != \"Mini Micro\" then return\n\tdisplay(2).mode = displayMode.text; td = display(2)\n\ttd.color = text.color; td.backColor = color.black\n\ttd.row = 25; td.column = 0\n\ttd.print \"sec  feet   speed     fuel    plot of distance\" + \" \"*21\nend function\n\nwhile true\n\tprint \"Beginning landing procedure..........\"; print\n\tprint \"G O O D  L U C K ! ! !\"\n\tprint; print\n\tprint \"sec  feet   speed     fuel    plot of distance\"\n\tdrawHeaders\n\tprint\n\tt=0; h=1000; v=50; fuel=150\n\twhile true\n\t\tprint pad(t,5) + pad(h,7) + pad(v, 10) + pad(fuel,8) + \"|\" + \" \"*floor(h/30) + \"*\"\n\t\tif fuel <= 0 then\n\t\t\tburn = 0\n\t\t\twait 0.5\t// (slight pause for drama and legibility)\n\t\telse\n\t\t\tburn = input(\"?\").val\n\t\t\tif burn < 0 then burn = 0\n\t\t\tif burn > 30 then burn=30\n\t\t\tif burn > fuel then\n\t\t\t\tburn = fuel\n\t\t\t\tprint \"**** out of fuel ****\"\n\t\t\tend if\n\t\tend if\n\t\tv1 = v - burn + 5\n\t\tfuel -= burn\n\t\th -= .5*(v+v1)\n\t\tif h <= 0 then break\n\t\tt += 1\n\t\tv = v1\n\tend while\n\tprint \"***** CONTACT *****\"\n\th = h+ .5*(v1+v)\n\tif burn == 5 then\n\t\td = h/v\n\telse\n\t\td = (-v+sqrt(v*v+h*(10-2*burn)))/(5-burn)\n\tend if\n\tv1 = v + (5-burn)*d\n\tprint \"Touchdown at \" + (t+d) + \" seconds.\"\n\tprint \"Landing velocity = \" + round(v1,1) + \" feet/sec.\"\n\tprint fuel + \" units of fuel remaining.\"\n\tif v1 == 0 then\n\t\tprint \"Congratulations! a perfect landing!!\"\n\t\tprint \"Your license will be renewed.......later.\"\n\telse if abs(v1) >= 2 then\n\t\tprint \"***** Sorry, but you blew it!!!!\"\n\t\tprint \"Appropriate condolences will be sent to your next of kin.\"\n\tend if\n\tprint; print; print\n\tyn = input(\"Another mission? \").lower\n\tif not yn or yn[0] != \"y\" then break\nend while\nprint;  print \"Control out.\";  print\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/lem.bas",
    "content": "2 PRINT TAB(34);\"LEM\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n7 REM ROCKT2 IS AN INTERACTIVE GAME THAT SIMULATES A LUNAR\n8 REM LANDING IS SIMILAR TO THAT OF THE APOLLO PROGRAM.\n9 REM THERE IS ABSOLUTELY NO CHANCE INVOLVED\n10 Z$=\"GO\"\n15 B1=1\n20 M=17.95\n25 F1=5.25\n30 N=7.5\n35 R0=926\n40 V0=1.29\n45 T=0\n50 H0=60\n55 R=R0+H0\n60 A=-3.425\n65 R1=0\n70 A1=8.84361E-04\n75 R3=0\n80 A3=0\n85 M1=7.45\n90 M0=M1\n95 B=750\n100 T1=0\n105 F=0\n110 P=0\n115 N=1\n120 M2=0\n125 S=0\n130 C=0\n135 IF Z$=\"YES\" THEN 1150\n140 PRINT\n145 PRINT \"LUNAR LANDING SIMULATION\"\n150 PRINT\n155 PRINT \"HAVE YOU FLOWN AN APOLLO/LEM MISSION BEFORE\";\n160 PRINT \" (YES OR NO)\";\n165 INPUT Q$\n170 IF Q$=\"YES\" THEN 190\n175 IF Q$=\"NO\" THEN 205\n180 PRINT \"JUST ANSWER THE QUESTION, PLEASE, \";\n185 GOTO 160\n190 PRINT\n195 PRINT \"INPUT MEASUREMENT OPTION NUMBER\";\n200 GOTO 225\n205 PRINT\n210 PRINT \"WHICH SYSTEM OF MEASUREMENT DO YOU PREFER?\"\n215 PRINT \" 1=METRIC     0=ENGLISH\"\n220 PRINT \"ENTER THE APPROPRIATE NUMBER\";\n225 INPUT K\n230 PRINT\n235 IF K=0 THEN 280\n240 IF K=1 THEN 250\n245 GOTO 220\n250 Z=1852.8\n255 M$=\"METERS\"\n260 G3=3.6\n265 N$=\" KILOMETERS\"\n270 G5=1000\n275 GOTO 305\n280 Z=6080\n285 M$=\"FEET\"\n290 G3=.592\n295 N$=\"N.MILES\"\n300 G5=Z\n305 IF B1=3 THEN 670\n310 IF Q$=\"YES\" THEN 485\n315 PRINT\n320 PRINT \"  YOU ARE ON A LUNAR LANDING MISSION.  AS THE PILOT OF\"\n325 PRINT \"THE LUNAR EXCURSION MODULE, YOU WILL BE EXPECTED TO\"\n330 PRINT \"GIVE CERTAIN COMMANDS TO THE MODULE NAVIGATION SYSTEM.\"\n335 PRINT \"THE ON-BOARD COMPUTER WILL GIVE A RUNNING ACCOUNT\"\n340 PRINT \"OF INFORMATION NEEDED TO NAVIGATE THE SHIP.\"\n345 PRINT\n350 PRINT\n355 PRINT \"THE ATTITUDE ANGLE CALLED FOR IS DESCRIBED AS FOLLOWS.\"\n360 PRINT \"+ OR -180 DEGREES IS DIRECTLY AWAY FROM THE MOON\"\n365 PRINT \"-90 DEGREES IS ON A TANGENT IN THE DIRECTION OF ORBIT\"\n370 PRINT \"+90 DEGREES IS ON A TANGENT FROM THE DIRECTION OF ORBIT\"\n375 PRINT \"0 (ZERO) DEGREES IS DIRECTLY TOWARD THE MOON\"\n380 PRINT\n385 PRINT TAB(30);\"-180|+180\"\n390 PRINT TAB(34);\"^\"\n395 PRINT TAB(27);\"-90 < -+- > +90\"\n400 PRINT TAB(34);\"!\"\n405 PRINT TAB(34);\"0\"\n410 PRINT TAB(21);\"<<<< DIRECTION OF ORBIT <<<<\"\n415 PRINT\n420 PRINT TAB(20);\"------ SURFACE OF MOON ------\"\n425 PRINT\n430 PRINT\n435 PRINT \"ALL ANGLES BETWEEN -180 AND +180 DEGREES ARE ACCEPTED.\"\n440 PRINT\n445 PRINT \"1 FUEL UNIT = 1 SEC. AT MAX THRUST\"\n450 PRINT \"ANY DISCREPANCIES ARE ACCOUNTED FOR IN THE USE OF FUEL\"\n455 PRINT \"FOR AN ATTITUDE CHANGE.\"\n460 PRINT \"AVAILABLE ENGINE POWER: 0 (ZERO) AND ANY VALUE BETWEEN\"\n465 PRINT \"10 AND 100 PERCENT.\"\n470 PRINT\n475 PRINT\"NEGATIVE THRUST OR TIME IS PROHIBITED.\"\n480 PRINT\n485 PRINT\n490 PRINT \"INPUT: TIME INTERVAL IN SECONDS ------ (T)\"\n495 PRINT \"       PERCENTAGE OF THRUST ---------- (P)\"\n500 PRINT \"       ATTITUDE ANGLE IN DEGREES ----- (A)\"\n505 PRINT\n510 IF Q$=\"YES\" THEN 535\n515 PRINT \"FOR EXAMPLE:\"\n520 PRINT \"T,P,A? 10,65,-60\"\n525 PRINT \"TO ABORT THE MISSION AT ANY TIME, ENTER 0,0,0\"\n530 PRINT\n535 PRINT \"OUTPUT: TOTAL TIME IN ELAPSED SECONDS\"\n540 PRINT \"        HEIGHT IN \";M$\n545 PRINT \"        DISTANCE FROM LANDING SITE IN \";M$\n550 PRINT \"        VERTICAL VELOCITY IN \";M$;\"/SECOND\"\n555 PRINT \"        HORIZONTAL VELOCITY IN \";M$;\"/SECOND\"\n560 PRINT \"        FUEL UNITS REMAINING\"\n565 PRINT\n570 GOTO 670\n575 PRINT\n580 PRINT \"T,P,A\";\n585 INPUT T1,F,P\n590 F=F/100\n595 IF T1<0 THEN 905\n600 IF T1=0 THEN 1090\n605 IF ABS(F-.05)>1 THEN 945\n610 IF ABS(F-.05)<.05 THEN 945\n615 IF ABS(P)>180 THEN 925\n620 N=20\n625 IF T1<400 THEN 635\n630 N=T1/20\n635 T1=T1/N\n640 P=P*3.14159/180\n645 S=SIN(P)\n650 C=COS(P)\n655 M2=M0*T1*F/B\n660 R3=-.5*R0*((V0/R)^2)+R*A1*A1\n665 A3=-2*R1*A1/R\n670 FOR I=1 TO N\n675 IF M1=0 THEN 715\n680 M1=M1-M2\n685 IF M1>0 THEN 725\n690 F=F*(1+M1/M2)\n695 M2=M1+M2\n700 PRINT \"YOU ARE OUT OF FUEL.\"\n705 M1=0\n710 GOTO 725\n715 F=0\n720 M2=0\n725 M=M-.5*M2\n730 R4=R3\n735 R3=-.5*R0*((V0/R)^2)+R*A1*A1\n740 R2=(3*R3-R4)/2+.00526*F1*F*C/M\n745 A4=A3\n750 A3=-2*R1*A1/R\n755 A2=(3*A3-A4)/2+.0056*F1*F*S/(M*R)\n760 X=R1*T1+.5*R2*T1*T1\n765 R=R+X\n770 H0=H0+X\n775 R1=R1+R2*T1\n780 A=A+A1*T1+.5*A2*T1*T1\n785 A1=A1+A2*T1\n790 M=M-.5*M2\n795 T=T+T1\n800 IF H0<3.287828E-04 THEN 810\n805 NEXT I\n810 H=H0*Z\n815 H1=R1*Z\n820 D=R0*A*Z\n825 D1=R*A1*Z\n830 T2=M1*B/M0\n835 PRINT \" \";T;TAB(10);H;TAB(23);D;\n840 PRINT TAB(37);H1;TAB(49);D1;TAB(60);T2\n845 IF H0<3.287828E-04 THEN 880\n850 IF R0*A>164.474 THEN 1050\n855 IF M1>0 THEN 580\n860 T1=20\n865 F=0\n870 P=0\n875 GOTO 620\n880 IF R1<-8.21957E-04 THEN 1020\n885 IF ABS(R*A1)>4.93174E-04 THEN 1020\n890 IF H0<-3.287828E-04 THEN 1020\n895 IF ABS(D)>10*Z THEN 1065\n900 GOTO 995\n905 PRINT\n910 PRINT \"THIS SPACECRAFT IS NOT ABLE TO VIOLATE THE SPACE-\";\n915 PRINT \"TIME CONTINUUM.\"\n920 GOTO 575\n925 PRINT\n930 PRINT \"IF YOU WANT TO SPIN AROUND, GO OUTSIDE THE MODULE\"\n935 PRINT \"FOR AN E.V.A.\"\n940 GOTO 575\n945 PRINT\n950 PRINT \"IMPOSSIBLE THRUST VALUE \";\n955 IF F<0 THEN 985\n960 IF F-.05<.05 THEN 975\n965 PRINT \"TOO LARGE\"\n970 GOTO 575\n975 PRINT \"TOO SMALL\"\n980 GOTO 575\n985 PRINT \"NEGATIVE\"\n990 GOTO 575\n995 PRINT\n1000 PRINT \"TRANQUILITY BASE HERE -- THE EAGLE HAS LANDED.\"\n1005 PRINT \"CONGRATULATIONS -- THERE WAS NO SPACECRAFT DAMAGE.\"\n1010 PRINT \"YOU MAY NOW PROCEED WITH SURFACE EXPLORATION.\"\n1015 GOTO 1100\n1020 PRINT\n1025 PRINT \"CRASH !!!!!!!!!!!!!!!!\"\n1030 PRINT \"YOUR IMPACT CREATED A CRATER\";ABS(H);M$;\" DEEP.\"\n1035 X1=SQR(D1*D1+H1*H1)*G3\n1040 PRINT \"AT CONTACT YOU WERE TRAVELING\";X1;N$;\"/HR\"\n1045 GOTO 1100\n1050 PRINT\n1055 PRINT \"YOU HAVE BEEN LOST IN SPACE WITH NO HOPE OF RECOVERY.\"\n1060 GOTO 1100\n1065 PRINT \"YOU ARE DOWN SAFELY - \"\n1075 PRINT\n1080 PRINT \"BUT MISSED THE LANDING SITE BY\";ABS(D/G5);N$;\".\"\n1085 GOTO 1100\n1090 PRINT\n1095 PRINT \"MISSION ABENDED\"\n1100 PRINT\n1105 PRINT \"DO YOU WANT TO TRY IT AGAIN (YES/NO)?\"\n1110 INPUT Z$\n1115 IF Z$=\"YES\" THEN 20\n1120 IF Z$=\"NO\" THEN 1130\n1125 GOTO 1105\n1130 PRINT\n1135 PRINT \"TOO BAD, THE SPACE PROGRAM HATES TO LOSE EXPERIENCED\"\n1140 PRINT \"ASTRONAUTS.\"\n1145 STOP\n1150 PRINT\n1155 PRINT \"OK, DO YOU WANT THE COMPLETE INSTRUCTIONS OR THE INPUT -\"\n1160 PRINT \"OUTPUT STATEMENTS?\"\n1165 PRINT \"1=COMPLETE INSTRUCTIONS\"\n1170 PRINT \"2=INPUT-OUTPUT STATEMENTS\"\n1175 PRINT \"3=NEITHER\"\n1180 INPUT B1\n1185 Q$=\"NO\"\n1190 IF B1=1 THEN 205\n1195 Q$=\"YES\"\n1200 IF B1=2 THEN 190\n1205 IF B1=3 THEN 190\n1210 GOTO 1165\n1215 END\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/lunar.bas",
    "content": "10 PRINT TAB(33);\"LUNAR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\"\n25 PRINT:PRINT:PRINT\n30 PRINT \"THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR\"\n40 PRINT \"LANDING CAPSULE.\": PRINT: PRINT\n50 PRINT \"THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY\"\n60 PRINT \"XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.\"\n70 PRINT: PRINT \"SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN\"\n80 PRINT \"0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.\"\n90 PRINT \"SET NEW BURN RATE EVERY 10 SECONDS.\": PRINT\n100 PRINT \"CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS.\"\n110 PRINT: PRINT: PRINT: PRINT \"GOOD LUCK\"\n120 L=0\n130 PRINT: PRINT \"SEC\",\"MI + FT\",\"MPH\",\"LB FUEL\",\"BURN RATE\":PRINT\n140 A=120:V=1:M=33000:N=16500:G=1E-03:Z=1.8\n150 PRINT L,INT(A);INT(5280*(A-INT(A))),3600*V,M-N,:INPUT K:T=10\n160 IF M-N<1E-03 THEN 240\n170 IF T<1E-03 THEN 150\n180 S=T: IF M>=N+S*K THEN 200\n190 S=(M-N)/K\n200 GOSUB 420: IF I<=0 THEN 340\n210 IF V<=0 THEN 230\n220 IF J<0 THEN 370\n230 GOSUB 330: GOTO 160\n240 PRINT \"FUEL OUT AT\";L;\"SECONDS\":S=(-V+SQR(V*V+2*A*G))/G\n250 V=V+G*S: L=L+S\n260 W=3600*V: PRINT \"ON MOON AT\";L;\"SECONDS - IMPACT VELOCITY\";W;\"MPH\"\n274 IF W<=1.2 THEN PRINT \"PERFECT LANDING!\": GOTO 440\n280 IF W<=10 THEN PRINT \"GOOD LANDING (COULD BE BETTER)\":GOTO 440\n282 IF W>60 THEN 300\n284 PRINT \"CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE\"\n286 PRINT \"PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!\"\n288 GOTO 440\n300 PRINT \"SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!\"\n310 PRINT \"IN FACT, YOU BLASTED A NEW LUNAR CRATER\";W*.227;\"FEET DEEP!\"\n320 GOTO 440\n330 L=L+S: T=T-S: M=M-S*K: A=I: V=J: RETURN\n340 IF S<5E-03 THEN 260\n350 D=V+SQR(V*V+2*A*(G-Z*K/M)):S=2*A/D\n360 GOSUB 420: GOSUB 330: GOTO 340\n370 W=(1-M*G/(Z*K))/2: S=M*V/(Z*K*(W+SQR(W*W+V/Z)))+.05:GOSUB 420\n380 IF I<=0 THEN 340\n390 GOSUB 330: IF J>0 THEN 160\n400 IF V>0 THEN 370\n410 GOTO 160\n420 Q=S*K/M: J=V+G*S+Z*(-Q-Q*Q/2-Q^3/3-Q^4/4-Q^5/5)\n430 I=A-G*S*S/2-V*S+Z*S*(Q/2+Q^2/6+Q^3/12+Q^4/20+Q^5/30):RETURN\n440 PRINT:PRINT:PRINT:PRINT \"TRY AGAIN??\": GOTO 70\n"
  },
  {
    "path": "00_Alternate_Languages/59_Lunar_LEM_Rocket/rocket.bas",
    "content": "10 PRINT TAB(30); \"ROCKET\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n70 PRINT \"LUNAR LANDING SIMULATION\"\n80 PRINT \"----- ------- ----------\": PRINT\n100 INPUT \"DO YOU WANT INSTRUCTIONS (YES OR NO)\";A$\n110 IF A$=\"NO\" THEN 390\n160 PRINT\n200 PRINT\"YOU ARE LANDING ON THE MOON AND AND HAVE TAKEN OVER MANUAL\"\n210 PRINT\"CONTROL 1000 FEET ABOVE A GOOD LANDING SPOT. YOU HAVE A DOWN-\"\n220 PRINT\"WARD VELOCITY OF 50 FEET/SEC. 150 UNITS OF FUEL REMAIN.\"\n225 PRINT\n230 PRINT\"HERE ARE THE RULES THAT GOVERN YOUR APOLLO SPACE-CRAFT:\": PRINT\n240 PRINT\"(1) AFTER EACH SECOND THE HEIGHT, VELOCITY, AND REMAINING FUEL\"\n250 PRINT\"    WILL BE REPORTED VIA DIGBY YOUR ON-BOARD COMPUTER.\"\n260 PRINT\"(2) AFTER THE REPORT A '?' WILL APPEAR. ENTER THE NUMBER\"\n270 PRINT\"    OF UNITS OF FUEL YOU WISH TO BURN DURING THE NEXT\"\n280 PRINT\"    SECOND. EACH UNIT OF FUEL WILL SLOW YOUR DESCENT BY\"\n290 PRINT\"    1 FOOT/SEC.\"\n310 PRINT\"(3) THE MAXIMUM THRUST OF YOUR ENGINE IS 30 FEET/SEC/SEC\"\n320 PRINT\"    OR 30 UNITS OF FUEL PER SECOND.\"\n330 PRINT\"(4) WHEN YOU CONTACT THE LUNAR SURFACE. YOUR DESCENT ENGINE\"\n340 PRINT\"    WILL AUTOMATICALLY SHUT DOWN AND YOU WILL BE GIVEN A\"\n350 PRINT\"    REPORT OF YOUR LANDING SPEED AND REMAINING FUEL.\"\n360 PRINT\"(5) IF YOU RUN OUT OF FUEL THE '?' WILL NO LONGER APPEAR\"\n370 PRINT\"    BUT YOUR SECOND BY SECOND REPORT WILL CONTINUE UNTIL\"\n380 PRINT\"    YOU CONTACT THE LUNAR SURFACE.\":PRINT\n390 PRINT\"BEGINNING LANDING PROCEDURE..........\":PRINT\n400 PRINT\"G O O D  L U C K ! ! !\"\n420 PRINT:PRINT\n430 PRINT\"SEC  FEET      SPEED     FUEL     PLOT OF DISTANCE\"\n450 PRINT\n455 T=0:H=1000:V=50:F=150\n490 PRINT T;TAB(6);H;TAB(16);V;TAB(26);F;TAB(35);\"I\";TAB(H/15);\"*\"\n500 INPUT B\n510 IF B<0 THEN 650\n520 IF B>30 THEN B=30\n530 IF B>F THEN B=F\n540 V1=V-B+5\n560 F=F-B\n570 H=H- .5*(V+V1)\n580 IF H<=0 THEN 670\n590 T=T+1\n600 V=V1\n610 IF F>0 THEN 490\n615 IF B=0 THEN 640\n620 PRINT\"**** OUT OF FUEL ****\"\n640 PRINT T;TAB(4);H;TAB(12);V;TAB(20);F;TAB(29);\"I\";TAB(H/12+29);\"*\"\n650 B=0\n660 GOTO 540\n670 PRINT\"***** CONTACT *****\"\n680 H=H+ .5*(V1+V)\n690 IF B=5 THEN 720\n700 D=(-V+SQR(V*V+H*(10-2*B)))/(5-B)\n710 GOTO 730\n720 D=H/V\n730 V1=V+(5-B)*D\n760 PRINT\"TOUCHDOWN AT\";T+D;\"SECONDS.\"\n770 PRINT\"LANDING VELOCITY=\";V1;\"FEET/SEC.\"\n780 PRINT F;\"UNITS OF FUEL REMAINING.\"\n790 IF V1<>0 THEN 810\n800 PRINT\"CONGRATULATIONS! A PERFECT LANDING!!\"\n805 PRINT\"YOUR LICENSE WILL BE RENEWED.......LATER.\"\n810 IF ABS(V1)<2 THEN 840\n820 PRINT\"***** SORRY, BUT YOU BLEW IT!!!!\"\n830 PRINT\"APPROPRIATE CONDOLENCES WILL BE SENT TO YOUR NEXT OF KIN.\"\n840 PRINT:PRINT:PRINT\n850 INPUT \"ANOTHER MISSION\";A$\n860 IF A$=\"YES\" THEN 390\n870 PRINT: PRINT \"CONTROL OUT.\": PRINT\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/60_Mastermind/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript mastermind.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"mastermind\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/60_Mastermind/MiniScript/mastermind.ms",
    "content": "//\n//  MASTERMIND II\n//  STEVE NORTH\n//  CREATIVE COMPUTING\n//  PO BOX 789-M MORRISTOWN NEW JERSEY 07960\n//\n//\tConverted to MiniScript by Joe Strout (Sep 2023)\n\n// Advance the given combination to the next possible combination.\n// Note that (unlike the BASIC program) our values are 0-based, not 1-based.\nincrementCombo = function(combo)\n\tidx = 0\n\twhile true\n\t\tcombo[idx] += 1\n\t\tif combo[idx] < colorCount then return\n\t\tcombo[idx] = 0\n\t\tidx += 1\n\tend while\nend function\n\n// Convert a numeric combination like [2, 0, 1] into a color string like \"RBW\".\ncomboToColorString = function(combo)\n\tresult = \"\"\n\tfor q in combo\n\t\tresult += colorCodes[q]\n\tend for\n\treturn result\nend function\n\n// Get a random color code like \"RBW\".\ngetRandomCode = function\n\t// We do this by starting with a numeric combo of all 0's (first color),\n\t// and then stepping through subsequent combos a random number of times.\n\tcombo = [0] * posCount\n\tsteps = floor(possibilities * rnd)\n\twhile steps\n\t\tincrementCombo combo\n\t\tsteps -= 1\n\tend while\n\treturn comboToColorString(combo)\nend function\n\n// Return [blackPins, whitePins] for the given guess and actual code.\n// blackPins is how many guess entries are the correct color AND position;\n// whitePins is how many guess entries have the right color, but wrong position.\n// This works with either color strings or numeric combos.\ncalcResult = function(guess, actual)\n\tif guess isa string then guess = guess.split(\"\") else guess = guess[:]\n\tif actual isa string then actual = actual.split(\"\") else actual = actual[:]\n\tblack = 0; white = 0\n\tfor i in guess.indexes\n\t\tif guess[i] == actual[i] then\n\t\t\tblack += 1\n\t\t\tactual[i] = null\n\t\telse\n\t\t\tfor j in actual.indexes\n\t\t\t\tif guess[i] == actual[j] and guess[j] != actual[j] then\n\t\t\t\t\twhite += 1\n\t\t\t\t\tactual[j] = null\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\tend for\n\t\tend if\n\t\tguess[i] = null\n\tend for\n\treturn [black, white]\nend function\n\n// Pad a string with spaces, to the given width.\npad = function(s, width=12)\n\treturn (s + \" \"*width)[:width]\nend function\n\n// Print the history of guesses and results.\nprintBoard = function\n\tprint\n\tprint \"BOARD\"\n\tprint \"Move     Guess          Black     White\"\n\tfor i in guessHistory.indexes\n\t\tprint pad(i+1, 9) + pad(guessHistory[i], 15) + \n\t\t  pad(guessResult[i][0], 10) + guessResult[i][1]\n\tend for\n\tprint\t\nend function\n\n// Quit the game (after reporting the computer's secret code).\nquit = function(computerCode)\n\tprint \"Quitter!  My combination was: \" + computerCode\n\tprint\n\tprint \"Good bye\"\n\texit\nend function\n\n// Prompt the user for a guess (e.g. \"RBW\").  \n// Also handle \"BOARD\" and \"QUIT\" commands.\ninputGuess = function(guessNum, secretCode)\n\twhile true\n\t\tguess = input(\"Move #\" + guessNum + \" Guess? \").upper\n\t\tif guess == \"BOARD\" then\n\t\t\tprintBoard\n\t\telse if guess == \"QUIT\" then\n\t\t\tquit secretCode\n\t\telse if guess.len != posCount then\n\t\t\tprint \"Bad number of positions.\"\n\t\telse\n\t\t\tok = true\n\t\t\tfor c in guess\n\t\t\t\tif colorCodes.indexOf(c) == null then\n\t\t\t\t\tprint \"'\" + c + \"' is unrecognized.\"\n\t\t\t\t\tok = false\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\tend for\n\t\t\tif ok then return guess\n\t\tend if\n\tend while\nend function\n\n// Play one half-round where the computer picks a code,\n// and the human tries to guess it.\ndoHumanGuesses = function\n\tprint \"Guess my combination.\"\n\tprint\n\tsecretCode = getRandomCode\n\t//print \"My secret combo is: \" + secretCode\t// (for debugging purposes)\n\t\n\tglobals.guessHistory = []\t// list of guesses, e.g. \"RBW\"\n\tglobals.guessResult = []\t// result of each guess, as [BlackPins, WhitePins]\n\t\n\tfor guessNum in range(1, 10)\n\t\tguess = inputGuess(guessNum, secretCode)\n\t\tresult = calcResult(guess, secretCode)\n\t\tif result[0] == posCount then\n\t\t\tprint \"You guessed it in \" + guessNum + \" moves!\"\n\t\t\tbreak\n\t\tend if\n\t\t// Tell human results\n\t\tprint \"You have \" + result[0] + \" blacks and \" + result[1] + \" whites.\"\n\t\t// Save all this stuff for board printout later\n\t\tguessHistory.push guess\n\t\tguessResult.push result\n\tend for\n\tif guess != secretCode then\n\t\tprint \"You ran out of moves!  That's all you get!\"\n\t\tprint \"The actual combination was: \" + secretCode\n\tend if\n\tglobals.humanScore += guessNum\nend function\n\n// Play one half-round where the human picks a code,\n// and the computer tries to guess it.\n// Return true if this goes OK, and false if we need a do-over.\ndoComputerGuesses = function\n\tprint \"Now I guess.  Think of a combination.\"\n\tinput \"Hit Return when ready:\"\n\t\n\t// Make a list of possible combination *numbers*, from 0 to possibilities-1.\n\t// We'll remove entries from this list as we eliminate them with our guesses.\n\tpossible = range(0, possibilities-1)\n\t\n\tgotIt = false\n\tfor guessNum in range(1, 10)\n\t\tif not possible then\n\t\t\tprint \"You have given me inconsistent information.\"\n\t\t\tprint \"Try again, and this time please be more careful.\"\n\t\t\treturn false\n\t\tend if\n\t\tguessIdx = possible[rnd * possible.len]\n\t\tguessCombo = [0] * posCount\n\t\tif guessIdx > 0 then\n\t\t\tfor x in range(0, guessIdx-1)\n\t\t\t\tincrementCombo guessCombo\n\t\t\tend for\n\t\tend if\n\t\t\n\t\tprint \"My guess is: \" + comboToColorString(guessCombo)\n\n\t\twhile true\n\t\t\ts = input(\"  Blacks, Whites? \").replace(\",\", \" \").replace(\"  \", \" \").split\n\t\t\tif s.len == 2 then break\n\t\tend while\n\t\tactualResult = [s[0].val, s[1].val]\n\n\t\tif actualResult[0] == posCount then\n\t\t\tprint \"I got it in \" + guessNum + \" moves!\"\n\t\t\tgotIt = true\n\t\t\tbreak\n\t\tend if\n\n\t\t// Now zip through all possibilities, and if it's still in our \n\t\t// possible list but doesn't match the given result, remove it.\n\t\tcombo = [0] * posCount\n\t\tfor x in range(0, possibilities-1)\n\t\t\tif x > 0 then incrementCombo combo\n\t\t\tidx = possible.indexOf(x)\n\t\t\tif idx == null then continue\t// (already eliminated)\n\t\t\tresult = calcResult(combo, guessCombo)\n\t\t\tif result != actualResult then\n\t\t\t\t//print \"Eliminating #\" + x + \", \" + comboToColorString(combo)\n\t\t\t\tpossible.remove idx\n\t\t\tend if\n\t\tend for\n\tend for\n\t\n\tif not gotIt then\n\t\tprint \"I used up all my moves!\"\n\t\tprint \"I guess my CPU is just having an off day.\"\n\tend if\n\tglobals.computerScore += guessNum\n\treturn true\nend function\n\n// Show the score (with the given header).\nshowScore = function(header=\"Score\")\n\tprint header + \":\"\n\tprint \"     COMPUTER \" + computerScore\n\tprint \"     HUMAN    \" + humanScore\n\tprint\nend function\n\n// Initialization of global variables\ncolorCodes = \"BWRGOYPT\"\ncolorNames = \"Black,White,Red,Green,Orange,Yellow,Purple,Tan\".split(\",\")\ncomputerScore = 0\nhumanScore = 0\n\n// Main program\nprint \" \"*30 + \"Mastermind\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nwhile true\n\tcolorCount = input(\"Number of colors? \").val\n\tif 0 < colorCount <= 8 then break\n\tprint \"No more than 8, please!\"\nend while\nposCount = input(\"Number of positions? \").val\nroundCount = input(\"Number of rounds? \").val\npossibilities = colorCount ^ posCount\nprint \"Total possibilities = \" + possibilities\n\nprint; print\nprint \"Color    Letter\"\nprint \"=====    ======\"\nfor x in range(0, colorCount-1)\n\tprint pad(colorNames[x], 9) + colorCodes[x]\nend for\nprint\n\nfor round in range(1, roundCount)\n\tprint\n\tprint \"Round number \" + round + \" ----\"\n\tprint\n\tdoHumanGuesses\n\tshowScore\n\twhile not doComputerGuesses; end while\n\tshowScore\nend for\n\nprint \"GAME OVER\"\nshowScore \"Final score\"\n"
  },
  {
    "path": "00_Alternate_Languages/60_Mastermind/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/60_Mastermind/mastermind.bas",
    "content": "2 PRINT TAB(30);\"MASTERMIND\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 REM\n20 REM     MASTERMIND II\n30 REM     STEVE NORTH\n40 REM     CREATIVE COMPUTING\n50 REM     PO BOX 789-M MORRISTOWN NEW JERSEY 07960\n60 REM\n70 REM\n80 INPUT \"NUMBER OF COLORS\";C9\n90 IF C9>8 THEN PRINT \"NO MORE THAN 8, PLEASE!\":GOTO 80\n100 INPUT \"NUMBER OF POSITIONS\";P9\n110 INPUT \"NUMBER OF ROUNDS\";R9\n120 P=C9^P9\n130 PRINT \"TOTAL POSSIBILITIES =\";P\n140 H=0:C=0\n150 DIM Q(P9),S(10,2),S$(10),A$(P9),G$(P9),I(P),H$(P9)\n160 L$=\"BWRGOYPT\"\n170 PRINT\n180 PRINT\n190 PRINT \"COLOR     LETTER\"\n200 PRINT \"=====     ======\"\n210 FOR X=1 TO C9\n220 READ X$\n230 PRINT X$;TAB(13);MID$(L$,X,1)\n240 NEXT X\n250 PRINT\n260 FOR R=1 TO R9\n270 PRINT\n280 PRINT \"ROUND NUMBER\";R;\"----\"\n290 PRINT\n300 PRINT \"GUESS MY COMBINATION.\":PRINT\n310 REM     GET A COMBINATION\n320 A=INT(P*RND(1)+1)\n330 GOSUB 3000\n340 FOR X=1 TO A\n350 GOSUB 3500\n360 NEXT X\n370 FOR M=1 TO 10\n380 PRINT \"MOVE # \";M;\" GUESS \";:INPUT X$\n390 IF X$=\"BOARD\" THEN 2000\n400 IF X$=\"QUIT\" THEN 2500\n410 IF LEN(X$)<>P9 THEN PRINT \"BAD NUMBER OF POSITIONS.\":GOTO 380\n420 REM     UNPACK X$ INTO G$(1-P9)\n430 FOR X=1 TO P9\n440 FOR Y=1 TO C9\n450 IF MID$(X$,X,1)=MID$(L$,Y,1) THEN 480\n460 NEXT Y\n470 PRINT \"'\"; MID$(X$,X,1); \"' IS UNRECOGNIZED.\":GOTO 380\n480 G$(X)=MID$(X$,X,1)\n490 NEXT X\n500 REM     NOW WE CONVERT Q(1-P9) INTO A$(1-P9) [ACTUAL GUESS]\n510 GOSUB 4000\n520 REM     AND GET NUMBER OF BLACKS AND WHITES\n530 GOSUB 4500\n540 IF B=P9 THEN 630\n550 REM     TELL HUMAN RESULTS\n560 PRINT \"YOU HAVE \";B;\" BLACKS AND \";W;\" WHITES.\"\n570 REM     SAVE ALL THIS STUFF FOR BOARD PRINTOUT LATER\n580 S$(M)=X$\n590 S(M,1)=B\n600 S(M,2)=W\n610 NEXT M\n620 PRINT \"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\":GOTO 640\n622 GOSUB 4000\n623 PRINT \"THE ACTUAL COMBINATION WAS: \";\n624 FOR X=1 TO P9\n625 PRINT A$(X);\n626 NEXT X\n627 PRINT\n630 PRINT \"YOU GUESSED IT IN \";M;\" MOVES!\"\n640 H=H+M\n650 GOSUB 5000\n660 REM\n670 REM     NOW COMPUTER GUESSES\n680 REM\n690 FOR X=1 TO P\n700 I(X)=1\n710 NEXT X\n720 PRINT \"NOW I GUESS.  THINK OF A COMBINATION.\"\n730 INPUT \"HIT RETURN WHEN READY:\";X$\n740 FOR M=1 TO 10\n750 GOSUB 3000\n760 REM     FIND A GUESS\n770 G=INT(P*RND(1)+1)\n780 IF I(G)=1 THEN 890\n790 FOR X=G TO P\n800 IF I(X)=1 THEN 880\n810 NEXT X\n820 FOR X=1 TO G\n830 IF I(X)=1 THEN 880\n840 NEXT X\n850 PRINT \"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\"\n860 PRINT \"TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\"\n870 GOTO 660\n880 G=X\n890 REM     NOW WE CONVERT GUESS #G INTO G$\n900 FOR X=1 TO G\n910 GOSUB 3500\n920 NEXT X\n930 GOSUB 6000\n940 PRINT \"MY GUESS IS: \";\n950 FOR X=1 TO P9\n960 PRINT H$(X);\n970 NEXT X\n980 INPUT \"  BLACKS, WHITES \";B1,W1\n990 IF B1=P9 THEN 1120\n1000 GOSUB 3000\n1010 FOR X=1 TO P\n1020 GOSUB 3500\n1030 IF I(X)=0 THEN 1070\n1035 GOSUB 6500\n1040 GOSUB 4000\n1050 GOSUB 4500\n1060 IF B1>B OR W1>W THEN I(X)=0\n1070 NEXT X\n1080 NEXT M\n1090 PRINT \"I USED UP ALL MY MOVES!\"\n1100 PRINT \"I GUESS MY CPU IS JUST HAVING AN OFF DAY.\"\n1110 GOTO 1130\n1120 PRINT \"I GOT IT IN \";M;\" MOVES!\"\n1130 C=C+M\n1140 GOSUB 5000\n1150 NEXT R\n1160 PRINT \"GAME OVER\"\n1170 PRINT \"FINAL SCORE:\"\n1180 GOSUB 5040\n1190 STOP\n2000 REM\n2010 REM     BOARD PRINTOUT ROUTINE\n2020 REM\n2025 PRINT\n2030 PRINT \"BOARD\"\n2040 PRINT \"MOVE     GUESS          BLACK     WHITE\"\n2050 FOR Z=1 TO M-1\n2060 PRINT Z;TAB(9);S$(Z);TAB(25);S(Z,1);TAB(35);S(Z,2)\n2070 NEXT Z\n2075 PRINT\n2080 GOTO 380\n2500 REM\n2510 REM     QUIT ROUTINE\n2520 REM\n2530 PRINT \"QUITTER!  MY COMBINATION WAS: \";\n2535 GOSUB 4000\n2540 FOR X=1 TO P9\n2550 PRINT A$(X);\n2560 NEXT X\n2565 PRINT\n2570 PRINT \"GOOD BYE\"\n2580 STOP\n3000 REM\n3010 REM     INITIALIZE Q(1-P9) TO ZEROS\n3020 REM\n3030 FOR S=1 TO P9\n3040 Q(S)=0\n3050 NEXT S\n3060 RETURN\n3500 REM\n3510 REM     INCREMENT Q(1-P9)\n3520 REM\n3522 IF Q(1)>0 THEN 3530\n3524 REM  IF ZERO, THIS IS OUR FIRST INCREMENT: MAKE ALL ONES\n3526 FOR S=1 TO P9\n3527 Q(S)=1\n3528 NEXT S\n3529 RETURN\n3530 Q=1\n3540 Q(Q)=Q(Q)+1\n3550 IF Q(Q)<=C9 THEN RETURN\n3560 Q(Q)=1\n3570 Q=Q+1\n3580 GOTO 3540\n4000 REM\n4010 REM     CONVERT Q(1-P9) TO A$(1-P9)\n4020 REM\n4030 FOR S=1 TO P9\n4040 A$(S)=MID$(L$,Q(S),1)\n4050 NEXT S\n4060 RETURN\n4500 REM\n4510 REM     GET NUMBER OF BLACKS (B) AND WHITES (W)\n4520 REM     MASHES G$ AND A$ IN THE PROCESS\n4530 REM\n4540 B=0:W=0:F=0\n4550 FOR S=1 TO P9\n4560 IF G$(S)<>A$(S) THEN 4620\n4570 B=B+1\n4580 G$(S)=CHR$(F)\n4590 A$(S)=CHR$(F+1)\n4600 F=F+2\n4610 GOTO 4660\n4620 FOR T=1 TO P9\n4630 IF G$(S)<>A$(T) THEN 4650\n4640 IF G$(T)=A$(T) THEN 4650\n4645 W=W+1:A$(T)=CHR$(F):G$(S)=CHR$(F+1):F=F+2:GOTO 4660\n4650 NEXT T\n4660 NEXT S\n4670 RETURN\n5000 REM\n5010 REM     PRINT SCORE\n5020 REM\n5030 PRINT \"SCORE:\"\n5040 PRINT \"     COMPUTER \";C\n5050 PRINT \"     HUMAN    \";H\n5060 PRINT\n5070 RETURN\n5500 REM\n5510 REM     CONVERT Q(1-P9) INTO G$(1-P9)\n5520 REM\n5530 FOR S=1 TO P9\n5540 G$(S)=MID$(L$,Q(S),1)\n5550 NEXT S\n5560 RETURN\n6000 REM\n6010 REM     CONVERT Q(1-P9) TO H$(1-P9)\n6020 REM\n6030 FOR S=1 TO P9\n6040 H$(S)=MID$(L$,Q(S),1)\n6050 NEXT S\n6060 RETURN\n6500 REM\n6510 REM     COPY H$ INTO G$\n6520 REM\n6530 FOR S=1 TO P9\n6540 G$(S)=H$(S)\n6550 NEXT S\n6560 RETURN\n8000 REM     PROGRAM DATA FOR COLOR NAMES\n8010 DATA BLACK,WHITE,RED,GREEN,ORANGE,YELLOW,PURPLE,TAN\n9998 REM   ...WE'RE SORRY BUT IT'S TIME TO GO...\n9999 END\n"
  },
  {
    "path": "00_Alternate_Languages/61_Math_Dice/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of mathdice.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript mathdice.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"mathdice\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/61_Math_Dice/MiniScript/mathdice.ms",
    "content": "print \" \"*31 + \"Math Dice\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"This program generates successive pictures of two dice.\"\nprint \"When two dice and an equal sign followed by a question\"\nprint \"mark have been printed, type your answer and the return key.\"\nprint \"To conclude the lesson, type Control-C as your answer.\"\nprint\n\nprintDie = function(d)\n    print\n    print \" -----\"\n    if d == 1 then\n        print \"|     |\"\n    else if d == 2 or d == 3 then\n        print \"| *   |\"\n    else\n        print \"| * * |\"\n    end if\n    if d == 2 or d == 4 then\n        print \"|     |\"\n    else if d == 6 then\n        print \"| * * |\"\n    else\n        print \"|  *  |\"\n    end if\n    if d == 1 then\n        print \"|     |\"\n    else if d == 2 or d == 3 then\n        print \"|   * |\"\n    else\n        print \"| * * |\"\n    end if\n    print \" -----\"\n    print\nend function\n\nwhile true\n    d1 = floor(6 * rnd + 1)\n    printDie d1\n    print \"   +\"\n    d2 = floor(6 * rnd + 1)\n    printDie d2\n    total = d1 + d2\n    answer = input(\"      =? \").val\n    if answer != total then\n        print \"No, count the spots and give another answer.\"\n        answer = input(\"      =? \").val\n    end if\n    if answer == total then\n        print \"Right!\"\n    else\n        print \"No, the answer is \" + total\n    end if\n    print\n    print \"The dice roll again...\"\nend while\n\n"
  },
  {
    "path": "00_Alternate_Languages/61_Math_Dice/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/61_Math_Dice/mathdice.bas",
    "content": "10 PRINT TAB(31);\"MATH DICE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 PRINT \"THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\"\n50 PRINT \"WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\"\n60 PRINT \"MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\"\n70 PRINT \"TO CONCLUDE THE LESSON, TYPE CONTROL-C AS YOUR ANSWER.\"\n80 PRINT\n90 PRINT\n100 N=N+1\n110 D=INT(6*RND(1)+1)\n120 PRINT\" ----- \"\n130 IF D=1 THEN 200\n140 IF D=2 THEN 180\n150 IF D=3 THEN 180\n160 PRINT \"I * * I\"\n170 GOTO 210\n180 PRINT \"I *   I\"\n190 GOTO 210\n200 PRINT \"I     I\"\n210 IF D=2 THEN 260\n220 IF D=4 THEN 260\n230 IF D=6 THEN 270\n240 PRINT \"I  *  I\"\n250 GOTO 280\n260 PRINT \"I     I\"\n265 GOTO 280\n270 PRINT \"I * * I\"\n280 IF D=1 THEN 350\n290 IF D=2 THEN 330\n300 IF D=3 THEN 330\n310 PRINT \"I * * I\"\n320 GOTO 360\n330 PRINT \"I   * I\"\n340 GOTO 360\n350 PRINT \"I     I\"\n360 PRINT \" ----- \"\n370 PRINT\n375 IF N=2 THEN 500\n380 PRINT \"   +\"\n381 PRINT\n400 A=D\n410 GOTO 100\n500 T=D+A\n510 PRINT \"      =\";\n520 INPUT T1\n530 IF T1=T THEN 590\n540 PRINT \"NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.\"\n541 PRINT \"      =\";\n550 INPUT T2\n560 IF T2=T THEN 590\n570 PRINT \"NO, THE ANSWER IS\";T\n580 GOTO 600\n590 PRINT \"RIGHT!\"\n600 PRINT\n601 PRINT \"THE DICE ROLL AGAIN...\"\n610 PRINT\n615 N=0\n620 GOTO 100\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/61_Math_Dice/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n\n##### Translator Notes:\nI tried to preserve as much of the original layout and flow of the code\nas possible.  I added a procedure for the printing of the die-face; and\nanother to read an integer from the player, as I was unhappy with the runtime\nerror message spat out when a non-number is given to readln(<integer>).\n\nI was torn between using the correct singular term \"die\" instead of \"dice\".\nIn the end I used a (poor?) combination of both.\n\nkrt@krt.com.au 2020-10-12\n"
  },
  {
    "path": "00_Alternate_Languages/61_Math_Dice/pascal/mathdice.pas",
    "content": "(*\n * Ported from mathdice.bas to Pascal by krt@krt.com.au\n *\n * Compile with Free Pascal (https://www.freepascal.org/) ~\n *    fpc mathdice.pas\n *)\n\nprogram MathDice;\n\n\nprocedure printDice( face_value: integer );\n(* Prints a box with spots representing a die face for the user *)\nbegin\n    writeln( ' ----- ' );\n\n    if ( face_value = 1 ) then\n        writeln( 'I     I' )\n    else if ( ( face_value = 2 ) or ( face_value = 3 ) ) then\n        writeln( 'I *   I' )\n    else\n        writeln( 'I * * I' );\n\n    if ( ( face_value = 2 ) or ( face_value = 4 ) ) then\n        writeln( 'I     I' )\n    else if ( face_value = 6 ) then\n        writeln( 'I * * I' )\n    else\n        writeln( 'I  *  I' );\n\n    if ( face_value = 1 ) then\n        writeln( 'I     I' )\n    else if ( ( face_value = 2 ) or ( face_value = 3 ) ) then\n        writeln( 'I   * I' )\n    else\n        writeln( 'I * * I' );\n\n    writeln( ' ----- ' );\nend;\n\n\nprocedure writeAtColumn( width: integer; words: string );\n(* Prints <width> worth of spaces before the <words> to justify the text *)\nvar\n    i: integer;\nbegin\n    for i := 1 to width do\n        write( ' ' );\n    writeln( words );\nend;\n\n\nfunction inputNumber(): integer;\n(* Get a number from the player with error checking.\n   If they type a non-number, ask them again *)\nvar\n    player_input:  string;    (* The string entered by the player *)\n    player_answer: integer;   (* The converted value of the text *)\n    input_error:   integer;   (* The letter's column that caused an error *)\nbegin\n\n    input_error := 1;\n    while ( input_error <> 0 ) do\n    begin\n        readln( player_input );\n\n        val( player_input, player_answer, input_error );\n\n        if ( input_error <> 0 ) then\n            write( 'Please input a number: ' );\n    end;\n\n    inputNumber := player_answer;\nend;\n\n\n\nvar\n    dice1:         integer;   (* die 1 face value *)\n    dice2:         integer;   (* die 2 face value *)\n    answer:        integer;   (* the sum of the dice *)\n    player_answer: integer;   (* The value entered by the player *)\nbegin\n    writeAtColumn( 31, 'MATH DICE' );\n    writeAtColumn( 15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY' );\n    writeAtColumn( 15, '(Ported to Pascal Oct 2012 krt@krt.com.au)' );\n    writeln( '' );\n    writeln( '' );\n    writeln( '' );\n\n    writeln( 'THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.' );\n    writeln( 'WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION' );\n    writeln( 'MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.' );\n    writeln( 'TO CONCLUDE THE LESSON, TYPE CONTROL-C AS YOUR ANSWER.' );\n    writeln( '' );\n    writeln( '' );\n\n    while ( true ) do\n    begin\n        dice1 := Random( 6 ) + 1;   (* Random number between 1 and 6 (including)  *)\n        dice2 := Random( 6 ) + 1;   (* Random number between 1 and 6 (including)  *)\n        answer := dice1 + dice2;\n\n        (* Show the player two dice faces *)\n        printDice( dice1 );\n        writeln( '   +' );\n        printDice( dice2 );\n\n        write( '      = ' );\n\n        player_answer := inputNumber();\n\n        if ( player_answer <> answer ) then\n        begin\n            (* Give the player a second chance at the answer... *)\n            writeln( 'NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.' );\n            write( '      = ' );\n            player_answer := inputNumber();\n        end;\n\n        if ( player_answer <> answer ) then\n            writeln( 'NO, THE ANSWER IS ', answer )\n        else\n            writeln( 'RIGHT!' );\n\n        writeln( '' );\n        writeln( 'THE DICE ROLL AGAIN...' );\n    end;\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/62_Mugwump/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of mathdice.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript mathdice.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"mathdice\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/62_Mugwump/MiniScript/mugwump.ms",
    "content": "print \" \"*33 + \"Mugwump\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n// Courtesy People's Computer Company\nprint \"The object of this game is to find four mugwumps\"\nprint \"hidden on a 10 by 10 grid.  Homebase is position 0,0.\"\nprint \"Any guess you make must be two numbers with each\"\nprint \"number between 0 and 9, inclusive.  First number\"\nprint \"is distance to right of homebase and second number\"\nprint \"is distance above homebase.\"\nprint\nprint \"You get 10 tries.  After each try, I will tell\"\nprint \"you how far you are from each mugwump.\"\nprint\n\nplayOneGame = function\n\tmugwump = {}\t// key: number 1-4; value: [x,y] position\n\tfor i in range(1, 4)\n\t\tmugwump[i] = [floor(10*rnd), floor(10*rnd)]\n\tend for\n\t\n\tfound = 0\n\tfor turn in range(1, 10)\n\t\tprint\n\t\tprint\n\t\twhile true\n\t\t\tinp = input(\"Turn no. \" + turn + \" -- what is your guess? \")\n\t\t\tinp = inp.replace(\",\", \" \").replace(\"  \", \" \").split\n\t\t\tif inp.len == 2 then break\n\t\tend while\n\t\tx = inp[0].val; y = inp[1].val\n\t\tfor i in range(1, 4)\n\t\t\tpos = mugwump[i]\n\t\t\tif pos == null then continue\t// (already found)\n\t\t\tif pos == [x,y] then\n\t\t\t\tprint \"You have found mugwump \" + i\n\t\t\t\tmugwump[i] = null\n\t\t\t\tfound += 1\n\t\t\telse\n\t\t\t\td = sqrt( (pos[0] - x)^2 + (pos[1] - y)^2 )\n\t\t\t\tprint \"You are \" + round(d, 1) + \" units from mugwump \" + i\n\t\t\tend if\n\t\tend for\n\t\tif found == 4 then\n    \t\tprint\n\t\t\tprint \"You got them all in \" + turn + \" turns!\"\n\t\t\treturn\n\t\tend if\n\tend for\n\tprint\n\tprint \"Sorry, that's 10 tries.  Here is where they're hiding:\"\n\tfor i in range(1, 4)\n\t\tpos = mugwump[i]\n\t\tif pos == null then continue\n\t\tprint \"Mugwump \" + i + \" is at (\" + pos[0] + \",\" + pos[1] + \")\"\n\tend for\nend function\n\n// Main loop\nwhile true\n\tplayOneGame\n\tprint\n\tprint \"That was fun! Let's play again.......\"\n\tprint \"Four more mugwumps are now in hiding.\"\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/62_Mugwump/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/62_Mugwump/mugwump.bas",
    "content": "1 PRINT TAB(33);\"MUGWUMP\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 REM     COURTESY PEOPLE'S COMPUTER COMPANY\n10 DIM P(4,2)\n20 PRINT \"THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS\"\n30 PRINT \"HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0.\"\n40 PRINT \"ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH\"\n50 PRINT \"NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER\"\n60 PRINT \"IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER\"\n70 PRINT \"IS DISTANCE ABOVE HOMEBASE.\"\n80 PRINT\n90 PRINT \"YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL\"\n100 PRINT \"YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\"\n110 PRINT\n240 GOSUB 1000\n250 T=0\n260 T=T+1\n270 PRINT\n275 PRINT\n290 PRINT \"TURN NO.\";T;\"-- WHAT IS YOUR GUESS\";\n300 INPUT M,N\n310 FOR I=1 TO 4\n320 IF P(I,1)=-1 THEN 400\n330 IF P(I,1)<>M THEN 380\n340 IF P(I,2)<>N THEN 380\n350 P(I,1)=-1\n360 PRINT \"YOU HAVE FOUND MUGWUMP\";I\n370 GOTO 400\n380 D=SQR((P(I,1)-M)^2+(P(I,2)-N)^2)\n390 PRINT \"YOU ARE\";(INT(D*10))/10;\"UNITS FROM MUGWUMP\";I\n400 NEXT I\n410 FOR J=1 TO 4\n420 IF P(J,1)<>-1 THEN 470\n430 NEXT J\n440 PRINT\n450 PRINT \"YOU GOT THEM ALL IN\";T;\"TURNS!\"\n460 GOTO 580\n470 IF T<10 THEN 260\n480 PRINT\n490 PRINT \"SORRY, THAT'S 10 TRIES.  HERE IS WHERE THEY'RE HIDING:\"\n540 FOR I=1 TO 4\n550 IF P(I,1)=-1 THEN 570\n560 PRINT \"MUGWUMP\";I;\"IS AT (\";P(I,1);\",\";P(I,2);\")\"\n570 NEXT I\n580 PRINT\n600 PRINT \"THAT WAS FUN! LET'S PLAY AGAIN.......\"\n610 PRINT \"FOUR MORE MUGWUMPS ARE NOW IN HIDING.\"\n630 GOTO 240\n1000 FOR J=1 TO 2\n1010 FOR I=1 TO 4\n1020 P(I,J)=INT(10*RND(1))\n1030 NEXT I\n1040 NEXT J\n1050 RETURN\n1099 END\n"
  },
  {
    "path": "00_Alternate_Languages/63_Name/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of name.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript name.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"name\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/63_Name/MiniScript/name.ms",
    "content": "print \" \"*34 + \"Name\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Hello.\"; print \"My name is Creative Computer.\"\nname = input(\"What's your name (first and last)? \")\n\ns = \"\"\nfor i in range(name.len - 1)\n\ts += name[i]\nend for\nprint; print \"Thank you, \" + s + \".\"\nprint \"Oops!  I guess I got it backwards.  A smart\"\nprint \"computer like me shouldn't make a mistake like that!\"; print\nprint \"But i just noticed your letters are out of order.\"\ns = name.split(\"\").sort.join(\"\")\nprint \"Let's put them in order like this: \" + s\nyn = input(\"Don't you like that better? \").lower\nprint\nif yn and yn[0] == \"y\" then\n\tprint \"I knew you'd agree!!\"\nelse\n\tprint \"I'm sorry you don't like it that way.\"\nend if\nprint; print \"I really enjoyed meeting you \" + name + \".\"\nprint \"Have a nice day!\"\n"
  },
  {
    "path": "00_Alternate_Languages/63_Name/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/63_Name/name.bas",
    "content": "1 PRINT TAB(34);\"NAME\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT: PRINT: PRINT\n5 DIM B$(40)\n10 PRINT \"HELLO.\": PRINT \"MY NAME IS CREATIVE COMPUTER.\"\n20 PRINT \"WHAT'S YOUR NAME (FIRST AND LAST\";: INPUT A$: L=LEN(A$)\n30 PRINT: PRINT \"THANK YOU, \";\n40 FOR I=1 TO L: B$(I)=MID$(A$,I,1): NEXT I\n50 FOR I=L TO 1 STEP -1: PRINT B$(I);: NEXT I\n60 PRINT \".\": PRINT \"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\"\n70 PRINT \"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\": PRINT\n80 PRINT \"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\"\n90 PRINT \"LET'S PUT THEM IN ORDER LIKE THIS: \";\n100 FOR J=2 TO L: I=J-1: T$=B$(J)\n110 IF T$>B$(I) THEN 130\n120 B$(I+1)=B$(I): I=I-1: IF I>0 THEN 110\n130 B$(I+1)=T$: NEXT J\n140 FOR I=1 TO L: PRINT B$(I);: NEXT I: PRINT: PRINT\n150 PRINT \"DON'T YOU LIKE THAT BETTER\";: INPUT D$\n160 IF D$=\"YES\" THEN 180\n170 PRINT: PRINT \"I'M SORRY YOU DON'T LIKE IT THAT WAY.\": GOTO 200\n180 PRINT: PRINT \"I KNEW YOU'D AGREE!!\"\n200 PRINT: PRINT \"I REALLY ENJOYED MEETING YOU \";A$;\".\"\n210 PRINT \"HAVE A NICE DAY!\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/64_Nicomachus/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript nicomachus.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"nicomachus\"\n\trun\n```\n3. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of nicomachus.ms, and click the \"Run Script\" button.\n"
  },
  {
    "path": "00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms",
    "content": "// Nicomachus\n// originally by David Ahl\n// Ported from BASIC to MiniScript by Joe Strout, 2023\n\nprint \" \"*33 + \"NICOMA\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\nprint \"Boomerang puzzle from Arithmetica of Nicomachus -- A.D. 90!\"\n\n// Get a yes/no (or at least y/n) response from the user.\naskYesNo = function(prompt)\n\twhile true\n\t\tanswer = input(prompt)\n\t\ta1 = answer.lower[:1]\n\t\tif a1 == \"y\" or a1 == \"n\" then return a1\n\t\tprint \"Eh?  I don't understand '\" + answer + \"'  Try 'yes' or 'no'.\"\n\tend while\nend function\n\ndoOne = function\n\tprint\n\tprint \"Please think of a number between 1 and 100.\"\n\tA = input(\"Your number divided by 3 has a remainder of: \").val\n\tB = input(\"Your number divided by 5 has a remainder of: \").val\n\tC = input(\"Your number divided by 7 has a remainder of: \").val\n\tprint\n\tprint \"Let me think a moment...\"\n\tprint\n\twait 1.5\n\tD = 70*A + 21*B + 15*C\n\tD = D % 105   // gets the remainder after dividing by 105\n\tyesNo = askYesNo(\"Your number was \" + D + \", right? \")\n\tif yesNo == \"y\" then\n\t\tprint \"How about that!\"\n\telse\n\t\tprint \"I feel your arithmetic is in error.\"\n\tend if\nend function\n\n// Main loop -- press Control-C to break\nwhile true\n\tdoOne\n\tprint\n\tprint \"Let's try another.\"\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/64_Nicomachus/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/64_Nicomachus/nicomachus.bas",
    "content": "2 PRINT TAB(33);\"NICOMA\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 PRINT \"BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\"\n20 PRINT\n30 PRINT \"PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\"\n40 PRINT \"YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF\";\n45 INPUT A\n50 PRINT \"YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF\";\n55 INPUT B\n60 PRINT \"YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF\";\n65 INPUT C\n70 PRINT\n80 PRINT \"LET ME THINK A MOMENT...\"\n85 PRINT\n90 FOR I=1 TO 1500: NEXT I\n100 D=70*A+21*B+15*C\n110 IF D<=105 THEN 140\n120 D=D-105\n130 GOTO 110\n140 PRINT \"YOUR NUMBER WAS\";D;\", RIGHT\";\n160 INPUT A$\n165 PRINT\n170 IF A$=\"YES\" THEN 220\n180 IF A$=\"NO\" THEN 240\n190 PRINT \"EH?  I DON'T UNDERSTAND '\";A$;\"'  TRY 'YES' OR 'NO'.\"\n200 GOTO 160\n220 PRINT \"HOW ABOUT THAT!!\"\n230 GOTO 250\n240 PRINT \"I FEEL YOUR ARITHMETIC IS IN ERROR.\"\n250 PRINT\n260 PRINT \"LET'S TRY ANOTHER.\"\n270 GOTO 20\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/65_Nim/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript nim.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"nim\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/65_Nim/MiniScript/nim.ms",
    "content": "print \" \"*33 + \"Nim\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\naskYesNo = function(prompt)\n\twhile true\n\t\tanswer = input(prompt + \"? \").lower\n\t\tif answer and answer[0] == \"y\" then return \"yes\"\n\t\tif answer and answer[0] == \"n\" then return \"no\"\n\t\tprint \"Please answer yes or no.\"\n\tend while\nend function\n\nprint \"This is the game of Nim.\"\nif askYesNo(\"Do you want instructions\") == \"yes\" then\n\tprint \"The game is played with a number of piles of objects.\"\n\tprint \"Any number of objects are removed from one pile by you and\"\n\tprint \"the machine alternately.  On your turn, you may take\"\n\tprint \"all the objects that remain in any pile, but you must\"\n\tprint \"take at least one object, and you may take objects from\"\n\tprint \"only one pile on a single turn.  You must specify whether\"\n\tprint \"winning is defined as taking or not taking the last object,\"\n\tprint \"the number of piles in the game, and how many objects are\"\n\tprint \"originally in each pile.  Each pile may contain a\"\n\tprint \"different number of objects.\"\n\tprint \"The machine will show its move by listing each pile and the\"\n\tprint \"number of objects remaining in the piles after each of its\"\n\tprint \"moves.\"\nend if\n\nallEmpty = function(piles)\n\tfor i in range(1, piles.len-1)\n\t\tif piles[i] then return false\n\tend for\n\treturn true\nend function\n\n// Do the computer's turn; return true if game over, false otherwise.\ndoComputerTurn = function(pile, winCondition)\n\tn = pile.len - 1\n\td = [0,0,0]\n\tb = [null]\n\tfor i in range(1, n)\n\t\tb.push [0]*11\n\tend for\n\t\n\tif winCondition == 2 then\n\t\tc = 0\n\t\tbroke = false\n\t\tfor i in range(1, n)\n\t\t\tif pile[i] == 0 then continue\n\t\t\tc += 1\n\t\t\tif c == 3 then; broke = true; break; end if\n\t\t\td[c] = i\n\t\tend for\n\t\tif not broke then\n\t\t\tif c == 2 and (pile[d[1]] == 1 or pile[d[2]] == 1) then\n\t\t\t\tprint \"Machine wins\"\n\t\t\t\treturn true\n\t\t\tend if\n\t\t\tif pile[d[1]] > 1 then\n\t\t\t\tprint \"Machine wins\"\n\t\t\t\treturn true\n\t\t\tend if\n\t\t\tprint \"Machine loses\"\n\t\t\treturn true\n\t\tend if\t\t\n\t\tc = 0\n\t\tbroke = false\n\t\tfor i in range(1, n)\n\t\t\tif pile[i] > 1 then; broke = true; break; end if\n\t\t\tif pile[i] == 0 then continue\n\t\t\tc += 1\n\t\tend for\n\t\tif not broke and c/2 != floor(c/2) then\n\t\t\tprint \"Machine loses\"\n\t\t\treturn true\n\t\tend if\n\tend if\n\n\tfor i in range(1, n)\n\t\te = pile[i]\n\t\tfor j in range(0, 10)\n\t\t\tf = e/2\n\t\t\tb[i][j] = 2*(f-floor(f))\n\t\t\te = floor(f)\n\t\tend for\n\tend for\n\tbroke = false\n\tfor j in range(10, 0)\n\t\tc = 0\n\t\th = 0\n\t\tfor i in range(1, n)\n\t\tif b[i][j] == 0 then continue\n\t\t\tc += 1\n\t\t\tif pile[i] <= h then continue\n\t\t\th = pile[i]\n\t\t\tg = i\n\t\tend for\n\t\tif c/2 != floor(c/2) then; broke = true; break; end if\n\tend for\n\tif not broke then\n\t\twhile true\n\t\t\te = floor(n*rnd+1)\n\t\t\tif pile[e] != 0 then break\n\t\tend while\n\t\tf = floor(pile[e]*rnd+1)\n\t\tpile[e] -= f\n\telse\n\t\tpile[g] = 0\n\t\tfor j in range(0, 10)\n\t\t\tb[g][j] = 0\n\t\t\tc=0\n\t\t\tfor i in range(1,n)\n\t\t\t\tif b[i][j] == 0 then continue\n\t\t\t\tc += 1\n\t\t\tend for\n\t\t\tpile[g] += 2*(c/2-floor(c/2))*2^j\n\t\tend for\n\t\tif winCondition != 1 then\n\t\t\tc = 0\n\t\t\tbroke = false\n\t\t\tfor i in range(1, n)\n\t\t\t\tif pile[i]>1 then; broke = true; break; end if\n\t\t\t\tif pile[i] == 0 then continue\n\t\t\t\tc += 1\n\t\t\tend for\n\t\t\tif not broke and c/2 == floor(c/2) then pile[g]= 1 - pile[g]\n\t\tend if\n\tend if\n\t\n\tprint \"Pile  Size\"\n\tfor i in range(1, n)\n\t\tprint i + \"     \" + pile[i]\n\tend for\n\tif winCondition == 1 and allEmpty(pile) then\n\t\tprint \"Machine wins\"\n\t\treturn true\n\tend if\n\treturn false\nend function\n\n// Do the human player's turn; return true if game over, false otherwise.\ndoPlayerTurn = function(pile, winCondition)\n\tn = pile.len - 1\n\twhile true\n\t\tinp = input(\"Your move - pile, number to be removed? \")\n\t\tinp = inp.replace(\",\", \" \").replace(\"  \", \" \").split\n\t\tif inp.len != 2 then continue\n\t\tx = inp[0].val; y = inp[1].val\n\t\tif x == floor(x) and y == floor(y) and 1 <= x <= n and 1 <= y <= pile[x] then break\n\tend while\n\n\tpile[x] -= y\n\tif allEmpty(pile) then\n\t\tif winCondition == 1 then print \"Machine loses\" else print \"Machine wins\"\n\t\treturn true\n\tend if\n\treturn false\nend function\n\nplayOneGame = function\n\tprint\n\twhile true\n\t\tw = input(\"Enter win option - 1 to take last, 2 to avoid last? \").val\n\t\tif w == 1 or w == 2 then break\n\tend while\n\twhile true\n\t\tn = input(\"Enter number of piles? \").val\n\t\tif n == floor(n) and 1 <= n <= 100 then break\n\tend while\n\n\tprint \"Enter pile sizes\"\n\tpile = [null] + [0]*n\t// (null at element 0 to make our array 1-based)\n\tfor i in range(1, n)\n\t\twhile true\n\t\t\tpile[i] = input(i + \"? \").val\n\t\t\tif pile[i] == floor(pile[i]) and 1 <= pile[i] <= 2000 then break\n\t\tend while\n\tend for\n\t\n\tif askYesNo(\"Do you want to move first\") == \"yes\" then\n\t\tif doPlayerTurn(pile, w) then return\n\tend if\n\twhile true\n\t\tif doComputerTurn(pile, w) then return\n\t\tif doPlayerTurn(pile, w) then return\n\tend while\nend function\n\nwhile true\n\tplayOneGame\n\tif askYesNo(\"Do you want to play another game\") == \"no\" then break\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/65_Nim/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/65_Nim/nim.bas",
    "content": "100 PRINT TAB(33);\"NIM\"\n110 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n120 PRINT:PRINT:PRINT\n210 DIM A(100),B(100,10),D(2)\n220 PRINT \"THIS IS THE GAME OF NIM.\"\n230 PRINT \"DO YOU WANT INSTRUCTIONS\";\n240 INPUT Z$\n250 IF Z$=\"NO\" THEN 440\n260 IF Z$=\"no\" THEN 440\n270 IF Z$=\"YES\" THEN 310\n280 IF Z$=\"yes\" THEN 310\n290 PRINT \"PLEASE ANSWER YES OR NO\"\n300 GOTO 240\n310 PRINT \"THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.\"\n320 PRINT \"ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND\"\n330 PRINT \"THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE\"\n340 PRINT \"ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST\"\n350 PRINT \"TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM\"\n360 PRINT \"ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER\"\n370 PRINT \"WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,\"\n380 PRINT \"THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE\"\n390 PRINT \"ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A\"\n400 PRINT \"DIFFERENT NUMBER OF OBJECTS.\"\n410 PRINT \"THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE\"\n420 PRINT \"NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS\"\n430 PRINT \"MOVES.\"\n440 PRINT\n450 PRINT \"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST\";\n460 INPUT W\n470 IF W=1 THEN 490\n480 IF W<>2 THEN 450\n490 PRINT \"ENTER NUMBER OF PILES\";\n500 INPUT N\n510 IF N>100 THEN 490\n520 IF N<1 THEN 490\n530 IF N<>INT(N) THEN 490\n540 PRINT \"ENTER PILE SIZES\"\n550 FOR I=1 TO N\n560 PRINT I;\n570 INPUT A(I)\n580 IF A(I)>2000 THEN 560\n590 IF A(I)<1 THEN 560\n600 IF A(I)<>INT(A(I)) THEN 560\n610 NEXT I\n620 PRINT \"DO YOU WANT TO MOVE FIRST\";\n630 INPUT Q9$\n640 IF Q9$=\"YES\" THEN 1450\n650 IF Q9$=\"yes\" THEN 1450\n660 IF Q9$=\"NO\" THEN 700\n670 IF Q9$=\"no\" THEN 700\n680 PRINT \"PLEASE ANSWER YES OR NO.\"\n690 GOTO 630\n700 IF W=1 THEN 940\n710 LET C=0\n720 FOR I=1 TO N\n730 IF A(I)=0 THEN 770\n740 LET C=C+1\n750 IF C=3 THEN 840\n760 LET D(C)=I\n770 NEXT I\n780 IF C=2 THEN 920\n790 IF A(D(1))>1 THEN 820\n800 PRINT \"MACHINE LOSES\"\n810 GOTO 1640\n820 PRINT \"MACHINE WINS\"\n830 GOTO 1640\n840 LET C=0\n850 FOR I=1 TO N\n860 IF A(I)>1 THEN 940\n870 IF A(I)=0 THEN 890\n880 LET C=C+1\n890 NEXT I\n900 IF C/2<>INT(C/2) THEN 800\n910 GOTO 940\n920 IF A(D(1))=1 THEN 820\n930 IF A(D(2))=1 THEN 820\n940 FOR I=1 TO N\n950 LET E=A(I)\n960 FOR J=0 TO 10\n970 LET F=E/2\n980 LET B(I,J)=2*(F-INT(F))\n990 LET E=INT(F)\n1000 NEXT J\n1010 NEXT I\n1020 FOR J=10 TO 0 STEP -1\n1030 LET C=0\n1040 LET H=0\n1050 FOR I=1 TO N\n1060 IF B(I,J)=0 THEN 1110\n1070 LET C=C+1\n1080 IF A(I)<=H THEN 1110\n1090 LET H=A(I)\n1100 LET G=I\n1110 NEXT I\n1120 IF C/2<>INT(C/2) THEN 1190\n1130 NEXT J\n1140 LET E=INT(N*RND(1)+1)\n1150 IF A(E)=0 THEN 1140\n1160 LET F=INT(A(E)*RND(1)+1)\n1170 LET A(E)=A(E)-F\n1180 GOTO 1380\n1190 LET A(G)=0\n1200 FOR J=0 TO 10\n1210 LET B(G,J)=0\n1220 LET C=0\n1230 FOR I=1 TO N\n1240 IF B(I,J)=0 THEN 1260\n1250 LET C=C+1\n1260 NEXT I\n1270 LET A(G)=A(G)+2*(C/2-INT(C/2))*2^J\n1280 NEXT J\n1290 IF W=1 THEN 1380\n1300 LET C=0\n1310 FOR I=1 TO N\n1320 IF A(I)>1 THEN 1380\n1330 IF A(I)=0 THEN 1350\n1340 LET C=C+1\n1350 NEXT I\n1360 IF C/2<>INT(C/2) THEN 1380\n1370 LET A(G)=1-A(G)\n1380 PRINT \"PILE  SIZE\"\n1390 FOR I=1 TO N\n1400 PRINT I;A(I)\n1410 NEXT I\n1420 IF W=2 THEN 1450\n1430 GOSUB 1570\n1440 IF Z=1 THEN 820\n1450 PRINT \"YOUR MOVE - PILE, NUMBER TO BE REMOVED\";\n1460 INPUT X,Y\n1470 IF X>N THEN 1450\n1480 IF X<1 THEN 1450\n1490 IF X<>INT(X) THEN 1450\n1500 IF Y>A(X) THEN 1450\n1510 IF Y<1 THEN 1450\n1520 IF Y<>INT(Y) THEN 1450\n1530 LET A(X)=A(X)-Y\n1540 GOSUB 1570\n1550 IF Z=1 THEN 800\n1560 GOTO 700\n1570 LET Z=0\n1580 FOR I=1 TO N\n1590 IF A(I)=0 THEN 1610\n1600 RETURN\n1610 NEXT I\n1620 LET Z=1\n1630 RETURN\n1640 PRINT \"do you want to play another game\";\n1650 INPUT Q9$\n1660 IF Q9$=\"YES\" THEN 1720\n1670 IF Q9$=\"yes\" THEN 1720\n1680 IF Q9$=\"NO\" THEN 1730\n1690 IF Q9$=\"no\" THEN 1730\n1700 PRINT \"PLEASE.  YES OR NO.\"\n1710 GOTO 1650\n1720 GOTO 440\n1730 END\n"
  },
  {
    "path": "00_Alternate_Languages/66_Number/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript number.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"number\"\n\trun\n```\n3. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of number.ms, and click the \"Run Script\" button.\n"
  },
  {
    "path": "00_Alternate_Languages/66_Number/MiniScript/number.ms",
    "content": "// Number Game\n// originally by Tom Adametx\n// Ported from BASIC to MiniScript by Joe Strout, 2023\n\nprint \" \"*33 + \"NUMBER\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\n\nprint \"You have 100 points.  By guessing numbers from 1 to 5, you\"\nprint \"can gain or lose points depending on how close you get to\"\nprint \"a random number selected by the computer.\"; print\nprint \"You occasionally will get a jackpot which will double(!)\"\nprint \"your point count.  You win when you get to 500 points.\"\nprint\n\nP = 100\nfnr = function; return ceil(5*rnd); end function\nwhile true\n\tguess = input(\"Guess a number from 1 to 5: \").val\n\tR = fnr\n\tS = fnr\n\tT = fnr\n\tU = fnr\n\tV = fnr\n\tif guess == R then\n\t\tP = P - 5\n\telse if guess == S then\n\t\tP = P + 5\n\telse if guess == T then\n\t\tP = P+P\n\t\tprint \"You hit the jackpot!!!\"\n\telse if guess == U then\n\t\tP = P + 1\n\telse if guess == V then\n\t\tP = P - floor(P*0.5)\n\telse if guess > 5 then\n\t\tcontinue\n\tend if\n\tif P > 500 then\n\t\tprint \"!!!!You win!!!! with \" + P + \" points.\"\n\t\tbreak\n\tend if\n\tprint \"You have \" + P + \" points.\"; print\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/66_Number/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/66_Number/number.bas",
    "content": "1 PRINT TAB(33);\"NUMBER\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\"\n5 PRINT \"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\"\n6 PRINT \"A RANDOM NUMBER SELECTED BY THE COMPUTER.\": PRINT\n7 PRINT \"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\"\n8 PRINT \"YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\"\n9 PRINT: P=100\n10 DEF FNR(X)=INT(5*RND(1)+1)\n12 INPUT \"GUESS A NUMBER FROM 1 TO 5\";G\n15 R=FNR(1)\n16 S=FNR(1)\n17 T=FNR(1)\n18 U=FNR(1)\n19 V=FNR(1)\n20 IF G=R THEN 30\n21 IF G=S THEN 40\n22 IF G=T THEN 50\n23 IF G=U THEN 60\n24 IF G=V THEN 70\n25 IF G>5 THEN 12\n30 P=P-5\n35 GOTO 80\n40 P=P+5\n45 GOTO 80\n50 P=P+P\n53 PRINT \"YOU HIT THE JACKPOT!!!\"\n55 GOTO 80\n60 P=P+1\n65 GOTO 80\n70 P=P-(P*.5)\n80 IF P>500 THEN 90\n82 PRINT \"YOU HAVE\";P;\"POINTS.\":PRINT\n85 GOTO 12\n90 PRINT \"!!!!YOU WIN!!!! WITH \";P;\"POINTS.\"\n99 END\n"
  },
  {
    "path": "00_Alternate_Languages/67_One_Check/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript onecheck.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"onecheck\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms",
    "content": "print \"Solitaire Checker Puzzle by David Ahl\"\nprint\nprint \"48 checkers are placed on the 2 outside spaces of a\"\nprint \"standard 64-square checkerboard.  The object is to\"\nprint \"remove as many checkers as possible by diagonal jumps\"\nprint \"(as in standard checkers).  Use the numbered board to\"\nprint \"indicate the square you wish to jump from and to.  On\"\nprint \"the board printed out on each turn '1' indicates a\"\nprint \"checker and '0' an empty square.  When you have no\"\nprint \"possible jumps remaining, input a '0' in response to\"\nprint \"question 'Jump from?'\"\nprint\ninput \"(Press Return.)\"\nprint\n\npad4 = function(n)\n\treturn (\"    \" + n)[-4:]\nend function\n\nprintBoard = function\n\t// Idea: This program could be greatly improved by printing the board\n\t// as the index numbers (1-64), indicating which of those positions\n\t// contain checkers via color or punctuation, e.g. \"(42)\" vs \" 42 \".\n\t// This would make it much easier for the user to figure out what\n\t// numbers correspond to the positions they have in mind.\n\tprint\n\tfor j in range(1, 57, 8)\n\t\tprint \" \" + board[j:j+8].join(\"  \")\n\tend for\nend function\n\ninitBoard = function\n\tglobals.board = [null] + [1] * 64\t// treat this as 1-based array\n\tfor j in range(19, 43, 8)\n\t\tfor i in range(j, j+3)\n\t\t\tboard[i] = 0\n\t\tend for\n\tend for\nend function\n\nisLegal = function(from, to)\n\tif board[from] == 0 then return false\n\tif board[to] == 1 then return false\n\tif board[(to+from)/2] == 0 then return false\n\tfromRow = floor((from-1) / 8)\t// row in range 0-7\n\tfromCol = from - fromRow*8\t\t// column in range 1-8\n\ttoRow = floor((to-1) / 8)\n\ttoCol = to - toRow*8\n\tif fromRow > 7 or toRow > 7 or fromCol > 8 or toCol > 8 then return false\n\tif abs(fromRow-toRow) != 2 or abs(fromCol-toCol) != 2 then return false\n\treturn true\nend function\n\naskYesNo = function(prompt)\n\twhile true\n\t\tanswer = input(prompt + \"? \").lower\n\t\tif answer and answer[0] == \"y\" then return \"yes\"\n\t\tif answer and answer[0] == \"n\" then return \"no\"\n\t\tprint \"Please answer 'yes' or 'no'.\"\n\tend while\nend function\n\nprint \"Here is the numerical board:\"\nprint\nfor j in range(1, 57, 8)\n\tprint pad4(j) + pad4(j+1) + pad4(j+2) + pad4(j+3) +\n\t  pad4(j+4) + pad4(j+5) + pad4(j+6) + pad4(j+7)\nend for\n\nwhile true\n\tinitBoard\n\tprint\n\tprint \"And here is the opening position of the checkers.\"\n\tprintBoard\n\tjumps = 0\n\twhile true\n\t\tfromPos = input(\"Jump from? \").val\n\t\tif fromPos == 0 then break\n\t\ttoPos = input(\"To? \").val\n\t\tprint\n\t\tif not isLegal(fromPos, toPos) then\n\t\t\tprint \"Illegal move.  Try again...\"\n\t\t\tcontinue\n\t\tend if\n\t\tboard[fromPos] = 0\n\t\tboard[toPos] = 1\n\t\tboard[(toPos+fromPos)/2] = 0\n\t\tjumps += 1\n\t\tprintBoard\n\tend while\n\t// End game summary\n\tsum = board[1:].sum\n\tprint \"You made \" + jumps + \" jumps and had \" + sum + \" pieces\"\n\tprint \"remaining on the board.\"\n\tprint\n\tif askYesNo(\"Try again\") == \"no\" then break\nend while\nprint\nprint \"O.K.  Hope you had fun!!\"\n\n\t"
  },
  {
    "path": "00_Alternate_Languages/67_One_Check/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/67_One_Check/onecheck.bas",
    "content": "2 PRINT TAB(30);\"ONE CHECK\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n8 DIM A(64)\n10 PRINT \"SOLITAIRE CHECKER PUZZLE BY DAVID AHL\"\n15 PRINT\n20 PRINT \"48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A\"\n25 PRINT \"STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO\"\n30 PRINT \"REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS\"\n35 PRINT \"(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO\"\n40 PRINT \"INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON\"\n45 PRINT \"THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A\"\n50 PRINT \"CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO\"\n55 PRINT \"POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO\"\n60 PRINT \"QUESTION 'JUMP FROM ?'\"\n62 PRINT\n63 PRINT \"HERE IS THE NUMERICAL BOARD:\"\n66 PRINT\n70 FOR J=1 TO 57 STEP 8\n74 PRINT J;TAB(4);J+1;TAB(8);J+2;TAB(12);J+3;TAB(16);J+4;TAB(20);J+5;\n75 PRINT TAB(24);J+6;TAB(28);J+7\n76 NEXT J\n77 PRINT\n78 PRINT \"AND HERE IS THE OPENING POSITION OF THE CHECKERS.\"\n79 PRINT\n80 FOR J=1 TO 64\n82 A(J)=1\n84 NEXT J\n86 FOR J=19 TO 43 STEP 8\n88 FOR I=J TO J+3\n90 A(I)=0\n92 NEXT I\n94 NEXT J\n96 M=0\n98 GOTO 340\n100 INPUT \"JUMP FROM\";F\n105 IF F=0 THEN 500\n110 INPUT \"TO\";T\n112 PRINT\n118 REM *** CHECK LEGALITY OF MOVE\n120 F1=INT((F-1)/8)\n130 F2=F-8*F1\n140 T1=INT((T-1)/8)\n150 T2=T-8*T1\n160 IF F1>7 THEN 230\n170 IF T1>7 THEN 230\n180 IF F2>8 THEN 230\n190 IF T2>8 THEN 230\n200 IF ABS(F1-T1)<>2 THEN 230\n210 IF ABS(F2-T2)<>2 THEN 230\n212 IF A((T+F)/2)=0 THEN 230\n215 IF A(F)=0 THEN 230\n220 IF A(T)=1 THEN 230\n225 GOTO 250\n230 PRINT \"ILLEGAL MOVE.  TRY AGAIN...\"\n240 GOTO 100\n245 REM *** UPDATE BOARD\n250 A(T)=1\n260 A(F)=0\n270 A((T+F)/2)=0\n290 M=M+1\n310 REM *** PRINT BOARD\n340 FOR J=1 TO 57 STEP 8\n350 FOR I=J TO J+7\n360 PRINT A(I);\n370 NEXT I\n380 PRINT\n390 NEXT J\n400 PRINT\n410 GOTO 100\n490 REM *** END GAME SUMMARY\n500 S=0\n510 FOR I=1 TO 64\n520 S=S+A(I)\n530 NEXT I\n540 PRINT:PRINT \"YOU MADE\";M;\"JUMPS AND HAD\";S;\"PIECES\"\n550 PRINT \"REMAINING ON THE BOARD.\"\n560 PRINT\n562 INPUT \"TRY AGAIN\";A$\n570 IF A$=\"YES\" THEN 70\n575 IF A$=\"NO\" THEN 600\n580 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.\"\n590 GOTO 562\n600 PRINT\n610 PRINT \"O.K.  HOPE YOU HAD FUN!!\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/68_Orbit/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript orbit.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"orbit\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/68_Orbit/MiniScript/orbit.ms",
    "content": "print \" \"*33 + \"Orbit\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Somewhere above your planet is a Romulan ship.\"\nprint\nprint \"The ship is in a constant polar orbit.  Its\"\nprint \"distance from the center of your planet is from\"\nprint \"10,000 to 30,000 miles and at its present velocity can\"\nprint \"circle your planet once every 12 to 36 hours.\"\nprint\nprint \"Unfortunately, they are using a cloaking device so\"\nprint \"you are unable to see them, but with a special\"\nprint \"instrument you can tell how near their ship your\"\nprint \"photon bomb exploded.  You have seven hours until they\"\nprint \"have built up sufficient power in order to escape\"\nprint \"your planet's gravity.\"\nprint\nprint \"Your planet has enough power to fire one bomb an hour.\"\nprint\nprint \"At the beginning of each hour you will be asked to give an\"\nprint \"angle (between 0 and 360) and a distance in units of\"\nprint \"100 miles (between 100 and 300), after which your bomb's\"\nprint \"distance from the enemy ship will be given.\"\nprint\nprint \"An explosion within 5,000 miles of the romulan ship\"\nprint \"will destroy it.\"\nprint; input \"(Press Return.)\"\nprint\nprint \"Below is a diagram to help you visualize your plight.\"\nprint\nprint\nprint \"                          90\"\nprint \"                    0000000000000\"\nprint \"                 0000000000000000000\"\nprint \"               000000           000000\"\nprint \"             00000                 00000\"\nprint \"            00000    xxxxxxxxxxx    00000\"\nprint \"           00000    xxxxxxxxxxxxx    00000\"\nprint \"          0000     xxxxxxxxxxxxxxx     0000\"\nprint \"         0000     xxxxxxxxxxxxxxxxx     0000\"\nprint \"        0000     xxxxxxxxxxxxxxxxxxx     0000\"\nprint \"180<== 00000     xxxxxxxxxxxxxxxxxxx     00000 ==>0\"\nprint \"        0000     xxxxxxxxxxxxxxxxxxx     0000\"\nprint \"         0000     xxxxxxxxxxxxxxxxx     0000\"\nprint \"          0000     xxxxxxxxxxxxxxx     0000\"\nprint \"           00000    xxxxxxxxxxxxx    00000\"\nprint \"            00000    xxxxxxxxxxx    00000\"\nprint \"             00000                 00000\"\nprint \"               000000           000000\"\nprint \"                 0000000000000000000\"\nprint \"                    0000000000000\"\nprint \"                         270\"\nprint\nprint \"x - your planet\"\nprint \"o - the orbit of the romulan ship\"\nprint; input \"(Press Return.)\"\nprint\nprint \"On the above diagram, the romulan ship is circling\"\nprint \"counterclockwise around your planet.  Don't forget that\"\nprint \"without sufficient power the romulan ship's altitude\"\nprint \"and orbital rate will remain constant.\"\nprint\nprint \"Good luck.  The federation is counting on you.\"\n\nwhile true\n\ta=floor(360*rnd)\n\td=floor(200*rnd + 200)\n\tr=floor(20*rnd + 10)\n\tfor h in range(1,7)\n\t\tprint\n\t\tprint\n\t\tprint \"This is hour \" + h + \", at what angle do you wish to send\"\n\t\ta1 = input(\"your photon bomb? \").val\n\t\td1 = input(\"How far out do you wish to detonate it? \").val\n\t\tprint\n\t\tprint\n\t\ta += r\n\t\tif a >= 360 then a -= 360\n\t\tt = abs(a-a1)\n\t\tif t >= 180 then t = 360 - t\n\t\tc = sqrt(d*d + d1*d1 - 2*d*d1*cos(t*pi/180))\n\t\tprint \"Your photon bomb exploded \" + round(c) + \" * 10^2 miles from the\"\n\t\tprint \"Romulan ship.\"\n\t\tif c<=50 then break\n\tend for\n\tif c <= 50 then\n\t\tprint \"You have succesfully completed your mission.\"\n\telse\n\t\tprint \"You have allowed the Romulans to escape.\"\n\tend if\n\tprint \"Another romulan ship has gone into orbit.\"\n\tyn = input(\"Do you wish to try to destroy it? \").lower + \" \"\n\tif yn[0] != \"y\" then break\nend while\nprint \"good bye.\"\n"
  },
  {
    "path": "00_Alternate_Languages/68_Orbit/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/68_Orbit/orbit.bas",
    "content": "2 PRINT TAB(33);\"ORBIT\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 PRINT \"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\"\n15 PRINT\n20 PRINT \"THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\"\n25 PRINT \"DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\"\n30 PRINT \"10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\"\n31 PRINT \"CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\"\n35 PRINT\n40 PRINT \"UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\"\n45 PRINT \"YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\"\n50 PRINT \"INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\"\n55 PRINT \"PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\"\n60 PRINT \"HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\"\n65 PRINT \"YOUR PLANET'S GRAVITY.\"\n70 PRINT\n75 PRINT \"YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\"\n80 PRINT\n85 PRINT \"AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\"\n90 PRINT \"ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\"\n95 PRINT \"100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\"\n100 PRINT \"DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\"\n105 PRINT\n110 PRINT \"AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\"\n111 PRINT \"WILL DESTROY IT.\"\n114 PRINT\n115 PRINT \"BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\"\n116 PRINT\n117 PRINT\n168 PRINT \"                          90\"\n170 PRINT \"                    0000000000000\"\n171 PRINT \"                 0000000000000000000\"\n172 PRINT \"               000000           000000\"\n173 PRINT \"             00000                 00000\"\n174 PRINT \"            00000    XXXXXXXXXXX    00000\"\n175 PRINT \"           00000    XXXXXXXXXXXXX    00000\"\n176 PRINT \"          0000     XXXXXXXXXXXXXXX     0000\"\n177 PRINT \"         0000     XXXXXXXXXXXXXXXXX     0000\"\n178 PRINT \"        0000     XXXXXXXXXXXXXXXXXXX     0000\"\n179 PRINT \"180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\"\n180 PRINT \"        0000     XXXXXXXXXXXXXXXXXXX     0000\"\n181 PRINT \"         0000     XXXXXXXXXXXXXXXXX     0000\"\n182 PRINT \"          0000     XXXXXXXXXXXXXXX     0000\"\n183 PRINT \"           00000    XXXXXXXXXXXXX    00000\"\n184 PRINT \"            00000    XXXXXXXXXXX    00000\"\n185 PRINT \"             00000                 00000\"\n186 PRINT \"               000000           000000\"\n187 PRINT \"                 0000000000000000000\"\n188 PRINT \"                    0000000000000\"\n190 PRINT \"                         270\"\n192 PRINT\n195 PRINT \"X - YOUR PLANET\"\n196 PRINT \"O - THE ORBIT OF THE ROMULAN SHIP\"\n197 PRINT\n198 PRINT \"ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\"\n199 PRINT \"COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\"\n200 PRINT \"WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\"\n210 PRINT \"AND ORBITAL RATE WILL REMAIN CONSTANT.\"\n220 PRINT\n230 PRINT \"GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\"\n270 A=INT(360*RND(1))\n280 D=INT(200*RND(1)+200)\n290 R=INT(20*RND(1)+10)\n300 H=0\n310 IF H=7 THEN 490\n320 H=H+1\n325 PRINT\n326 PRINT\n330 PRINT \"THIS IS HOUR\";H;\", AT WHAT ANGLE DO YOU WISH TO SEND\"\n335 PRINT \"YOUR PHOTON BOMB\";\n340 INPUT A1\n350 PRINT \"HOW FAR OUT DO YOU WISH TO DETONATE IT\";\n360 INPUT D1\n365 PRINT\n366 PRINT\n370 A=A+R\n380 IF A<360 THEN 400\n390 A=A-360\n400 T=ABS(A-A1)\n410 IF T<180 THEN 430\n420 T=360-T\n430 C=SQR(D*D+D1*D1-2*D*D1*COS(T*3.14159/180))\n440 PRINT \"YOUR PHOTON BOMB EXPLODED\";C;\"*10^2 MILES FROM THE\"\n445 PRINT \"ROMULAN SHIP.\"\n450 IF C<=50 THEN 470\n460 GOTO 310\n470 PRINT \"YOU HAVE SUCCESFULLY COMPLETED YOUR MISSION.\"\n480 GOTO 500\n490 PRINT \"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\"\n500 PRINT \"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\"\n510 PRINT \"DO YOU WISH TO TRY TO DESTROY IT\";\n520 INPUT C$\n530 IF C$=\"YES\" THEN 270\n540 PRINT \"GOOD BYE.\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/69_Pizza/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript pizza.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"pizza\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms",
    "content": "print \" \"*33 + \"Pizza\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Pizza Delivery Game\"; print\nname = input(\"What is your first name? \"); print\nprint \"Hi, \" + name + \".  In this game you are to take orders\"\nprint \"for pizzas.  Then you are to tell a delivery boy\"\nprint \"where to deliver the ordered pizzas.\"; print; print\n\n// Convert a house name like \"G\" into coordinates like [3,2].\nnameToCoords = function(name)\n\tidx = name.code - \"A\".code\n\trow = floor(idx / 4)\n\tcol = idx % 4\n\treturn [col+1, row+1]\nend function\n\n// Convert house coordinates like [3,2] into a house name like \"G\".\ncoordsToName = function(coords)\n\tidx = (coords[1]-1)*4 + (coords[0]-1)\n\treturn char(\"A\".code + idx)\nend function\n\naskYesNo = function(prompt)\n\twhile true\n\t\tyn = input(prompt + \"? \").lower + \" \"\n\t\tif yn[0] == \"y\" then return \"yes\"\n\t\tif yn[0] == \"n\" then return \"no\"\n\t\tprint \"'Yes' or 'no' please, now then,\"\n\tend while\nend function\t\n\ninput \"(Press Return.)\"; print\n\nprint \"Map of the city of Hyattsville\"; print\nprint \" -----1-----2-----3-----4-----\"\nfor row in range(4, 1)\n\tprint \"-\"; print \"-\"; print \"-\"\n\ts = row + \"     \"\n\tfor col in range(1, 4)\n\t\ts += coordsToName([col, row]) + \"     \"\n\tend for\n\ts += row\n\tprint s\nend for\nprint \"-\"; print \"-\"; print \"-\"\nprint \" -----1-----2-----3-----4-----\"\n\ninput\nprint \"The output is a map of the homes where\"\nprint \"you are to send pizzas.\"; print\nprint \"Your job is to give a truck driver\"\nprint \"the location or coordinates of the\"\nprint \"home ordering the pizza.\"; print\nif askYesNo(\"Do you need more directions\") == \"yes\" then\n\tprint; print \"Somebody will ask for a pizza to be\"\n\tprint \"delivered.  Then a delivery boy will\"\n\tprint \"ask you for the location.\";\n\tprint \"     Example:\"\n\tprint \"This is J.  Please send a pizza.\"\n\tprint \"Driver to \" + name + \".  Where does j live?\"\n\tprint \"Your answer would be 2,3\"; print\n\tif askYesNo(\"Understand\") == \"no\" then\n\t\tprint \"This job is definitely too difficult for you. Thanks anyway\"\n\t\texit\n\tend if\n\tprint \"Good.  you are now ready to start taking orders.\"; print\n\tprint \"Good luck!!\"; print\nend if\n\nwhile true\n\tfor turn in range(1,5)\n\t\tcoords = [floor(rnd*4+1), floor(rnd*4+1)]\n\t\tbuyer = coordsToName(coords)\n\t\tprint \"Hello \" + name + \"'s Pizza.  This is \" + buyer + \n\t\t  \".  Please send a pizza.\"\n\t\twhile true\n\t\t\twhile true\n\t\t\t\tinp = input(\"  Driver to \" + name + \":  Where does \" + buyer + \" live? \")\n\t\t\t\tinp = inp.replace(\",\", \" \").replace(\"  \", \" \")\n\t\t\t\tinp = inp.split + [\"0\",\"0\"]\n\t\t\t\tguess = [inp[0].val, inp[1].val]\n\t\t\t\tif 1 <= guess[0] <= 4 and 1 <= guess[1] <= 4 then break\n\t\t\tend while\n\t\t\tif guess == coords then\n\t\t\t\tprint \"Hello \" + name + \".  This is \" + buyer + \", thanks for the pizza.\"\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tprint \"This is \" + coordsToName(guess) + \".  I did not order a pizza.\"\n\t\t\t\tprint \"I live at \" + guess.join(\",\")\n\t\t\tend if\n\t\tend while\n\t\tprint\n\tend for\n\tif askYesNo(\"Do you want to deliver more pizzas\") == \"no\" then break\nend while\n\nprint; print \"O.K. \" + name + \", see you later!\"; print\n"
  },
  {
    "path": "00_Alternate_Languages/69_Pizza/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/69_Pizza/pizza.bas",
    "content": "5 PRINT TAB(33);\"PIZZA\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n15 PRINT: PRINT: PRINT\n20 DIM S$(16),M$(4)\n30 PRINT \"PIZZA DELIVERY GAME\": PRINT\n50 INPUT \"WHAT IS YOUR FIRST NAME\";N$: PRINT\n80 PRINT \"HI, \";N$;\".  IN THIS GAME YOU ARE TO TAKE ORDERS\"\n90 PRINT \"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\"\n100 PRINT \"WHERE TO DELIVER THE ORDERED PIZZAS.\": PRINT: PRINT\n140 FOR I=1 TO 16\n150 READ S$(I)\n160 NEXT I\n170 FOR I=1 TO 4\n180 READ M$(I)\n190 NEXT I\n200 DATA \"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\"\n210 DATA \"P\",\"1\",\"2\",\"3\",\"4\"\n230 PRINT \"MAP OF THE CITY OF HYATTSVILLE\": PRINT\n250 PRINT \" -----1-----2-----3-----4-----\"\n260 K=4\n270 FOR I=1 TO 4\n280 PRINT \"-\": PRINT \"-\": PRINT\"-\": PRINT \"-\"\n320 PRINT M$(K);\n330 S1=16-4*I+1\n340 PRINT \"     \";S$(S1);\"     \";S$(S1+1);\"     \";S$(S1+2);\"     \";\n350 PRINT S$(S1+3);\"     \";M$(K)\n380 K=K-1\n390 NEXT I\n400 PRINT \"-\": PRINT \"-\": PRINT \"-\": PRINT \"-\"\n440 PRINT \" -----1-----2-----3-----4-----\": PRINT\n460 PRINT \"THE OUTPUT IS A MAP OF THE HOMES WHERE\"\n470 PRINT \"YOU ARE TO SEND PIZZAS.\": PRINT\n490 PRINT \"YOUR JOB IS TO GIVE A TRUCK DRIVER\"\n500 PRINT \"THE LOCATION OR COORDINATES OF THE\"\n510 PRINT \"HOME ORDERING THE PIZZA.\": PRINT\n520 INPUT \"DO YOU NEED MORE DIRECTIONS\";A$\n530 IF A$=\"YES\" THEN 590\n540 IF A$=\"NO\" THEN 750\n550 PRINT \"'YES' OR 'NO' PLEASE, NOW THEN,\": GOTO 520\n590 PRINT: PRINT \"SOMEBODY WILL ASK FOR A PIZZA TO BE\"\n600 PRINT \"DELIVERED.  THEN A DELIVERY BOY WILL\"\n610 PRINT \"ASK YOU FOR THE LOCATION.\":PRINT \"     EXAMPLE:\"\n620 PRINT \"THIS IS J.  PLEASE SEND A PIZZA.\"\n640 PRINT \"DRIVER TO \";N$;\".  WHERE DOES J LIVE?\"\n650 PRINT \"YOUR ANSWER WOULD BE 2,3\": PRINT\n660 INPUT \"UNDERSTAND\";A$\n670 IF A$=\"YES\" THEN 690\n680 PRINT \"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\"\n685 GOTO 999\n690 PRINT \"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\": PRINT\n700 PRINT \"GOOD LUCK!!\": PRINT\n750 FOR I=1 TO 5\n760 S=INT(RND(1)*16+1): PRINT\n770 PRINT \"HELLO \";N$;\"'S PIZZA.  THIS IS \";S$(S);\".\";\n775 PRINT \"  PLEASE SEND A PIZZA.\"\n780 PRINT \"  DRIVER TO \";N$;\":  WHERE DOES \";S$(S);\" LIVE\";\n790 INPUT A(1),A(2)\n870 T=A(1)+(A(2)-1)*4\n880 IF T=S THEN 920\n890 PRINT \"THIS IS \";S$(T);\".  I DID NOT ORDER A PIZZA.\"\n900 PRINT \"I LIVE AT \";A(1);\",\";A(2)\n910 GOTO 780\n920 PRINT \"HELLO \"N$;\".  THIS IS \";S$(S);\", THANKS FOR THE PIZZA.\"\n930 NEXT I\n940 PRINT: INPUT \"DO YOU WANT TO DELIVER MORE PIZZAS\";A$\n960 IF A$=\"YES\" THEN 750\n970 PRINT: PRINT \"O.K. \";N$;\", SEE YOU LATER!\":PRINT\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/70_Poetry/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript poetry.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"poetry\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms",
    "content": "print \" \"*30 + \"POETRY\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\n\nI = 0; J = 0; K = 0; U = 0\n\n// Note: infinite loop.  Press control-C to break.\nwhile true\n\tif J == 1 then\n\t\tprint [\"MIDNIGHT DREARY\", \"FIERY EYES\", \n\t\t \"BIRD OR FIEND\", \"THING OF EVIL\", \"PROPHET\"][I-1], \"\"\n\telse if J == 2 then\n\t\tif I == 1 or I == 4 then U = 2\n\t\tif I == 3 then U = 0\n\t\tprint [\"BEGUILING ME\", \"THRILLED ME\", \n\t\t \"STILL SITTING....\", \"NEVER FLITTING\", \"BURNED\"][I-1], \"\"\n\telse if J == 3 then\n\t\tif U != 0 or I < 5 then\n\t\t\tprint [\"AND MY SOUL\", \"DARKNESS THERE\", \n\t\t\t \"SHALL BE LIFTED\", \"QUOTH THE RAVEN\", \"SIGN OF PARTING\"][I-1], \"\"\n\t\tend if\n\telse if J == 4 then\n\t\tprint [\"NOTHING MORE\", \"YET AGAIN\", \n\t\t  \"SLOWLY CREEPING\", \"...EVERMORE\", \"NEVERMORE\"][I-1], \"\"\n\tend if\n\tif U != 0 and rnd <= 0.19 then\n\t\tprint \",\", \"\"\n\t\tU = 2\n\tend if\n\tif rnd <= 0.65 then\n\t\tprint \" \", \"\"\n\t\tU += 1\n\telse\n\t\tprint\n\t\tU = 0\n\tend if\n\twhile true\n\t\tI =floor(floor(10*rnd)/2)+1\n\t\tJ += 1\n\t\tK += 1\n\t\tif U == 0 and floor(J/2) == J/2 then print \"     \", \"\"\n\t\tif J <= 5 then break\n\t\tJ = 0\n\t\tprint\n\t\tif K <= 20 then continue\n\t\tprint\n\t\tU = 0\n\t\tK = 0\n\t\tbreak\n\tend while\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/70_Poetry/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/70_Poetry/poetry.bas",
    "content": "10 PRINT TAB(30);\"POETRY\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n90 ON I GOTO 100,101,102,103,104\n100 PRINT \"MIDNIGHT DREARY\";:GOTO 210\n101 PRINT \"FIERY EYES\";:GOTO 210\n102 PRINT \"BIRD OR FIEND\";:GOTO 210\n103 PRINT \"THING OF EVIL\";:GOTO 210\n104 PRINT \"PROPHET\";:GOTO 210\n110 ON I GOTO 111,112,113,114,115\n111 PRINT \"BEGUILING ME\";:U=2:GOTO 210\n112 PRINT \"THRILLED ME\";:GOTO 210\n113 PRINT \"STILL SITTING....\";:GOTO 212\n114 PRINT \"NEVER FLITTING\";:U=2:GOTO 210\n115 PRINT \"BURNED\";:GOTO 210\n120 ON I GOTO 121,122,123,124,125\n121 PRINT \"AND MY SOUL\";:GOTO 210\n122 PRINT \"DARKNESS THERE\";:GOTO 210\n123 PRINT \"SHALL BE LIFTED\";:GOTO 210\n124 PRINT \"QUOTH THE RAVEN\";:GOTO 210\n125 IF U=0 THEN 210\n126 PRINT \"SIGN OF PARTING\";:GOTO 210\n130 ON I GOTO 131,132,133,134,135\n131 PRINT \"NOTHING MORE\";:GOTO 210\n132 PRINT \"YET AGAIN\";:GOTO 210\n133 PRINT \"SLOWLY CREEPING\";:GOTO 210\n134 PRINT \"...EVERMORE\";:GOTO 210\n135 PRINT \"NEVERMORE\";\n210 IF U=0 OR RND(1)>.19 THEN 212\n211 PRINT \",\";:U=2\n212 IF RND(1)>.65 THEN 214\n213 PRINT \" \";:U=U+1:GOTO 215\n214 PRINT : U=0\n215 I=INT(INT(10*RND(1))/2)+1\n220 J=J+1 : K=K+1\n230 IF U>0 OR INT(J/2)<>J/2 THEN 240\n235 PRINT \"     \";\n240 ON J GOTO 90,110,120,130,250\n250 J=0 : PRINT : IF K>20 THEN 270\n260 GOTO 215\n270 PRINT : U=0 : K=0 : GOTO 110\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/70_Poetry/poetry.pl",
    "content": "#!/usr/bin/perl\n#use strict;\n# Automatic converted by bas2perl.pl\n# Too much spaguetti code to be properly converted.\n\n\nprint ' 'x 30 . \"POETRY\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nLine90:\nif ($I==1) { goto Line100; } elsif ($I==2) { goto Line101; } elsif ($I==3) { goto Line102; } elsif ($I==4) { goto Line103; } elsif ($I==5) { goto Line104; } ;\nLine100:\nprint \"MIDNIGHT DREARY\"; goto Line210;\nLine101:\nprint \"FIERY EYES\"; goto Line210;\nLine102:\nprint \"BIRD OR FIEND\"; goto Line210;\nLine103:\nprint \"THING OF EVIL\"; goto Line210;\nLine104:\nprint \"PROPHET\"; goto Line210;\nLine110:\nif ($I==1) { goto Line111; } elsif ($I==2) { goto Line112; } elsif ($I==3) { goto Line113; } elsif ($I==4) { goto Line114; } elsif ($I==5) { goto Line115; } ;\nLine111:\nprint \"BEGUILING ME\"; $U=2; goto Line210;\nLine112:\nprint \"THRILLED ME\"; goto Line210;\nLine113:\nprint \"STILL SITTING....\"; goto Line212;\nLine114:\nprint \"NEVER FLITTING\"; $U=2; goto Line210;\nLine115:\nprint \"BURNED\"; goto Line210;\nLine120:\nif ($I==1) { goto Line121; } elsif ($I==2) { goto Line122; } elsif ($I==3) { goto Line123; } elsif ($I==4) { goto Line124; } elsif ($I==5) { goto Line125; } ;\nLine121:\nprint \"AND MY SOUL\"; goto Line210;\nLine122:\nprint \"DARKNESS THERE\"; goto Line210;\nLine123:\nprint \"SHALL BE LIFTED\"; goto Line210;\nLine124:\nprint \"QUOTH THE RAVEN\"; goto Line210;\nLine125:\nif ($U==0) { goto Line210; }\nprint \"SIGN OF PARTING\"; goto Line210;\nLine130:\nif ($I==1) { goto Line131; } elsif ($I==2) { goto Line132; } elsif ($I==3) { goto Line133; } elsif ($I==4) { goto Line134; } elsif ($I==5) { goto Line135; } ;\nLine131:\nprint \"NOTHING MORE\"; goto Line210;\nLine132:\nprint \"YET AGAIN\"; goto Line210;\nLine133:\nprint \"SLOWLY CREEPING\"; goto Line210;\nLine134:\nprint \"...EVERMORE\"; goto Line210;\nLine135:\nprint \"NEVERMORE\";\nLine210:\nif ($U==0 || rand(1)>.19) { goto Line212; }\nprint \",\"; $U=2;\nLine212:\nif (rand(1)>.65) { goto Line214; }\nprint \" \"; $U=$U+1; goto Line215;\nLine214:\nprint \"\\n\"; $U=0;\nLine215:\n$I=int(int(10*rand(1))/2)+1;\n$J=$J+1; $K=$K+1;\nif ($U>0 || int($J/2)!=$J/2) { goto Line240; }\nprint \" \";\nLine240:\nif ($J==1) { goto Line90; } elsif ($J==2) { goto Line110; } elsif ($J==3) { goto Line120; } elsif ($J==4) { goto Line130; } elsif ($J==5) { goto Line250; } ;\nLine250:\n$J=0; print \"\\n\"; if ($K>20) { goto Line270; }\ngoto Line215;\nLine270:\nprint \"\\n\"; $U=0; $K=0; goto Line110;\nexit;\n"
  },
  {
    "path": "00_Alternate_Languages/71_Poker/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript poker.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"poker\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/71_Poker/MiniScript/poker.ms",
    "content": "print \" \"*33 + \"POKER\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"Welcome to the casino.  We each have $200.\"\nprint \"I will open the betting before the draw; you open after.\"\nprint \"To fold bet 0; to check bet .5.\"\nprint \"Enough talk -- let's get down to business.\"\nprint\n\naskYesNo = function(prompt)\n\twhile true\n\t\tyn = input(prompt + \"? \").lower + \" \"\n\t\tif yn[0] == \"y\" then return \"yes\"\n\t\tif yn[0] == \"n\" then return \"no\"\n\t\tprint \"Answer yes or no, please.\"\n\tend while\nend function\naskNumber = function(prompt, maxQty=3, minQty=1, maxErr=null, minErr=null)\n\twhile true\n\t\tvalue = input(prompt + \"? \").val\n\t\tif minQty <= value <= maxQty then return value\n\t\tif value < minQty and minErr != null then\n\t\t\tprint minErr\n\t\telse if maxErr != null then\n\t\t\tprint maxErr\n\t\telse\n\t\t\tprint \"Enter a value between \" + minQty + \" and \" + maxQty + \", please.\"\n\t\tend if\n\tend while\nend function\nrandom = function(n)\n\treturn floor(n * rnd)\nend function\nrand10 = function\n\treturn floor(10 * rnd)\nend function\npad = function(s, width)\n\treturn s + \" \" * (width - s.len)\nend function\n\n// Bonus little feature when running in Mini Micro: display a header bar\n// always at the top of the screen, showing current balances.  Does nothing\n// on other platforms.\ndrawHeaders = function\n\tif version.hostName != \"Mini Micro\" then return\n\tdisplay(2).mode = displayMode.text; td = display(2)\n\ttd.color = color.black; td.backColor = text.color\n\ttd.row = 25; td.column = 0\n\ttd.print pad(\"Computer: $\" + computer.balance, 25) +\n\t  pad(\"Table: $\" + Table.pot, 25) + \n\t  pad(\"Player: $\" + human.balance, 18)\nend function\n\n\n// Card class: represents a single playing card\nCard = {}\nCard.rank = 0\t\t// from 2 to 14 (Ace)\nCard.suit = \"Clubs\"\nCard.keep = false\t// temp flag, used to note which cards to keep vs. discard\nCard.make = function(rank, suit)\n\tresult = new Card\n\tresult.rank = rank\n\tresult.suit = suit\n\treturn result\nend function\nCard.rankStr = function(plural=false)\n\tif self.rank > 10 then\n\t\treturn [\"Jack\", \"Queen\", \"King\", \"Ace\"][self.rank-11] + \"s\"*plural\n\telse\n\t\treturn str(self.rank) + \"'s\" * plural\n\tend if\nend function\nCard.str = function\n\treturn self.rankStr + \" of \" + self.suit\nend function\n\n// Prepare a standard deck of 52 cards, and functions to draw and discard\ndeck = []\nfor suit in [\"Clubs\", \"Diamonds\", \"Hearts\", \"Spades\"]\n\tfor rank in range(2, 14)\n\t\tdeck.push Card.make(rank, suit)\n\tend for\nend for\ndeck.shuffle\ndiscardPile = []\ndrawCard = function\n\tif not deck then\n\t\tglobals.deck = discardPile\n\t\tdeck.shuffle\n\t\tglobals.discardPile = []\n\tend if\n\treturn deck.pop\nend function\ndiscard = function(cardOrCards)\n\tif cardOrCards isa Hand then\n\t\tglobals.discardPile += cardOrCards.cards\n\telse if cardOrCards isa list then\n\t\tglobals.discardPile += cardOrCards\n\telse\n\t\tdiscardPile.push cardOrCards\n\tend if\nend function\n\n// Hand ranks: how we compare Poker hands\nHandRank = {}\nHandRank.value = 0\nHandRank.str = function(highCard); return \"\"; end function\nHandRank.make = function(value)\n\tresult = new HandRank\n\tresult.value = value\n\treturn result\nend function\n\nHandRank.None = new HandRank\nHandRank.Schmaltz = HandRank.make(1)\nHandRank.Schmaltz.str = function(c); return \"schmaltz, \" + c.rankStr + \" high\"; end function\nHandRank.PartialStraight = HandRank.make(2)\nHandRank.PartialStraight.str = function(c); return \"\"; end function\t// (no display string; this is used only internally)\nHandRank.Pair = HandRank.make(3)\nHandRank.Pair.str = function(c); return \"a pair of \" + c.rankStr(true); end function\nHandRank.TwoPair = HandRank.make(4)\nHandRank.TwoPair.str = function(c); return \"two pair, \" + c.rankStr(true); end function\nHandRank.Three = HandRank.make(5)\nHandRank.Three.str = function(c); return \"three \" + c.rankStr(true); end function\nHandRank.Straight = HandRank.make(6)\nHandRank.Straight.str = function(c); return \"straight, \" + c.rankStr + \" high\"; end function\nHandRank.Flush = HandRank.make(7)\nHandRank.Flush.str = function(c); return \"a flush in \" + c.suit; end function\nHandRank.FullHouse = HandRank.make(8)\nHandRank.FullHouse.str = function(c); return \"full house, \" + c.rankStr(true); end function\nHandRank.Four = HandRank.make(9)\nHandRank.Four.str = function(c); return \"four \" + c.rankStr(true); end function\n// Note: original code does not detect a straight flush or royal flush.\n\n// Hand: represents a set of cards in the hand of one player.\nHand = {}\nHand.cards = null\t\t// list of Card\nHand.rank = null\t\t// HandRank instance\nHand.highCard = null\t// reference to which (of self.cards) determines relative value\nHand.afterDraw = false\t// true if we've already had a chance to draw cards\nHand.make = function(cards)\n\tresult = new Hand\n\tresult.cards = cards\n\tresult.analyze\n\treturn result\nend function\nHand.deal = function\n\treturn Hand.make([drawCard, drawCard, drawCard, drawCard, drawCard])\nend function\nHand.replaceCard = function(index)\n\tdiscard self.cards[index]\n\tself.cards[index] = drawCard\nend function\nHand.rankStr = function\n\treturn self.rank.str(self.highCard)\nend function\nHand.isWeak = function\n\treturn self.rank.value < HandRank.PartialStraight.value or\n\t\t (self.rank.value == HandRank.PartialStraight.value and self.afterDraw) or\n\t\t (self.rank <= HandRank.TwoPair.value and self.highCard.rank <= 6)\nend function\t\t \nHand.beats = function(other)\n\tif self.rank.value > other.rank.value then return true\n\tif self.rank.value < other.rank.value then return false\n\treturn self.highCard.rank > other.highCard.rank\nend function\nHand.print = function(startingNumber=1)\n\tnum = startingNumber\n\tfor c in self.cards\t\n\t\ts = \" \" * (num < 10) + num + \" -- \" + c.str\n\t\tprint \"  \" + s, \"\"\n\t\tif num % 2 == 0 then\n\t\t\tprint\n\t\telse\n\t\t\tprint \" \" * (28-s.len), \"\"\n\t\tend if\n\t\tnum += 1\n\tend for\n\tif num % 2 == 0 then print\nend function\nHand.analyze = function\n\tallSameSuit = true\n\tfor i in range(1, self.cards.len-1)\n\t\tif self.cards[i].suit != self.cards[0].suit then allSameSuit = false\n\tend for\n\tif allSameSuit then\n\t\tself.rank = HandRank.Flush\n\t\tself.highCard = self.cards[0]\n\t\treturn\n\tend if\n\t\n\tsortedCards = self.cards[:]\n\tsortedCards.sort \"rank\"\n\tself.rank = HandRank.Schmaltz\n\tfor c in sortedCards; c.keep = false; end for\n\tkeepAny = false\n\t\n\tfor i in range(0, sortedCards.len-2)\n\t\tmatchesNextCard = (sortedCards[i].rank == sortedCards[i+1].rank)\n\t\tif matchesNextCard then\n\t\t\tself.highCard = sortedCards[i]\n\t\t\tmatchesPrevCard = (i > 0 and sortedCards[i].rank == sortedCards[i-1].rank)\n\t\t\tsortedCards[i].keep = true\n\t\t\tsortedCards[i+1].keep = true\n\t\t\tkeepAny = true\n\t\t\tif self.rank.value < HandRank.Pair.value then\n\t\t\t\tself.rank = HandRank.Pair\n\t\t\telse if matchesPrevCard and self.rank == HandRank.Pair then\n\t\t\t\tself.rank = HandRank.Three\n\t\t\telse if self.rank == HandRank.Pair then\n\t\t\t\tself.rank = HandRank.TwoPair\n\t\t\telse if self.rank == HandRank.TwoPair then\n\t\t\t\tself.rank = HandRank.FullHouse\n\t\t\telse if matchesPrevCard then\n\t\t\t\tself.rank = HandRank.Four\n\t\t\telse\n\t\t\t\tself.rank = HandRank.FullHouse\n\t\t\tend if\n\t\tend if\n\tend for\n\tif not keepAny then\n\t\tif sortedCards[3].rank - sortedCards[0].rank == 3 then\n\t\t\tfor i in range(0,3); sortedCards[i].keep = true; end for\n\t\t\tself.rank = HandRank.PartialStraight\n\t\tend if\n\t\tif sortedCards[4].rank - sortedCards[1].rank == 3 then\n\t\t\tif self.rank == HandRank.PartialStraight then\n\t\t\t\tself.rank = HandRank.Straight\n\t\t\t\tsortedCards[4].keep = true\n\t\t\t\tself.highCard = sortedCards[4]\n\t\t\telse\n\t\t\t\tself.rank = HandRank.PartialStraight\n\t\t\t\tfor i in range(1,4); sortedCards[i].keep = true; end for\n\t\t\tend if\n\t\tend if\n\tend if\n\tif self.rank == HandRank.Schmaltz then\n\t\tself.highCard = sortedCards[4]\n\t\tsortedCards[4].keep = true\n\t\tsortedCards[3].keep = true\n\tend if\n\t\nend function\n\n// Some global constants, just to make the code more understandable\nAnte = 5\n\n// Player -- base class for computer and human\nPlayer = {}\nPlayer.balance = 200\nPlayer.hand = null\nPlayer.totalBet = 0\nPlayer.anteUp = function\n\tself.balance -= Ante\n\treturn Ante\nend function\nPlayer.newHand = function\n\tif self.hand then discard self.hand\n\tself.hand = Hand.deal\n\tself.totalBet = 0\nend function\nPlayer.addToPot = function(amount)\n\tself.balance -= amount\n\tTable.pot += amount\n\tdrawHeaders\nend function\nPlayer.win = function\n\tself.balance += Table.pot\n\tTable.pot = 0\n\tdrawHeaders\nend function\n\n// strategies the computer player might employ\nStrategy = {}\nStrategy.make = function(name, value=2, drawCount=null)\n\tresult = new Strategy\n\tresult.name = name\n\tresult.value = value\n\tresult.drawCount = drawCount\n\treturn result\nend function\nStrategy.fold = Strategy.make(\"FOLD\")\nStrategy.check = Strategy.make(\"CHECK\")\nStrategy.raise = Strategy.make(\"RAISE\", 2)\nStrategy.bluff = function(value, drawCount); return Strategy.make(\"BLUFF\", value, drawCount); end function\nStrategy.bet = function(value); return Strategy.make(\"BET\", value); end function\n\n// computer player\ncomputer = new Player\ncomputer.strategy = null\ncomputer.newHand = function\n\tsuper.newHand\n\tif self.hand.isWeak then\n\t\tif rand10 < 2 then\n\t\t\tself.strategy = Strategy.bluff(23, 2)\n\t\telse if rand10 < 2 then\n\t\t\tself.strategy = Strategy.bluff(23, 1)\n\t\telse if rand10 < 1 then\n\t\t\tself.strategy = Strategy.bluff(23, 0)\n\t\telse\n\t\t\tself.strategy = Strategy.fold\n\t\tend if\n\telse if self.hand.rank.value < HandRank.Three.value then\n\t\t\tif rand10 < 2 then self.strategy = Strategy.bluff(23, null) else self.strategy = Strategy.check\n\telse if self.hand.rank.value < HandRank.FullHouse.value then\n\t\tself.strategy = Strategy.bet(35)\n\telse\n\t\tif rand10 < 1 then self.strategy = Strategy.bet(35) else self.strategy = Strategy.raise\n\tend if\nend function\ncomputer.bet = function(minBet=1, openingBet=false)\n\t//print \"My hand: \"; self.hand.print; print \"Strategy: \" + self.strategy\n\tif self.balance < minBet then\n\t\tprint \"I fold.\"\n\t\treturn 0\n\tend if\n\tif openingBet and (self.strategy == Strategy.check or self.strategy == Strategy.fold) then\n\t\tprint \"I check.\"\n\t\treturn 0.5\n\telse if self.strategy == Strategy.fold and human.totalBet > 5 then\n\t\tprint \"I fold.\"\n\t\treturn 0\n\telse if self.strategy == Strategy.check then\n\t\tprint \"I'll see you.\"\n\t\treturn minBet\n\telse if openingBet then\n\t\tresult = self.strategy.value + rand10\n\t\tif result > self.balance then result = self.balance\n\t\tif result == 0 then\n\t\t\tprint \"I check.\"\n\t\t\treturn 0.5\n\t\tend if\n\t\tprint \"I'll open with $\" + result\n\t\treturn result\t\n\telse\n\t\tbet = self.strategy.value + rand10\n\t\tif self.strategy == Strategy.raise then bet += minBet\n\t\tif bet > self.balance then bet = self.balance\n\t\traise = bet - minBet\t\t\n\t\tif raise <= 0 then\n\t\t\tprint \"I'll see you.\"\n\t\t\treturn minBet\n\t\telse\n\t\t\tprint \"I'll see you, and raise you \" + raise\n\t\t\treturn bet\n\t\tend if\n\tend if\nend function\ncomputer.drawCards = function\n\t//print \"My hand:\"; self.hand.print\t\n\tdrawCount = 0\n\tfor c in self.hand.cards; if not c.keep then drawCount += 1; end for\n\tprint \"I am taking \" + drawCount + \" card\" + \"s\" * (drawCount != 1)\n\tfor i in self.hand.cards.indexes\n\t\tif not self.hand.cards[i].keep then self.hand.replaceCard i\t\t\n\tend for\n\tself.hand.analyze\n\t//print \"My new hand: \"; self.hand.print\n\tif self.strategy.name == \"BLUFF\" then\n\t\tself.strategy = Strategy.bluff(28)\n\telse if self.hand.isWeak then\n\t\tself.strategy = Strategy.fold\n\telse if self.hand.rank.value < HandRank.Three.value then\n\t\tif rand10 == 0 then self.strategy = Strategy.bet(19) else self.strategy = Strategy.raise\n\telse if self.hand.rank.value < HandRank.FullHouse.value then\n\t\tif rand10 == 0 then self.strategy = Strategy.bet(11) else self.strategy = Strategy.bet(19)\n\telse\n\t\tself.strategy = Strategy.raise\n\tend if\t\t\nend function\ncomputer.win = function\n\tprint; print \"I win.\"\n\tsuper.win\nend function\ncomputer.checkFunds = function\n\tif self.balance >= Ante then return\n\tif human.balance < 50 then return\t// BUGFIX\n\tif human.hasWatch or askYesNo(\"Would you like to buy back your watch for $50\") == \"no\" then\n\t\tprint \"I'm busted.  Conglatulations!\"\n\t\texit\n\tend if\n\tself.balance += 50\n\t// Note: original BASIC code does not take money from the player, but let's fix that:\n\thuman.balance -= 50\t\t// BUGFIX\n\thuman.hasWatch = true\n\tdrawHeaders\nend function\n\t\t\n\nhuman = new Player\nhuman.hasWatch = true\nhuman.bet = function(minBet=1, openingBet=false)\n\twhile true\n\t\tbetStr = input(\"What is your bet? \")\n\t\tbet = betStr.val\n\t\tif bet == 0 and betStr != \"0\" then\n\t\t\tprint \"Enter 0 to fold, 0.5 to check, or a value of 1 or more to bet.\"\n\t\t\tcontinue\n\t\telse if bet == 0.5 and openingBet then\n\t\t\treturn bet\t// (check)\n\t\telse if 0 < bet < 1 then\n\t\t\tprint \"No small change, please.\"\n\t\t\tcontinue\n\t\telse if bet < minBet then\n\t\t\tprint \"If you can't see my bet, then fold.\"\n\t\t\tcontinue\n\t\telse if bet > self.balance then\n\t\t\tprint \"You can't bet with what you haven't got.\"\n\t\t\tself.trySellWatch\n\t\t\tcontinue\n\t\tend if\n\t\treturn bet\n\tend while\nend function\nhuman.drawCards = function\n\tqty = askNumber(\"How many cards do you want\", 3, 0, \"You can't draw more than three cards.\")\n\tif qty == 0 then return\n\tprint \"What are their numbers: \"\n\tfor i in range(1, qty)\n\t\tnum = askNumber(\"\", 5, 1)\n\t\tself.hand.replaceCard num - 1\n\tend for\n\tprint \"Your new hand:\"\n\tself.hand.print\n\tself.hand.analyze\nend function\nhuman.win = function\n\tprint; print \"You win.\"\n\tsuper.win\nend function\nhuman.checkFunds = function\n\tif self.balance < Ante then self.trySellWatch\n\tif self.balance < Ante then\n\t\tprint \"Your wad is shot.  So long, sucker!\"\n\t\texit\n\tend if\nend function\nhuman.trySellWatch = function\n\tif not self.hasWatch then return\n\tif rand10 < 7 then\n\t\tvalue = 75\n\t\tmsg = \"I'll give you $\" + value + \" for it.\"\n\telse\n\t\tvalue = 25\n\t\tmsg = \"That's a pretty crummy watch - I'll give you $\" + value + \".\"\n\tend if\n\tif computer.balance < value then return\t// BUGFIX\n\tif askYesNo(\"Would you like to sell your watch\") == \"no\" then return\n\tprint msg\n\tself.balance += value\n\tself.hasWatch = false\n\t// Note: the original BASIC program does not actually take any money from the computer.\n\t// But let's do it right here:\n\tcomputer.balance -= value\t\t// BUGFIX\n\tdrawHeaders\nend function\n\nTable = {}\nTable.pot = 0\n\n\ndeal = function\n\tTable.pot += computer.anteUp + human.anteUp\n\tdrawHeaders\n\tcomputer.newHand\n\thuman.newHand\nend function\n\n// Do a round of betting.  Return true to continue, or false\n// if either player folds (ending the hand).\ntakeBets = function(computerFirst)\n\tif computerFirst then\n\t\tbet = computer.bet(1, true)\n\t\tif bet == 0 then\n\t\t\thuman.win\n\t\t\treturn false\n\t\tend if\n\t\tif bet == 0.5 then bet = 0\t// \"check\" (no bet, but stay in the hand)\n\t\tcomputer.addToPot bet\n\telse\n\t\tbet = 0\n\tend if\n\traise = bet\n\tcanCheck = (bet == 0)\n\twhile true\n\t\tbet = human.bet(raise, canCheck)\n\t\tif bet == 0 then\n\t\t\tcomputer.win\n\t\t\treturn false\n\t\tend if\n\t\tif bet == 0.5 then\t// (checked)\n\t\t\tif computerFirst then return true\n\t\t\tbet = 0\n\t\telse\n\t\t\thuman.addToPot bet\n\t\t\traise = bet - raise\n\t\t\tif raise == 0 then return true\n\t\tend if\n\t\tif computerFirst or bet > 0 then canCheck = false\n\t\t\n\t\tbet = computer.bet(raise, canCheck)\n\t\tif bet == 0 then\n\t\t\thuman.win\n\t\t\treturn false\n\t\tend if\n\t\tif bet == 0.5 then return true  // (checked)\n\t\tcanCheck = false\n\t\tcomputer.addToPot bet\n\t\traise = bet - raise\n\t\tif raise == 0 then return true\n\tend while\nend function\n\nplayHand = function\n\tprint\n\tcomputer.checkFunds\n\thuman.checkFunds\n\tprint \"The ante is \" + Ante + \".  I will deal:\"\n\tprint\n\t\n\tdeal\n\t\n\tprint \"Your hand:\"\n\thuman.hand.print\n\t\n\tprint\t\n\tif not takeBets(true) then return\n\t\n\tprint; print \"Now we draw -- \", \"\"\n\thuman.drawCards\n\tcomputer.drawCards\n\t\n\tif not takeBets(false) then return\n\t\n\tprint; print \"Now we compare hands:\"\n\tprint \"My hand:\"\n\tcomputer.hand.print 6\n\tprint\n\tprint \"You have \" + human.hand.rankStr\n\tprint \"I have \" + computer.hand.rankStr\n\tif computer.hand.beats(human.hand) then\n\t\tcomputer.win\n\telse if human.hand.beats(computer.hand) then\n\t\thuman.win\n\telse\n\t\tprint \"The hand is drawn.\"\n\t\tprint \"All $\" + Table.pot + \" remains in the pot.\"\n\tend if\nend function\n\ndrawHeaders\nwhile true\n\tplayHand\n\tprint \"Now I have $\" + computer.balance + \" and you have $\" + human.balance\n\tif askYesNo(\"Do you wish to continue\") == \"no\" then break\t\nend while"
  },
  {
    "path": "00_Alternate_Languages/71_Poker/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/71_Poker/poker.bas",
    "content": "2 PRINT TAB(33);\"POKER\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 DIM A(50),B(15)\n20 DEF FNA(X)=INT(10*RND(1))\n30 DEF FNB(X)=X-100*INT(X/100)\n40 PRINT \"WELCOME TO THE CASINO.  WE EACH HAVE $200.\"\n50 PRINT \"I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.\"\n60 PRINT \"TO FOLD BET 0; TO CHECK BET .5.\"\n70 PRINT \"ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.\"\n80 PRINT\n90 LET O=1\n100 LET C=200\n110 LET S=200\n120 LET P=0\n130 REM\n140 PRINT\n150 IF C<=5 THEN 3670\n160 PRINT \"THE ANTE IS $5.  I WILL DEAL:\"\n170 PRINT\n180 IF S>5 THEN 200\n190 GOSUB 3830\n200 LET P=P+10\n210 LET S=S-5\n220 LET C=C-5\n230 FOR Z=1 TO 10\n240 GOSUB 1740\n250 NEXT Z\n260 PRINT \"YOUR HAND:\"\n270 N=1\n280 GOSUB 1850\n290 N=6\n300 I=2\n310 GOSUB 2170\n320 PRINT\n330 IF I<>6 THEN 470\n340 IF FNA(0)<=7 THEN 370\n350 LET X=11100\n360 GOTO 420\n370 IF FNA(0)<=7 THEN 400\n380 LET X=11110\n390 GOTO 420\n400 IF FNA(0)>=1 THEN 450\n410 X=11111\n420 I=7\n430 Z=23\n440 GOTO 580\n450 Z=1\n460 GOTO 510\n470 IF U>=13 THEN 540\n480 IF FNA(0)>=2 THEN 500\n490 GOTO 420\n500 Z=0\n510 K=0\n520 PRINT \"I CHECK.\"\n530 GOTO 620\n540 IF U<=16 THEN 570\n550 Z=2\n560 IF FNA(0)>=1 THEN 580\n570 Z=35\n580 V=Z+FNA(0)\n590 GOSUB 3480\n600 PRINT \"I'LL OPEN WITH $\"V\n610 K=V\n620 GOSUB 3050\n630 GOSUB 650\n640 GOTO 820\n650 IF I<>3 THEN 760\n660 PRINT\n670 PRINT \"I WIN.\"\n680 C=C+P\n690 PRINT \"NOW I HAVE $\"C\"AND YOU HAVE $\"S\n700 PRINT \"DO YOU WISH TO CONTINUE\";\n710 INPUT H$\n720 IF H$=\"YES\" THEN 120\n730 IF H$=\"NO\" THEN 4100\n740 PRINT \"ANSWER YES OR NO, PLEASE.\"\n750 GOTO 700\n760 IF I<>4 THEN 810\n770 PRINT\n780 PRINT \"YOU WIN.\"\n790 S=S+P\n800 GOTO 690\n810 RETURN\n820 PRINT\n830 PRINT \"NOW WE DRAW -- HOW MANY CARDS DO YOU WANT\";\n840 INPUT T\n850 IF T=0 THEN 980\n860 Z=10\n870 IF T<4 THEN 900\n880 PRINT \"YOU CAN'T DRAW MORE THAN THREE CARDS.\"\n890 GOTO 840\n900 PRINT \"WHAT ARE THEIR NUMBERS:\"\n910 FOR Q=1 TO T\n920 INPUT U\n930 GOSUB 1730\n940 NEXT Q\n950 PRINT \"YOUR NEW HAND:\"\n960 N=1\n970 GOSUB 1850\n980 Z=10+T\n990 FOR U=6 TO 10\n1000 IF INT(X/10^(U-6))<>10*INT(X/10^(U-5)) THEN 1020\n1010 GOSUB 1730\n1020 NEXT U\n1030 PRINT\n1040 PRINT \"I AM TAKING\"Z-10-T\"CARD\";\n1050 IF Z=11+T THEN 1090\n1060 PRINT \"S\"\n1070 PRINT\n1080 GOTO 1100\n1090 PRINT\n1100 N=6\n1110 V=I\n1120 I=1\n1130 GOSUB 2170\n1140 B=U\n1150 M=D\n1160 IF V<>7 THEN 1190\n1170 Z=28\n1180 GOTO 1330\n1190 IF I<>6 THEN 1220\n1200 Z=1\n1210 GOTO 1330\n1220 IF U>=13 THEN 1270\n1230 Z=2\n1240 IF FNA(0)<>6 THEN 1260\n1250 Z=19\n1260 GOTO 1330\n1270 IF U>=16 THEN 1320\n1280 Z=19\n1290 IF FNA(0)<>8 THEN 1310\n1300 Z=11\n1310 GOTO 1330\n1320 Z=2\n1330 K=0\n1340 GOSUB 3050\n1350 IF T<>.5 THEN 1450\n1360 IF V=7 THEN 1400\n1370 IF I<>6 THEN 1400\n1380 PRINT \"I'LL CHECK\"\n1390 GOTO 1460\n1400 V=Z+FNA(0)\n1410 GOSUB 3480\n1420 PRINT \"I'LL BET $\"V\n1430 K=V\n1440 GOSUB 3060\n1450 GOSUB 650\n1460 PRINT\n1470 PRINT \"NOW WE COMPARE HANDS:\"\n1480 J$=H$\n1490 K$=I$\n1500 PRINT \"MY HAND:\"\n1510 N=6\n1520 GOSUB 1850\n1530 N=1\n1540 GOSUB 2170\n1550 PRINT\n1560 PRINT \"YOU HAVE \";\n1570 K=D\n1580 GOSUB 3690\n1590 H$=J$\n1600 I$=K$\n1610 K=M\n1620 PRINT \"AND I HAVE \";\n1630 GOSUB 3690\n1640 IF B>U THEN 670\n1650 IF U>B THEN 780\n1660 IF H$=\"A FLUS\" THEN 1700\n1662 IF FNB(M)<FNB(D) THEN 780\n1664 IF FNB(M)>FNB(D) THEN 670\n1670 PRINT \"THE HAND IS DRAWN.\"\n1680 PRINT \"ALL $\"P\"REMAINS IN THE POT.\"\n1690 GOTO 140\n1700 IF FNB(M)>FNB(D) THEN 670\n1710 IF FNB(D)>FNB(M) THEN 780\n1720 GOTO 1670\n1730 Z=Z+1\n1740 A(Z)=100*INT(4*RND(1))+INT(100*RND(1))\n1750 IF INT(A(Z)/100)>3 THEN 1740\n1760 IF A(Z)-100*INT(A(Z)/100)>12 THEN 1740\n1765 IF Z=1 THEN 1840\n1770 FOR K=1 TO Z-1\n1780 IF A(Z)=A(K) THEN 1740\n1790 NEXT K\n1800 IF Z<=10 THEN 1840\n1810 N=A(U)\n1820 A(U)=A(Z)\n1830 A(Z)=N\n1840 RETURN\n1850 FOR Z=N TO N+4\n1860 PRINT Z\"--  \";\n1870 GOSUB 1950\n1880 PRINT \" OF\";\n1890 GOSUB 2070\n1900 IF Z/2<>INT(Z/2) THEN 1920\n1910 PRINT\n1920 NEXT Z\n1930 PRINT\n1940 RETURN\n1950 K=FNB(A(Z))\n1960 IF K<>9 THEN 1980\n1970 PRINT \"JACK\";\n1980 IF K<>10 THEN 2000\n1990 PRINT \"QUEEN\";\n2000 IF K<>11 THEN 2020\n2010 PRINT \"KING\";\n2020 IF K<>12 THEN 2040\n2030 PRINT \"ACE\";\n2040 IF K>=9 THEN 2060\n2050 PRINT K+2;\n2060 RETURN\n2070 K=INT(A(Z)/100)\n2080 IF K<>0 THEN 2100\n2090 PRINT \" CLUBS\",\n2100 IF K<>1 THEN 2120\n2110 PRINT \" DIAMONDS\",\n2120 IF K<>2 THEN 2140\n2130 PRINT \" HEARTS\",\n2140 IF K<>3 THEN 2160\n2150 PRINT \" SPADES\",\n2160 RETURN\n2170 U=0\n2180 FOR Z=N TO N+4\n2190 B(Z)=FNB(A(Z))\n2200 IF Z=N+4 THEN 2230\n2210 IF INT(A(Z)/100)<>INT(A(Z+1)/100) THEN 2230\n2220 U=U+1\n2230 NEXT Z\n2240 IF U<>4 THEN 2310\n2250 X=11111\n2260 D=A(N)\n2270 H$=\"A FLUS\"\n2280 I$=\"H IN\"\n2290 U=15\n2300 RETURN\n2310 FOR Z=N TO N+3\n2320 FOR K=Z+1 TO N+4\n2330 IF B(Z)<=B(K) THEN 2390\n2340 X=A(Z)\n2350 A(Z)=A(K)\n2360 B(Z)=B(K)\n2370 A(K)=X\n2380 B(K)=A(K)-100*INT(A(K)/100)\n2390 NEXT K\n2400 NEXT Z\n2410 X=0\n2420 FOR Z=N TO N+3\n2430 IF B(Z)<>B(Z+1) THEN 2470\n2440 X=X+11*10^(Z-N)\n2450 D=A(Z)\n2460 GOSUB 2760\n2470 NEXT Z\n2480 IF X<>0 THEN 2620\n2490 IF B(N)+3<>B(N+3) THEN 2520\n2500 X=1111\n2510 U=10\n2520 IF B(N+1)+3<>B(N+4) THEN 2620\n2530 IF U<>10 THEN 2600\n2540 U=14\n2550 H$=\"STRAIG\"\n2560 I$=\"HT\"\n2570 X=11111\n2580 D=A(N+4)\n2590 RETURN\n2600 U=10\n2610 X=11110\n2620 IF U>=10 THEN 2690\n2630 D=A(N+4)\n2640 H$=\"SCHMAL\"\n2650 I$=\"TZ, \"\n2660 U=9\n2670 X=11000\n2680 GOTO 2740\n2690 IF U<>10 THEN 2720\n2700 IF I=1 THEN 2740\n2710 GOTO 2750\n2720 IF U>12 THEN 2750\n2730 IF FNB(D)>6 THEN 2750\n2740 I=6\n2750 RETURN\n2760 IF U>=11 THEN 2810\n2770 U=11\n2780 H$=\"A PAIR\"\n2790 I$=\" OF \"\n2800 RETURN\n2810 IF U<>11 THEN 2910\n2820 IF B(Z)<>B(Z-1) THEN 2870\n2830 H$=\"THREE\"\n2840 I$=\" \"\n2850 U=13\n2860 RETURN\n2870 H$=\"TWO P\"\n2880 I$=\"AIR, \"\n2890 U=12\n2900 RETURN\n2910 IF U>12 THEN 2960\n2920 U=16\n2930 H$=\"FULL H\"\n2940 I$=\"OUSE, \"\n2950 RETURN\n2960 IF B(Z)<>B(Z-1) THEN 3010\n2970 U=17\n2980 H$=\"FOUR\"\n2990 I$=\" \"\n3000 RETURN\n3010 U=16\n3020 H$=\"FULL H\"\n3030 I$=\"OUSE, \"\n3040 RETURN\n3050 G=0\n3060 PRINT:PRINT \"WHAT IS YOUR BET\";\n3070 INPUT T\n3080 IF T-INT(T)=0 THEN 3140\n3090 IF K<>0 THEN 3120\n3100 IF G<>0 THEN 3120\n3110 IF T=.5 THEN 3410\n3120 PRINT \"NO SMALL CHANGE, PLEASE.\"\n3130 GOTO 3060\n3140 IF S-G-T>=0 THEN 3170\n3150 GOSUB 3830\n3160 GOTO 3060\n3170 IF T<>0 THEN 3200\n3180 I=3\n3190 GOTO 3380\n3200 IF G+T>=K THEN 3230\n3210 PRINT \"IF YOU CAN'T SEE MY BET, THEN FOLD.\"\n3220 GOTO 3060\n3230 G=G+T\n3240 IF G=K THEN 3380\n3250 IF Z<>1 THEN 3420\n3260 IF G>5 THEN 3300\n3270 IF Z>=2 THEN 3350\n3280 V=5\n3290 GOTO 3420\n3300 IF Z=1 THEN 3320\n3310 IF T<=25 THEN 3350\n3320 I=4\n3330 PRINT \"I FOLD.\"\n3340 RETURN\n3350 IF Z=2 THEN 3430\n3360 PRINT \"I'LL SEE YOU.\"\n3370 K=G\n3380 S=S-G\n3390 C=C-K\n3400 P=P+G+K\n3410 RETURN\n3420 IF G>3*Z THEN 3350\n3430 V=G-K+FNA(0)\n3440 GOSUB 3480\n3450 PRINT \"I'LL SEE YOU, AND RAISE YOU\"V\n3460 K=G+V\n3470 GOTO 3060\n3480 IF C-G-V>=0 THEN 3660\n3490 IF G<>0 THEN 3520\n3500 V=C\n3510 RETURN\n3520 IF C-G>=0 THEN 3360\n3530 IF (O/2)<>INT(O/2) THEN 3600\n3540 PRINT \"WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50\";\n3550 INPUT J$\n3560 IF LEFT$(J$,1)=\"N\" THEN 3600\n3570 C=C+50\n3580 O=O/2\n3590 RETURN\n3600 IF O/3<>INT(O/3) THEN 3670\n3610 PRINT \"WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50\";\n3620 INPUT J$\n3630 IF LEFT$(J$,1)=\"N\" THEN 3670\n3640 C=C+50\n3650 O=O/3\n3660 RETURN\n3670 PRINT \"I'M BUSTED.  CONGRATULATIONS!\"\n3680 STOP\n3690 PRINT H$;I$;\n3700 IF H$<>\"A FLUS\" THEN 3750\n3710 K=INT(K/100)\n3720 GOSUB 2080\n3730 PRINT\n3740 RETURN\n3750 K=FNB(K)\n3760 GOSUB 1960\n3770 IF H$=\"SCHMAL\" THEN 3790\n3780 IF H$<>\"STRAIG\" THEN 3810\n3790 PRINT \" HIGH\"\n3800 RETURN\n3810 PRINT \"'S\"\n3820 RETURN\n3830 PRINT\n3840 PRINT \"YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.\"\n3850 IF O/2=INT(O/2) THEN 3970\n3860 PRINT \"WOULD YOU LIKE TO SELL YOUR WATCH\";\n3870 INPUT J$\n3880 IF LEFT$(J$,1)=\"N\" THEN 3970\n3890 IF FNA(0)>=7 THEN 3930\n3900 PRINT \"I'LL GIVE YOU $75 FOR IT.\"\n3910 S=S+75\n3920 GOTO 3950\n3930 PRINT \"THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.\"\n3940 S=S+25\n3950 O=O*2\n3960 RETURN\n3970 IF O/3<>INT(O/3) THEN 4090\n3980 PRINT \"WILL YOU PART WITH THAT DIAMOND TIE TACK\":\n3990 INPUT J$\n4000 IF LEFT$(J$,1)=\"N\" THEN 4080\n4010 IF FNA(0)>=6 THEN 4050\n4020 PRINT \"YOU ARE NOW $100 RICHER.\"\n4030 S=S+100\n4040 GOTO 4070\n4050 PRINT \"IT'S PASTE.  $25.\"\n4060 S=S+25\n4070 O=O*3\n4080 RETURN\n4090 PRINT \"YOUR WAD IS SHOT.  SO LONG, SUCKER!\"\n4100 END\n"
  },
  {
    "path": "00_Alternate_Languages/72_Queen/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript queen.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"queen\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/72_Queen/MiniScript/queen.ms",
    "content": "print \" \"*33 + \"QUEEN\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\ngetYesNo = function(prompt)\n\twhile true\n\t\tinp = input(prompt + \"? \").lower + \" \"\n\t\tif inp[0] == \"y\" then return \"yes\"\n\t\tif inp[0] == \"n\" then return \"no\"\n\t\tprint \"Please answer 'yes' or 'no'.\"\n\tend while\nend function\n\nprintDirections = function\n\tprint \"We are going to play a game based on one of the chess\"\n\tprint \"moves.  Our queen will be able to move only to the left \"\n\tprint \"down  or diagonally down and to the left.\"\n\tprint\n\tprint \"The object of the game is to place the queen in the lower\"\n\tprint \"left hand square by alternating moves between you and the\"\n\tprint \"computer.  The first one to place the queen there wins.\"\n\tprint\n\tprint \"You go first and place the queen in any one of the squares\"\n\tprint \"on the top row or right hand column.\"\n\tprint \"That will be your first move.\"\n\tprint \"We alternate moves.\"\n\tprint \"You may forfeit by typing '0' as your move.\"\n\tprint \"Be sure to press the return key after each response.\"\n\tprint\n\tinput \"(Press Return to continue.)\"\n\tprint\nend function\n\nprintCoordinates = function\n\t// Porting note: I cannot imagine what possessed the original author to\n\t// use such a crazy numbering scheme, which is not easy for the human\n\t// player OR the code.  But assumptions about it are scattered throughout\n\t// the whole program, so we're stuck with it.\n\tprint\n\tprint \"  81   71   61   51   41   31   21   11\"\n\tprint \"  92   82   72   62   52   42   32   22\"\n\tprint \" 103   93   83   73   63   53   43   33\"\n\tprint \" 114  104   94   84   74   64   54   44\"\n\tprint \" 125  115  105   95   85   75   65   55\"\n\tprint \" 136  126  116  106   96   86   76   66\"\n\tprint \" 147  137  127  117  107   97   87   77\"\n\tprint \" 158  148  138  128  118  108   98   88\"\n\tprint\nend function\n\ngetStartPos = function\n\twhile true\n\t\tm1 = input(\"Where would you like to start? \").val\n\t\ttens = floor(m1/10)\n\t\tones = m1 % 10\n\t\tif ones == 1 or tens == ones or m1 == 0 then return m1\n\t\tprint \"Please read the directions again.\"\n\t\tprint \"You have begun illegally.\"\n\t\tprint\n\tend while\nend function\n\nisGoodMove = function(ones, tens)\n\tpos = 10 * tens + ones\n\treturn [158, 127, 126, 75, 73].indexOf(pos) != null\nend function\n\ngetRandomMove = function(queenPos)\n\ttens = floor(queenPos/10)\n\tones = queenPos % 10\n\tz = rnd\n\tif z > 0.6 then\n\t\treturn 10 * (tens+1) + ones\n\telse if z > 0.3 then\n\t\treturn 10 * (tens+2) + (ones+1)\n\telse\n\t\treturn 10 * (tens+1) + ones\n\tend if\nend function\n\ngetComputerMove = function(queenPos)\n\ttens = floor(queenPos/10)\n\tones = queenPos % 10\n\tif [41, 44, 73, 75, 126, 127].indexOf(queenPos) != null then return getRandomMove(queenPos)\n\tfor k in range(7, 1)\n\t\tif isGoodMove(ones, tens+k) then return 10 * (tens+k) + ones\t\t// left\n\t\tif isGoodMove(ones+k, tens+k) then return 10 * (tens+k) + (ones+k)\t// down\n\t\tif isGoodMove(ones+k, tens+k*2) then return 10 * (tens+k*2) + (ones+k) // down-left\n\tend for\n\treturn getRandomMove(queenPos)\t\t\nend function\n\ngetHumanMove = function(queenPos)\n\ttens = floor(queenPos/10)\n\tones = queenPos % 10\n\twhile true\n\t\tpos = input(\"What is your move? \").val\n\t\tif pos == 0 then return 0\n\t\tdTens = floor(pos/10) - tens\n\t\tdOnes = pos % 10 - ones\n\t\tok = false\n\t\tif dOnes == 0 and dTens > 0 then ok = true\t// moving left\n\t\tif dOnes == dTens and dOnes > 0 then ok = true\t// moving down\n\t\tif dTens == dOnes*2 and dOnes > 0 then ok = true\t// moving down-left\n\t\tif ok then return pos\n\t\tprint\n\t\tprint \"Y O U   C H E A T . . .  Try again\";\n\tend while\nend function\n\nplayGame = function\n\tqueenPos = getStartPos\n\twhile true\n\t\tif queenPos == 0 then\n\t\t\tprint \"It looks like I have won by forfeit.\"\n\t\t\treturn\n\t\tend if\n\t\t\n\t\t// computer move\n\t\tqueenPos = getComputerMove(queenPos)\n\t\tprint \"Computer moves to square \" + queenPos\n\t\tif queenPos == 158 then\n\t\t\tprint\n\t\t\tprint \"Nice try, but it looks like I have won.\"\n\t\t\treturn\n\t\tend if\n\n\t\t// human move\n\t\tqueenPos = getHumanMove(queenPos)\n\t\tif queenPos == 158 then\n\t\t\tprint\n\t\t\tprint \"C O N G R A T U L A T I O N S . . .\"\n\t\t\tprint\n\t\t\tprint \"You have won--very well played.\"\n\t\t\tprint \"It looks like I have met my match.\"\n\t\t\tprint \"Thanks for playing---I can't win all the time.\"\n\t\t\treturn\n\t\tend if\n\tend while\t\t\nend function\n\n// Main program\nif getYesNo(\"Do you want instructions\") == \"yes\" then printDirections\nwhile true\n\tprintCoordinates\n\tplayGame\n\tprint\n\tif getYesNo(\"Anyone else care to try\") == \"no\" then break\nend while\nprint\nprint \"OK --- Thanks again.\"\n"
  },
  {
    "path": "00_Alternate_Languages/72_Queen/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/72_Queen/queen.bas",
    "content": "1 PRINT TAB(33);\"QUEEN\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n10 DIM S(64)\n11 FOR I=1 TO 64\n12 READ S(I)\n13 NEXT I\n14 DATA  81,  71,  61,  51,  41,  31,  21,  11\n15 DATA  92,  82,  72,  62,  52,  42,  32,  22\n16 DATA 103,  93,  83,  73,  63,  53,  43,  33\n17 DATA 114, 104,  94,  84,  74,  64,  54,  44\n18 DATA 125, 115, 105,  95,  85,  75,  65,  55\n19 DATA 136, 126, 116, 106,  96,  86,  76,  66\n20 DATA 147, 137, 127, 117, 107,  97,  87,  77\n21 DATA 158, 148, 138, 128, 118, 108,  98,  88\n22 INPUT \"DO YOU WANT INSTRUCTIONS\";W$\n23 IF W$=\"NO\" THEN 30\n24 IF W$=\"YES\" THEN 28\n25 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.\"\n26 GOTO 22\n28 GOSUB 5000\n29 GOTO 100\n30 GOSUB 5160\n90 REM     ERROR CHECKS\n100 PRINT \"WHERE WOULD YOU LIKE TO START\";\n110 INPUT M1\n115 IF M1=0 THEN 232\n120 T1=INT(M1/10)\n130 U1=M1-10*T1\n140 IF U1=1 THEN 200\n150 IF U1=T1 THEN 200\n160 PRINT \"PLEASE READ THE DIRECTIONS AGAIN.\"\n170 PRINT \"YOU HAVE BEGUN ILLEGALLY.\"\n175 PRINT\n180 GOTO 100\n200 GOSUB 2000\n210 PRINT \"COMPUTER MOVES TO SQUARE\";M\n215 IF M=158 THEN 3400\n220 PRINT \"WHAT IS YOUR MOVE\";\n230 INPUT M1\n231 IF M1<>0 THEN 239\n232 PRINT\n233 PRINT \"IT LOOKS LIKE I HAVE WON BY FORFEIT.\"\n234 PRINT\n235 GOTO 4000\n239 IF M1<=M THEN 3200\n240 T1=INT(M1/10)\n250 U1=M1-10*T1\n260 P=U1-U\n270 IF P<>0 THEN 300\n280 L=T1-T\n290 IF L<=0 THEN 3200\n295 GOTO 200\n300 IF T1-T <>P THEN 320\n310 GOTO 200\n320 IF T1-T <>2*P THEN 3200\n330 GOTO 200\n1990 REM     LOCATE MOVE FOR COMPUTER\n2000 IF M1=41 THEN 2180\n2010 IF M1=44 THEN 2180\n2020 IF M1=73 THEN 2180\n2030 IF M1=75 THEN 2180\n2040 IF M1=126 THEN 2180\n2050 IF M1=127 THEN 2180\n2060 IF M1=158 THEN 3300\n2065 C=0\n2070 FOR K=7 TO 1 STEP -1\n2080 U=U1\n2090 T=T1+K\n2100 GOSUB 3500\n2105 IF C=1 THEN 2160\n2110 U=U+K\n2120 GOSUB 3500\n2125 IF C=1 THEN 2160\n2130 T=T+K\n2140 GOSUB 3500\n2145 IF C=1 THEN 2160\n2150 NEXT K\n2155 GOTO 2180\n2160 C=0\n2170 RETURN\n2180 GOSUB 3000\n2190 RETURN\n2990 REM     RANDOM MOVE\n3000 Z=RND(1)\n3010 IF Z>.6 THEN 3110\n3020 IF Z>.3 THEN 3070\n3030 U=U1\n3040 T=T1+1\n3050 M=10*T+U\n3060 RETURN\n3070 U=U1+1\n3080 T=T1+2\n3090 M=10*T+U\n3100 RETURN\n3110 U=U1+1\n3120 T=T1+1\n3130 M=10*T+U\n3140 RETURN\n3190 REM     ILLEGAL MOVE MESSAGE\n3200 PRINT\n3210 PRINT \"Y O U   C H E A T . . .  TRY AGAIN\";\n3220 GOTO 230\n3290 REM     PLAYER WINS\n3300 PRINT\n3310 PRINT \"C O N G R A T U L A T I O N S . . .\"\n3320 PRINT\n3330 PRINT \"YOU HAVE WON--VERY WELL PLAYED.\"\n3340 PRINT \"IT LOOKS LIKE I HAVE MET MY MATCH.\"\n3350 PRINT \"THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\"\n3360 PRINT\n3370 GOTO 4000\n3390 REM     COMPUTER WINS\n3400 PRINT\n3410 PRINT \"NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\"\n3420 PRINT \"THANKS FOR PLAYING.\"\n3430 PRINT\n3440 GOTO 4000\n3490 REM     TEST FOR COMPUTER MOVE\n3500 M=10*T+U\n3510 IF M=158 THEN 3570\n3520 IF M=127 THEN 3570\n3530 IF M=126 THEN 3570\n3540 IF M=75 THEN 3570\n3550 IF M=73 THEN 3570\n3560 RETURN\n3570 C=1\n3580 GOTO 3560\n3990 REM     ANOTHER GAME???\n4000 PRINT \"ANYONE ELSE CARE TO TRY\";\n4010 INPUT Q$\n4020 PRINT\n4030 IF Q$=\"YES\" THEN 30\n4040 IF Q$=\"NO\" THEN 4050\n4042 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.\"\n4045 GOTO 4000\n4050 PRINT:PRINT \"OK --- THANKS AGAIN.\"\n4060 STOP\n4990 REM     DIRECTIONS\n5000 PRINT \"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\"\n5010 PRINT \"MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\"\n5020 PRINT \"DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\"\n5030 PRINT\n5040 PRINT \"THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\"\n5050 PRINT \"LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\"\n5060 PRINT \"COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\"\n5070 PRINT\n5080 PRINT \"YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\"\n5090 PRINT \"ON THE TOP ROW OR RIGHT HAND COLUMN.\"\n5100 PRINT \"THAT WILL BE YOUR FIRST MOVE.\"\n5110 PRINT \"WE ALTERNATE MOVES.\"\n5120 PRINT \"YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\"\n5130 PRINT \"BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\"\n5140 PRINT\n5150 PRINT\n5160 PRINT\n5170 FOR A=0 TO 7\n5180 FOR B=1 TO 8\n5185 I=8*A+B\n5190 PRINT S(I);\n5200 NEXT B\n5210 PRINT\n5220 PRINT\n5230 PRINT\n5240 NEXT A\n5250 PRINT\n5260 RETURN\n9999 END\n"
  },
  {
    "path": "00_Alternate_Languages/73_Reverse/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n\tminiscript reverse.ms\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n\tload \"reverse\"\n\trun\n"
  },
  {
    "path": "00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms",
    "content": "num = 9\n\nreverse = function(i)\n\tif i == null then return i\n\tret = []\n\tfor item in i\n\t\tret.insert(0,item)\n\tend for\n\treturn ret\nend function\n\nshowRules = function\n\tprint\n\tprint \"This is the game of 'Reverse'. To win, all you have\"\n\tprint \"to do is arrange a list of numbers (1 through \" + num + \")\"\n\tprint \"in numerical order from left to right. To move, you\"\n\tprint \"tell me how many numbers (counting from the left) to\"\n\tprint \"reverse. For example, if the current list is:\"\n\tprint; print \"2 3 4 5 1 6 7 8 9\"\n\tprint; print \"and you reverse 4, the result will be:\"\n\tprint; print \"5 4 3 2 1 6 7 8 9\"\n\tprint; print \"Now if reverse 5, you win!\"\n\tprint; print \"1 2 3 4 5 6 7 8 9\"\n\tprint\n\tprint \"No doubt you will like this game, but\"\n\tprint \"if you want to quit, reverse 0 (zero).\"\n\tprint\n\treturn\nend function\n\nprintState = function\n\tprint;print digits.join(\" \"); print\nend function\n\nprint \" \" * 32 + \"Reverse\"\nprint \" \" * 15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"Reverse -- a game of skill\"\nprint\n\nans = input(\"Do you want the rules? \") + \" \"\nif ans != null and ans[0].lower == \"y\" then showRules\n\nwhile true\n\tturns = 0\n\tdigits = range(1, num)\n\tdigits.shuffle\n\tprint;print \"Here we go ... the list is:\"\n\twhile true\n\t\tprintState\n\t\tamt = input(\"How many shall I reverse? \").val\n\t\tif amt == null or amt == 0 then break\n\t\t\n\t\tif amt > num then\n\t\t\tprint \"OOPS! Too many! I can reverse at most \" + num\n\t\telse\n\t\t\tturns += 1\n\t\t\tdigits = reverse(digits[:amt]) + digits[amt:]\n\t\tend if\n\t\tif digits == range(1,num) then\n\t\t\tprintState\n\t\t\tprint \"You won it in \" + turns + \" moves!!\"\n\t\t\tbreak\n\t\tend if\n\tend while\n\tprint\n\tans = input(\"Try again (YES or NO)? \") + \" \"\n\tprint\n\tif ans == null or ans[0].lower != \"y\" then break\nend while\nprint \"O.K. Hope you had fun!!\"\n"
  },
  {
    "path": "00_Alternate_Languages/73_Reverse/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/73_Reverse/reverse.bas",
    "content": "10 PRINT TAB(32);\"REVERSE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"REVERSE -- A GAME OF SKILL\": PRINT\n130 DIM A(20)\n140 REM *** N=NUMBER OF NUMBERS\n150 N=9\n160 PRINT \"DO YOU WANT THE RULES\";\n170 INPUT A$\n180 IF A$=\"NO\" THEN 210\n190 GOSUB 710\n200 REM *** MAKE A RANDOM LIST A(1) TO A(N)\n210 A(1)=INT((N-1)*RND(1)+2)\n220 FOR K=2 TO N\n230 A(K)=INT(N*RND(1)+1)\n240 FOR J=1 TO K-1\n250 IF A(K)=A(J) THEN 230\n260 NEXT J:NEXT K\n280 REM *** PRINT ORIGINAL LIST AND START GAME\n290 PRINT: PRINT \"HERE WE GO ... THE LIST IS:\"\n310 T=0\n320 GOSUB 610\n330 PRINT \"HOW MANY SHALL I REVERSE\";\n340 INPUT R\n350 IF R=0 THEN 520\n360 IF R<=N THEN 390\n370 PRINT \"OOPS! TOO MANY! I CAN REVERSE AT MOST\";N:GOTO 330\n390 T=T+1\n400 REM *** REVERSE R NUMBERS AND PRINT NEW LIST\n410 FOR K=1 TO INT(R/2)\n420 Z=A(K)\n430 A(K)=A(R-K+1)\n440 A(R-K+1)=Z\n450 NEXT K\n460 GOSUB 610\n470 REM *** CHECK FOR A WIN\n480 FOR K=1 TO N\n490 IF A(K)<>K THEN 330\n500 NEXT K\n510 PRINT \"YOU WON IT IN\";T;\"MOVES!!!\":PRINT\n520 PRINT\n530 PRINT \"TRY AGAIN (YES OR NO)\";\n540 INPUT A$\n550 IF A$=\"YES\" THEN 210\n560 PRINT: PRINT \"O.K. HOPE YOU HAD FUN!!\":GOTO 999\n600 REM *** SUBROUTINE TO PRINT LIST\n610 PRINT:FOR K=1 TO N:PRINT A(K);:NEXT K\n650 PRINT:PRINT:RETURN\n700 REM *** SUBROUTINE TO PRINT THE RULES\n710 PRINT:PRINT \"THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE\"\n720 PRINT \"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH\";N;\")\"\n730 PRINT \"IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\"\n740 PRINT \"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\"\n750 PRINT \"REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\"\n760 PRINT:PRINT \"2 3 4 5 1 6 7 8 9\"\n770 PRINT:PRINT \"AND YOU REVERSE 4, THE RESULT WILL BE:\"\n780 PRINT:PRINT \"5 4 3 2 1 6 7 8 9\"\n790 PRINT:PRINT \"NOW IF YOU REVERSE 5, YOU WIN!\"\n800 PRINT:PRINT \"1 2 3 4 5 6 7 8 9\":PRINT\n810 PRINT \"NO DOUBT YOU WILL LIKE THIS GAME, BUT\"\n820 PRINT \"IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\":PRINT: RETURN\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of rockscissors.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript rockscissors.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"rockscissors\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/rockscissors.ms",
    "content": "print \" \"*21 + \"Game of Rock, Scissors, Paper\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\nwhile true\n\tnumGames = input(\"How many games? \").val\n\tif 0 < numGames < 11 then break\n\tprint \"Sorry, but we aren't allowed to play that many.\"\nend while\n\ncomputerWins = 0\nplayerWins = 0\nfor game in range(1, numGames)\n\tprint; print \"Game number \" + game\n\tmyChoice = floor(rnd*3 + 1)\n\twhile true\n\t\tprint \"3=Rock...2=Scissors...1=Paper\"\n\t\tplayerChoice = input(\"1...2...3...What's your choice? \").val\n\t\tif [1,2,3].indexOf(playerChoice) != null then break\n\t\tprint \"Invalid.\"\n\tend while\n\tprint \"This is my choice...\"\n\tprint [\"...Paper\", \"...Scissors\", \"...Rock\"][myChoice-1]\n\tdiff = myChoice - playerChoice\n\tif diff == 0 then\n\t\tprint \"Tie game.  No winner.\"\n\telse if diff == 1 or diff == -2 then\n\t\tprint \"Wow!  I win!!!\"\n\t\tcomputerWins += 1\n\telse\n\t\tprint \"You win!!!\"\n\t\tplayerWins += 1\n\tend if\nend for\n\nprint; print \"Here is the final game score:\"\nprint \"I have won \" + computerWins + \" game(s).\"\nprint \"You have won \" + playerWins + \" game(s).\"\nprint \"And \" + (numGames - computerWins - playerWins) + \" game(s) ended in a tie.\"\nprint; print \"Thanks for playing!!\"\n"
  },
  {
    "path": "00_Alternate_Languages/74_Rock_Scissors_Paper/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/74_Rock_Scissors_Paper/bash/rockscissors.sh",
    "content": "#!/bin/bash\n\n#10 PRINT TAB(21);\"GAME OF ROCK, SCISSORS, PAPER\"\n#20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n#25 PRINT:PRINT:PRINT\nprintf \"%*s GAME OF ROCK, SCISSORS, PAPER\\n\" 21\nprintf \"%*s CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\" 15\necho ; echo\n\n#30 INPUT \"HOW MANY GAMES\";Q\n#40 IF Q<11 THEN 60\n#50 PRINT \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\": GOTO 30\nwhile true; do\n\tprintf \"HOW MANY GAMES \"\n\tread NUMBER_OF_GAMES\n\t[ $NUMBER_OF_GAMES -ge 11 ] || break;\n\techo \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\"\ndone\n\nCOMPUTER_WINS=0\nHUMAN_WINS=0\nTIES=0\n\n#60 FOR G=1 TO Q\nfor GAME_NUMBER in $( seq 1 $NUMBER_OF_GAMES )\ndo\n\t#70 PRINT: PRINT \"GAME NUMBER\";G\n\techo\n\tprintf \"GAME NUMBER %s\\n\" $GAME_NUMBER\n\n\t#80 X=INT(RND(1)*3+1)\n\tCOMPUTER_PICK=$((RANDOM%3+1))\n\n\t#90 PRINT \"3=ROCK...2=SCISSORS...1=PAPER\"\n\t#100 INPUT \"1...2...3...WHAT'S YOUR CHOICE\";K\n\t#110 IF (K-1)*(K-2)*(K-3)<>0 THEN PRINT \"INVALID.\": GOTO 90\n\twhile true; do\n\t\techo \"3=ROCK...2=SCISSORS...1=PAPER\"\n\t\tprintf \"1...2...3...WHAT'S YOUR CHOICE \"\n\t\tread HUMAN_PICK\n\t\t[ $(( (HUMAN_PICK-1)*(HUMAN_PICK-2)*(HUMAN_PICK-3) )) -eq 0 ] && break;\n\t\techo \"INVALID.\"\n\tdone\n\n\t\n\t#120 PRINT \"THIS IS MY CHOICE...\"\n\t#130 ON X GOTO 140,150,160\n\t#140 PRINT \"...PAPER\": GOTO 170\n\t#150 PRINT \"...SCISSORS\": GOTO 170\n\t#160 PRINT \"...ROCK\"\n\tprintf \"THIS IS MY CHOICE...\"\n\tif [ $COMPUTER_PICK -eq 1 ]; then\n\t\techo \"...PAPER\"\n\telif [ $COMPUTER_PICK -eq 2 ]; then\n\t\techo \"...SCISSORS\"\n\telse\n\t\techo \"...ROCK\"\n\tfi\n\n\t#170 IF X=K THEN 250\n\t#180 IF X>K THEN 230\n\t#190 IF X=1 THEN 210\n\t#200 PRINT \"YOU WIN!!!\":H=H+1: GOTO 260\n\t#210 IF K<>3 THEN 200\n\t#220 PRINT \"WOW!  I WIN!!!\":C=C+1:GOTO 260\n\t#230 IF K<>1 OR X<>3 THEN 220\n\t#240 GOTO 200\n\t#250 PRINT \"TIE GAME.  NO WINNER.\"\n\t#260 NEXT G\n\tif [ $COMPUTER_PICK -eq $HUMAN_PICK ]; then\n\t\techo \"TIE GAME.  NO WINNER.\"\n\t\t((TIES+=1))\n\t\tcontinue\n\telif ([ $COMPUTER_PICK -gt $HUMAN_PICK ] && ([ $COMPUTER_PICK -ne 3 ] || [ $HUMAN_PICK -ne 1 ])) \\\n\t\t|| ([ $COMPUTER_PICK -eq 1 ] && [ $HUMAN_PICK -eq 3 ]); then\n\t\techo \"WOW!  I WIN!!!\"\n\t\t((COMPUTER_WINS+=1))\n\t\tcontinue\n\telse\n\t\techo \"YOU WIN!!!\"\n\t\t((HUMAN_WINS+=1))\n\t\tcontinue\n\tfi\ndone\n\n\n#270 PRINT: PRINT \"HERE IS THE FINAL GAME SCORE:\"\n#280 PRINT \"I HAVE WON\";C;\"GAME(S).\"\n#290 PRINT \"YOU HAVE WON\";H;\"GAME(S).\"\n#300 PRINT \"AND\";Q-(C+H);\"GAME(S) ENDED IN A TIE.\"\n#310 PRINT: PRINT \"THANKS FOR PLAYING!!\"\necho\necho \"HERE IS THE FINAL GAME SCORE:\"\nprintf \"I HAVE WON %d GAME(S).\\n\" $COMPUTER_WINS\nprintf \"YOU HAVE WON %d GAME(S).\\n\" $HUMAN_WINS\nprintf \"AND %d GAME(S) ENDED IN A TIE.\\n\" $TIES\necho\necho \"THANKS FOR PLAYING!!\"\n\n#320 END\n"
  },
  {
    "path": "00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim",
    "content": "import std/[random,strformat,strutils]\n\ntype\n  symbol = enum\n    PAPER = 1, SCISSORS = 2, ROCK = 3\n\nvar\n  cpuChoice, playerChoice, turns: int\n  cpuWins, playerWins, ties: int = 0\n\nrandomize()\n\n# Function: player makes a choice\nproc choose(): int =\n  echo \"3=ROCK...2=SCISSORS...1=PAPER...WHAT'S YOUR CHOICE?\"\n  result = readLine(stdin).parseInt()\n\n# Function: determine the outcome\nproc outcome(p: symbol, c: symbol): string =\n  if p == c:\n    ties += 1\n    result = \"TIE GAME.  NO WINNER.\"\n  else:\n    const\n      winTable = [\n        PAPER: (ROCK, \"COVERS\"),\n        SCISSORS: (PAPER, \"CUTS\"),\n        ROCK: (SCISSORS, \"CRUSHES\")\n      ]\n    let (winCond, winVerb) = winTable[p]\n    if winCond == c:\n      playerWins += 1\n      result = fmt\"{p} {winVerb} {c}.  YOU WIN.\"\n    else:\n      let (_, winVerb) = winTable[c]\n      cpuWins += 1\n      result = fmt\"{c} {winVerb} {p}.  I WIN.\"\n\n# Start the game\necho spaces(21), \"GAME OF ROCK, SCISSORS, PAPER\"\necho spaces(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\necho \"\\n\"\necho \"HOW MANY GAMES?\"\nturns = readLine(stdin).parseInt()\nwhile turns > 10:\n  echo \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\"\n  turns = readLine(stdin).parseInt()\n\n# Play the game\nfor i in 1..turns:\n  echo \"\"\n  echo \"GAME NUMBER \", i\n  playerChoice = choose()\n  while playerChoice != 1 and playerChoice != 2 and playerChoice != 3:\n    echo \"INVALID\"\n    playerChoice = choose()\n  cpuChoice = rand(1..3) # match against range in symbol\n  echo \"THIS IS MY CHOICE... \", symbol(cpuChoice)\n  echo outcome(symbol(playerChoice), symbol(cpuChoice))\n\n# Results\necho \"\"\necho \"HERE IS THE FINAL GAME SCORE:\"\necho \"I HAVE WON \", cpuWins,\" GAME(S).\"\necho \"YOU HAVE WON \", playerWins,\" GAME(S).\"\necho \"AND \", ties,\" GAME(S) ENDED IN A TIE.\"\necho \"\"\necho \"THANKS FOR PLAYING!!\"\n"
  },
  {
    "path": "00_Alternate_Languages/74_Rock_Scissors_Paper/rockscissors.bas",
    "content": "10 PRINT TAB(21);\"GAME OF ROCK, SCISSORS, PAPER\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n25 PRINT:PRINT:PRINT\n30 INPUT \"HOW MANY GAMES\";Q\n40 IF Q<11 THEN 60\n50 PRINT \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\": GOTO 30\n60 FOR G=1 TO Q\n70 PRINT: PRINT \"GAME NUMBER\";G\n80 X=INT(RND(1)*3+1)\n90 PRINT \"3=ROCK...2=SCISSORS...1=PAPER\"\n100 INPUT \"1...2...3...WHAT'S YOUR CHOICE\";K\n110 IF (K-1)*(K-2)*(K-3)<>0 THEN PRINT \"INVALID.\": GOTO 90\n120 PRINT \"THIS IS MY CHOICE...\"\n130 ON X GOTO 140,150,160\n140 PRINT \"...PAPER\": GOTO 170\n150 PRINT \"...SCISSORS\": GOTO 170\n160 PRINT \"...ROCK\"\n170 IF X=K THEN 250\n180 IF X>K THEN 230\n190 IF X=1 THEN 210\n200 PRINT \"YOU WIN!!!\":H=H+1: GOTO 260\n210 IF K<>3 THEN 200\n220 PRINT \"WOW!  I WIN!!!\":C=C+1:GOTO 260\n230 IF K<>1 OR X<>3 THEN 220\n240 GOTO 200\n250 PRINT \"TIE GAME.  NO WINNER.\"\n260 NEXT G\n270 PRINT: PRINT \"HERE IS THE FINAL GAME SCORE:\"\n280 PRINT \"I HAVE WON\";C;\"GAME(S).\"\n290 PRINT \"YOU HAVE WON\";H;\"GAME(S).\"\n300 PRINT \"AND\";Q-(C+H);\"GAME(S) ENDED IN A TIE.\"\n310 PRINT: PRINT \"THANKS FOR PLAYING!!\"\n320 END\n"
  },
  {
    "path": "00_Alternate_Languages/75_Roulette/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript roulette.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"roulette\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/75_Roulette/MiniScript/roulette.ms",
    "content": "print \" \"*32 + \"Roulette\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\nif version.hostName == \"Mini Micro\" then\n\timport \"dateTime\"\n\tglobals.date = dateTime.str(dateTime.now, \"MMM d, yyyy\")\nelse\n\tglobals.date = input(\"Enter the current date (as in 'Jan 23, 1979') - \")\nend if\n\nyn = input(\"Do you want instructions? \").lower + \" \"\nif yn[0] != \"n\" then\n\tprint\n\tprint \"This is the betting layout\"\n\tprint \"  (*=Red)\"\n\tprint\n\tprint \" 1*    2     3*\"\n\tprint \" 4     5*    6 \"\n\tprint \" 7*    8     9*\"\n\tprint \"10    11    12*\"\n\tprint \"---------------\"\n\tprint \"13    14*   15 \"\n\tprint \"16*   17    18*\"\n\tprint \"19*   20    21*\"\n\tprint \"22    23*   24 \"\n\tprint \"---------------\"\n\tprint \"25*   26    27*\"\n\tprint \"28    29    30*\"\n\tprint \"31    32*   33 \"\n\tprint \"34*   35    36*\"\n\tprint \"---------------\"\n\tprint \"    00    0    \"\n\tprint\n\tinput \"(Press Return at each pause.)\"\n\tprint\n\tprint \"Types of Bets\"\n\tprint\n\tprint \"The numbers 1 to 36 signify a straight bet\"\n\tprint \"on that number.\"\n\tprint \"These pay off 35:1\"\n\tprint\n\tprint \"The 2:1 bets are:\"\n\tprint \" 37) 1-12     40) first column\"\n\tprint \" 38) 13-24    41) second column\"\n\tprint \" 39) 25-36    42) third column\"\n\tprint\n\tprint \"The even money bets are:\"\n\tprint \" 43) 1-18     46) odd\"\n\tprint \" 44) 19-36    47) red\"\n\tprint \" 45) even     48) black\"\n\tprint\n\tprint \" 49)0 and 50)00 pay off 35:1\"\n\tprint \" NOTE: 0 and 00 do not count under any\"\n\tprint \"       bets except their own.\"\n\tinput\n\tprint \"When I ask for each bet, type the number\"\n\tprint \"and the amount, separated by a comma.\"\n\tprint \"For example: to bet $500 on black, type 48,500\"\n\tprint \"when I ask for a bet.\"\n\tprint\n\tprint \"The minimum bet is $5, the maximum is $500.\"\n\tprint\nend if\n\nredNumbers = [1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36]\n\n// function to convert a number 1-38 to a number/description, like \"00\"\n// or \"7 RED\"\nnumDesc = function(number)\n\tif number == 37 then return \"0\"\n\tif number == 38 then return \"00\"\n\ts = str(number)\n\tif redNumbers.indexOf(number) == null then\n\t\treturn s + \" BLACK\"\n\telse\n\t\treturn s + \" RED\"\n\tend if\nend function\n\n// function to calculate the payout factor (positive if player wins,\n// or -1 if player loses) for the given bet and actual spin.\npayoutFactor = function(bet, spin)\n\tif bet <= 36 then\t\t\t// straight bet, pays 35:1\n\t\tif bet == spin then return 35 else return -1\n\telse if bet == 49 then\t\t// 0, pays 35:1\n\t\tif spin == 37 then return 35 else return -1\n\telse if bet == 50 then\t\t// 00, pays 35:1\n\t\tif spin == 38 then return 35 else return -1\n\telse if bet == 37 then\t\t// 1-12, pays 2:1\n\t\tif 1 <= spin <= 12 then return 2 else return -1\n\telse if bet == 38 then\t\t// 13-24, pays 2:1\n\t\tif 13 <= spin <= 24 then return 2 else return -1\n\telse if bet == 39 then\t\t// 25-36, pays 2:1\n\t\tif 25 <= spin <= 36 then return 2 else return -1\n\telse if bet == 40 then\t\t// first column, pays 2:1\n\t\tif spin % 3 == 1 then return 2 else return -1\n\telse if bet == 41 then\t\t// second column, pays 2:1\n\t\tif spin % 3 == 2 then return 2 else return -1\n\telse if bet == 42 then\t\t// third column, pays 2:1\n\t\tif spin % 3 == 0 then return 2 else return -1\n\telse if bet == 43 then\t\t// 1-18, even money\n\t\tif 1 <= spin <= 18 then return 1 else return -1\n\telse if bet == 44 then\t\t// 19-36, even money\n\t\tif 19 <= spin <= 36 then return 1 else return -1\n\telse if bet == 45 then\t\t// even number, even money\n\t\tif spin % 2 == 0 then return 1 else return -1\n\telse if bet == 46 then\t\t// odd number, even money\n\t\tif spin % 2 == 1 then return 1 else return -1\n\telse if bet == 47 then\t\t// red, even money\n\t\tif redNumbers.indexOf(spin) != null then return 1 else return -1\n\telse if bet == 48 then\t\t// black, even money\n\t\tif redNumbers.indexOf(spin) == null then return 1 else return -1\n\tend if\n\tprint \"Invalid bet \" + bet + \" in payoutFactor\"\nend function\n\nplayerCash = 1000\nhouseCash = 100000\nx = [0] * 38\t// (keeps track of how often each number comes up)\nwhile playerCash > 0\n\t// Get the player's bets\n\tnumBets = input(\"How many bets? \").val\n\tif numBets < 1 then continue\n\tbets = []; amounts = []\n\tfor i in range(1, numBets)\n\t\twhile true\n\t\t\ts = input(\"Number \" + i + \"? \").replace(\",\", \" \").replace(\"  \", \" \").split\n\t\t\tif s.len != 2 then continue\n\t\t\tbet = s[0].val; amount = s[1].val\n\t\t\tif bets.indexOf(bet) != null then\n\t\t\t\tprint \"You made that bet once already,dum-dum\"\n\t\t\t\tcontinue\n\t\t\tend if\n\t\t\tif 1 <= bet <= 50 and 5 <= amount <= 500 then\n\t\t\t\tbets.push bet\n\t\t\t\tamounts.push amount\n\t\t\t\tbreak\n\t\t\tend if\n\t\tend while\n\tend for\n\t\n\t// Spin the wheel!\n\tprint \"Spinning\"\n\tprint\n\tprint\n\tspin = floor(38 * rnd + 1)\n\tx[spin] += 1\n\tprint numDesc(spin)\n\tprint\n\t\n\t// Now, pay out the bets\n\tfor i in bets.indexes\n\t\tf = payoutFactor(bets[i], spin)\n\t\tif f > 0 then\n\t\t\tprint \"You win \" + f*amounts[i] + \" on bet \" + i\n\t\telse\n\t\t\tprint \"You lose \" + (-f)*amounts[i] + \" on bet \" + i\n\t\tend if\n\t\tplayerCash += f * amounts[i]\n\t\thouseCash -= f * amounts[i]\t\t\n\tend for\n\tprint\n\tprint \"Totals:      ME          YOU\"\n\tprint \"             \" + (houseCash+\" \"*12)[:12] + playerCash\n\tif playerCash > 0 and houseCash > 0 then\n\t\tyn = input(\"Again? \").lower + \" \"\n\t\tif yn[0] != \"y\" then break\n\tend if\nend while\n\nif houseCash < 1 then\n\tprint \"You broke the house!\"\n\tplayerCash = 101000\nend if\nif playerCash < 1 then\n\tprint \"Oops! You just spent your last dollar!\"\n\tprint \"Thanks for your money.\"\n\tprint \"I'll use it to buy a solid gold roulette wheel\"\n\tprint\nelse\n\tname = input(\"To whom shall I make the check? \")\n\tprint\n\tprint \"-\"*68\n\tprint \" \"*55 + \"Check No. \" + floor(rnd*100)\n\tprint\n\tprint \" \"*(67 - date.len) + date\n\tprint\n\tprint\n\tprint \"Pay to the order of-----\" + name + \"-----$ \" + playerCash\n\tprint\n\tprint\n\tprint \" \"*10 + \"The Memory Bank of New York\"\n\tprint\n\tprint \" \"*35 + \"The Computer\"\n\tprint \" \"*35 + \"----------X-----\"\n\tprint\n\tprint \"-\"*68\n\tprint \"Come back soon!\"\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/75_Roulette/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/75_Roulette/roulette.bas",
    "content": "10 PRINT TAB(32);\"ROULETTE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 PRINT \"ENTER THE CURRENT DATE (AS IN 'JANUARY 23, 1979') -\";\n50 INPUT D$,E$\n1000 REM-ROULETTE\n1010 REM-DAVID JOSLIN\n1020 PRINT \"WELCOME TO THE ROULETTE TABLE\"\n1030 PRINT\n1040 PRINT \"DO YOU WANT INSTRUCTIONS\";\n1050 INPUT Y$\n1060 IF LEFT$(Y$,1)=\"N\" THEN 1550\n1070 PRINT\n1080 PRINT \"THIS IS THE BETTING LAYOUT\"\n1090 PRINT \"  (*=RED)\"\n1100 PRINT\n1110 PRINT \" 1*    2     3*\"\n1120 PRINT \" 4     5*    6 \"\n1130 PRINT \" 7*    8     9*\"\n1140 PRINT \"10    11    12*\"\n1150 PRINT \"---------------\"\n1160 PRINT \"13    14*   15 \"\n1170 PRINT \"16*   17    18*\"\n1180 PRINT \"19*   20    21*\"\n1190 PRINT \"22    23*   24 \"\n1200 PRINT \"---------------\"\n1210 PRINT \"25*   26    27*\"\n1220 PRINT \"28    29    30*\"\n1230 PRINT \"31    32*   33 \"\n1240 PRINT \"34*   35    36*\"\n1250 PRINT \"---------------\"\n1260 PRINT \"    00    0    \"\n1270 PRINT\n1280 PRINT \"TYPES OF BETS\"\n1290 PRINT\n1300 PRINT \"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\"\n1310 PRINT \"ON THAT NUMBER.\"\n1320 PRINT \"THESE PAY OFF 35:1\"\n1330 PRINT\n1340 PRINT \"THE 2:1 BETS ARE:\"\n1350 PRINT \" 37) 1-12     40) FIRST COLUMN\"\n1360 PRINT \" 38) 13-24    41) SECOND COLUMN\"\n1370 PRINT \" 39) 25-36    42) THIRD COLUMN\"\n1380 PRINT\n1390 PRINT \"THE EVEN MONEY BETS ARE:\"\n1400 PRINT \" 43) 1-18     46) ODD\"\n1410 PRINT \" 44) 19-36    47) RED\"\n1420 PRINT \" 45) EVEN     48) BLACK\"\n1430 PRINT\n1440 PRINT \" 49)0 AND 50)00 PAY OFF 35:1\"\n1450 PRINT \" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\"\n1460 PRINT \"       BETS EXCEPT THEIR OWN.\"\n1470 PRINT\n1480 PRINT \"WHEN I ASK FOR EACH BET, TYPE THE NUMBER\"\n1490 PRINT \"AND THE AMOUNT, SEPARATED BY A COMMA.\"\n1500 PRINT \"FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\"\n1510 PRINT \"WHEN I ASK FOR A BET.\"\n1520 PRINT\n1530 PRINT \"THE MINIMUM BET IS $5, THE MAXIMUM IS $500.\"\n1540 PRINT\n1550 REM-PROGRAM BEGINS HERE\n1560 REM-TYPE OF BET(NUMBER) ODDS\n1570 REM  DON'T NEED TO DIMENSION STRINGS\n1580 DIM B(100),C(100),T(100),X(38)\n1590 DIM A(50)\n1600 FOR I=1 TO 38: X(I)=0: NEXT I: REM  MAT X=ZER\n1610 P=1000\n1620 D=100000.\n1630 PRINT \"HOW MANY BETS\";\n1640 INPUT Y\n1650 IF Y<1 OR Y<>INT(Y) THEN 1630\n1660 FOR I=1 TO 50: A(I)=0: NEXT I: REM  MAT A=ZER\n1670 FOR C=1 TO Y\n1680 PRINT \"NUMBER\";C;\n1690 INPUT X,Z\n1700 B(C)=Z\n1710 T(C)=X\n1720 IF X<1 OR X>50 OR X<>INT(X) THEN 1680\n1730 IF Z<1 OR Z<>INT(Z) THEN 1680\n1740 IF Z<5 OR Z>500 THEN 1680\n1750 IF A(X)=0 THEN 1780\n1760 PRINT \"YOU MADE THAT BET ONCE ALREADY,DUM-DUM\"\n1770 GOTO 1680\n1780 A(X)=1\n1790 NEXT C\n1800 PRINT \"SPINNING\"\n1810 PRINT\n1820 PRINT\n1830 S=INT(RND(1)*100)\n1840 IF S=0 OR S>38 THEN 1830\n1850 X(S)=X(S)+1\n1860 IF S<37 THEN 1920\n1870 IF S=37 THEN 1900\n1880 PRINT \"00\"\n1890 GOTO 2020\n1900 PRINT \"0\"\n1910 GOTO 2020\n1920 RESTORE\n1930 FOR I1=1 TO 18\n1940 READ R\n1950 IF R=S THEN 2000\n1960 NEXT I1\n1970 A$=\"BLACK\"\n1980 PRINT S;A$\n1990 GOTO 2020\n2000 A$=\"RED\"\n2010 GOTO 1980\n2020 PRINT\n2030 FOR C=1 TO Y\n2040 IF T(C)<37 THEN 2710\n2050 ON T(C)-36 GOTO 2090,2190,2220,2250,2300,2350,2400,2470,2500\n2060 ON T(C)-45 GOTO 2530,2560,2630\n2070 GOTO 2710\n2080 STOP\n2090 REM  1-12(37) 2:1\n2100 IF S <= 12 THEN 2150\n2110 PRINT \"YOU LOSE\";B(C);\"DOLLARS ON BET\";C\n2120 D=D+B(C)\n2130 P=P-B(C)\n2140 GOTO 2180\n2150 PRINT \"YOU WIN\";B(C)*2;\"DOLLARS ON BET\"C\n2160 D=D-B(C)*2\n2170 P=P+B(C)*2\n2180 GOTO 2810\n2190 REM  13-24(38) 2:1\n2200 IF S>12 AND S<25 THEN 2150\n2210 GOTO 2110\n2220 REM  25-36(39) 2:1\n2230 IF S>24 AND S<37 THEN 2150\n2240 GOTO 2110\n2250 REM  FIRST COLUMN(40) 2:1\n2260 FOR I=1 TO 34 STEP 3\n2270 IF S=I THEN 2150\n2280 NEXT I\n2290 GOTO 2110\n2300 REM  SECOND COLUMN(41) 2:1\n2310 FOR I=2 TO 35 STEP 3\n2320 IF S=I THEN 2150\n2330 NEXT I\n2340 GOTO 2110\n2350 REM  THIRD COLUMN(42) 2:1\n2360 FOR I=3 TO 36 STEP 3\n2370 IF S=I THEN 2150\n2380 NEXT I\n2390 GOTO 2110\n2400 REM  1-18(43) 1:1\n2410 IF S<19 THEN 2430\n2420 GOTO 2110\n2430 PRINT \"YOU WIN\";B(C);\"DOLLARS ON BET\";C\n2440 D=D-B(C)\n2450 P=P+B(C)\n2460 GOTO 2810\n2470 REM  19-36(44) 1:1\n2480 IF S<37 AND S>18 THEN 2430\n2490 GOTO 2110\n2500 REM  EVEN(45) 1:1\n2510 IF S/2=INT(S/2) AND S<37 THEN 2430\n2520 GOTO 2110\n2530 REM  ODD(46) 1:1\n2540 IF S/2<>INT(S/2) AND S<37 THEN 2430\n2550 GOTO 2110\n2560 REM  RED(47) 1:1\n2570 RESTORE\n2580 FOR I=1 TO 18\n2590 READ R\n2600 IF S=R THEN 2430\n2610 NEXT I\n2620 GOTO 2110\n2630 REM  BLACK(48) 1:1\n2640 RESTORE\n2650 FOR I=1 TO 18\n2660 READ R\n2670 IF S=R THEN 2110\n2680 NEXT I\n2690 IF S>36 THEN 2110\n2700 GOTO 2430\n2710 REM--1TO36,0,00(1-36,49,50)35:1\n2720 IF T(C)<49 THEN 2760\n2730 IF T(C)=49 AND S=37 THEN 2780\n2740 IF T(C)=50 AND S=38 THEN 2780\n2750 GOTO 2110\n2760 IF T(C)=S THEN 2780\n2770 GOTO 2110\n2780 PRINT \"YOU WIN\";B(C)*35;\"DOLLARS ON BET\";C\n2790 D=D-B(C)*35\n2800 P=P+B(C)*35\n2810 NEXT C\n2820 PRINT\n2830 PRINT \"TOTALS:\",\"ME\",\"YOU\"\n2840 PRINT \" \",D,P\n2850 IF P>0 THEN 2880\n2860 PRINT \"OOPS! YOU JUST SPENT YOUR LAST DOLLAR!\"\n2870 GOTO 3190\n2880 IF D>0 THEN 2920\n2890 PRINT \"YOU BROKE THE HOUSE!\"\n2900 P=101000.\n2910 GOTO 2960\n2920 PRINT \"AGAIN\";\n2930 INPUT Y$\n2940 IF LEFT$(Y$,1)=\"Y\" THEN 1630\n2950 DATA 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36\n2960 IF P<1 THEN 3190\n2970 PRINT \"TO WHOM SHALL I MAKE THE CHECK\";\n2980 INPUT B$\n2990 PRINT\n3000 FOR I=1 TO 72: PRINT \"-\";: NEXT I: REM PRINT 72 DASHES\n3010 PRINT TAB(50);\"CHECK NO. \";INT(RND(1)*100)\n3020 PRINT\n3030 GOSUB 3230\n3040 PRINT TAB(40);M$\n3050 PRINT\n3060 PRINT\n3070 PRINT \"PAY TO THE ORDER OF-----\";B$;\"-----$ \";\n3080 PRINT P\n3090 PRINT\n3100 PRINT\n3110 PRINT TAB(10),\"THE MEMORY BANK OF NEW YORK\"\n3120 PRINT\n3130 PRINT TAB(40),\"THE COMPUTER\"\n3140 PRINT TAB(40)\"----------X-----\"\n3150 PRINT\n3160 FOR I=1 TO 62: PRINT \"-\";: NEXT I\n3170 PRINT \"COME BACK SOON!\"\n3180 GOTO 3210\n3190 PRINT \"THANKS FOR YOUR MONEY.\"\n3200 PRINT \"I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\"\n3210 PRINT\n3220 GOTO 3420\n3230 REM\n3240 REM     THIS ROUTINE RETURNS THE CURRENT DATE IN M$\n3250 REM     IF YOU HAVE SYSTEM FUNCTIONS TO HANDLE THIS\n3260 REM     THEY CAN BE USED HERE.  HOWEVER IN THIS\n3270 REM     PROGRAM, WE JUST INPUT THE DATE AT THE START\n3280 REM     THE GAME\n3290 REM\n3300 REM     THE DATE IS RETURNED IN VARIABLE M$\n3310 M$=D$+\", \"+E$\n3320 RETURN\n3420 END\n"
  },
  {
    "path": "00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. Try-It! Page:\nGo to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of russianroulette.ms.  Then click the \"Run Script\" button.  Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript russianroulette.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"russianroulette\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/76_Russian_Roulette/MiniScript/russianroulette.ms",
    "content": "print \" \"*28 + \"Russian Roulette\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\nprint \"This is a game of >>>>>>>>>>Russian Roulette.\"\n\nwhile true\n\tprint; print \"Here is a revolver.\"\n\tprint \"Type '1' to spin chamber and pull trigger.\"\n\tprint \"Type '2' to give up.\"\n\tprint \"GO\"\n\n\tn = 0\n\twhile n < 10\n\t\tinp = input(\"? \").val\n\t\tif inp == 2 then\n\t\t\tprint \"     CHICKEN!!!!!\"\n\t\t\tbreak\n\t\telse if rnd > 0.833333 then\n\t\t\tprint \"     BANG!!!!!   You're dead!\"\n\t\t\tprint \"Condolences will be sent to your relatives.\"\n\t\t\tbreak\n\t\telse\n\t\t\tn += 1\n\t\t\tprint \"- CLICK -\"\n\t\t\tprint\n\t\tend if\n\tend while\n\t\n\tif n >= 10 then\n\t\tprint \"You win!!!!!\"\n\t\tprint \"Let someone else blow his brains out.\"\n\telse\n\t\tprint; print; print\n\t\tprint \"...Next victim...\"\n\tend if\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/76_Russian_Roulette/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/76_Russian_Roulette/russianroulette.bas",
    "content": "1 PRINT TAB(28);\"RUSSIAN ROULETTE\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n5 PRINT \"THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\"\n10 PRINT:PRINT \"HERE IS A REVOLVER.\"\n20 PRINT \"TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\"\n22 PRINT \"TYPE '2' TO GIVE UP.\"\n23 PRINT \"GO\";\n25 N=0\n30 INPUT I\n31 IF I<>2 THEN 35\n32 PRINT \"     CHICKEN!!!!!\"\n33 GOTO 72\n35 N=N+1\n40 IF RND(1)>.833333 THEN 70\n45 IF N>10 THEN 80\n50 PRINT \"- CLICK -\"\n60 PRINT: GOTO 30\n70 PRINT \"     BANG!!!!!   YOU'RE DEAD!\"\n71 PRINT \"CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\"\n72 PRINT:PRINT:PRINT\n75 PRINT \"...NEXT VICTIM...\":GOTO 20\n80 PRINT \"YOU WIN!!!!!\"\n85 PRINT \"LET SOMEONE ELSE BLOW HIS BRAINS OUT.\"\n90 GOTO 10\n99 END\n"
  },
  {
    "path": "00_Alternate_Languages/77_Salvo/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript salvo.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"salvo\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/77_Salvo/MiniScript/salvo.ms",
    "content": "print \" \"*33 + \"Salvo\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\nimport \"listUtil\"\n\nShip = {}\nShip.name = \"Ship\"\nShip.positions = null\t\t// list of [x,y] coordinates for this ship\nShip.shots = 1\t\t\t\t// how many shots this ship provides\nShip.hitPoints = 1\t\t\t// how many hits this ship can take before sinking\nShip.make = function(name, shots=1, size=2)\n\tresult = new Ship\n\tresult.name = name\n\tresult.shots = shots\n\tresult.positions = []\n\tresult.hitPoints = size\n\treturn result\nend function\n\nBoard = {}\nBoard.ships = null\t\t\t// list of Ship instances\nBoard.splash = null\t\t\t// 2D array of: none, or turn on which it was hit\nBoard.shipAt = function(xy)\n\tfor ship in self.ships\n\t\tif ship.positions.contains(xy) then return ship\n\tend for\nend function\nBoard.isEmptySpot = function(xy)\n\treturn 0 < xy[0] < 11 and 0 < xy[1] < 11 and self.shipAt(xy) == null\nend function\nBoard.make = function\n\tresult = new Board\n\tresult.ships = []\n\tresult.splash = list.init2d(11, 11)\n\treturn result\nend function\nBoard.totalShots = function\n\tsum = 0\n\tfor ship in self.ships\n\t\tsum += ship.shots\n\tend for\n\treturn sum\nend function\n\ncomputerBoard = Board.make\nplayerBoard = Board.make\n\ndirections = [[-1,-1], [-1,0], [-1,1], [0,-1], [0,1], [1,-1], [1,0], [1,1]]\n\nrandomPosition = function\n\treturn [1 + floor(rnd*10), 1 + floor(rnd*10)]\nend function\n\ninputCoords = function(prompt=\"?\")\n\twhile true\n\t\tinp = input(prompt + \"? \").replace(\",\", \" \").replace(\"  \", \" \").split\n\t\tif inp.len != 2 then\n\t\t\tprint \"Please enter coordinates such as: 5,3\"\n\t\telse\n\t\t\tx = inp[0].val\n\t\t\ty = inp[1].val\n\t\t\tif 0 < x < 11 and 0 < y < 11 then return [x,y]\n\t\t\tprint \"X and Y coordinates must be in the range 1-10.\"\n\t\tend if\n\tend while\nend function\t\t\n\ninBounds = function(pos)\n\treturn 0 < pos[0] < 11 and 0 < pos[1] < 11\nend function\n\nplaceComputerShips = function\n\tplaceOne = function(ship)\n\t\twhile true\n\t\t\tpos = randomPosition\n\t\t\tdir = directions.any\n\t\t\tok = true\n\t\t\tp = pos[:]\n\t\t\tfor i in range(0, ship.hitPoints - 1)\n\t\t\t\tif not computerBoard.isEmptySpot(p) then ok = false\n\t\t\t\tp.add dir\n\t\t\tend for\n\t\t\tif ok then break\n\t\tend while\n\t\tfor i in range(0, ship.hitPoints - 1)\n\t\t\tship.positions.push pos[:]\n\t\t\tpos.add dir\n\t\tend for\n\t\tcomputerBoard.ships.push ship\n\tend function\n\tplaceOne Ship.make(\"Battleship\", 3, 5)\n\tplaceOne Ship.make(\"Cruiser\", 2, 3)\n\tplaceOne Ship.make(\"Destroyer<A>\", 1, 2)\n\tplaceOne Ship.make(\"Destroyer<B>\", 1, 2)\nend function\n\nplacePlayerShips = function\n\tplaceOne = function(ship)\n\t\tprint ship.name\n\t\tplayerBoard.ships.push ship\n\t\t// Note: like the original BASIC program, we do no validation on\n\t\t// the input other than making sure it is in range.  So you can\n\t\t// have a ship scattered all over the map, have ships overlap, etc.\t\t\n\t\tfor i in range(1, ship.hitPoints)\n\t\t\tship.positions.push inputCoords\n\t\tend for\n\tend function\n\tprint \"Enter coordinates for...\"\n\tplaceOne Ship.make(\"Battleship\", 3, 5)\n\tplaceOne Ship.make(\"Cruiser\", 2, 3)\n\tplaceOne Ship.make(\"Destroyer<A>\", 1, 2)\n\tplaceOne Ship.make(\"Destroyer<B>\", 1, 2)\nend function\n\nprintComputerShips = function\n\tfor ship in computerBoard.ships\n\t\tprint ship.name\n\t\tfor pos in ship.positions\n\t\t\tprint \" \" + pos.join(\"  \")\n\t\tend for\n\tend for\nend function\n\ndoPlayerTurn = function(turnNum = 1)\n\tshots = playerBoard.totalShots\n\tprint \"You have \" + shots + \" shot\" + \"s\"*(shots!=1) + \".\"\n\tif shots < 1 then\n\t\tprint \"I have won.\"\n\t\texit\n\tend if\n\thits = []\n\tfor i in range(1, shots)\n\t\twhile true\n\t\t\tpos = inputCoords\n\t\t\tprevHitOnTurn = computerBoard.splash[pos[0]][pos[1]]\n\t\t\tif prevHitOnTurn == null then break\n\t\t\tprint \"You shot there before on turn \" + prevHitOnTurn\n\t\tend while\n\t\tcomputerBoard.splash[pos[0]][pos[1]] = turnNum\n\t\thit = computerBoard.shipAt(pos)\n\t\tif hit then hits.push hit\n\tend for\n\tfor hit in hits\n\t\tprint \"You hit my \" + hit.name + \".\"\n\t\thit.hitPoints -= 1\n\t\tif hit.hitPoints == 0 then\n\t\t\tprint \"...and sank it!\"\t// (not in original BASIC program)\n\t\t\tcomputerBoard.ships.removeVal hit\n\t\tend if\n\tend for\nend function\n\npickShot = function\n\t// Pick a spot for the computer to shoot at.  We'll do this by\n\t// computing a \"neighbor score\" for each spot: the number of\n\t// neighboring spots that (1) we have previously hit, and (2)\n\t// contain an enemy ship.  Then we'll pick randomly from the\n\t// set of spots with the highest neighbor score.\n\tbestScore = 0\n\tspots = []\n\tfor i in range(1,10)\n\t\tfor j in range(1,10)\n\t\t\tpos = [i,j]\n\t\t\tif playerBoard.splash[pos[0]][pos[1]] then continue\n\t\t\tscore = 0\n\t\t\tfor dir in directions\n\t\t\t\tn = pos.plus(dir)\n\t\t\t\tif inBounds(n) and playerBoard.splash[n[0]][n[1]] and playerBoard.shipAt(n) then\n\t\t\t\t\tscore += 1\n\t\t\t\tend if\n\t\t\tend for\n\t\t\tif score > bestScore then\n\t\t\t\tbestScore = score\n\t\t\t\tspots = [pos]\n\t\t\telse if score == bestScore then\n\t\t\t\tspots.push pos\n\t\t\tend if\n\t\tend for\n\tend for\n\treturn spots.any\nend function\n\ndoComputerTurn = function(turnNum = 1)\n\tshots = computerBoard.totalShots\n\tprint \"I have \" + shots + \" shot\" + \"s\"*(shots!=1) + \".\"\n\tif shots < 1 then\n\t\tprint \"You have won.\"\n\t\texit\n\tend if\n\thits = []\n\tfor i in range(1, shots)\n\t\tpos = pickShot\n\t\tplayerBoard.splash[pos[0]][pos[1]] = turnNum\n\t\thit = playerBoard.shipAt(pos)\n\t\tif hit then hits.push hit\n\t\tif seeComputerShots then print \" \" + pos.join(\"  \")\n\tend for\n\tfor hit in hits\n\t\tprint \"I hit your \" + hit.name + \".\"\n\t\thit.hitPoints -= 1\n\t\tif hit.hitPoints == 0 then\n\t\t\tprint \"...and sank it!\"\t// (not in original BASIC program)\n\t\t\tplayerBoard.ships.removeVal hit\n\t\tend if\n\tend for\nend function\n\n// Main Program\n\nplaceComputerShips\nplacePlayerShips\nwhile true\n\tyn = input(\"Do you want to start? \").lower\n\tif yn == \"where are your ships?\" then\n\t\tprintComputerShips\n\telse if yn and (yn[0] == \"y\" or yn[0] == \"n\") then\n\t\tbreak\n\tend if\nend while\nstartWithPlayer = (yn[0] == \"y\")\nwhile true\n\tyn = input(\"Do you want to see my shots? \").lower\n\tif yn and (yn[0] == \"y\" or yn[0] == \"n\") then break\nend while\nseeComputerShots = (yn[0] == \"y\")\n\nturnNumber = 1\nwhile true\n\tprint\n\tprint \"Turn \" + turnNumber\n\tif startWithPlayer then\n\t\tdoPlayerTurn turnNumber\n\t\tdoComputerTurn turnNumber\n\telse\n\t\tdoComputerTurn turnNumber\n\t\tdoPlayerTurn turnNumber\n\tend if\n\tturnNumber += 1\nend while"
  },
  {
    "path": "00_Alternate_Languages/77_Salvo/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/77_Salvo/salvo.bas",
    "content": "1000 PRINT TAB(33);\"SALVO\"\n1010 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n1020 PRINT:PRINT:PRINT\n1030 REM\n1040 DIM A(10,10),B(10,10),C(7),D(7),E(12),F(12),G(12),H(12),K(10,10)\n1050 Z8=0\n1060 FOR W=1 TO 12\n1070 E(W)=-1\n1080 H(W)=-1\n1090 NEXT W\n1100 FOR X=1 TO 10\n1110 FOR Y=1 TO 10\n1120 B(X,Y)=0\n1130 NEXT Y\n1140 NEXT X\n1150 FOR X=1 TO 12\n1160 F(X)=0\n1170 G(X)=0\n1180 NEXT X\n1190 FOR X=1 TO 10\n1200 FOR Y=1 TO 10\n1210 A(X,Y)=0\n1220 NEXT Y\n1230 NEXT X\n1240 FOR K=4 TO 1 STEP -1\n1250 U6=0\n1260 GOSUB 2910\n1270 DEF FNA(K)=(5-K)*3-2*INT(K/4)+SGN(K-1)-1\n1280 DEF FNB(K)=K+INT(K/4)-SGN(K-1)\n1290 IF V+V2+V*V2=0 THEN 1260\n1300 IF Y+V*FNB(K)>10 THEN 1260\n1310 IF Y+V*FNB(K)<1 THEN 1260\n1320 IF X+V2*FNB(K)>10 THEN 1260\n1330 IF X+V2*FNB(K)<1 THEN 1260\n1340 U6=U6+1\n1350 IF U6>25 THEN 1190\n1360 FOR Z=0 TO FNB(K)\n1370 F(Z+FNA(K))=X+V2*Z\n1380 G(Z+FNA(K))=Y+V*Z\n1390 NEXT Z\n1400 U8=FNA(K)\n1405 IF U8>U8+FNB(K) THEN 1460\n1410 FOR Z2= U8 TO U8+FNB(K)\n1415 IF U8<2 THEN 1450\n1420 FOR Z3=1 TO U8-1\n1430 IF SQR((F(Z3)-F(Z2))^2 + (G(Z3)-G(Z2))^2) < 3.59 THEN 1260\n1440 NEXT Z3\n1450 NEXT Z2\n1460 FOR Z=0 TO FNB(K)\n1470 A(F(Z+U8),G(Z+U8))=.5+SGN(K-1)*(K-1.5)\n1480 NEXT Z\n1490 NEXT K\n1500 PRINT \"ENTER COORDINATES FOR...\"\n1510 PRINT \"BATTLESHIP\"\n1520 FOR X=1 TO 5\n1530 INPUT Y,Z\n1540 B(Y,Z)=3\n1550 NEXT X\n1560 PRINT \"CRUISER\"\n1570 FOR X=1 TO 3\n1580 INPUT Y,Z\n1590 B(Y,Z)=2\n1600 NEXT X\n1610 PRINT \"DESTROYER<A>\"\n1620 FOR X=1 TO 2\n1630 INPUT Y,Z\n1640 B(Y,Z)=1\n1650 NEXT X\n1660 PRINT \"DESTROYER<B>\"\n1670 FOR X=1 TO 2\n1680 INPUT Y,Z\n1690 B(Y,Z)=.5\n1700 NEXT X\n1710 PRINT \"DO YOU WANT TO START\";\n1720 INPUT J$\n1730 IF J$<>\"WHERE ARE YOUR SHIPS?\" THEN 1890\n1740 PRINT \"BATTLESHIP\"\n1750 FOR Z=1 TO 5\n1760 PRINT F(Z);G(Z)\n1770 NEXT Z\n1780 PRINT \"CRUISER\"\n1790 PRINT F(6);G(6)\n1800 PRINT F(7);G(7)\n1810 PRINT F(8);G(8)\n1820 PRINT \"DESTROYER<A>\"\n1830 PRINT F(9);G(9)\n1840 PRINT F(10);G(10)\n1850 PRINT \"DESTROYER<B>\"\n1860 PRINT F(11);G(11)\n1870 PRINT F(12);G(12)\n1880 GOTO 1710\n1890 C=0\n1900 PRINT \"DO YOU WANT TO SEE MY SHOTS\";\n1910 INPUT K$\n1920 PRINT\n1930 IF J$<>\"YES\" THEN 2620\n1940 REM*******************START\n1950 IF J$<>\"YES\" THEN 1990\n1960 C=C+1\n1970 PRINT\n1980 PRINT \"TURN\";C\n1990 A=0\n2000 FOR W=.5 TO 3 STEP .5\n2010 FOR X=1 TO 10\n2020 FOR Y=1 TO 10\n2030 IF B(X,Y)=W THEN 2070\n2040 NEXT Y\n2050 NEXT X\n2060 GOTO 2080\n2070 A=A+INT(W+.5)\n2080 NEXT W\n2090 FOR W=1 TO 7\n2100 C(W)=0\n2110 D(W)=0\n2120 F(W)=0\n2130 G(W)=0\n2140 NEXT W\n2150 P3=0\n2160 FOR X=1 TO 10\n2170 FOR Y=1 TO 10\n2180 IF A(X,Y)>10 THEN 2200\n2190 P3=P3+1\n2200 NEXT Y\n2210 NEXT X\n2220 PRINT \"YOU HAVE\";A;\"SHOTS.\"\n2230 IF P3>=A THEN 2260\n2240 PRINT \"YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES.\"\n2250 GOTO 2890\n2260 IF A<>0 THEN 2290\n2270 PRINT \"I HAVE WON.\"\n2280 STOP\n2290 FOR W=1 TO A\n2300 INPUT X,Y\n2310 IF X<>INT(X) THEN 2370\n2320 IF X>10 THEN 2370\n2330 IF X<1 THEN 2370\n2340 IF Y<>INT(Y) THEN 2370\n2350 IF Y>10 THEN 2370\n2360 IF Y>=1 THEN 2390\n2370 PRINT \"ILLEGAL, ENTER AGAIN.\"\n2380 GOTO 2300\n2390 IF A(X,Y)>10 THEN 2440\n2400 C(W)=X\n2410 D(W)=Y\n2420 NEXT W\n2430 GOTO 2460\n2440 PRINT \"YOU SHOT THERE BEFORE ON TURN\";A(X,Y)-10\n2450 GOTO 2300\n2460 FOR W=1 TO A\n2470 IF A(C(W),D(W))=3 THEN 2540\n2480 IF A(C(W),D(W))=2 THEN 2560\n2490 IF A(C(W),D(W))=1 THEN 2580\n2500 IF A(C(W),D(W))=.5 THEN 2600\n2510 A(C(W),D(W))=10+C\n2520 NEXT W\n2530 GOTO 2620\n2540 PRINT \"YOU HIT MY BATTLESHIP.\"\n2550 GOTO 2510\n2560 PRINT \"YOU HIT MY CRUISER.\"\n2570 GOTO 2510\n2580 PRINT \"YOU HIT MY DESTROYER<A>.\"\n2590 GOTO 2510\n2600 PRINT \"YOU HIT MY DESTROYER<B>.\"\n2610 GOTO 2510\n2620 A=0\n2630 IF J$=\"YES\" THEN 2670\n2640 C=C+1\n2650 PRINT\n2660 PRINT \"TURN\";C\n2670 A=0\n2680 FOR W=.5 TO 3 STEP .5\n2690 FOR X=1 TO 10\n2700 FOR Y=1 TO 10\n2710 IF A(X,Y)=W THEN 2750\n2720 NEXT Y\n2730 NEXT X\n2740 GOTO 2760\n2750 A=A+INT(W+.5)\n2760 NEXT W\n2770 P3=0\n2780 FOR X=1 TO 10\n2790 FOR Y=1 TO 10\n2800 IF A(X,Y)>10 THEN 2820\n2810 P3=P3+1\n2820 NEXT Y\n2830 NEXT X\n2840 PRINT \"I HAVE\";A;\"SHOTS.\"\n2850 IF P3>A THEN 2880\n2860 PRINT \"I HAVE MORE SHOTS THAN BLANK SQUARES.\"\n2870 GOTO 2270\n2880 IF A<>0 THEN 2960\n2890 PRINT \"YOU HAVE WON.\"\n2900 STOP\n2910 X=INT(RND(1)*10+1)\n2920 Y=INT(RND(1)*10+1)\n2930 V=INT(3*RND(1)-1)\n2940 V2=INT(3*RND(1)-1)\n2950 RETURN\n2960 FOR W=1 TO 12\n2970 IF H(W)>0 THEN 3800\n2980 NEXT W\n2990 REM*******************RANDOM\n3000 W=0\n3010 R3=0\n3020 GOSUB 2910\n3030 RESTORE\n3040 R2=0\n3050 R3=R3+1\n3060 IF R3>100 THEN 3010\n3070 IF X>10 THEN 3110\n3080 IF X>0 THEN 3120\n3090 X=1+INT(RND(1)*2.5)\n3100 GOTO 3120\n3110 X=10-INT(RND(1)*2.5)\n3120 IF Y>10 THEN 3160\n3130 IF Y>0 THEN 3270\n3140 Y=1+INT(RND(1)*2.5)\n3150 GOTO 3270\n3160 Y=10-INT(RND(1)*2.5)\n3170 GOTO 3270\n3180 F(W)=X\n3190 G(W)=Y\n3200 IF W=A THEN 3380\n3210 IF R2=6 THEN 3030\n3220 READ X1,Y1\n3230 R2=R2+1\n3240 DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1\n3250 X=X+X1\n3260 Y=Y+Y1\n3270 IF X>10 THEN 3210\n3280 IF X<1 THEN 3210\n3290 IF Y>10 THEN 3210\n3300 IF Y<1 THEN 3210\n3310 IF B(X,Y)>10 THEN 3210\n3320 FOR Q9=1 TO W\n3330 IF F(Q9)<>X THEN 3350\n3340 IF G(Q9)=Y THEN 3210\n3350 NEXT Q9\n3360 W=W+1\n3370 GOTO 3180\n3380 IF K$<>\"YES\" THEN 3420\n3390 FOR Z5=1 TO A\n3400 PRINT F(Z5);G(Z5)\n3410 NEXT Z5\n3420 FOR W=1 TO A\n3430 IF B(F(W),G(W))=3 THEN 3500\n3440 IF B(F(W),G(W))=2 THEN 3520\n3450 IF B(F(W),G(W))=1 THEN 3560\n3460 IF B(F(W),G(W))=.5 THEN 3540\n3470 B(F(W),G(W))=10+C\n3480 NEXT W\n3490 GOTO 1950\n3500 PRINT \"I HIT YOUR BATTLESHIP\"\n3510 GOTO 3570\n3520 PRINT \"I HIT YOUR CRUISER\"\n3530 GOTO 3570\n3540 PRINT \"I HIT YOUR DESTROYER<B>\"\n3550 GOTO 3570\n3560 PRINT \"I HIT YOUR DESTROYER<A>\"\n3570 FOR Q=1 TO 12\n3580 IF E(Q)<>-1 THEN 3730\n3590 E(Q)=10+C\n3600 H(Q)=B(F(W),G(W))\n3610 M3=0\n3620 FOR M2=1 TO 12\n3630 IF H(M2)<>H(Q) THEN 3650\n3640 M3=M3+1\n3650 NEXT M2\n3660 IF M3<>INT(H(Q)+.5)+1+INT(INT(H(Q)+.5)/3) THEN 3470\n3670 FOR M2=1 TO 12\n3680 IF H(M2)<>H(Q) THEN 3710\n3690 E(M2)=-1\n3700 H(M2)=-1\n3710 NEXT M2\n3720 GOTO 3470\n3730 NEXT Q\n3740 PRINT \"PROGRAM ABORT:\"\n3750 FOR Q=1 TO 12\n3760 PRINT \"E(\";Q;\") =\";E(Q)\n3770 PRINT \"H(\";Q;\") =\";H(Q)\n3780 NEXT Q\n3790 STOP\n3800 REM************************USINGEARRAY\n3810 FOR R=1 TO 10\n3820 FOR S=1 TO 10\n3830 K(R,S)=0\n3840 NEXT S\n3850 NEXT R\n3860 FOR U=1 TO 12\n3870 IF E(U)<10 THEN 4020\n3880 FOR R=1 TO 10\n3890 FOR S=1 TO 10\n3900 IF B(R,S)<10 THEN 3930\n3910 K(R,S)=-10000000\n3920 GOTO 4000\n3930 FOR M=SGN(1-R) TO SGN(10-R)\n3940 FOR N=SGN(1-S) TO SGN(10-S)\n3950 IF N+M+N*M=0 THEN 3980\n3960 IF B(R+M,S+N)<>E(U) THEN 3980\n3970 K(R,S)=K(R,S)+E(U)-S*INT(H(U)+.5)\n3980 NEXT N\n3990 NEXT M\n4000 NEXT S\n4010 NEXT R\n4020 NEXT U\n4030 FOR R=1 TO A\n4040 F(R)=R\n4050 G(R)=R\n4060 NEXT R\n4070 FOR R=1 TO 10\n4080 FOR S=1 TO 10\n4090 Q9=1\n4100 FOR M=1 TO A\n4110 IF K(F(M),G(M))>=K(F(Q9),G(Q9)) THEN 4130\n4120 Q9=M\n4130 NEXT M\n4131 IF R>A THEN 4140\n4132 IF R=S THEN 4210\n4140 IF K(R,S)<K(F(Q9),G(Q9)) THEN 4210\n4150 FOR M=1 TO A\n4160 IF F(M)<>R THEN 4190\n4170 IF G(M)=S THEN 4210\n4180 NEXT M\n4190 F(Q9)=R\n4200 G(Q9)=S\n4210 NEXT S\n4220 NEXT R\n4230 GOTO 3380\n4240 END\n"
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/C++/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [C++17](https://en.wikipedia.org/wiki/C%2B%2B17)"
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/C++/sinewave.cpp",
    "content": "#include <iostream> // std::cout, std::endl\n#include <string>\t// std::string(size_t n, char c)\n#include <cmath>\t// std::sin(double x)\n\nint main()\n{\n\tstd::cout << std::string(30, ' ') << \"SINE WAVE\" << std::endl;\n\tstd::cout << std::string(15, ' ') << \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\" << std::endl;\n\tstd::cout << std::string(5, '\\n');\n\n\tbool b = true;\n\n\tfor (double t = 0.0; t <= 40.0; t += 0.25)\n\t{\n\t\tint a = int(26 + 25 * std::sin(t));\n\t\tstd::cout << std::string(a, ' ') << (b ? \"CREATIVE\" : \"COMPUTING\") << std::endl;\n\t\tb = !b;\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript sinewave.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"sinewave\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms",
    "content": "print \" \"*30 + \"SINE WAVE\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print; print; print\n// Remarkable program by David Ahl, ported\n// from BASIC to MiniScript by Joe Strout\n\nB = 0\n// start long loop\nfor t in range(0, 40, 0.25)\n\tA = floor(26 + 25*sin(t))\n\tprint \" \"*A, \"\"\n\tif not B then print \"CREATIVE\" else print \"COMPUTING\"\n\tB = not B\n\twait 0.01\nend for\n"
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/pascal/sinewave.pas",
    "content": "program sinewave;\n\nprocedure tabWriteLn(text: string; indent: integer);\nbegin\n  Writeln(text:length(text)+indent);\nend;\n\nvar\n  a, t, b: integer;\nbegin\n  tabWriteLn('SINE WAVE', 30);\n  tabWriteLn('CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY', 15);\n  Writeln();\n  Writeln();\n  Writeln();\n  Writeln();\n  Writeln();\n  // REMARKABLE PROGRAM BY DAVID AHL\n  b := 0;\n  // START LONG LOOP\n  for t := 0 to 40*4 do\n  begin\n    a := Trunc(26+25*Sin(t/4));\n    if (b = 0) then\n    begin\n      tabWriteLn('CREATIVE', a);\n      b := 1;\n    end\n    else\n    begin\n      tabWriteLn('COMPUTING', a);\n      b := 0;\n    end;\n  end;\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/78_Sine_Wave/sinewave.bas",
    "content": "10 PRINT TAB(30);\"SINE WAVE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT: PRINT: PRINT\n40 REMARKABLE PROGRAM BY DAVID AHL\n50 B=0\n100 REM  START LONG LOOP\n110 FOR T=0 TO 40 STEP .25\n120 A=INT(26+25*SIN(T))\n130 PRINT TAB(A);\n140 IF B=1 THEN 180\n150 PRINT \"CREATIVE\"\n160 B=1\n170 GOTO 200\n180 PRINT \"COMPUTING\"\n190 B=0\n200 NEXT T\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/79_Slalom/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript slalom.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"slalom\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/79_Slalom/MiniScript/slalom.ms",
    "content": "print \" \"*33 + \"Slalom\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\ngateSpeeds = [14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20,\n\t\t 18,26,25,33,31,22]\n\nmedals = {}\nmedals.gold = 0\nmedals.silver = 0\nmedals.bronze = 0\n\nwhile true\n\tqtyGates = input(\"How many gates does this course have (1 to 25)? \").val\n\tif qtyGates > 25 then\n\t\tprint \"25 is the limit.\"\n\t\tqtyGates = 25\n\tend if\n\tif qtyGates >= 1 then break\n\tprint \"Try again,\"\nend while\n\nprint \"Type \"\"ins\"\" for instructions\"\nprint \"Type \"\"max\"\" for approximate maximum speeds\"\nprint \"Type \"\"run\"\" for the beginning of the race\"\nwhile true\n\tcmd = input(\"Command--\").lower\n\tif cmd == \"ins\" then\n\t\tprint\n\t\tprint \"*** Slalom: This is the 1976 Winter Olympic Giant Slalom.  You are\"\n\t\tprint \"            the American team's only hope of a gold medal.\"\n\t\tprint\n\t\tprint \"     0 -- type this if you want to see how long you've taken.\"\n\t\tprint \"     1 -- type this if you want to speed up a lot.\"\n\t\tprint \"     2 -- type this if you want to speed up a little.\"\n\t\tprint \"     3 -- type this if you want to speed up a teensy.\"\n\t\tprint \"     4 -- type this if you want to keep going the same speed.\"\n\t\tprint \"     5 -- type this if you want to check a teensy.\"\n\t\tprint \"     6 -- type this if you want to check a little.\"\n\t\tprint \"     7 -- type this if you want to check a lot.\"\n\t\tprint \"     8 -- type this if you want to cheat and try to skip a gate.\"\n\t\tprint\n\t\tprint \" The place to use these options is when the computer asks:\"\n\t\tprint\n\t\tprint \"Option?\"\n\t\tprint\n\t\tprint \"                Good luck!\"\n\t\tprint\n\telse if cmd == \"max\" then\n\t\tprint \"GATE  MAX\"\n\t\tprint \" #   M.P.H.\"\n\t\tprint \"-----------\"\n\t\tfor i in range(1, qtyGates)\n\t\t\tprint \" \" + i + \" \"*(i<10) + \"   \" + gateSpeeds[i-1]\n\t\tend for\n\telse if cmd == \"run\" then\n\t\tbreak\n\tend if\nend while\n\nwhile true\n\tskill = input(\"Rate yourself as a skier, (1=worst, 3=best)? \").val\n\tif 1 <= skill <= 3 then break\n\tprint \"The bounds are 1-3\"\nend while\n\ndoOneRace = function\n\tprint \"The starter counts down...5...4...3...2...1..GO!\"\n\ttime = 0\n\tspeed = floor(rnd * 9 + 9)\n\tprint\n\tprint \"You're off!\"\n\tgate = 0\n\twhile gate+1 <= qtyGates\n\t\tgate += 1\n\t\tgateSpeed = gateSpeeds[(gate-1) % gateSpeeds.len]\n\t\tprint\n\t\tprint \"Here comes gate #\" + gate + \":\"\n\t\tprint speed + \" M.P.H.\"\n\t\tprevSpeed = speed\n\t\twhile true\n\t\t\topt = input(\"Option? \").val\n\t\t\tif opt == 0 then\n\t\t\t\tprint \"You've taken \" + time + \" seconds.\"\n\t\t\telse if opt < 1 or opt > 8 then\n\t\t\t\tprint \"What?\"\n\t\t\telse\n\t\t\t\tbreak\n\t\t\tend if\n\t\tend while\n\t\tif opt == 1 then\n\t\t\tspeed += floor(rnd*(10-5)+5)\n\t\telse if opt == 2 then\n\t\t\tspeed += floor(rnd*(5-3)+3)\n\t\telse if opt == 3 then\n\t\t\tspeed += floor(rnd*(4-1)+1)\n\t\telse if opt == 4 then\n\t\t\t// (no change)\n\t\telse if opt == 5 then\n\t\t\tspeed -= floor(rnd*(4-1)+1)\n\t\telse if opt == 6 then\n\t\t\tspeed -= floor(rnd*(5-3)+3)\n\t\telse if opt == 7 then\n\t\t\tspeed -= floor(rnd*(10-5)+5)\n\t\telse if opt == 8 then\n\t\t\tprint \"***CHEAT\"\n\t\t\tif rnd < 0.7 then\n\t\t\t\tprint \"An official caught you!\"\n\t\t\t\tprint \"You took \" + round(time+rnd, 3) + \" seconds.\"\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tprint \"You made it!\" + char(7)\n\t\t\t\ttime += 1.5\n\t\t\t\tcontinue\n\t\t\tend if\n\t\tend if\n\t\tprint speed + \" M.P.H.\"\n\t\tif speed > gateSpeed then\n\t\t\tif rnd < (speed - gateSpeed)*0.1 + 0.2 then\n\t\t\t\tmsg = \"You went over the maximum speed and \"\n\t\t\t\tif rnd < 0.5 then msg += \"snagged a flag!\" else msg += \"wiped out!\"\n\t\t\t\tprint msg\n\t\t\t\tprint \"You took \" + round(time+rnd, 3) + \" seconds.\"\n\t\t\telse\n\t\t\t\tprint \"You went over the maximum speed and made it!\"\n\t\t\tend if\n\t\telse if speed > gateSpeed - 1 then\n\t\t\tprint \"Close one!\"\n\t\tend if\n\t\tif speed < 7 then\n\t\t\tprint \"Let's be realistic, OK?  Let's go back and try again...\"\n\t\t\tspeed = prevSpeed\n\t\t\tgate -= 1\n\t\t\tcontinue\n\t\tend if\n\t\ttime += gateSpeed - speed + 1\n\t\tif speed > gateSpeed then time += 0.5\n\tend while\n\n\tprint\n\tprint \"You took \" + round(time+rnd, 3) + \" seconds.\"\n\tavg = time / qtyGates\n\tif avg < 1.5 - (skill * 0.1) then\n\t\tprint \"You won a gold medal!\"\n\t\tmedals.gold += 1\t\n\telse if avg < 2.9 - (skill * 0.1) then\n\t\tprint \"You won a silver medal\"\n\t\tmedals.silver += 1\t\n\telse if avg < 4.4 - (skill * 0.01) then\n\t\tprint \"You won a bronze medal\"\n\t\tmedals.bronze += 1\t\n\tend if\nend function\n\nwhile true\n\tdoOneRace\n\twhile true\n\t\tyesno = input(\"Do you want to race again? \").lower + \" \"\n\t\tif yesno[0] == \"y\" or yesno[0] == \"n\" then break\n\t\tprint \"Please type 'yes' or 'no'\"\n\tend while\n\tif yesno[0] == \"n\" then break\n\tprint\nend while\n\nprint\nprint \"Thanks for the race\"\nif medals.gold then print \"Gold medals: \" + medals.gold\nif medals.silver then print \"Silver medals: \" + medals.silver\nif medals.bronze then print \"Bronze medals: \" + medals.bronze\n"
  },
  {
    "path": "00_Alternate_Languages/79_Slalom/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/79_Slalom/slalom.bas",
    "content": "10 PRINT TAB(33);\"SLALOM\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n310 PRINT \"HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)\";\n320 INPUT V\n330 IF V>25 THEN 360\n340 IF V<1 THEN 390\n350 GOTO 1440\n360 PRINT \"25 IS THE LIMIT.\"\n370 LET V=25\n380 GOTO 1440\n390 PRINT \"TRY AGAIN,\"\n400 GOTO 310\n410 PRINT \"RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)\";\n420 INPUT A\n430 IF A<1 THEN 460\n440 IF A>3 THEN 460\n450 GOTO 480\n460 PRINT \"THE BOUNDS ARE 1-3\"\n470 GOTO 410\n480 PRINT\"THE STARTER COUNTS DOWN...5...4...3...2...1...GO!\";\n490 REM\n500 LET T=0\n510 LET S=INT(RND(1)*(18-9)+9)\n520 PRINT\n525 PRINT \"YOU'RE OFF!\"\n530 FOR O=1 TO V\n540    READ Q\n550    PRINT\n555    PRINT \"HERE COMES GATE #\";STR$(O);\":\"\n560    PRINT S;\"M.P.H.\"\n570    LET S1=S\n580    PRINT \"OPTION\";\n590    INPUT O1\n600    IF O1=0 THEN 970\n610   IF O1>8 THEN 1420\n620    IF O1<1 THEN 1420\n630    GOSUB 990\n640    IF S<7 THEN 1390\n650    LET T=T+(Q-S+1)\n660    IF S>Q THEN 1630\n670 NEXT O\n680 PRINT:PRINT \"YOU TOOK\";(T+RND(1));\"SECONDS.\"\n690 LET M=T\n700 LET M=M/V\n710 IF M<1.5-(A*.1) THEN 1650\n720 IF M<2.9-(A*.1) THEN 1680\n730 IF M<4.4-(A*.01) THEN 1710\n740 PRINT:PRINT \"DO YOU WANT TO RACE AGAIN\";\n750 INPUT B$\n760 REM\n770 IF B$=\"NO\" THEN 1740\n780 IF B$=\"YES\" THEN 480\n790 PRINT \"PLEASE TYPE 'YES' OR 'NO'\"\n800 GOTO 740\n810 STOP\n820 PRINT\n825 PRINT \"*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM.  YOU ARE\"\n830 PRINT \"            THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL.\"\n840 PRINT\n845 PRINT \"     0 -- TYPE THIS IF YOU WANT TO SEE HOW LONG YOU'VE TAKEN.\"\n850 PRINT \"     1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT.\"\n860 PRINT \"     2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE.\"\n870 PRINT \"     3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY.\"\n880 PRINT \"     4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED.\"\n890 PRINT \"     5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY.\"\n900 PRINT \"     6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE.\"\n910 PRINT \"     7 -- TYPE THIS IF YOU WANT TO CHECK A LOT.\"\n920 PRINT \"     8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE.\"\n930 PRINT\n935 PRINT \" THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:\"\n940 PRINT\n945 PRINT \"OPTION?\"\n950 PRINT\n955 PRINT \"                GOOD LUCK!\"\n957 PRINT\n960 GOTO 1470\n970 PRINT \"YOU'VE TAKEN\";(T+RND(1));\"SECONDS.\"\n980 GOTO 580\n990 ON O1 GOTO 1130,1010,1170,1080,1190,1100,1150,1210\n1000 STOP\n1010 LET S=S+INT(RND(1)*(5-3)+3)\n1020 PRINT S;\"M.P.H.\"\n1030 IF S>Q THEN 1290\n1040 IF S>Q-1 THEN 1060\n1050 RETURN\n1060 PRINT \"CLOSE ONE!\"\n1070 RETURN\n1080 PRINT S;\"M.P.H.\"\n1090 GOTO 1030\n1100 LET S=S-INT(RND(1)*(5-3)+3)\n1110 PRINT S;\"M.P.H.\"\n1120 GOTO 1030\n1130 LET S=S+INT(RND(1)*(10-5)+5)\n1140 GOTO 1080\n1150 LET S=S-INT(RND(1)*(10-5)+5)\n1160 GOTO 1110\n1170 LET S=S+INT(RND(1)*(4-1)+1)\n1180 GOTO 1110\n1190 LET S=S-INT(RND(1)*(4-1)+1)\n1200 GOTO 1110\n1210 PRINT \"***CHEAT\"\n1220 IF RND(1)<.7 THEN 1260\n1230 PRINT \"YOU MADE IT!\u0007\"\n1240 LET T=T+1.5\n1250 RETURN\n1260 PRINT \"AN OFFICIAL CAUGHT YOU!\"\n1270 PRINT \"YOU TOOK\";(T+RND(1));\"SECONDS.\"\n1280 GOTO 740\n1290 IF RND(1)<((S-Q)*.1)+.2 THEN 1320\n1300 PRINT \"YOU WENT OVER THE NAXIMUM SPEED AND MADE IT!\"\n1310 RETURN\n1320 PRINT \"YOU WENT OVER THE MAXIMUM SPEED AND \";\n1330 IF RND(1)<.5 THEN 1370\n1340 PRINT \"WIPED OUT!\"\n1350 PRINT \"YOU TOOK\";(T+RND(1));\"SECONDS\"\n1360 GOTO 740\n1370 PRINT \"SNAGGED A FLAG!\"\n1380 GOTO 1350\n1390 PRINT \"LET'S BE REALISTIC, OK?  LET'S GO BACK AND TRY AGAIN...\"\n1400 LET S=S1\n1410 GOTO 550\n1420 PRINT \"WHAT?\"\n1430 GOTO 580\n1440 PRINT\n1445 PRINT \"TYPE \";CHR$(34);\"INS\";CHR$(34);\" FOR INSTRUCTIONS\"\n1450 PRINT \"TYPE \";CHR$(34);\"MAX\";CHR$(34);\" FOR APPROXIMATE MAXIMUM SPEEDS\"\n1460 PRINT \"TYPE \";CHR$(34);\"RUN\";CHR$(34);\" FOR THE BEGINNING OF THE RACE\"\n1470 PRINT \"COMMAND--\";\n1480 INPUT A$\n1490 REM\n1500 IF A$=\"INS\" THEN 820\n1510 IF A$=\"MAX\" THEN 1550\n1520 IF A$=\"RUN\" THEN 410\n1530 PRINT CHR$(34);A$;CHR$(34);\" IS AN ILLEGAL COMMAND--RETRY\";\n1540 GOTO 1480\n1550 PRINT \"GATE MAX\"\n1560 PRINT \" #  M.P.H.\"\n1570 PRINT\"----------\"\n1580 FOR B=1 TO V\n1590    READ Q\n1600    PRINT B;\"  \";Q\n1610 NEXT B\n1620 GOTO 1470\n1630 LET T=T+.5\n1640 GOTO 670\n1650 PRINT \"YOU WON A GOLD MEDAL!\"\n1660 LET G(1)=G(1)+1\n1670 GOTO 1730\n1680 PRINT \"YOU WON A SILVER MEDAL\"\n1690 LET S(1)=S(1)+1\n1700 GOTO 1730\n1710 PRINT \"YOU WON A BRONZE MEDAL\"\n1720 LET B(1)=B(1)+1\n1730 GOTO 740\n1740 PRINT \"THANKS FOR THE RACE\"\n1750 IF G(1)<1 THEN 1770\n1760 PRINT \"GOLD MEDALS:\";G(1)\n1770 IF S(1)<1 THEN 1790\n1780 PRINT \"SILVER MEDALS:\";S(1)\n1790 IF B(1)<1 THEN 1830\n1800 PRINT \"BRONZE MEDALS:\";B(1)\n1810 DATA 14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20\n1820 DATA 18,26,25,33,31,22\n1830 END\n"
  },
  {
    "path": "00_Alternate_Languages/80_Slots/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript slots.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"slots\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/80_Slots/MiniScript/slots.ms",
    "content": "print \" \"*30 + \"Slots\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\n// PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973\n// IT SIMULATES THE SLOT MACHINE.\n// (Ported to MiniScript by Joe Strout on Oct 04, 2023)\n\nprint \"You are in the H&M casino,in front of one of our\"\nprint \"one-arm bandits. Bet from $1 to $100.\"\nprint \"To pull the arm, punch the return key after making your bet.\"\n\nsymbols = [\"BAR\", \"BELL\", \"ORANGE\", \"LEMON\", \"PLUM\", \"CHERRY\"]\n\n\nwinTriple = function(symbol, bet)\n\tif symbol == \"BAR\" then\n\t\tprint \"***JACKPOT***\"\n\t\tglobals.profit += 101 * bet\n\telse\n\t\tprint \"**TOP DOLLAR**\"\n\t\tglobals.profit += 11 * bet\n\tend if\n\tprint \"You won!\"\nend function\n\nwinDouble = function(symbol, bet)\n\tif symbol == \"BAR\" then\n\t\tprint \"*DOUBLE BAR*\"\n\t\tglobals.profit += 6 * bet\n\telse\n\t\tprint \"Double!\"\n\t\tglobals.profit += 3 * bet\n\tend if\n\tprint \"You won!\"\nend function\n\nlose = function(bet)\n\tprint \"You lost.\"\n\tglobals.profit -= bet\nend function\n\ncalcWinLoss = function(spun, bet)\n\tif spun[0] == spun[1] then\n\t\tif spun[0] == spun[2] then\n\t\t\twinTriple spun[0], bet\n\t\telse\n\t\t\twinDouble spun[0], bet\n\t\tend if\n\telse if spun[0] == spun[2] then\n\t\twinDouble spun[0], bet\n\telse if spun[1] == spun[2] then\n\t\twinDouble spun[1], bet\n\telse\n\t\tlose bet\n\tend if\nend function\n\nringBells = function(qty=5)\n\t// I believe all the obnoxious beeping was to slow down the game\n\t// and build suspense as each \"wheel\" appears.  Our version:\n\twait 0.1\n\tfor i in range(1, qty)\n\t\tprint char(7), \"\"\n\t\twait 0.05\n\tend for\nend function\n\n// Main program\nprofit = 0\nwhile true\n\tprint\n\t\n\t// Get bet\n\twhile true\n\t\tbet = input(\"Your bet? \").val\n\t\tif 1 <= bet <= 100 then break\n\t\tif bet < 1 then print \"Minimum bet is $1\" else print \"House limits are $100\"\n\tend while\n\t\n\t// Spin 3 wheels (randomly picking a symbol for each one)\n\tspun = []\n\tspun.push symbols[rnd * symbols.len]\n\tspun.push symbols[rnd * symbols.len]\n\tspun.push symbols[rnd * symbols.len]\n\tprint\n\tringBells 10; print spun[0], \" \"\n\tringBells 5;  print spun[1], \" \"\n\tringBells 5;  print spun[2]\n\tprint\n\t\n\t// Calculate and display win/loss\n\twait 0.5\n\tcalcWinLoss spun, bet\n\t\n\t// Show new state, and maybe play again\n\tprint \"Your standings are $ \" + profit\t\n\tyn = input(\"Again? \").lower + \" \"\n\tif yn[0] != \"y\" then break\nend while\n\nif profit == 0 then\n\tprint \"Hey, you broke even.\"\nelse if profit > 0 then\n\tprint \"Collect your winnings from the H&M cashier.\"\nelse\n\tprint \"Pay up!  Please leave your money on the terminal.\"\nend if\n"
  },
  {
    "path": "00_Alternate_Languages/80_Slots/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/80_Slots/slots.bas",
    "content": "10 PRINT TAB(30);\"SLOTS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 REM PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973\n110 REM IT SIMULATES THE SLOT MACHINE.\n120 PRINT \"YOU ARE IN THE H&M CASINO,IN FRONT OF ONE OF OUR\"\n130 PRINT \"ONE-ARM BANDITS. BET FROM $1 TO $100.\"\n140 PRINT \"TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET.\"\n150 LET P=0\n160 PRINT: PRINT\"YOUR BET\";\n170 INPUT M\n180 IF M>100 THEN 860\n190 IF M<1 THEN 880\n200 M=INT(M)\n210 GOSUB 1270\n220 PRINT\n230 LET X=INT(6*RND(1)+1)\n240 LET Y=INT(6*RND(1)+1)\n250 LET Z=INT(6*RND(1)+1)\n260 PRINT\n270 IF X=1 THEN 910\n280 IF X=2 THEN 930\n290 IF X=3 THEN 950\n300 IF X=4 THEN 970\n310 IF X=5 THEN 990\n320 IF X=6 THEN 1010\n330 IF Y=1 THEN 1030\n340 IF Y=2 THEN 1050\n350 IF Y=3 THEN 1070\n360 IF Y=4 THEN 1090\n370 IF Y=5 THEN 1110\n380 IF Y=6 THEN 1130\n390 IF Z=1 THEN 1150\n400 IF Z=2 THEN 1170\n410 IF Z=3 THEN 1190\n420 IF Z=4 THEN 1210\n430 IF Z=5 THEN 1230\n440 IF Z=6 THEN 1250\n450 IF X=Y THEN 600\n460 IF X=Z THEN 630\n470 IF Y=Z THEN 650\n480 PRINT\n490 PRINT \"YOU LOST.\"\n500 LET P=P-M\n510 PRINT \"YOUR STANDINGS ARE $\"P\n520 PRINT \"AGAIN\";\n530 INPUT A$\n540 IF A$=\"Y\" THEN 160\n550 PRINT\n560 IF P<0 THEN 670\n570 IF P=0 THEN 690\n580 IF P>0 THEN 710\n590 GOTO 1350\n600 IF Y=Z THEN 730\n610 IF Y=1 THEN 820\n620 GOTO 1341\n630 IF Z=1 THEN 820\n640 GOTO 470\n650 IF Z=1 THEN 820\n660 GOTO 1341\n670 PRINT \"PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\"\n680 GOTO 1350\n690 PRINT\"HEY, YOU BROKE EVEN.\"\n700 GOTO 1350\n710 PRINT \"COLLECT YOUR WINNINGS FROM THE H&M CASHIER.\"\n720 GOTO 1350\n730 IF Z=1 THEN 780\n740 PRINT: PRINT\"**TOP DOLLAR**\"\n750 PRINT \"YOU WON!\"\n760 P=(((10*M)+M)+P)\n770 GOTO 510\n780 PRINT:PRINT\"***JACKPOT***\"\n790 PRINT \"YOU WON!\"\n800 P=(((100*M)+M)+P)\n810 GOTO 510\n820 PRINT:PRINT\"*DOUBLE BAR*\"\n830 PRINT\"YOU WON!\"\n840 P=(((5*M)+M)+P)\n850 GOTO 510\n860 PRINT\"HOUSE LIMITS ARE $100\"\n870 GOTO 160\n880 PRINT\"MINIMUM BET IS $1\"\n890 GOTO 160\n900 GOTO 220\n910 PRINT\"BAR\";:GOSUB 1310\n920 GOTO 330\n930 PRINT\"BELL\";:GOSUB 1310\n940 GOTO 330\n950 PRINT\"ORANGE\";:GOSUB 1310\n960 GOTO 330\n970 PRINT\"LEMON\";:GOSUB 1310\n980 GOTO 330\n990 PRINT\"PLUM\";:GOSUB 1310\n1000 GOTO 330\n1010 PRINT\"CHERRY\";:GOSUB 1310\n1020 GOTO 330\n1030 PRINT\" BAR\";:GOSUB 1310\n1040 GOTO 390\n1050 PRINT\" BELL\";:GOSUB 1310\n1060 GOTO 390\n1070 PRINT\" ORANGE\";:GOSUB 1310\n1080 GOTO 390\n1090 PRINT\" LEMON\";:GOSUB 1310\n1100 GOTO 390\n1110 PRINT\" PLUM\";:GOSUB 1310\n1120 GOTO 390\n1130 PRINT\" CHERRY\";:GOSUB 1310\n1140 GOTO 390\n1150 PRINT\" BAR\"\n1160 GOTO 450\n1170 PRINT\" BELL\"\n1180 GOTO 450\n1190 PRINT\" ORANGE\"\n1200 GOTO 450\n1210 PRINT\" LEMON\"\n1220 GOTO 450\n1230 PRINT\" PLUM\"\n1240 GOTO 450\n1250 PRINT\" CHERRY\"\n1260 GOTO 450\n1270 FOR Q4=1 TO 10\n1280 PRINT CHR$(7);\n1290 NEXT Q4\n1300 RETURN\n1310 FOR T8=1 TO 5\n1320 PRINT CHR$(7);\n1330 NEXT T8\n1340 RETURN\n1341 PRINT: PRINT \"DOUBLE!!\"\n1342 PRINT\"YOU WON!\"\n1343 P=(((2*M)+M)+P)\n1344 GOTO 510\n1350 STOP\n9999 END\n"
  },
  {
    "path": "00_Alternate_Languages/81_Splat/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript splat.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"splat\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/81_Splat/MiniScript/splat.ms",
    "content": "within5pct = function(n)\n\treturn n * (1 + rnd / 20 - rnd / 20)\nend function\n\nsplatMsg = [\"Requiescat in pace.\", \"May the Angel of Heaven lead you into Paradise.\",\n\t\t\t\"Rest in piece.\", \"Son-Of-A-Gun.\", \"#$%&&%!$\", \n\t\t\t\"A kick in the pants is a boost if you're headed right.\",\n\t\t\t\"Hmm. Should have picked a shorter time.\", \"Mutter. Mutter. Mutter.\",\n\t\t\t\"Pushing up daisies.\", \"Easy come, easy go.\"]\n\nhistory = []\n//clear\t\t// (works on Mini Micro only)\nprint \" \" * 33 + \"Splat\"\nprint \" \" * 15 + \"Creative Computing  Morristown, New Jersey\"\nprint;print;print\nprint \"Welcome to 'Splat' -- the game that simulates a parachute\"\nprint \"jump. Try to open your chute at the last possible\"\nprint \"moment without going splat.\"\nans = \"y\"\nwhile ans == \"y\"\n\tprint;print\n\n\tdistance = floor(9001 * rnd) + 1000\n\t\n\tans = input(\"Select your own terminal velocity (Yes or No)? \") + \" \"\n\tif ans[0].lower == \"y\" then\n\t\tterminalVel = input(\"What terminal velocity (mi/hr)? \").val\n\telse\n\t\tterminalVel = floor(1000 * rnd)\n\t\tprint \"Ok. Terminal velocity = \" + terminalVel + \"mi/hr\"\n\tend if\n\n\tterminalVel = terminalVel * 5280/3600\n\tvelocity = within5pct(terminalVel)\n\n\tans = input(\"Want to select acceleration due to gravity (Yes or No)? \") + \" \"\n\tif ans[0].lower == \"y\" then\n\t\tacceleration = input(\"What acceleration (ft/sec/sec)? \").val\n\t\tacceleration = within5pct(acceleration)\n\telse\n\t\tbodies = [\"Mercury\", \"Venus\", \"Earth\", \"the moon\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\", \"the Sun\"]\n\t\tgravity = [12.2, 28.3,32.16,5.15,12.5,85.2,37.6,33.8,39.6,896]\n\t\t\n\t\tinitialStmt = [\"Fine. You're on \", \"All right. You're on \", \"Then you're on \"]\n\t\t\n\t\ti = floor(rnd * 10)\n\t\tacceleration = gravity[i]\n\t\tstmt = initialStmt[i%3] + bodies[i] + \". Acceleration=\" + acceleration + \" ft/sec/sec.\"\n\t\tprint stmt\n\tend if\n\t\t\n\tactAccel = within5pct(acceleration)\n\tprint\n\tprint \"    Altitude         = \" + distance + \" ft\"\n\tprint \"    Term. Velocity   = \" + terminalVel + \" ft/sec +/-5%\"\n\tprint \"    Acceleration     = \" + acceleration + \" ft/sec/sec +/-5%\"\n\tprint \"Set the timer for your freefall.\"\n\tsec = input(\"How many seconds? \").val\n\n\tprint \"Here we go.\"; print\n\n\tprint \"Time (sec)\" + char(9) + \"Dist to Fall (ft)\"\n\tprint \"==========\" + char(9) + \"=================\"\n\ttermVelHit = false\n\tfor i in range(0, sec, sec/8)\n\t\tsec = velocity/actAccel\n\t\tif i <= sec and termVelHit == false then\n\t\t\tdist = distance - ((actAccel/2)*i^2)\n\t\telse if termVelHit == false then\n\t\t\ttermVelHit = true\n\t\t\tprint \"Terminal velocity reached a T plus \" + velocity/actAccel + \" seconds.\"\n\t\tend if\n\t\tif termVelHit then\n\t\t\tdist = distance - ((velocity^2/(2*actAccel))+(velocity*(i-sec)))\n\t\tend if\n\n\t\tif dist <= 0 then break\n\t\tprint (\" \" + i + \" \" * 9)[:9] + char(9) + \" \" + dist\n\tend for\n\n\tif dist > 0 then\n\t\tprint \"Chute open\"\n\t\thistory.push(dist)\n\t\tnumJumps = history.len\n\t\tnumLowerJumps = 0\n\t\tfor d in history\n\t\t\tnumLowerJumps += (dist <= d)\n\t\tend for\n\t\t\n\t\tjumpDiff = numJumps - numLowerJumps\n\t\tif numJumps < 4 then\n\t\t\tordinal = [\"1st\", \"2nd\", \"3rd\"]\n\t\t\tprint \"Amazing!! Not bad for your \" + ordinal[numJumps-1] + \" successful jump!!!\"\n\t\telse if jumpDiff <= numJumps * 0.10 then\n\t\t\tprint \"Wow! That's some jumping. Of the \" + numJumps + \" successful jumps\"\n\t\t\tprint \"before yours, only \" + jumpDiff + \" opened their chutes lower than\"\n\t\t\tprint \"you did.\"\n\t\telse if jumpDiff <= numJumps * 0.25 then\n\t\t\tprint \"Pretty good! \" + numJumps + \" successful jumps preceded yours and only\"\n\t\t\tprint jumpDiff + \" of them got lower than you did before their chute\"\n\t\t\tprint \"opened.\"\n\t\telse if jumpDiff <= numJumps * 0.50 then\n\t\t\tprint \"Not bad. There have been \" + numJumps + \" successful jumps before yours.\"\n\t\t\tprint \"You were beaten out by  \" + jumpDiff + \" of them.\"\n\t\telse if jumpDiff <= numJumps * 0.75 then\n\t\t\tprint \"Conservative, aren't you? You ranked only \" + jumpDiff + \" in the\"\n\t\t\tprint numJumps + \" successful jumps before yours.\"\n\t\telse if jumpDiff <= numJumps * 0.90 then\n\t\t\tprint \"Humph! Don't you have any sporting blood? There were\"\n\t\t\tprint numJumps + \" successful jumps before yours and you came in \" + numLowerJumps + \" jumps\"\n\t\t\tprint \"better than the worst. Shape up!!!\"\n\t\telse\n\t\t\tprint \"Hey! You pulled the rip code much too soon. \" + numJumps + \" successful\"\n\t\t\tprint \"jumps before yours and you came in number \" + jumpDiff + \"! Get with it.\"\n\t\tend if\n\telse if dist <= 0 and not termVelHit then\n\t\tprint (2 * distance / actAccel) ^ .5 + \" \" * 5 + \"Splat\"\n\telse if dist <= 0 and termVelHit then\n\t\tprint velocity/actAccel + ((distance - (velocity^2/(2*actAccel)))/velocity) + \" \" *5 + \"Splat\"\n\tend if\n\n\tif dist <=0 then\n\t\tsplatMsg.shuffle\n\t\tprint splatMsg[0]\n\t\tprint \"I'll give you another chance.\"\n\tend if\n\n\tans = input(\"Do you want to play again? \") + \" \"\n\tans = ans[0].lower\nend while\n\nprint \"S\" * 10\nprint"
  },
  {
    "path": "00_Alternate_Languages/81_Splat/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/81_Splat/splat.bas",
    "content": "10 PRINT TAB(33);\"SPLAT\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n40 PRINT:PRINT:PRINT\n50 DIM A(42)\n95 PRINT \"WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\"\n96 PRINT \"JUMP.  TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\"\n97 PRINT \"MOMENT WITHOUT GOING SPLAT.\"\n118 PRINT:PRINT:D1=0:V=0:A=0:N=0:M=0:D1=INT(9001*RND(1)+1000)\n119 PRINT \"SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO)\";:INPUT A1$\n120 IF A1$=\"NO\" THEN 128\n121 IF A1$<>\"YES\" THEN PRINT \"YES OR NO\";:INPUT A1$:GOTO 120\n123 PRINT \"WHAT TERMINAL VELOCITY (MI/HR)\";:INPUT V1\n125 V1=V1*(5280/3600):V=V1+((V1*RND(1))/20)-((V1*RND(1))/20):GOTO 135\n128 V1=INT(1000*RND(1))\n130 PRINT \"OK.  TERMINAL VELOCITY =\"V1\"MI/HR\"\n131 V1=V1*(5280/3600):V=V1+((V1*RND(1))/20)-((V1*RND(1))/20)\n135  PRINT \"WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO)\";\n136 INPUT B1$\n140 IF B1$=\"NO\" THEN 150\n141 IF B1$<>\"YES\" THEN PRINT \"YES OR NO\";:INPUT B1$:GOTO 140\n143 PRINT \"WHAT ACCELERATION (FT/SEC/SEC)\";:INPUT A2\n145 A=A2+((A2*RND(1))/20)-((A2*RND(1))/20):GOTO 205\n150 ON INT(1+(10*RND(1)))GOTO 151,152,153,154,155,156,157,158,159,160\n151 PRINT\"FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC.\":GOTO 161\n152 PRINT\"ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC.\":GOTO 162\n153 PRINT \"THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC.\":GOTO 163\n154 PRINT\"FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC.\":GOTO 164\n155 PRINT\"ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC.\":GOTO 165\n156 PRINT\"THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC.\":GOTO 166\n157 PRINT\"FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC.\":GOTO 167\n158 PRINT\"ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC.\":GOTO 168\n159 PRINT\"THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC.\":GOTO 169\n160 PRINT\"FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC.\":GOTO 170\n161 A2=12.2:GOTO 145\n162 A2=28.3:GOTO 145\n163 A2=32.16:GOTO 145\n164 A2=5.15:GOTO 145\n165 A2=12.5:GOTO 145\n166 A2=85.2:GOTO 145\n167 A2=37.6:GOTO 145\n168 A2=33.8 :GOTO 145\n169 A2=39.6:GOTO 145\n170 A2=896:GOTO 145\n205 PRINT\n206 PRINT \"    ALTITUDE         =\"D1\"FT\"\n207 PRINT \"    TERM. VELOCITY   =\"V1\"FT/SEC +/-5%\"\n208 PRINT \"    ACCELERATION     =\"A2\"FT/SEC/SEC +/-5%\"\n210 PRINT \"SET THE TIMER FOR YOUR FREEFALL.\"\n211 PRINT \"HOW MANY SECONDS\";:INPUT T\n215 PRINT \"HERE WE GO.\"\n217 PRINT\n218 PRINT \"TIME (SEC)\",\"DIST TO FALL (FT)\"\n219 PRINT \"==========\",\"=================\"\n300 FOR I=0 TO T STEP (T/8)\n310 IF I>V/A THEN 400\n320 D=D1-((A/2)*I^2)\n330 IF D<=0 THEN 1000\n340 PRINT I,D\n350 NEXT I\n360 GOTO 500\n400 PRINT \"TERMINAL VELOCITY REACHED AT T PLUS\"V/A\"SECONDS.\"\n405 FOR I=I TO T STEP (T/8)\n410 D=D1-((V^2/(2*A))+(V*(I-(V/A))))\n420 IF D<=0 THEN 1010\n430 PRINT I,D\n440 NEXT I\n500 PRINT \"CHUTE OPEN\"\n510 K=0:K1=0\n550 FOR J=0 TO 42\n555 IF A(J)=0 THEN 620\n560 K=K+1\n570 IF D>=A(J) THEN 600\n580 K1=K1+1\n600 NEXT J\n610 GOTO 540\n620 A(J)=D\n630 IF J>2 THEN 650\n635 PRINT \"AMAZING!!! NOT BAD FOR YOUR \";\n636 IF J=0 THEN PRINT \"1ST \";\n637 IF J=1 THEN PRINT \"2ND \";\n638 IF J=2 THEN PRINT \"3RD \";\n639 PRINT \"SUCCESSFUL JUMP!!!\":GOTO 2000\n650 IF K-K1<=.1*K THEN 700\n660 IF K-K1<=.25*K THEN 710\n670 IF K-K1<=.5*K THEN 720\n680 IF K-K1<=.75*K THEN 730\n690 IF K-K1<=.9*K THEN 740\n695 GOTO 750\n700 PRINT \"WOW!  THAT'S SOME JUMPING.  OF THE\"K\"SUCCESSFUL JUMPS\"\n701 PRINT \"BEFORE YOURS, ONLY\"K-K1\"OPENED THEIR CHUTES LOWER THAN\"\n702 PRINT \"YOU DID.\"\n703 GOTO 2000\n710 PRINT \"PRETTY GOOD! \" K\"SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\"\n711 PRINT K-K1\" OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\"\n712 PRINT \"OPENED.\" :GOTO 2000\n720 PRINT \"NOT BAD.  THERE HAVE BEEN\"K\"SUCCESSFUL JUMPS BEFORE YOURS.\"\n721 PRINT\"YOU WERE BEATEN OUT BY\"K-K1\"OF THEM.\":GOTO 2000\n730 PRINT \"CONSERVATIVE, AREN'T YOU?  YOU RANKED ONLY\"K-K1\"IN THE\"\n731 PRINT K\"SUCCESSFUL JUMPS BEFORE YOURS.\":GOTO 2000\n740 PRINT \"HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD?  THERE WERE\"\n741 PRINT K\"SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN\"K1\"JUMPS\"\n742 PRINT \"BETTER THAN THE WORST.  SHAPE UP!!!\":GOTO 2000\n750 PRINT \"HEY!  YOU PULLED THE RIP CORD MUCH TOO SOON.  \"K\"SUCCESSFUL\"\n751 PRINT \"JUMPS BEFORE YOURS AND YOU CAME IN NUMBER\"K-K1\"!  GET WITH IT!\"\n752 GOTO 2000\n800 PRINT \"REQUIESCAT IN PACE.\":GOTO 1950\n801 PRINT \"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\":GOTO 1950\n802 PRINT \"REST IN PEACE.\":GOTO 1950\n803 PRINT \"SON-OF-A-GUN.\":GOTO 1950\n804 PRINT \"#$%&&%!$\":GOTO 1950\n805 PRINT \"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\":GOTO 1950\n806 PRINT \"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\":GOTO 1950\n807 PRINT \"MUTTER. MUTTER. MUTTER.\":GOTO 1950\n808 PRINT \"PUSHING UP DAISIES.\":GOTO 1950\n809 PRINT \"EASY COME, EASY GO.\":GOTO 1950\n1000 PRINT SQR(2*D1/A),\"SPLAT\"\n1005 ON INT(1+(10*RND(1)))GOTO 800,801,802,803,804,805,806,807,808,809\n1010 PRINT (V/A)+((D1-(V^2/(2*A)))/V),\"SPLAT\"\n1020 GOTO 1005\n1950 PRINT \"I'LL GIVE YOU ANOTHER CHANCE.\":GOTO 2000\n2000 PRINT \"DO YOU WANT TO PLAY AGAIN\";:INPUT Z$\n2001 IF Z$=\"YES\" THEN 118\n2002 IF Z$=\"NO\" THEN 2005\n2003 PRINT \"YES OR NO\":GOTO 2000\n2005 PRINT \"PLEASE\";:INPUT Z$:IF Z$=\"YES\" THEN 118\n2006 IF Z$<>\"NO\" THEN PRINT \"YES OR NO \";:GOTO 2005\n2007 PRINT \"SSSSSSSSSS.\":PRINT:GOTO 2046\n2046 END\n"
  },
  {
    "path": "00_Alternate_Languages/82_Stars/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\r\n\r\nConversion to [MiniScript](https://miniscript.org).\r\n\r\nWays to play:\r\n\r\n1. Command-Line MiniScript:\r\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\r\n```\r\n\tminiscript stars.ms\r\n```\r\n\r\n2. Mini Micro:\r\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\r\n```\r\n\tload \"stars\"\r\n\trun\r\n```\r\n"
  },
  {
    "path": "00_Alternate_Languages/82_Stars/MiniScript/stars.ms",
    "content": "kMaxNum = 100\nkTries = 7\n\ninstructions = function\n\tprint \"I am thinking of a whole number from 1 to \" + kMaxNum\n\tprint \"Try to guess my number. After you guess, I\"\n\tprint \"will output one or more stars (*). The more\"\n\tprint \"stars I type, the closer you are to my number.\"\n\tprint \"One star (*) means far away, seven stars (*******)\"\n\tprint \"means really close! You get \" + kTries + \" guesses.\"\n\tprint\nend function\n\nprint \" \" * 34 + \"Stars\"\nprint \" \" * 15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nans = input(\"Do you want instructions? \").lower + \" \"\nif ans[0] == \"y\" then\n\tinstructions\nend if\n\nwhile true\n\tprint\n\tprint \"OK, I am thinking of a number, start guessing.\"\n\tstarNum = floor(rnd * kMaxNum) + 1\n\ttry = 0\n\twhile try < kTries\n\t\tprint\n\t\tguess = input(\"Your guess: \").val\n\t\t\n\t\tif guess == starNum then\n\t\t\tbreak\n\t\telse\n\t\t\td = abs(guess - starNum)\n\t\t\tprint \"*\" * (7 - floor(log(d,2)))\n\t\tend if\n\t\ttry += 1\n\tend while\n\t\n\tif try < kTries then\n\t\tprint \"*\" * 59\n\t\tprint \"You got it in \" + (try + 1) + \" guesses! Let's play again.\"\n\telse\n\t\tprint \"Sorry, that's \" + try + \" guesses. The number was \" + starNum\n\tend if\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/82_Stars/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/82_Stars/stars.bas",
    "content": "10 PRINT TAB(34);\"STARS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 REM *** STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA\n140 REM *** A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES\n150 A=100:M=7\n170 INPUT \"DO YOU WANT INSTRUCTIONS\";A$\n190 IF LEFT$(A$,1)=\"N\" THEN 280\n200 REM *** INSTRUCTIONS ON HOW TO PLAY\n210 PRINT \"I AM THINKING OF A WHOLE NUMBER FROM 1 TO\";A\n220 PRINT \"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\"\n230 PRINT \"WILL TYPE ONE OR MORE STARS (*).  THE MORE\"\n240 PRINT \"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\"\n250 PRINT \"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\"\n260 PRINT \"MEANS REALLY CLOSE!  YOU GET\";M;\"GUESSES.\"\n270 REM *** COMPUTER THINKS OF A NUMBER\n280 PRINT\n290 PRINT\n300 X=INT(A*RND(1)+1)\n310 PRINT \"OK, I AM THINKING OF A NUMBER, START GUESSING.\"\n320 REM *** GUESSING BEGINS, HUMAN GETS M GUESSES\n330 FOR K=1 TO M\n340 PRINT\n350 PRINT \"YOUR GUESS\";\n360 INPUT G\n370 IF G=X THEN 600\n380 D=ABS(G-X)\n390 IF D>=64 THEN 510\n400 IF D>=32 THEN 500\n410 IF D>=16 THEN 490\n420 IF D>=8 THEN 480\n430 IF D>=4 THEN 470\n440 IF D>=2 THEN 460\n450 PRINT \"*\";\n460 PRINT \"*\";\n470 PRINT \"*\";\n480 PRINT \"*\";\n490 PRINT \"*\";\n500 PRINT \"*\";\n510 PRINT \"*\";\n520 PRINT\n530 NEXT K\n540 REM *** DID NOT GUESS IN M GUESSES\n550 PRINT\n560 PRINT \"SORRY, THAT'S\";M;\"GUESSES. THE NUMBER WAS\";X\n580 GOTO 650\n590 REM *** WE HAVE A WINNER\n600 PRINT:FOR N=1 TO 79\n610 PRINT \"*\";\n620 NEXT N\n630 PRINT:PRINT\n640 PRINT \"YOU GOT IT IN\";K;\"GUESSES!!!  LET'S PLAY AGAIN...\"\n650 GOTO 280\n660 END\n"
  },
  {
    "path": "00_Alternate_Languages/83_Stock_Market/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript stockmarket.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"stockmarket\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/83_Stock_Market/MiniScript/stockmarket.ms",
    "content": "print \" \"*30 + \"Stock Market\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\n// Stock Market Simulation     -STOCK-\n// Revised 8/18/70 (D. Pessel, L. Braun, C. Losik)\n// Ported to MiniScript 10/07/23 (J. Strout)\n\n\n// Ask a yes/no question; return true if yes, false if no\nyes = function(prompt)\n\twhile true\n\t\tresponse = input(prompt + \" (YES-Type 1, NO-Type 0)? \")\n\t\tif not response then continue\n\t\tif response == \"1\" or response[0].lower == \"y\" then return true\n\t\tif response == \"0\" or response[0].lower == \"n\" then return false\n\tend while\nend function\n\nprintInstructions = function\n\tprint; print\n\tprint \"This program plays the stock market.  You will be given\"\n\tprint \"$10,000 and may buy or sell stocks.  The stock prices will\"\n\tprint \"be generated randomly and therefore this model does not\"\n\tprint \"represent exactly what happens on the exchange.  A table\"\n\tprint \"of available stocks, their prices, and the number of shares\"\n\tprint \"in your portfolio will be printed.  Following this, the\"\n\tprint \"initials of each stock will be printed with a question\"\n\tprint \"mark.  Here you indicate a transaction.  To buy a stock\"\n\tprint \"type +NNN, to sell a stock type -NNN, where NNN is the\"\n\tprint \"number of shares.  A brokerage fee of 1% will be charged\"\n\tprint \"on all transactions.  Note that if a stock's value drops\"\n\tprint \"to zero it may rebound to a positive value again.  You\"\n\tprint \"have $10,000 to invest.  Use integers for all your inputs.\"\n\tprint \"(Note:  To get a 'feel' for the market run for at least\"\n\tprint \"10 days)\"\n\tprint \"-----Good luck!-----\"\n\tprint\n\tinput \"(Press Return to continue.)\"\nend function\n\nrandomIndex = function; return floor(rnd * stockPrices.len); end function\n\n// Randomly produce new stock values based on previous day's values.\n// N1,N2 are random numbers of days which respectively determine\n// when a stock will increase or decrease 10 points.\nadjustStockPrices = function\n\tfor i in changePerShare.indexes\n\t\tchangePerShare[i] = 0\n\tend for\n\t// if N1 days have passed, increase a random stock by 10\n\tif N1 < 1 then\n\t\tchangePerShare[randomIndex] = 10\n\t\tglobals.N1 = floor(4.99 * rnd + 1)\n\tend if\n\t// if N2 days have passed, decrease a random stock by 10\n\tif N2 < 1 then\n\t\tchangePerShare[randomIndex] = -10\n\t\tglobals.N2 = floor(4.99 * rnd + 1)\n\tend if\n\t// Deduct one day from N1 and N2\n\tglobals.N1 -= 1\n\tglobals.N2 -= 1\n\t// update all stocks\n\tfor i in stockPrices.indexes\n\t\tsmallChange = rnd\n\t\tif smallChange < 0.25 then smallChange = 0.25\n\t\tif smallChange > 0.5 then smallChange = 0.5\n\t\tchangePerShare[i] += marketTrendSlope * stockPrices[i] + smallChange + floor(3 - 6*rnd + 0.5)\n\t\tchangePerShare[i] = round(changePerShare[i], 2)\n\t\tstockPrices[i] += changePerShare[i]\n\t\tif stockPrices[i] < 0 then\n\t\t\tchangePerShare[i] = 0\n\t\t\tstockPrices[i] = 0\n\t\tend if\n\t\tstockPrices[i] = round(stockPrices[i], 2)\n\tend for\t\n\t// After trendDaysLeft, randomly change trend sign and slope\n\tglobals.trendDaysLeft -= 1\n\tif trendDaysLeft < 1 then\n\t\tglobals.trendDaysLeft = floor(4.99 * rnd + 1)\n\t\tglobals.marketTrendSlope = floor(rnd*10 + 0.5)/100\n\t\tif rnd < 0.5 then globals.marketTrendSlope = -marketTrendSlope\n\tend if\nend function\n\npad = function(s, width=20)\n\ts = str(s)\n\treturn s + \" \"*(width - s.len)\nend function\n\nprintInitialPortfolio = function\n\tprint pad(\"Stock\", 30) + pad(\"Initials\", 12) + \"Price/Share\"\n\tfor i in stockSymbols.indexes\t\n\t\tprint pad(stockNames[i], 32) + pad(stockSymbols[i], 14) + stockPrices[i]\n\tend for\nend function\n\nprintMarketResults = function\n\tprint\n\tprint \"**********     END OF DAY'S TRADING     **********\"\n\tprint\n\tprint\n\tprint pad(\"Stock\", 8) + pad(\"Price/Share\", 14) + pad(\"Holdings\", 12) +\n\t  pad(\"Value\", 10) + \"Net Price Change\"\n\tfor i in stockSymbols.indexes\n\t\tvalue = round(stockPrices[i] + sharesOwned[i], 2)\n\t\tprint pad(stockSymbols[i], 9) + pad(stockPrices[i], 14) +\n\t\t  pad(sharesOwned[i], 12) + pad(value, 10) + changePerShare[i]\n\tend for\n\tprint\nend function\n\nprintStatus = function\n\taverage = stockPrices.sum / stockPrices.len\n\tprint\n\tprint \"New York Stock Exchange Average: \" + round(average, 2), \"\"\n\tif prevAverage != null then \n\t\tprint \" Net Change \" + round(average - prevAverage, 2)\n\telse\n\t\tprint\n\tend if\n\tglobals.prevAverage = average\n\tprint\n\tstockValue = 0\n\tfor i in stockPrices.indexes\n\t\tstockValue += stockPrices[i] * sharesOwned[i]\n\tend for\n\tprint \"Total stock assets are   $ \" + round(stockValue, 2)\n\tprint \"Total cash assets are    $ \" + round(cash, 2)\n\tprint \"Total assets are         $ \" + round(stockValue + cash, 2)\n\tprint\n\t// Uncomment the following line to cheat/debug:\n\t//print \"marketTrendSlope: \" + marketTrendSlope + \"; trendDaysLeft: \" + trendDaysLeft\nend function\n\n// Calculate total cost, including brokerage fee, to buy the given\n// stock (or if qtyToBuy < 0, negative cash gains minus the fee).\ntotalCost = function(stockIndex, qtyToBuy)\n\tbaseVal = stockPrices[stockIndex] * qtyToBuy\n\tfee = round(abs(baseVal) * 0.01, 2)\n\treturn baseVal + fee\nend function\n\nbuySell = function\n\tprint \"What is your transaction in\"\n\ti = 0\n\twhile i < stockSymbols.len\n\t\twhile true\n\t\t\tqty = input(stockSymbols[i] + \"? \")\n\t\t\tif qty == \"\" or qty == \"0\" or qty.val != 0 then break\n\t\t\tprint \"Enter quantity to buy/sell like +10 or -2.\"\n\t\tend while\n\t\tqty = qty.val\n\t\tif qty < 0 and -qty > sharesOwned[i] then\n\t\t\t\tprint \"You have only \" + sharesOwned[i] + \" of \" + stockSymbols[i] + \"; try again.\"\n\t\t\t\tcontinue\n\t\t\tend if\n\t\tif totalCost(i, qty) > cash then\n\t\t\tprint \"This would cost \" + (totalCost(i, qty) - cash) + \" more than you have.\"\n\t\t\tcontinue\n\t\tend if\n\t\tsharesOwned[i] += qty\n\t\tglobals.cash -= totalCost(i, qty)\n\t\ti += 1\n\tend while\nend function\n\n// Introduction\nif yes(\"Do you want the instructions\") then printInstructions\nprint; print\n\n// Initial stock values and trends\nstockSymbols = [\"IBM\", \"RCA\", \"LBJ\", \"ABC\", \"CBS\"]\nstockNames = [\"Int. Ballistic Missiles\", \"Red Cross of America\", \n  \"Lichtenstein, Bumrap & Joke\", \"American Bankrupt Co.\", \"Censured Books Store\"]\nsharesOwned = [0] * stockSymbols.len\ncash = 10000\nstockPrices = [100, 85, 150, 140, 110]\nchangePerShare = [0] * stockSymbols.len\ntrendDaysLeft = floor(4.99 * rnd + 1)\nmarketTrendSlope = floor(rnd*10 + 0.5)/100\nif rnd > 0.5 then marketTrendSlope = -marketTrendSlope\nN1 = 0\t\t// days until a big positive jump in a random price\nN2 = 0\t\t// days until a big negative jump in a random price\nadjustStockPrices\nprevAverage = null\n\nprintInitialPortfolio\nprintStatus\nwhile true\n\tbuySell\n\tadjustStockPrices\n\tprintMarketResults\n\tprintStatus\n\tif not yes(\"Do you wish to continue\") then break\nend while\nprint \"Hope you had fun!!\"\n\n"
  },
  {
    "path": "00_Alternate_Languages/83_Stock_Market/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/83_Stock_Market/stockmarket.bas",
    "content": "10 PRINT TAB(30);\"STOCK MARKET\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 REM STOCK MARKET SIMULATION     -STOCK-\n101 REM REVISED 8/18/70 (D. PESSEL, L. BRAUN, C. LOSIK)\n102 REM IMP VRBLS: A-MRKT TRND SLP; B5-BRKRGE FEE; C-TTL CSH ASSTS;\n103 REM C5-TTL CSH ASSTS (TEMP); C(I)-CHNG IN STK VAL; D-TTL ASSTS;\n104 REM E1,E2-LRG CHNG MISC; I-STCK #; I1,I2-STCKS W LRG CHNG;\n105 REM N1,N2-LRG CHNG DAY CNTS; P5-TTL DAYS PRCHSS; P(I)-PRTFL CNTNTS;\n106 REM Q9-NEW CYCL?; S4-SGN OF A; S5-TTL DYS SLS; S(I)-VALUE/SHR;\n107 REM T-TTL STCK ASSTS; T5-TTL VAL OF TRNSCTNS;\n108 REM W3-LRG CHNG; X1-SMLL CHNG(<$1); Z4,Z5,Z6-NYSE AVE.; Z(I)-TRNSCT\n110 DIM S(5),P(5),Z(5),C(5)\n112 REM SLOPE OF MARKET TREND:A  (SAME FOR ALL STOCKS)\n113 LET X=1\n114 LET A=INT((RND(X)/10)*100+.5)/100\n115 LET T5=0\n116 LET X9=0\n117 LET N1=0\n118 LET N2=0\n119 LET E1=0\n120 LET E2=0\n121 REM INTRODUCTION\n122 PRINT \"DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)\";\n123 INPUT Z9\n124 PRINT\n125 PRINT\n126 IF Z9<1 THEN 200\n130 PRINT \"THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\"\n132 PRINT \"$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\"\n134 PRINT \"BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\"\n135 PRINT \"REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\"\n136 PRINT \"OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\"\n137 PRINT \"IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\"\n138 PRINT \"INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\"\n139 PRINT \"MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\"\n140 PRINT \"TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\"\n141 PRINT \"NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\"\n142 PRINT \"ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\"\n143 PRINT \"TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\"\n144 PRINT \"HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\"\n145 PRINT \"(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\"\n146 PRINT \"10 DAYS)\"\n147 PRINT \"-----GOOD LUCK!-----\"\n200 REM GENERATION OF STOCK TABLE; INPUT REQUESTS\n210 REM INITIAL STOCK VALUES\n220 LET S(1)=100\n230 LET S(2)=85\n240 LET S(3)=150\n250 LET S(4)=140\n260 LET S(5)=110\n265 REM INITIAL T8 - # DAYS FOR FIRST TREND SLOPE (A)\n266 LET T8=INT(4.99*RND(X)+1)\n267 REM RANDOMIZE SIGN OF FIRST TREND SLOPE (A)\n268 IF RND(X)>.5 THEN 270\n269 LET A=-A\n270 REM RANDOMIZE INITIAL VALUES\n280 GOSUB 830\n285 REM INITIAL PORTFOLIO CONTENTS\n290 FOR I=1 TO 5\n300 LET P(I)=0\n305 LET Z(I)=0\n310 NEXT I\n320 PRINT\n330 PRINT\n333 REM INITIALIZE CASH ASSETS:C\n335 LET C=10000\n338 REM PRINT INITIAL PORTFOLIO\n340 PRINT \"STOCK\",\" \",\"INITIALS\",\"PRICE/SHARE\"\n350 PRINT \"INT. BALLISTIC MISSILES\",\"  IBM\",S(1)\n352 PRINT \"RED CROSS OF AMERICA\",\"  RCA\",S(2)\n354 PRINT \"LICHTENSTEIN, BUMRAP & JOKE\",\"  LBJ\",S(3)\n356 PRINT \"AMERICAN BANKRUPT CO.\",\"  ABC\",S(4)\n358 PRINT \"CENSURED BOOKS STORE\",\"  CBS\",S(5)\n360 PRINT\n361 REM NYSE AVERAGE:Z5; TEMP. VALUE:Z4; NET CHANGE:Z6\n363 LET Z4=Z5\n364 LET Z5=0\n365 LET T=0\n370 FOR I=1 TO 5\n375 LET Z5=Z5+S(I)\n380 LET T=T+S(I)*P(I)\n390 NEXT I\n391 LET Z5=INT(100*(Z5/5)+.5)/100\n392 LET Z6=INT((Z5-Z4)*100+.5)/100\n393 REM TOTAL ASSETS:D\n394 LET D=T+C\n395 IF X9>0 THEN 398\n396 PRINT \"NEW YORK STOCK EXCHANGE AVERAGE: \"Z5\n397 GOTO 399\n398 PRINT \"NEW YORK STOCK EXCHANGE AVERAGE: \"Z5\"NET CHANGE\"Z6\n399 PRINT\n400 LET T=INT(100*T+.5)/100\n401 PRINT \"TOTAL STOCK ASSETS ARE   $\";T\n403 LET C=INT(100*C+.5)/100\n405 PRINT \"TOTAL CASH ASSETS ARE    $\";C\n407 LET D=INT(100*D+.5)/100\n408 PRINT \"TOTAL ASSETS ARE         $\";D\n410 PRINT\n411 IF X9=0 THEN 416\n412 PRINT \"DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)\";\n413 INPUT Q9\n414 IF Q9<1 THEN 998\n416 REM INPUT TRANSACTIONS\n420 PRINT \"WHAT IS YOUR TRANSACTION IN\"\n430 PRINT \"IBM\";\n440 INPUT Z(1)\n450 PRINT \"RCA\";\n460 INPUT Z(2)\n470 PRINT \"LBJ\";\n480 INPUT Z(3)\n490 PRINT \"ABC\";\n500 INPUT Z(4)\n510 PRINT \"CBS\";\n520 INPUT Z(5)\n525 PRINT\n530 REM TOTAL DAY'S PURCHASES IN $:P5\n540 LET P5=0\n550 REM TOTAL DAY'S SALES IN $:S5\n560 LET S5=0\n570 FOR I=1 TO 5\n575 LET Z(I)=INT(Z(I)+.5)\n580 IF Z(I)<=0 THEN 610\n590 LET P5=P5+Z(I)*S(I)\n600 GOTO 620\n610 LET S5=S5-Z(I)*S(I)\n612 IF -Z(I)<=P(I) THEN 620\n614 PRINT \"YOU HAVE OVERSOLD A STOCK; TRY AGAIN.\"\n616 GOTO 420\n620 NEXT I\n622 REM TOTAL VALUE OF TRANSACTIONS:T5\n625 LET T5=P5+S5\n630 REM BROKERAGE FEE:B5\n640 LET B5=INT(.01*T5*100+.5)/100\n650 REM CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES\n652 REM -BROKERAGE FEES+TOTAL SALES:C5\n654 LET C5=C-P5-B5+S5\n656 IF C5>=0 THEN 674\n658 PRINT \"YOU HAVE USED $\"-C5\" MORE THAN YOU HAVE.\"\n660 GOTO 420\n674 LET C=C5\n675 REM CALCULATE NEW PORTFOLIO\n680 FOR I=1 TO 5\n690 LET P(I)=P(I)+Z(I)\n700 NEXT I\n710 REM CALCULATE NEW STOCK VALUES\n720 GOSUB 830\n750 REM PRINT PORTFOLIO\n751 REM BELL RINGING-DIFFERENT ON MANY COMPUTERS\n755 PRINT\n756 PRINT \"**********     END OF DAY'S TRADING     **********\"\n757 PRINT\n758 PRINT\n759 IF X9<1 THEN 769\n769 PRINT \"STOCK\",\"PRICE/SHARE\",\"HOLDINGS\", \"VALUE\", \"NET PRICE CHANGE\"\n770 PRINT \"IBM\", S(1), P(1), S(1)*P(1), C(1)\n771 PRINT \"RCA\", S(2), P(2), S(2)*P(2), C(2)\n772 PRINT \"LBJ\", S(3), P(3), S(3)*P(3), C(3)\n773 PRINT \"ABC\", S(4), P(4), S(4)*P(4), C(4)\n774 PRINT \"CBS\", S(5), P(5), S(5)*P(5), C(5)\n775 LET X9=1\n780 PRINT\n790 PRINT\n810 GOTO 360\n829 REM NEW STOCK VALUES - SUBROUTINE\n830 REM RANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS\n831 REM DAY'S VALUES\n832 REM N1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY\n833 REM DETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK\n834 REM I2 WILL DECREASE 10 PTS.\n840 REM IF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1\n841 IF N1>0 THEN 850\n845 LET I1=INT(4.99*RND(X)+1)\n846 LET N1=INT(4.99*RND(X)+1)\n847 LET E1=1\n850 REM IF N2 DAYS HAVE PASSED, PICK AN I2, SET E2, DETERMINE NEW N2\n851 IF N2>0 THEN 860\n855 LET I2=INT(4.99*RND(X)+1)\n856 LET N2=INT(4.99*RND(X)+1)\n857 LET E2=1\n860 REM DEDUCT ONE DAY FROM N1 AND N2\n861 LET N1=N1-1\n862 LET N2=N2-1\n890 REM LOOP THROUGH ALL STOCKS\n900 FOR I=1 TO 5\n910 LET X1=RND(X)\n915 IF X1>.25 THEN 920\n916 LET X1=.25\n917 GOTO 935\n920 IF X1>.5 THEN 925\n921 LET X1=.5\n922 GOTO 935\n925 IF X1>.75 THEN 930\n926 LET X1=.75\n927 GOTO 935\n930 LET X1=0.0\n931 REM BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)\n935 LET W3=0\n936 IF E1<1 THEN 945\n937 IF INT(I1+.5)<>INT(I+.5) THEN 945\n938 REM ADD 10 PTS. TO THIS STOCK;  RESET E1\n939 LET W3=10\n943 LET E1=0\n945 IF E2<1 THEN 955\n947 IF INT(I2+.5)<>INT(I+.5) THEN 955\n948 REM SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2\n949 LET W3=W3-10\n953 LET E2=0\n954 REM C(I) IS CHANGE IN STOCK VALUE\n955 LET C(I)=INT(A*S(I))+X1+INT(3-6*RND(X)+.5)+W3\n956 LET C(I)=INT(100*C(I)+.5)/100\n957 LET S(I)=S(I)+C(I)\n960 IF S(I)>0 THEN 967\n964 LET C(I)=0\n965 LET S(I)=0\n966 GOTO 970\n967 LET S(I)=INT(100*S(I)+.5)/100\n970 NEXT I\n972 REM AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE\n973 LET T8=T8-1\n974 IF T8<1 THEN 985\n980 RETURN\n985 REM RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION\n986 REM OF TREND (T8)\n990 LET T8=INT(4.99*RND(X)+1)\n992 LET A=INT((RND(X)/10)*100+.5)/100\n993 LET S4=RND(X)\n994 IF S4<=.5 THEN 997\n995 LET A=-A\n997 RETURN\n998 PRINT \"HOPE YOU HAD FUN!!\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).  Note that while the original game separated the instructions into a separate BASIC program (probably due to memory limitations), we have chosen here to combine them into one MiniScript program with both instructions and gameplay.  The instructions are available at the start of the game, and later at any time via the HLP command.\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript superstartrek.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"superstartrek\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms",
    "content": "// SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY\n//\n// ****        **** STAR TREK ****        ****\n// **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n// **** AS SEEN ON THE STAR TREK TV SHOW.\n// **** ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n// **** PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n// **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n// *** LEEDOM - APRIL & DECEMBER 1974,\n// *** WITH A LITTLE HELP FROM HIS FRIENDS . . .\n// *** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --\n// *** SEND TO;  R. C. LEEDOM\n// ***           WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.\n// ***           BOX 746, M.S. 338\n// ***           BALTIMORE, MD  21203\n// ***\n// *** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS\n// *** Convertod te MiniScript 10/10/23 by Joe Strout\n// *** (based heavily on the Python port by @jkboyce)\n\nimport \"listUtil\"\nimport \"stringUtil\"\nimport \"mathUtil\"\n\n//=================================================================\n// Instructions\n// (This was originally in a separate program, superstartreckins.bas,\n// for memory reasons.  I've chosen to incorporate it into the main\n// program, as that's more convenient for everybody.)\n//=================================================================\nInstructions = {}\nInstructions.print = function\n\tprint\n\tprint \"At each pause, press Return to continue.\"\n\tinput\n\n\tprint \"      Instructions for 'Super Star Trek'\"\n\tprint\n\tprint \"1. When you see \\Command?\\ printed, enter one of the legal\"\n\tprint \"     commands (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\"\n\tprint \"2. If you should type in an illegal command, you'll get a short\"\n\tprint \"     list of the legal commands printed out.\"\n\tprint \"3. Some commands require you to enter data (for example, the\"\n\tprint \"     'NAV' command comes back with 'Course (1-9)?'.)  If you\"\n\tprint \"     type in illegal data (like negative numbers), that command\"\n\tprint \"     will be aborted\"\n\tprint\n\tprint \"     The galaxy is divided into an 8 x 8 quadrant grid,\"\n\tprint \"and each quadrant is further divided into an 8 x 8 sector grid.\"\n\tprint\n\tprint \"     You will be assigned a starting point somewhere in the\"\n\tprint \"galaxy to begin a tour of duty as comander of the starship\"\n\tprint \"\\Enterprise\\; your mission: to seek and destroy the fleet of\"\n\tprint \"klingon warwhips which are menacing the United Federation of\"\n\tprint \"Planets.\"\n\tinput\n\t\n\tprint\n\tprint \"     You have the following commands available to you as captain\"\n\tprint \"of the starship Enterprise:\"\n\tprint\n\tprint \"\\NAV\\ command = warp engine control --\"\n\tprint \"     course is in a circular numerical      4  3  2\"\n\tprint \"     vector arrangement as shown             . | .\"\n\tprint \"     integer and real values may be           .|.\"\n\tprint \"     used.  (Thus course 1.5 is half-     5 ---*--- 1\"\n\tprint \"     way between 1 and 2.)                    .|.\"\n\tprint \"                                             . | .\"\n\tprint \"     Values may approach 9.0, which         6  7  8\"\n\tprint \"     itself is equivalent to 1.0\"\n\tprint \"                                            course\"\n\tprint \"     One warp factor is the size of \"\n\tprint \"     one quadrant.  Therefore, to get\"\n\tprint \"     from quadrant 6,5 to 5,5, you would\"\n\tprint \"     use course 3, warp factor 1.\"\n\tinput\n\t\n\tprint\n\tprint \"\\SRS\\ command = short range sensor scan\"\n\tprint \"     Shows you a scan of your present quadrant.\"\n\tprint\n\tprint \"     Symbology on your sensor screen is as follows:\"\n\tprint \"        <*> = your starship's position\"\n\tprint \"        +K+ = klingon battle cruiser\"\n\tprint \"        >!< = federation starbase (refuel/repair/re-arm here!)\"\n\tprint \"         *  = star\"\n\tprint\n\tprint \"     A condensed 'status report' will also be presented.\"\n\tinput\n\t\n\tprint\n\tprint \"\\LRS\\ command = long range sensor scan\"\n\tprint \"     Shows conditions in space for one quadrant on each side\"\n\tprint \"     of the enterprise (which is in the middle of the scan).\"\n\tprint \"     The scan is coded in the form \\###\\, where the units digit\"\n\tprint \"     is the number of stars, the tens digit is the number of\"\n\tprint \"     starbases, and the hundresds digit is the number of\"\n\tprint \"     klingons.\"\n\tprint\n\tprint \"     Example - 207 = 2 klingons, no starbases, & 7 stars.\"\n\tinput\n\t\n\tprint\n\tprint \"\\PHA\\ command = phaser control.\"\n\tprint \"     Allows you to destroy the klingon battle cruisers by \"\n\tprint \"     zapping them with suitably large units of energy to\"\n\tprint \"     deplete their shield power.  (Remember, klingons have\"\n\tprint \"     phasers too!)\"\n\tprint\n\tprint \"\\TOR\\ command = photon torpedo control\"\n\tprint \"     Torpedo course is the same as used in warp engine control.\"\n\tprint \"     If you hit the klingon vessel, he is destroyed and\"\n\tprint \"     cannot fire back at you.  If you miss, you are subject to\"\n\tprint \"     his phaser fire.  In either case, you are also subject to \"\n\tprint \"     the phaser fire of all other klingons in the quadrant.\"\n\tprint\n\tprint \"     The library-computer (\\COM\\ command) has an option to \"\n\tprint \"     compute torpedo trajectory for you (option 2).\"\n\tinput\n\t\n\tprint\n\tprint \"\\SHE\\ command = shield control\"\n\tprint \"     Defines the number of energy units to be assigned to the\"\n\tprint \"     shields.  Energy is taken from total ship's energy.  Note\"\n\tprint \"     that the status display total energy includes shield energy.\"\n\tprint\n\tprint \"\\DAM\\ command = dammage control report\"\n\tprint \"     Gives the state of repair of all devices, where a negative\"\n\tprint \"     'state of repair' shows that the device is temporarily\"\n\tprint \"     damaged.\"\n\tinput\n\t\n\tprint\n\tprint \"\\COM\\ command = library-computer\"\n\tprint \"     The library-computer contains six options:\"\n\tprint \"     option 0 = cumulative galactic record\"\n\tprint \"         This option showes computer memory of the results of all\"\n\tprint \"        previous short and long range sensor scans.\"\n\tprint \"     option 1 = status report\"\n\tprint \"        This option shows the number of klingons, stardates,\"\n\tprint \"        and starbases remaining in the game.\"\n\tprint \"     option 2 = photon torpedo data\"\n\tprint \"        Which gives directions and distance from the enterprise\"\n\tprint \"        to all klingons in your quadrant.\"\n\tprint \"     option 3 = starbase nav data\"\n\tprint \"        This option gives direction and distance to any \"\n\tprint \"        starbase within your quadrant.\"\n\tprint \"     option 4 = direction/distance calculator\"\n\tprint \"        This option allows you to enter coordinates for\"\n\tprint \"        direction/distance calculations.\"\n\tprint \"     option 5 = galactic /region name/ map\"\n\tprint \"        This option prints the names of the sixteen major \"\n\tprint \"        galactic regions referred to in the game.\"\n\tinput\n\tprint\nend function\n\n//=================================================================\n// Constants (tweak these to make the game easier or harder!)\n//=================================================================\nConstant = {}\nConstant.klingonShieldStrength = 200\nConstant.maxEnergy = 3000\nConstant.maxTorpedos = 10\nConstant.minDays = 25\nConstant.maxDays = 34\n\n// Directions.  NOTE: this game has an unusual coordinate\n// system, where x is the row (higher X values are further\n// down on the screen), and y is the column (higher Y values\n// are further to the right).\ndirs = [\t// (down, right)\n    [0, 1],\t\t// 1: go right (same as #9)\n    [-1, 1],\t// 2: go up-right\n    [-1, 0],\t// 3: go up  (lower x-coordines; north)\n    [-1, -1],\t// 4: go up-left (north-west)\n    [0, -1],\t// 5: go left (west)\n    [1, -1],\t// 6: go down-left (south-west)\n    [1, 0],\t\t// 7: go down (higher x-coordines; south)\n    [1, 1],\t\t// 8: go down-right\n    [0, 1]]\t\t// 9: go right (east)\n\n\n\n//=================================================================\n// Global Utility Functions\n//=================================================================\n\n// Generate a random integer from 0 to 7 inclusive.\nfnr = function\n\treturn floor(rnd * 8)\nend function\n\n// Generate a random integer between any two limits (inclusive).\nrandInt = function(minVal, maxVal)\n\treturn floor(rnd * (maxVal - minVal + 1)) + minVal\nend function\n\n// Print distance and direction between two points on a grid.\nprintDirection = function(source, dest)\n\tdelta1 = -(dest.x - source.x)\n\tdelta2 = dest.y - source.y\n\t\n\tif delta2 > 0 then\n\t\tif delta1 < 0 then\n\t\t\tbase = 7\n\t\telse\n\t\t\tbase = 1\n\t\t\ttemp = delta1; delta1 = delta2; delta2 = temp\n\t\tend if\n\telse\n\t\tif delta1 > 0 then\n\t\t\tbase = 3\n\t\telse\n\t\t\tbase = 5\n\t\t\ttemp = delta1; delta1 = delta2; delta2 = temp\n\t\tend if\n\tend if\n\n\tdelta1 = abs(delta1)\n\tdelta2 = abs(delta2)\n\tif delta1 or delta2 then\t// bug in original: failed when source == dest\n\t\tif delta1 >= delta2 then\n\t\t\tprint \"Direction = \" + round(base + delta2 / delta1, 6)\n\t\telse\n\t\t\tprint \"Direction = \" + round(base + 2 - delta1 / delta2, 6)\n\t\tend if\n\tend if\n\tprint \"Distance = \" + round(sqrt(delta1 ^ 2 + delta2 ^ 2), 6)\nend function\n\ngetYesNo = function(prompt)\n\twhile true\n\t\tans = input(prompt + \"? \").lower + \" \"\n\t\tif ans[0] == \"y\" then return \"yes\"\n\t\tif ans[0] == \"n\" then return \"no\"\n\t\tprint \"Please answer Yes or No.\"\n\tend while\nend function\n\ngetXY = function(prompt)\n\twhile true\n\t\tans = input(prompt + \"? \").split(\",\")\n\t\tif ans.len == 2 then return {\"x\":ans[0].val, \"y\":ans[1].val}\n\t\tprint \"Please enter two numbers separated by a comma.  Example: 5,2\"\n\tend while\nend function\n\nstring.padBoth = function(length, padChar=\" \")\n\t// Pad a string on BOTH sides, so that it ends up centered.\n\tif self.len > length then return self.len[:length]\n\textra = length - self.len\n\tleftExtra = floor(extra/2)\n\trightExtra = extra - leftExtra\n\treturn padChar * leftExtra + self + padChar * rightExtra\nend function\n\n//=================================================================\n// Entity: map of strings used both as unique identifiers for\n// things that can be at any position in a quadrant, AND also used\n// as display strings in the short-range scan.\n//=================================================================\nEntity = {}\nEntity.klingon = \"+K+\"\nEntity.ship = \"<*>\"\nEntity.empty = \"   \"\nEntity.starbase = \">!<\"\nEntity.star = \" * \"\n\n//=================================================================\n// Point class: represents an X,Y position.  Note that because\n// the original game used 1-based coordinates, we have a conversion\n// to string method that adds 1 to X and Y.  But internally, these\n// are assumed to be 0-based.\n//=================================================================\nPoint = {}\nPoint.make = function(x,y)\n\tp = new Point\n\tp.x = x\n\tp.y = y\n\treturn p\nend function\nPoint.random = function\n\treturn Point.make(fnr, fnr)\nend function\nPoint.oneBasedStr = function\n\treturn (self.x + 1) + \" , \" + (self.y + 1)\nend function\n\n//=================================================================\n// Position: combination of quadrant and sector\n//=================================================================\nPosition = {}\nPosition.make = function(quadX, quadY, secX, secY)\n\tpos = new Position\n\tpos.quadrant = Point.make(quadX, quadY)\n\tpos.sector = Point.make(secX, secY)\n\treturn pos\nend function\nPosition.random = function\n\treturn Position.make(fnr, fnr, fnr, fnr)\nend function\n\n//=================================================================\n// Quadrant: represents one area of the map\n//=================================================================\nQuadrant = {}\nQuadrant.make = function(quadrantX, quadrantY, klingons, bases, stars)\n\tq = new Quadrant\n\tq.point = Point.make(quadrantX, quadrantY)\n\tq.klingons = klingons\n\tq.bases = bases\n\tq.stars = stars\n\tq.extraRepairTime = rnd * 0.5\n\tq.klingonShips = []\t// (list of KlingonShip)\n\tq.starbase = null\t// (Point of starbase, if any)\n\tq.charted = false\n\tq.data = null\n\treturn q\nend function\n\n// Get the name of the region of this quadrant (e.g. \"Rigel\").\nQuadrant.name = function\n\tregion1 = [\n\t\t\"Antares\",\n\t\t\"Rigel\",\n\t\t\"Procyon\",\n\t\t\"Vega\",\n\t\t\"Canopus\",\n\t\t\"Altair\",\n\t\t\"Sagittarius\",\n\t\t\"Pollux\"]\n\tregion2 = [\n\t\t\"Sirius\",\n\t\t\"Deneb\",\n\t\t\"Capella\",\n\t\t\"Betelgeuse\",\n\t\t\"Aldebaran\",\n\t\t\"Regulus\",\n\t\t\"Arcturus\",\n\t\t\"Spica\"]\n\tif self.point.y < 4 then return region1[self.point.x]\n\treturn region2[self.point.x]\nend function\n\n// Get the full name of this quadrant (e.g. \"Rigel IV\")\nQuadrant.fullName = function\n\treturn self.name + \" \" + [\"I\", \"II\", \"III\", \"IV\"][self.point.y % 4]\nend function\n\n// Store the given entity for the given cell in this quadrant\n// (rounding to the nearest integer coordinates).\nQuadrant.setValue = function(x, y, entity)\n\tself.data[round(x)][round(y)] = entity\nend function\n\n// Get the entity in the given cell of this quadrant\n// (again rounding to the nearest integers).\nQuadrant.value = function(x, y)\n\treturn self.data[round(x)][round(y)]\nend function\n\n// Find an empty position within this quadrant.\nQuadrant.findEmptyPoint = function\n\twhile true\n\t\tp = Point.random\n\t\tif self.value(p.x, p.y) == Entity.empty then return p\n\tend while\nend function\n\nQuadrant.addStarbase = function\n\tpos = self.findEmptyPoint\n\tself.setValue pos.x, pos.y, Entity.starbase\n\tself.starbase = pos\t// (note: assumes 0 or 1 starbases)\nend function\n\n// Fill out the contents of this quadrant, given the position of\n// the ship and our number of klingons, bases, and stars.\nQuadrant.populate = function(shipPos)\n\tself.data = list.init2d(8, 8, Entity.empty)\n\tif shipPos != null then self.setValue shipPos.x, shipPos.y, Entity.ship\n\tfor i in range(0, self.klingons-1, 1)\n\t\tpos = self.findEmptyPoint\n\t\tself.setValue pos.x, pos.y, Entity.klingon\n\t\tself.klingonShips.push KlingonShip.make(pos.x, pos.y)\n\tend for\n\tif self.bases > 0 then self.addStarbase\n\tfor i in range(0, self.stars-1, 1)\n\t\tpos = self.findEmptyPoint\n\t\tself.setValue pos.x, pos.y, Entity.star\n\tend for\nend function\n\n// Return the three-digit number that represents the contents of \n// this quadrant in a long-range scan: <klingons><bases><stars>\nQuadrant.lrsValue = function\n\treturn str(self.klingons) + str(self.bases) + str(self.stars)\nend function\n\n// Return a list of lines representing the short-range scan\n// of this quadrant (i.e., a representation of what entities\n// it contains).\nQuadrant.scanLines = function\n\tresult = []\n\tfor row in self.data\n\t\tresult.push row.join\n\tend for\n\treturn result\nend function\n\n//=================================================================\n// KlingonShip: represents an enemy ship.  These are very simple;\n// they need only their position (sector) within the quadrant,\n// and their current shield level.\n//=================================================================\nKlingonShip = {}\nKlingonShip.make = function(x, y)\n\tk = new KlingonShip\n\tk.sector = Point.make(x,y)\n\tk.shield = Constant.klingonShieldStrength * (rnd + 0.5)\n\treturn k\nend function\nKlingonShip.distance = function(ship)\n\t// Find distance, in sector units, between this ship and the given\n\t// (player) ship.  Assumes both are in the same quadrant.\n\treturn mathUtil.distance(self.sector, ship.position.sector)\nend function\n\t\n//=================================================================\n// Ship: represents the starship Enterprise and all its systems.\n//=================================================================\nShip = {}\nShip.maxEnergy = Constant.maxEnergy\nShip.maxTorpedos = Constant.maxTorpedos\nShip.init = function\n\tself.position = Position.random\n\tself.devices = [\n\t\t\"Warp Engines\",\n\t\t\"Short Range Sensors\",\n\t\t\"Long Range Sensors\",\n\t\t\"Phaser Control\",\n\t\t\"Photon Tubes\",\n\t\t\"Damage Control\",\n\t\t\"Shield Control\",\n\t\t\"Library-Computer\",\n\t]\n\tself.deviceStatus = [0] * self.devices.len  // > 0 means working; < 0 means broken\n\tself.docked = false\n\tself.shields = 0\n\tself.refill\nend function\n\nShip.useWarpEnergy = function(warpRounds)\n\t// Note: movement costs 10 energy per sub-step (sector change).\n\tself.energy -= warpRounds * 10\n\tif self.energy < 0 then\n\t\tprint \"Shield control supplies energy to complete the maneuver.\"\n\t\tself.shields += self.energy\n\t\tself.energy = 0\n\t\tif self.shields < 0 then self.shields = 0\n\tend if\nend function\n\nShip.refill = function\n\tself.energy = self.maxEnergy\n\tself.torpedos = self.maxTorpedos\nend function\n\nShip.stranded = function\n\treturn self.shields + self.energy <= 10 or\n\t  (self.energy <= 10 and self.deviceStatus[6] < 0)\nend function\n\n//=================================================================\n// Galaxy: all 64 quadrants, plus global information about how many\n// klingons there are, the current game time, etc.  Basically \n// represents the state of the game (but not the flow; that happens\n// in the Game class).\n//=================================================================\nGalaxy = {}\nGalaxy.init = function(minDuration=20)\n\tself.qtyKlingons = 0\n\tself.qtyBases = 0\n\tself.startDate = 100 * randInt(20, 39)\n\tself.endDate = self.startDate + randInt(Constant.minDays, Constant.maxDays)\n\tself.stardate = self.startDate\n\tself.ship = new Ship\n\tself.ship.init\n\tself.quadrants = list.init2d(8, 8)\n\tfor x in range(0, 7)\n\t\tfor y in range(0, 7)\n\t\t\tklingons = 0\n\t\t\tr1 = rnd\n\t\t\tif r1 > 0.80 then klingons = 1\n\t\t\tif r1 > 0.95 then klingons = 2\n\t\t\tif r1 > 0.98 then klingons = 3\n\t\t\tbases = (rnd > 0.96)\n\t\t\tself.quadrants[x][y] = Quadrant.make(x, y, klingons, bases, fnr+1)\n\t\t\tself.qtyKlingons += klingons\n\t\t\tself.qtyBases += bases\n\t\tend for\n\tend for\n\tself.missionDuration = minDuration\n\tif self.qtyKlingons > self.missionDuration then\n\t\tself.missionDuration = self.qtyKlingons + 1\n\tend if\n\there = self.localQuadrant\n\tif self.qtyBases == 0 then self.qtyBases = 1\n\tself.ship.position.sector = Point.random\nend function\n\nGalaxy.daysElapsed = function; return self.stardate - self.startDate; end function\nGalaxy.daysLeft = function; return self.endDate - self.stardate; end function\nGalaxy.missionOver = function; return self.stardate > self.endDate; end function\n\nGalaxy.localQuadrant = function\n\tqp = self.ship.position.quadrant\n\treturn self.quadrants[qp.x][qp.y]\nend function\n\nGalaxy.printLongRangeScan = function(point)\n\tsep = \"-\" * 19\n\tfor x in range(point.x - 1, point.x + 1)\n\t\tprint sep\n\t\tentries = []\n\t\tfor y in range(point.y - 1, point.y + 1)\n\t\t\tif not (0 <= x <= 7 and 0 <= y <= 7) then\n\t\t\t\tentries.push \"***\"\n\t\t\telse\n\t\t\t\tq = self.quadrants[x][y]\n\t\t\t\tentries.push q.lrsValue\n\t\t\t\tq.charted = true\n\t\t\tend if\n\t\tend for\n\t\tprint \": \" + entries.join(\" : \") + \" :\"\n\tend for\n\tprint sep\nend function\n\n//=================================================================\n// Game: represents the flow of the game, and handles user actions.\n//=================================================================\nGame = {}\nGame.init = function\n\tself.galaxy = new Galaxy\n\tself.galaxy.init\n\tself.gameOver = false\nend function\n\nGame.printIntro = function\n\tprint;print;print;print;print;print;print;print;print;print;print\n\tprint \"                                    ,------*------,\"\n\tprint \"                    ,-------------   '---  ------'\"\n\tprint \"                     '-------- --'      / /\"\n\tprint \"                         ,---' '-------/ /--,\"\n\tprint \"                          '----------------'\";print\n\tprint \"                    THE USS ENTERPRISE --- NCC-1701\"\n\tprint;print;print;print;print\n\tk = self.galaxy.qtyKlingons\n\tsb = self.galaxy.qtyBases\n\tif sb == 1 then isAre = \"is\" else isAre = \"are\"\n\tdays = self.galaxy.endDate - self.galaxy.startDate\n\torders = [\"Your orders are as follows:\"]\n\torders.push \"     Destroy the \" + k + \" Klingon warships which have invaded\"\n\torders.push \"   the galaxy before they can attack federation headquarters\"\n\torders.push \"   on stardate \" + self.galaxy.endDate + \".  This gives you \" + \n\t   days + \" days.  There \" + isAre\n \torders.push \"   \" + sb + \" starbase\" + \"s\"*(sb!=1) + \" in the galaxy for resupplying your ship.\"\n \tfor line in orders\n \t\tprint line\t\t// for extra drama, add a `wait 0.5` line here!\n \tend for\n \tprint\n \tinput \"Press Return when ready to accept command\"\n \tprint\n \tself.enterQuadrant\nend function\n\nGame.enterQuadrant = function\n\t// Populate the local quadrant and print a short-range scan.\n\tship = self.galaxy.ship\n\there = self.galaxy.localQuadrant\n\there.charted = true\n\there.populate ship.position.sector\n\t\n\tif self.galaxy.daysElapsed == 0 then\n\t\tprint \"Your mission begins with your ship located\"\n\t\tprint \"in the galactic quadrant, '\" + here.fullName + \"'\"\n\telse\n\t\tprint \"Now entering \" + here.fullName + \" quadrant . . .\"\n\tend if\n\tprint\n\n\tif here.klingons > 0 then\n\t\tprint \"COMBAT AREA      CONDITION RED\"\n\t\tif ship.shields <= 200 then print \"   SHIELDS DANGEROUSLY LOW\"\n\tend if\n\tself.shortRangeScan\nend function\n\nGame.shortRangeScan = function\n\tship = self.galaxy.ship\n\tship.docked = false\n\tquad = self.galaxy.localQuadrant\n\tcs = null\n\tfor x in range(ship.position.sector.x - 1, ship.position.sector.x + 1)\n\t\tfor y in range(ship.position.sector.y - 1, ship.position.sector.y + 1)\n\t\t\tif 0 <= x <= 7 and 0 <= y <= 7 and quad.value(x, y) == Entity.starbase then\n\t\t\t\tship.docked = true\n\t\t\t\tcs = \"DOCKED\"\n\t\t\t\tship.refill\n\t\t\t\tprint \"Shields dropped for docking purposes\"\n\t\t\t\tship.shields = 0\n\t\t\tend if\n\t\tend for\n\tend for\n\tif not cs then\n\t\tif quad.klingons then\n\t\t\tcs = \"*RED*\"\n\t\telse if ship.energy < ship.maxEnergy * 0.1 then\n\t\t\tcs = \"*YELLOW*\"\n\t\telse\n\t\t\tcs = \"GREEN\"\n\t\tend if\n\tend if\n\tif ship.deviceStatus[1] < 0 then\n\t\tprint\n\t\tprint \"*** Short range sensors are out ***\"\n\t\treturn\n\tend if\n\tprint \"-\"*33\n\tfor x in range(0, 7)\n\t\tline = quad.data[x].join\n\t\tif x == 0 then\n\t\t\tline += \"        STARDATE           \" + round(self.galaxy.stardate, 1)\n\t\telse if x == 1 then\n\t\t\tline += \"        CONDITION          \" + cs\n\t\telse if x == 2 then\n\t\t\tline += \"        QUADRANT           \" + ship.position.quadrant.oneBasedStr\n\t\telse if x == 3 then\n\t\t\tline += \"        SECTOR             \" + ship.position.sector.oneBasedStr\n\t\telse if x == 4 then\n\t\t\tline += \"        PHOTON TORPEDOES   \" + ship.torpedos\n\t\telse if x == 5 then\n\t\t\tline += \"        TOTAL ENERGY       \" + floor(ship.energy + ship.shields)\n\t\telse if x == 6 then\n\t\t\tline += \"        SHIELDS            \" + floor(ship.shields)\n\t\telse if x == 7 then\n\t\t\tline += \"        KLINGONS REMAINING \" + self.galaxy.qtyKlingons\n\t\tend if\n\t\tprint line\n\tend for\n\tprint \"-\"*33\nend function\n\nGame.longRangeScan = function\n\tship = self.galaxy.ship\n\tif ship.deviceStatus[2] < 0 then\n\t\tprint \"Long range sensors are inoperable\"\n\t\treturn\n\tend if\n\tprint \"Long range scan for quadrant \" + ship.position.quadrant.oneBasedStr\n\tself.galaxy.printLongRangeScan ship.position.quadrant\nend function\n\nGame.updateKlingons = function\n\t// Move klingons around randomly within the sector\n\there = self.galaxy.localQuadrant\n\tif not here.klingonShips then return\n\t\n\tfor klingonShip in here.klingonShips\n\t\tif klingonShip.shield <= 0 then continue\t// (already disabled/destroyed)\n\t\there.setValue klingonShip.sector.x, klingonShip.sector.y, Entity.empty\n\t\tklingonShip.sector = here.findEmptyPoint\n\t\there.setValue klingonShip.sector.x, klingonShip.sector.y, Entity.klingon\n\tend for\n\t\n\tself.klingonsFire\nend function\n\nGame.klingonsFire = function\n\t// Nearby klingons fire on the player ship.\n\there = self.galaxy.localQuadrant\n\tif here.klingons <= 0 then return\n\tship = self.galaxy.ship\n\tif ship.docked then\n\t\tprint \"Starbase shields protect the Enterprise\"\n\t\treturn\n\tend if\n\tfor klingonShip in here.klingonShips\n\t\tif klingonShip.shield <= 0 then continue\t// (already disabled/destroyed)\n\t\thit = floor((klingonShip.shield / klingonShip.distance(ship)) * (rnd + 2))\n\t\tship.shields -= hit\n\t\tprint \" \" + hit + \" unit hit on Enterprise from sector \" + klingonShip.sector.oneBasedStr\n\t\tif ship.shields <= 0 then\n\t\t\tself.endGame false, false, true\n\t\t\treturn\n\t\tend if\n\t\tprint \"      <Shields down to \" + ship.shields + \" units>\"\n\t\tif hit >= 20 and rnd < 0.60 and hit / ship.shields > 0.02 then\n\t\t\tdeviceNum = floor(rnd * ship.devices.len)\n\t\t\tship.deviceStatus[deviceNum] -= hit / ship.shields + 0.5 * rnd\n\t\t\tprint \"Damage control reports  '\" + ship.devices[deviceNum] + \" damaged by the hit'\"\n\t\tend if\n\tend for\t\nend function\n\nGame.damControlWhileUnderway = function(improvement=1)\n\t// Work on repairing damaged devices, and 20% of the time, do additional work on \n\t// some random device (which may make it better or worse).\n\tship = self.galaxy.ship\n\tfirst = true\n\tfor i in range(0, ship.devices.len-1)\n\t\tif ship.deviceStatus[i] >= 0 then continue\n\t\tship.deviceStatus[i] += improvement\n\t\tif -0.1 < ship.deviceStatus[i] < 0 then ship.deviceStatus[i] = -0.1\n\t\tif ship.deviceStatus[i] >= 0 then\n\t\t\tif first then s = \"Damage control report:\" else s = \"\"\n\t\t\ts += \"   \" + ship.devices[i] + \" repair completed\"\n\t\t\tprint s\n\t\t\tfirst = false\n\t\tend if\n\tend for\n\t\n\tif rnd > 0.2 then return\n\tdeviceNum = floor(rnd * ship.devices.len)\n\tif rnd < 0.6 then\n\t\tship.deviceStatus[deviceNum] -= rnd * 5 + 1\n\t\tprint \"Damage control report:   \" + ship.devices[deviceNum] + \" damaged\"\n\telse\n\t\tship.deviceStatus[deviceNum] += rnd * 3 + 1\n\t\tprint \"Damage control report:   \" + ship.devices[deviceNum] + \" state of repair improved\"\n\tend if\nend function\t\n\nGame.navigate = function\n\tgalaxy = self.galaxy\n\tship = galaxy.ship\n\tcd = input(\"Course (1-9)? \").val - 1\t// (convert input to 0-8)\n\tif cd == dirs.len - 1 then cd == 0\n\tif cd < 0 or cd >= dirs.len then\n\t\tprint \"   Lt. Sulu reports, 'Incorrect course data, sir!'\"\n\t\treturn\n\tend if\n\t\n\tif ship.deviceStatus[0] < 0 then maxWarp = 0.2 else maxWarp = 8\n\twarp = input(\"Warp factor (0-\" + maxWarp + \")? \").val\n\tif warp > maxWarp and maxWarp < 1 then\n\t\tprint \"Warp engines are damaged. Maximum speed = warp \" + maxWarp\n\t\treturn\n\tend if\n\tif warp == 0 then return\n\tif warp < 0 or warp > 8 then\n\t\tprint \"   Chief engineer Scott reports 'The engines won't take warp \" + warp + \"!'\"\n\t\treturn\n\tend if\n\t\n\twarpRounds = round(warp * 8)\n\t// Note that we check for sufficient energy based on 1/10th of what it\n\t// will actually cost.  This is apparently intentional.\n\tif ship.energy < warpRounds then\n\t\tprint \"Engineering reports   'Insufficient energy available\"\n\t\tprint \"                       for maneuvering at warp \" + warp + \"!'\"\n\t\tif ship.shields >= warpRounds - ship.energy and ship.deviceStatus[6] >= 0 then\n\t\t\tprint \"Deflector control room acknowledges \" + ship.shields + \" units of energy\"\n\t\t\tprint \"                         presently deployed to shields.\"\n\t\tend if\n\t\treturn\n\tend if\n\t\n\tself.updateKlingons\n\tself.damControlWhileUnderway\n\t\n\there = galaxy.localQuadrant\n\there.setValue ship.position.sector.x, ship.position.sector.y, Entity.empty\n\tstartQuad = Point.make(here.point.x, here.point.y)\n//\tprint \"DEBUG set value at \" + ship.position.sector.x + \",\" + ship.position.sector.y + \" to Entity.empty\"\n\t// interpolate the direction\n\tcdi = floor(cd)\n\tdx = mathUtil.lerp(dirs[cdi][0], dirs[cdi+1][0], cd - cdi)\n\tdy = mathUtil.lerp(dirs[cdi][1], dirs[cdi+1][1], cd - cdi)\n\tfinalGlobalX = ship.position.quadrant.x * 8 + ship.position.sector.x + dx * warpRounds\n\tfinalGlobalY = ship.position.quadrant.y * 8 + ship.position.sector.y + dy * warpRounds\n\tfor i in range(1, warpRounds)\n\t\tship.position.sector.x += dx\n\t\tship.position.sector.y += dy\n\t\tif not (0 <= ship.position.sector.x <= 7 and 0 <= ship.position.sector.y <= 7) then\n\t\t\t// Exceeded quadrant limits; calculate final position.\n\t\t\t// Note that we randomly re-generate all the stuff in a quadrant every\n\t\t\t// time we enter it.  So we can jump right to the final position now;\n\t\t\t// We only check for collisions when moving *within* your starting sector.\n\t\t\t// your starting sector.\n\t\t\tship.position.quadrant.x = floor(finalGlobalX / 8)\n\t\t\tship.position.quadrant.y = floor(finalGlobalY / 8)\n\t\t\tship.position.sector.x = finalGlobalX  - ship.position.quadrant.x * 8\n\t\t\tship.position.sector.y = finalGlobalY  - ship.position.quadrant.y * 8\n\t\t\thitEdge = false\n\t\t\tif ship.position.quadrant.x < 0 then\n\t\t\t\thitEdge = true\n\t\t\t\tship.position.quadrant.x = 0\n\t\t\t\tship.position.sector.x = 0\n\t\t\telse if ship.position.quadrant.x > 7 then\n\t\t\t\thitEdge = true\n\t\t\t\tship.position.quadrant.x = 7\n\t\t\t\tship.position.sector.x = 7\n\t\t\tend if\n\t\t\tif ship.position.quadrant.y < 0 then\n\t\t\t\thitEdge = true\n\t\t\t\tship.position.quadrant.y = 0\n\t\t\t\tship.position.sector.y = 0\n\t\t\telse if ship.position.quadrant.y > 7 then\n\t\t\t\thitEdge = true\n\t\t\t\tship.position.quadrant.y = 7\n\t\t\t\tship.position.sector.y = 7\n\t\t\tend if\n\t\t\tif hitEdge then\n\t\t\t\tprint \"Lt. Uhura reports message from Starfleet Command:\"\n\t\t\t\tprint \"  'Permission to attempt crossing of galactic perimeter\"\n\t\t\t\tprint \"  is hereby *denied*. Shut down your engines.'\"\n\t\t\t\tprint \"Chief Engineer Scott reports  'Warp engines shut down\"\n\t\t\t\tprint \"  at sector \" + ship.position.sector.oneBasedStr + \n\t\t\t\t  \" of quadrant \" + ship.position.quadrant.oneBasedStr + \".'\"\n\t\t\tend if\n\t\t\tbreak\n\t\tend if\n\t\tx = floor(ship.position.sector.x)\n\t\ty = floor(ship.position.sector.y)\n\t\tif here.value(x, y) != Entity.empty then\n\t\t\tship.position.sector.x = floor(x - dx)\n\t\t\tship.position.sector.y = floor(y - dy)\n\t\t\tprint \"Warp engines shut down at sector \" + ship.position.sector.oneBasedStr +\n\t\t\t  \" due to bad navigation\"\n\t\t\tbreak\n\t\tend if\n\tend for\n\tship.position.sector.x = floor(ship.position.sector.x)\n\tship.position.sector.y = floor(ship.position.sector.y)\n\tdoScan = true\n\tif ship.position.quadrant != startQuad then\n\t\tself.enterQuadrant\n\t\tdoScan = false\n\telse\n\t\there.setValue ship.position.sector.x, ship.position.sector.y, Entity.ship\n//\t\tprint \"DEBUG set value at \" + ship.position.sector.x + \",\" + ship.position.sector.y + \" to Entity.ship\"\n\tend if\n\tship.useWarpEnergy warpRounds\n\tif warp < 1 then galaxy.stardate += round(warp, 1) else galaxy.stardate += 1\n\tif galaxy.missionOver then\n\t\tself.endGame false, false, false\n\telse if doScan then\n\t\tself.shortRangeScan\n\tend if\nend function\n\nGame.damageControl = function\n\tship = self.galaxy.ship\n\tif ship.deviceStatus[5] < 0 then\n\t\tprint \"Damage control report not available.\"\n\telse\n\t\tprint\n\t\tprint \"DEVICE             STATE OF REPAIR\"\n\t\tfor i in range(0, ship.devices.len-1)\n\t\t\tprint ship.devices[i].pad(26) + round(ship.deviceStatus[i], 2)\n\t\tend for\n\t\tprint\n\tend if\n\n\tif not ship.docked then return\n\t\n\trepairTime = 0\n\tfor status in ship.deviceStatus\n\t\tif status < 0 then repairTime += 0.1\n\tend for\n\tif repairTime == 0 then return\n\t\n\trepairTime += self.galaxy.localQuadrant.extraRepairTime\n\tif repairTime >= 1 then repairTime = 0.9\n\tprint\n\tprint \"Technicians standing by to effect repairs to your ship;\"\n\tprint \"estimated time to repair: \" + round(repairTime, 2) + \" stardates\"\n\tif getYesNo(\"Will you authorize the repair order (Y/N)\") == \"no\" then return\n\t\n\tfor i in range(0, ship.devices.len-1)\n\t\tif ship.deviceStatus[i] < 0 then ship.deviceStatus[i] = 0\n\tend for\n\tself.galaxy.stardate += repairTime + 0.1\nend function\n\nGame.shieldControl = function\n\tship = self.galaxy.ship\n\tif ship.deviceStatus[6] < 0 then\n\t\tprint \"Shield control inoperable\"\n\t\treturn\n\tend if\n\ttotalEnergy = ship.energy + ship.shields\n\tshieldEnergy = input(\"Energy available = \" + totalEnergy + \"  Number of units to shields? \")\n\tif shieldEnergy == \"\" then shieldEnergy = ship.shields else shieldEnergy = shieldEnergy.val\n\tif shieldEnergy > totalEnergy then\n\t\tprint \"Shield control reports  'This is not the federation treasury.'\"\n\t\tprint\n\t\tshieldEnergy = -1\n\tend if\n\tif shieldEnergy < 0 or shieldEnergy == ship.shields then\n\t\tprint \"<Shields unchanged>\"\n\t\treturn\n\tend if\n\tship.energy += ship.shields - shieldEnergy\n\tship.shields = shieldEnergy\n\tprint \"Deflector control room report:\"\n\tprint \"  'Shields now at \" + ship.shields + \" units per your command.'\"\nend function\n\nGame.computer = function\n\tgalaxy = self.galaxy\n\tship = galaxy.ship\n\tif ship.deviceStatus[7] < 0 then\n\t\tprint \"Computer disabled\"\n\t\treturn\n\tend if\n\t\n\twhile true\n\t\tcommand = input(\"Computer active and awaiting command? \")\n\t\tprint\n\t\tif command == \"0\" then\t// Cumulative Galactic Record\n\t\t\tprint\n\t\t\tprint \"        COMPUTER RECORD OF GALAXY FOR QUADRANT \" + \n\t\t\t  ship.position.quadrant.oneBasedStr\n\t\t\tprint \"       1     2     3     4     5     6     7     8\"\n\t\t\tsep = \"     ----- ----- ----- ----- ----- ----- ----- -----\"\n\t\t\tprint sep\n\t\t\tfor i in range(0,7)\n\t\t\t\tline = \" \" + (i+1) + \" \"\n\t\t\t\tfor j in range(0, 7)\n\t\t\t\t\tline += \"   \"\n\t\t\t\t\tif galaxy.quadrants[i][j].charted then\n\t\t\t\t\t\tline += galaxy.quadrants[i][j].lrsValue\n\t\t\t\t\telse\n\t\t\t\t\t\tline += \"***\"\n\t\t\t\t\tend if\n\t\t\t\tend for\n\t\t\t\tprint line\n\t\t\t\tprint sep\n\t\t\tend for\n\t\telse if command == \"1\" then\t// Status Report\n\t\t\tprint \"   STATUS REPORT:\"\n\t\t\tprint \"Klingon\" + \"s\" * (galaxy.qtyKlingons != 1) + \" left: \" + galaxy.qtyKlingons\n\t\t\tprint \"Mission must be completed in \" + round(galaxy.daysLeft, 1) + \" stardates\"\n\n\t\t\tif galaxy.qtyBases == 0 then\n\t\t\t\tprint \"Your stupidity has left you on your own in\"\n\t\t\t\tprint \"  the galaxy -- you have no starbases left!\"\n\t\t\telse\n\t\t\t\tprint \"The Federation is maintaining \" + galaxy.qtyBases +\n\t\t\t     \" starbase\" + \"s\" * (galaxy.qtyBases != 1) + \" in the galaxy\"\n\t\t\tend if\n\n\t\t\tself.damageControl\n\t\telse if command == \"2\" then\t// Photon Torpedo Data\n\t\t\there = galaxy.localQuadrant\n\t\t\tif here.klingons <= 0 then\n\t\t\t\tprint \"Science officer Spock reports  'Sensors show no enemy ships\"\n\t\t\t\tprint \"                                in this quadrant'\"\n\t\t\telse\n\t\t\t\tprint \"FROM ENTERPRISE TO KLINGON BATTLE CRUISER\" + \"S\" * (here.klingons != 1)\n\t\t\t\tfor klingonShip in here.klingonShips\n\t\t\t\t\tif klingonShip.shield <= 0 then continue\n\t\t\t\t\tprintDirection ship.position.sector, klingonShip.sector\n\t\t\t\tend for\n\t\t\tend if\n\t\telse if command == \"3\" then\t// Starbase Nav Data\n\t\t\there = galaxy.localQuadrant\n\t\t\tif not here.starbase then\n\t\t\t\tprint \"Science officer Spock reports,  'Sensors show no starbases\"\n\t\t\t\tprint \"                                 in this quadrant.'\"\n\t\t\telse\n\t\t\t\tprint \"FROM ENTERPRISE TO STARBASE:\"\n\t\t\t\tprintDirection ship.position.sector, here.starbase\n\t\t\tend if\n\t\telse if command == \"4\" then\t// Direction/Distance Calculator\n\t\t\tprint \"DIRECTION/DISTANCE CALCULATOR:\"\n\t\t\tprint \"You are at quadrant \" + ship.position.quadrant.oneBasedStr +\n\t\t\t  \" SECTOR \" + ship.position.sector.oneBasedStr\n\t\t\tprint \"Please enter\"\n\t\t\tfromXY = getXY(\"  Initial coordinates (X,Y)\")\n\t\t\ttoXY = getXY(\"  Final coordinates (X,Y)\")\n\t\t\tprintDirection fromXY, toXY\n\t\telse if command == \"5\" then\t// Galaxy 'Region Name' Map\n\t\t\tprint\n\t\t\tprint \"                       THE GALAXY\"\n\t\t\tprint \"       1     2     3     4     5     6     7     8\"\n\t\t\tsep = \"     ----- ----- ----- ----- ----- ----- ----- -----\"\n\t\t\tprint sep\n\t\t\tfor i in range(0,7)\n\t\t\t\tline = \" \" + (i+1) + \" \"\n\t\t\t\tline += galaxy.quadrants[i][0].name.padBoth(25)\n\t\t\t\tline += galaxy.quadrants[i][4].name.padBoth(25)\n\t\t\t\tprint line\n\t\t\t\tprint sep\n\t\t\tend for\n\t\telse\n\t\t\tprint \"Functions available from Library-Computer:\"\n\t\t\tprint \"   0 = Cumulative Galactic Record\"\n\t\t\tprint \"   1 = Status Report\"\n\t\t\tprint \"   2 = Photon Torpedo Data\"\n\t\t\tprint \"   3 = Starbase Nav Data\"\n\t\t\tprint \"   4 = Direction/Distance Calculator\"\n\t\t\tprint \"   5 = Galaxy 'Region Name' Map\"\n\t\t\tcontinue\n\t\tend if\n\t\tprint\n\t\tbreak\t// break out after any valid command\n\tend while\nend function\n\nGame.destroyKlingon = function(x, y)\n\t// Destroy the Klingon in the local quadrant at sector x,y.\n\t// Return true if the game is now won (last klingon destroyed),\n\t// or false otherwise.\n\tgalaxy = self.galaxy\n\there = galaxy.localQuadrant\n\tprint \"*** KLINGON DESTROYED ***\"\n\tgalaxy.qtyKlingons -= 1\n\there.klingons -= 1\n\there.setValue x, y, Entity.empty\n\tfor i in here.klingonShips.indexes\n\t\tks = here.klingonShips[i]\n\t\tif ks.sector.x == x and ks.sector.y == y then\n\t\t\tks.shield = 0\n\t\t\there.klingonShips.remove i\n\t\t\tbreak\n\t\tend if\n\tend for\n\t\t\n\tif galaxy.qtyKlingons <= 0 then\n\t\tself.endGame true, false, false\n\t\treturn true\n\tend if\n\treturn false\nend function\n\n\nGame.phasers = function\n\tgalaxy = self.galaxy\n\tship = galaxy.ship\n\there = galaxy.localQuadrant\n\tklingonShips = here.klingonShips\n\t\n\tif ship.deviceStatus[3] < 0 then\n\t\tprint \"Phasers inoperative\"\n\t\treturn\n\tend if\n\t\n\tif here.klingons <= 0 then\n\t\tprint \"Science officer Spock reports  'Sensors show no enemy ships\"\n\t\tprint \"                                in this quadrant'\"\n\t\treturn\n\tend if\n\t\n\tif ship.deviceStatus[7] < 0 then\n\t\tprint \"Computer failure hampers accuracy\"\n\tend if\n\t\n\tprint \"Phasers locked on target;  energy available = \" + ship.energy + \" units\"\n\twhile true\n\t\tphaserPower = input(\"Number of units to fire? \").val\n\t\tif phaserPower <= 0 then return\n\t\tif phaserPower <= ship.energy then break\n\t\tprint \"Energy available = \" + ship.energy + \" units\"\n\tend while\n\t\n\tship.energy -= phaserPower\n\tif ship.deviceStatus[7] < 0 then\t\t// (bug in original; was d(6)\n\t\tphaserPower *= rnd\n\tend if\n\t\n\tphaserPerKlingon = floor(phaserPower / here.klingons)\n\tfor i in range(klingonShips.len - 1)\n\t\tks = klingonShips[i]\n\t\tif ks.shield <= 0 then continue\n\t\tdistance = mathUtil.distance(ks.sector, ship.position.sector)\n\t\thit = floor((phaserPerKlingon / distance) * (rnd + 2))\n\t\tif hit <= 0.15 * ks.shield then\n\t\t\tprint \"Sensors show no damage to enemy at \" + ks.sector.oneBasedStr\n\t\telse\n\t\t\tks.shield -= hit\n\t\t\tprint \" \" + hit + \" unit hit on Klingon at sector \" + ks.sector.oneBasedStr\n\t\t\tif ks.shield <= 0 then\n\t\t\t\tif self.destroyKlingon(ks.sector.x, ks.sector.y) then return\n\t\t\telse\n\t\t\t\tprint \"   (Sensors show \" + round(ks.shield, 6) + \" units remaining)\"\n\t\t\tend if\n\t\tend if\t\t\t\n\tend for\n\t\n\tself.klingonsFire\nend function\n\nGame.torpedos = function\n\tgalaxy = self.galaxy\n\tship = galaxy.ship\n\there = galaxy.localQuadrant\n\tklingonShips = here.klingonShips\n\t\n\tif ship.torpedos <= 0 then\n\t\tprint \"All photon torpedos expended\"\n\t\treturn\n\telse if ship.deviceStatus[4] < 0 then\n\t\tprint \"Photon tubes are not operational\"\n\t\treturn\n\tend if\n\t\n\tcd = input(\"Course (1-9)? \").val - 1\t// (convert input to 0-8)\n\tif cd == dirs.len - 1 then cd == 0\n\tif cd < 0 or cd >= dirs.len then\n\t\tprint \"   Lt. Sulu reports, 'Incorrect course data, sir!'\"\n\t\treturn\n\tend if\n\t\n\tcdi = floor(cd)\n\tdx = mathUtil.lerp(dirs[cdi][0], dirs[cdi+1][0], cd - cdi)\n\tdy = mathUtil.lerp(dirs[cdi][1], dirs[cdi+1][1], cd - cdi)\n\t\n\tship.energy -= 2\n\tship.torpedos -= 1\n\t\n\tx = ship.position.sector.x\n\ty = ship.position.sector.y\n\tprint \"Torpedo track:\"\n\twhile true\n\t\tx += dx\n\t\ty += dy\n\t\troundX = round(x); roundY = round(y)\n\t\tif not (0 <= roundX <= 7) or not (0 <= roundY <= 7) then\n\t\t\tprint \"Torpedo missed\"\n\t\t\tself.klingonsFire\n\t\t\treturn\n\t\tend if\n\t\tprint \"                \" + (roundX+1) + \" , \" + (roundY+1)\n\t\twait 0.5\t// (added for dramatic effect)\n\t\tentityHit = here.value(roundX, roundY)\n\t\tif entityHit != Entity.empty then break\n\tend while\n\t\n\tif entityHit == Entity.klingon then\n\t\tif self.destroyKlingon(roundX, roundY) then return\n\telse if entityHit == Entity.star then\n\t\tprint \"Star at \" + (roundX+1) + \" , \" + (roundY+1) + \" absorbed torpedo energy.\"\n\telse if entityHit == Entity.starbase then\n\t\tprint \"*** STARBASE DESTROYED ***\"\n\t\there.bases -= 1\n\t\there.setValue roundX, roundY, Entity.empty\n\t\tgalaxy.qtyBases -= 1\n\t\tif galaxy.qtyBases == 0 and galaxy.qtyKlingons <= galaxy.daysLeft then\n\t\t\t// (Note: bug in original code, compared qtyKlingons to \n\t\t\t// quantity daysLeft - missionDuration, which would always be a negative\n\t\t\t// number.  So this hard-labor message could never appear.  I've chosen\n\t\t\t// a different comparison which at least can be true sometimes.)\n\t\t\tprint \"That does it, captain!! You are hereby relieved of command\"\n\t\t\tprint \"and sentenced to 99 stardates at hard labor on Cygnus 12!!\"\n\t\t\tself.endGame false, false, false\n\t\t\treturn\n\t\tend if\n\t\tprint \"Starfleet Command reviewing your record to consider\"\n\t\tprint \"court martial!\"\n\t\tship.docked = false\n\tend if\n\t\n\tself.klingonsFire\t\nend function\n\nGame.endGame = function(won=false, quit=true, shipDestroyed=false)\n\tif won then\n\t\tprint \"Congratulations, captain! The last klingon battle cruiser\"\n\t\tprint \"menacing the federation has been destroyed.\"\n\t\tefficiency = round(1000 * self.galaxy.qtyKlingons / self.galaxy.daysElapsed^2, 4)\n\t\tprint \"Your efficiency rating is \" + efficiency\n\t\tprint\n\telse\n\t\tif not quit then\n\t\t\tif shipDestroyed then\n\t\t\t\tprint\n\t\t\t\tprint \"The enterprise has been destroyed. The Federation \"\n\t\t\t\tprint \"will be conquered.\"\n\t\t\tend if\n\t\t\tprint \"It is stardate \" + round(self.galaxy.stardate, 1)\n\t\tend if\n\n\t\tprint \"There were \" + self.galaxy.qtyKlingons + \" klingon battle cruisers left at\"\n\t\tprint \"the end of your mission.\"\n\t\tprint\n\tend if\n\tif self.galaxy.qtyBases == 0 then exit\n\tprint \"The Federation is in need of a new starship commander\"\n\tprint \"for a similar mission -- if there is a volunteer,\"\n\tif input(\"let him step forward and enter 'aye'? \").lower().trim != \"aye\" then exit\n\tself.gameOver = true\nend function\n\nnotImplemented = function\n\tprint\n\tprint \"Not implemented yet.\"\n\tprint\nend function\n\nGame.commands = []\t// each entry is [command, summary, function]\nGame.addCommand = function(command, summary, func)\n\tself.commands.push [command, summary, @func]\nend function\n\nGame.addCommand \"NAV\", \"to set course\", @Game.navigate\nGame.addCommand \"SRS\", \"for short range sensor scan\", @Game.shortRangeScan\nGame.addCommand \"LRS\", \"for long range sensor scan\", @Game.longRangeScan\nGame.addCommand \"PHA\", \"to fire phasers\", @Game.phasers\nGame.addCommand \"TOR\", \"to fire photon torpedos\", @Game.torpedos\nGame.addCommand \"SHE\", \"to raise or lower shields\", @Game.shieldControl\nGame.addCommand \"DAM\", \"for damage control reports\", @Game.damageControl\nGame.addCommand \"COM\", \"to call on library-computer\", @Game.computer\nGame.addCommand \"HLP\", \"for help, i.e. instructions\", @Instructions.print\t// (not in original game)\nGame.addCommand \"XXX\", \"to resign your command\", @Game.endGame\n\n\nGame.doOneCommand = function\n\tcmd = input(\"Command? \").upper\n\tfor entry in self.commands\n\t\tif cmd == entry[0] then\n\t\t\tself.curCmdFunc = entry[2]\n\t\t\tself.curCmdFunc\n\t\t\treturn\n\t\tend if\n\tend for\n\tprint \"Enter one of the following:\"\n\tfor entry in self.commands\n\t\tprint \"  \" + entry[0] + \"  (\" + entry[1] + \")\"\n\tend for\n\tprint\nend function\n\nGame.mainLoop = function\n\twhile not self.gameOver\t\t\n\t\tself.doOneCommand\n\t\tif self.galaxy.ship.stranded then\n\t\t\tprint\n\t\t\tprint \"** FATAL ERROR **   You've just stranded your ship in space.\"\n\t\t\tprint \"You have insufficient maneuvering energy, and shield control\"\n\t\t\tprint \"is presently incapable of cross-circuiting to engine room!!\"\n\t\tend if\n\tend while\nend function\n\nfor i in range(1,12); print; end for\nprint \" \"*10 + \"*************************************\"\nprint \" \"*10 + \"*                                   *\"\nprint \" \"*10 + \"*                                   *\"\nprint \" \"*10 + \"*      * * SUPER STAR TREK * *      *\"\nprint \" \"*10 + \"*                                   *\"\nprint \" \"*10 + \"*                                   *\"\nprint \" \"*10 + \"*************************************\"\nfor i in range(1,8); print; end for\nif getYesNo(\"Do you need instructions (y/n)\") == \"yes\" then\n\tInstructions.print\nend if\n\nwhile true\n\tgame = new Game\n\tgame.init\n\tgame.printIntro\n\tgame.mainLoop\nend while"
  },
  {
    "path": "00_Alternate_Languages/84_Super_Star_Trek/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/84_Super_Star_Trek/instructions.txt",
    "content": "\n\n\n\n\n\n\n\n\n\n*************************************\n*                                   *\n*                                   *\n*      * * SUPER STAR TREK * *      *\n*                                   *\n*                                   *\n*************************************\n\n\n\n\n\n\n\n\n      INSTRUCTIONS FOR 'SUPER STAR TREK'\n\n1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL\n     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\n2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\n     LIST OF THE LEGAL COMMANDS PRINTED OUT.\n3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\n     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\n     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\n     WILL BE ABORTED\n\n     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\nAND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\n\n     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\nGALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\n\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\nKLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\nPLANETS.\n\n     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\nOF THE STARSHIP ENTERPRISE:\n\n\\NAV\\ COMMAND = WARP ENGINE CONTROL --\n     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\n     VECTOR ARRANGEMENT AS SHOWN             . . .\n     INTEGER AND REAL VALUES MAY BE           ...\n     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\n     WAY BETWEEN 1 AND 2                      ...\n                                             . . .\n     VALUES MAY APPROACH 9.0, WHICH         6  7  8\n     ITSELF IS EQUIVALENT TO 1.0\"\n                                            COURSE\n     ONE WARP FACTOR IS THE SIZE OF\n     ONE QUADRANT.  THEREFORE, TO GET\n     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\n     USE COURSE 3, WARP FACTOR 1.\n\n\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN\n     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\n\n     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\n        <*> = YOUR STARSHIP'S POSITION\n        +K+ = KLINGON BATTLE CRUISER\n        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\n         *  = STAR\n\n     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\n\n\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN\n     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\n     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\n     THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT\n     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\n     STARBASES, AND THE HUNDREDS DIGIT IS THE NUMBER OF\n     KLINGONS.\n\n     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\n\n\\PHA\\ COMMAND = PHASER CONTROL.\n     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY\n     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\n     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE\n     PHASERS TOO!)\n\n\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL\n     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\n     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\n     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\n     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO\n     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\n\n     THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO\n     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\n\n\\SHE\\ COMMAND = SHIELD CONTROL\n     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\n     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\n     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\n\n\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT\n     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\n     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\n     DAMAGED.\n\n\\COM\\ COMMAND = LIBRARY-COMPUTER\n     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\n     OPTION 0 = CUMULATIVE GALACTIC RECORD\n        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\n        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\n     OPTION 1 = STATUS REPORT\n        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\n        AND STARBASES REMAINING IN THE GAME.\n     OPTION 2 = PHOTON TORPEDO DATA\n        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\n        TO ALL KLINGONS IN YOUR QUADRANT\n     OPTION 3 = STARBASE NAV DATA\n        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY\n        STARBASE WITHIN YOUR QUADRANT\n     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\n        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\n        DIRECTION/DISTANCE CALCULATIONS\n     OPTION 5 = GALACTIC /REGION NAME/ MAP\n        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR\n        GALACTIC REGIONS REFERRED TO IN THE GAME.\n"
  },
  {
    "path": "00_Alternate_Languages/84_Super_Star_Trek/superstartrek.bas",
    "content": "10 REM SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY\n30 REM\n40 REM ****        **** STAR TREK ****        ****\n50 REM **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n60 REM **** AS SEEN ON THE STAR TREK TV SHOW.\n70 REM **** ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n80 REM **** PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n90 REM **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n100 REM *** LEEDOM - APRIL & DECEMBER 1974,\n110 REM *** WITH A LITTLE HELP FROM HIS FRIENDS . . .\n120 REM *** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --\n130 REM *** SEND TO:  R. C. LEEDOM\n140 REM ***           WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.\n150 REM ***           BOX 746, M.S. 338\n160 REM ***           BALTIMORE, MD  21203\n170 REM ***\n180 REM *** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS\n190 REM *** LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS\n200 REM *** MUCH AS POSSIBLE WHILE USING MULTIPLE STATEMENTS PER LINE\n205 REM *** SOME LINES ARE LONGER THAN 72 CHARACTERS; THIS WAS DONE\n210 REM *** BY USING \"?\" INSTEAD OF \"PRINT\" WHEN ENTERING LINES\n215 REM ***\n220 PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT\n221 PRINT \"                                    ,------*------,\"\n222 PRINT \"                    ,-------------   '---  ------'\"\n223 PRINT \"                     '-------- --'      / /\"\n224 PRINT \"                         ,---' '-------/ /--,\"\n225 PRINT \"                          '----------------'\":PRINT\n226 PRINT \"                    THE USS ENTERPRISE --- NCC-1701\"\n227 PRINT:PRINT:PRINT:PRINT:PRINT\n260 REM CLEAR 600\n270 Z$=\"                         \"\n330 DIM G(8,8),C(9,2),K(3,3),N(3),Z(8,8),D(8)\n370 T=INT(RND(1)*20+20)*100:T0=T:T9=25+INT(RND(1)*10):D0=0:E=3000:E0=E\n440 P=10:P0=P:S9=200:S=0:B9=2:K9=0:X$=\"\":X0$=\" IS \"\n470 DEF FND(D)=SQR((K(I,1)-S1)^2+(K(I,2)-S2)^2)\n475 DEF FNR(R)=INT(RND(R)*7.98+1.01)\n480 REM INITIALIZE ENTERPRIZE'S POSITION\n490 Q1=FNR(1):Q2=FNR(1):S1=FNR(1):S2=FNR(1)\n530 FOR I=1 TO 9:C(I,1)=0:C(I,2)=0:NEXT I\n540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1\n600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1\n670 FOR I=1 TO 8:D(I)=0:NEXT I\n710 A1$=\"NAVSRSLRSPHATORSHEDAMCOMXXX\"\n810 REM SETUP WHAT EXHISTS IN GALAXY . . .\n815 REM K3= # KLINGONS  B3= # STARBASES  S3 = # STARS\n820 FOR I=1 TO 8:FOR J=1 TO 8:K3=0:Z(I,J)=0:R1=RND(1)\n850 IF R1>.98 THEN K3=3:K9=K9+3:GOTO 980\n860 IF R1>.95 THEN K3=2:K9=K9+2:GOTO 980\n870 IF R1>.80 THEN K3=1:K9=K9+1\n980 B3=0:IF RND(1)>.96 THEN B3=1:B9=B9+1\n1040 G(I,J)=K3*100+B3*10+FNR(1):NEXT J:NEXT I:IF K9>T9 THEN T9=K9+1\n1100 IF B9<>0 THEN 1200\n1150 IF G(Q1,Q2)<200 THEN G(Q1,Q2)=G(Q1,Q2)+120:K9=K9+1\n1160 B9=1:G(Q1,Q2)=G(Q1,Q2)+10:Q1=FNR(1):Q2=FNR(1)\n1200 K7=K9:IF B9<>1 THEN X$=\"S\":X0$=\" ARE \"\n1230 PRINT \"YOUR ORDERS ARE AS FOLLOWS:\"\n1240 PRINT \"     DESTROY THE\";K9;\"KLINGON WARSHIPS WHICH HAVE INVADED\"\n1252 PRINT \"   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\"\n1260 PRINT \"   ON STARDATE\";T0+T9;\"  THIS GIVES YOU\";T9;\"DAYS.  THERE\";X0$\n1272 PRINT \"  \";B9;\"STARBASE\";X$;\" IN THE GALAXY FOR RESUPPLYING YOUR SHIP\"\n1280 PRINT:REM PRINT \"HIT ANY KEY EXCEPT RETURN WHEN READY TO ACCEPT COMMAND\"\n1300 I=RND(1):REM IF INP(1)=13 THEN 1300\n1310 REM HERE ANY TIME NEW QUADRANT ENTERED\n1320 Z4=Q1:Z5=Q2:K3=0:B3=0:S3=0:G5=0:D4=.5*RND(1):Z(Q1,Q2)=G(Q1,Q2)\n1390 IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 1600\n1430 GOSUB 9030:PRINT:IF T0<>T THEN 1490\n1460 PRINT \"YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\"\n1470 PRINT \"IN THE GALACTIC QUADRANT, '\";G2$;\"'.\":GOTO 1500\n1490 PRINT \"NOW ENTERING \";G2$;\" QUADRANT . . .\"\n1500 PRINT:K3=INT(G(Q1,Q2)*.01):B3=INT(G(Q1,Q2)*.1)-10*K3\n1540 S3=G(Q1,Q2)-100*K3-10*B3:IF K3=0 THEN 1590\n1560 PRINT \"COMBAT AREA      CONDITION RED\":IF S>200 THEN 1590\n1580 PRINT \"   SHIELDS DANGEROUSLY LOW\"\n1590 FOR I=1 TO 3:K(I,1)=0:K(I,2)=0:NEXT I\n1600 FOR I=1 TO 3:K(I,3)=0:NEXT I:Q$=Z$+Z$+Z$+Z$+Z$+Z$+Z$+LEFT$(Z$,17)\n1660 REM POSITION ENTERPRISE IN QUADRANT, THEN PLACE \"K3\" KLINGONS, &\n1670 REM \"B3\" STARBASES, & \"S3\" STARS ELSEWHERE.\n1680 A$=\"<*>\":Z1=S1:Z2=S2:GOSUB 8670:IF K3<1 THEN 1820\n1720 FOR I=1 TO K3:GOSUB 8590:A$=\"+K+\":Z1=R1:Z2=R2\n1780 GOSUB 8670:K(I,1)=R1:K(I,2)=R2:K(I,3)=S9*(0.5+RND(1)):NEXT I\n1820 IF B3<1 THEN 1910\n1880 GOSUB 8590:A$=\">!<\":Z1=R1:B4=R1:Z2=R2:B5=R2:GOSUB 8670\n1910 FOR I=1 TO S3:GOSUB 8590:A$=\" * \":Z1=R1:Z2=R2:GOSUB 8670:NEXT I\n1980 GOSUB 6430\n1990 IF S+E>10 THEN IF E>10 OR D(7)=0 THEN 2060\n2020 PRINT:PRINT \"** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP IN \"\n2030 PRINT \"SPACE\":PRINT \"YOU HAVE INSUFFICIENT MANEUVERING ENERGY,\";\n2040 PRINT \" AND SHIELD CONTROL\":PRINT \"IS PRESENTLY INCAPABLE OF CROSS\";\n2050 PRINT \"-CIRCUITING TO ENGINE ROOM!!\":GOTO 6220\n2060 INPUT\"COMMAND\";A$\n2080 FOR I=1 TO 9:IF LEFT$(A$,3)<>MID$(A1$,3*I-2,3) THEN 2160\n2140 ON I GOTO 2300,1980,4000,4260,4700,5530,5690,7290,6270\n2160 NEXT I:PRINT \"ENTER ONE OF THE FOLLOWING:\"\n2180 PRINT \"  NAV  (TO SET COURSE)\"\n2190 PRINT \"  SRS  (FOR SHORT RANGE SENSOR SCAN)\"\n2200 PRINT \"  LRS  (FOR LONG RANGE SENSOR SCAN)\"\n2210 PRINT \"  PHA  (TO FIRE PHASERS)\"\n2220 PRINT \"  TOR  (TO FIRE PHOTON TORPEDOES)\"\n2230 PRINT \"  SHE  (TO RAISE OR LOWER SHIELDS)\"\n2240 PRINT \"  DAM  (FOR DAMAGE CONTROL REPORTS)\"\n2250 PRINT \"  COM  (TO CALL ON LIBRARY-COMPUTER)\"\n2260 PRINT \"  XXX  (TO RESIGN YOUR COMMAND)\":PRINT:GOTO 1990\n2290 REM COURSE CONTROL BEGINS HERE\n2300 INPUT\"COURSE (0-9)\";C1:IF C1=9 THEN C1=1\n2310 IF C1>=1 AND C1<9 THEN 2350\n2330 PRINT \"   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'\":GOTO 1990\n2350 X$=\"8\":IF D(1)<0 THEN X$=\"0.2\"\n2360 PRINT \"WARP FACTOR (0-\";X$;\")\";:INPUT W1:IF D(1)<0 AND W1>.2 THEN 2470\n2380 IF W1>0 AND W1<=8 THEN 2490\n2390 IF W1=0 THEN 1990\n2420 PRINT \"   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE\";\n2430 PRINT \" WARP \";W1;\"!'\":GOTO 1990\n2470 PRINT \"WARP ENGINES ARE DAMAGED.  MAXIUM SPEED = WARP 0.2\":GOTO 1990\n2490 N=INT(W1*8+.5):IF E-N>=0 THEN 2590\n2500 PRINT \"ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE\"\n2510 PRINT \"                       FOR MANEUVERING AT WARP\";W1;\"!'\"\n2530 IF S<N-E OR D(7)<0 THEN 1990\n2550 PRINT \"DEFLECTOR CONTROL ROOM ACKNOWLEDGES\";S;\"UNITS OF ENERGY\"\n2560 PRINT \"                         PRESENTLY DEPLOYED TO SHIELDS.\"\n2570 GOTO 1990\n2580 REM KLINGONS MOVE/FIRE ON MOVING STARSHIP . . .\n2590 FOR I=1 TO K3:IF K(I,3)=0 THEN 2700\n2610 A$=\"   \":Z1=K(I,1):Z2=K(I,2):GOSUB 8670:GOSUB 8590\n2660 K(I,1)=Z1:K(I,2)=Z2:A$=\"+K+\":GOSUB 8670\n2700 NEXT I:GOSUB 6000:D1=0:D6=W1:IF W1>=1 THEN D6=1\n2770 FOR I=1 TO 8:IF D(I)>=0 THEN 2880\n2790 D(I)=D(I)+D6:IF D(I)>-.1 AND D(I)<0 THEN D(I)=-.1:GOTO 2880\n2800 IF D(I)<0 THEN 2880\n2810 IF D1<>1 THEN D1=1:PRINT \"DAMAGE CONTROL REPORT:  \";\n2840 PRINT TAB(8);:R1=I:GOSUB 8790:PRINT G2$;\" REPAIR COMPLETED.\"\n2880 NEXT I:IF RND(1)>.2 THEN 3070\n2910 R1=FNR(1):IF RND(1)>=.6 THEN 3000\n2930 D(R1)=D(R1)-(RND(1)*5+1):PRINT \"DAMAGE CONTROL REPORT:  \";\n2960 GOSUB 8790:PRINT G2$;\" DAMAGED\":PRINT:GOTO 3070\n3000 D(R1)=D(R1)+RND(1)*3+1:PRINT \"DAMAGE CONTROL REPORT:  \";\n3030 GOSUB 8790:PRINT G2$;\" STATE OF REPAIR IMPROVED\":PRINT\n3060 REM BEGIN MOVING STARSHIP\n3070 A$=\"   \":Z1=INT(S1):Z2=INT(S2):GOSUB 8670\n3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):X=S1:Y=S2\n3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):Q4=Q1:Q5=Q2\n3170 FOR I=1 TO N:S1=S1+X1:S2=S2+X2:IF S1<1 OR S1>=9 OR S2<1 OR S2>=9 THEN 3500\n3240 S8=INT(S1)*24+INT(S2)*3-26:IF MID$(Q$,S8,2)=\"  \" THEN 3360\n3320 S1=INT(S1-X1):S2=INT(S2-X2):PRINT \"WARP ENGINES SHUT DOWN AT \";\n3350 PRINT \"SECTOR\";S1;\",\";S2;\"DUE TO BAD NAVAGATION\":GOTO 3370\n3360 NEXT I:S1=INT(S1):S2=INT(S2)\n3370 A$=\"<*>\":Z1=INT(S1):Z2=INT(S2):GOSUB 8670:GOSUB 3910:T8=1\n3430 IF W1<1 THEN T8=.1*INT(10*W1)\n3450 T=T+T8:IF T>T0+T9 THEN 6220\n3470 REM SEE IF DOCKED, THEN GET COMMAND\n3480 GOTO 1980\n3490 REM EXCEEDED QUADRANT LIMITS\n3500 X=8*Q1+X+N*X1:Y=8*Q2+Y+N*X2:Q1=INT(X/8):Q2=INT(Y/8):S1=INT(X-Q1*8)\n3550 S2=INT(Y-Q2*8):IF S1=0 THEN Q1=Q1-1:S1=8\n3590 IF S2=0 THEN Q2=Q2-1:S2=8\n3620 X5=0:IF Q1<1 THEN X5=1:Q1=1:S1=1\n3670 IF Q1>8 THEN X5=1:Q1=8:S1=8\n3710 IF Q2<1 THEN X5=1:Q2=1:S2=1\n3750 IF Q2>8 THEN X5=1:Q2=8:S2=8\n3790 IF X5=0 THEN 3860\n3800 PRINT \"LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:\"\n3810 PRINT \"  'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER\"\n3820 PRINT \"  IS HEREBY *DENIED*.  SHUT DOWN YOUR ENGINES.'\"\n3830 PRINT \"CHIEF ENGINEER SCOTT REPORTS  'WARP ENGINES SHUT DOWN\"\n3840 PRINT \"  AT SECTOR\";S1;\",\";S2;\"OF QUADRANT\";Q1;\",\";Q2;\".'\"\n3850 IF T>T0+T9 THEN 6220\n3860 IF 8*Q1+Q2=8*Q4+Q5 THEN 3370\n3870 T=T+1:GOSUB 3910:GOTO 1320\n3900 REM MANEUVER ENERGY S/R **\n3910 E=E-N-10:IF E>=0 THEN RETURN\n3930 PRINT \"SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.\"\n3940 S=S+E:E=0:IF S<=0 THEN S=0\n3980 RETURN\n3990 REM LONG RANGE SENSOR SCAN CODE\n4000 IF D(3)<0 THEN PRINT \"LONG RANGE SENSORS ARE INOPERABLE\":GOTO 1990\n4030 PRINT \"LONG RANGE SCAN FOR QUADRANT\";Q1;\",\";Q2\n4040 O1$=\"-------------------\":PRINT O1$\n4060 FOR I=Q1-1TOQ1+1:N(1)=-1:N(2)=-2:N(3)=-3:FOR J=Q2-1TOQ2+1\n4120 IF I>0 AND I<9 AND J>0 AND J<9 THEN N(J-Q2+2)=G(I,J):Z(I,J)=G(I,J)\n4180 NEXT J:FOR L=1 TO 3:PRINT \": \";:IF N(L)<0 THEN PRINT \"*** \";:GOTO 4230\n4210 PRINT RIGHT$(STR$(N(L)+1000),3);\" \";\n4230 NEXT L:PRINT \":\":PRINT O1$:NEXT I:GOTO 1990\n4250 REM PHASER CONTROL CODE BEGINS HERE\n4260 IF D(4)<0 THEN PRINT \"PHASERS INOPERATIVE\":GOTO 1990\n4265 IF K3>0 THEN 4330\n4270 PRINT \"SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS\"\n4280 PRINT \"                                IN THIS QUADRANT'\":GOTO 1990\n4330 IF D(8)<0 THEN PRINT \"COMPUTER FAILURE HAMPERS ACCURACY\"\n4350 PRINT \"PHASERS LOCKED ON TARGET;  \";\n4360 PRINT \"ENERGY AVAILABLE =\";E;\"UNITS\"\n4370 INPUT\"NUMBER OF UNITS TO FIRE\";X:IF X<=0 THEN 1990\n4400 IF E-X<0 THEN 4360\n4410 E=E-X:IF D(7)<0 THEN X=X*RND(1)\n4450 H1=INT(X/K3):FOR I=1TO3:IF K(I,3)<=0 THEN 4670\n4480 H=INT((H1/FND(0))*(RND(1)+2)):IF H>.15*K(I,3) THEN 4530\n4500 PRINT \"SENSORS SHOW NO DAMAGE TO ENEMY AT \";K(I,1);\",\";K(I,2):GOTO 4670\n4530 K(I,3)=K(I,3)-H:PRINT H;\"UNIT HIT ON KLINGON AT SECTOR\";K(I,1);\",\";\n4550 PRINT K(I,2):IF K(I,3)<=0 THEN PRINT \"*** KLINGON DESTROYED ***\":GOTO 4580\n4560 PRINT \"   (SENSORS SHOW\";K(I,3);\"UNITS REMAINING)\":GOTO 4670\n4580 K3=K3-1:K9=K9-1:Z1=K(I,1):Z2=K(I,2):A$=\"   \":GOSUB 8670\n4650 K(I,3)=0:G(Q1,Q2)=G(Q1,Q2)-100:Z(Q1,Q2)=G(Q1,Q2):IF K9<=0 THEN 6370\n4670 NEXT I:GOSUB 6000:GOTO 1990\n4690 REM PHOTON TORPEDO CODE BEGINS HERE\n4700 IF P<=0 THEN PRINT \"ALL PHOTON TORPEDOES EXPENDED\":GOTO 1990\n4730 IF D(5)<0 THEN PRINT \"PHOTON TUBES ARE NOT OPERATIONAL\":GOTO 1990\n4760 INPUT\"PHOTON TORPEDO COURSE (1-9)\";C1:IF C1=9 THEN C1=1\n4780 IF C1>=1ANDC1<9 THEN 4850\n4790 PRINT \"ENSIGN CHEKOV REPORTS,  'INCORRECT COURSE DATA, SIR!'\"\n4800 GOTO 1990\n4850 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):E=E-2:P=P-1\n4860 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):X=S1:Y=S2\n4910 PRINT \"TORPEDO TRACK:\"\n4920 X=X+X1:Y=Y+X2:X3=INT(X+.5):Y3=INT(Y+.5)\n4960 IF X3<1 OR X3>8 OR Y3<1 OR Y3>8 THEN 5490\n5000 PRINT \"               \";X3;\",\";Y3:A$=\"   \":Z1=X:Z2=Y:GOSUB 8830\n5050 IF Z3<>0 THEN 4920\n5060 A$=\"+K+\":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5210\n5110 PRINT \"*** KLINGON DESTROYED ***\":K3=K3-1:K9=K9-1:IF K9<=0 THEN 6370\n5150 FOR I=1TO3:IF X3=K(I,1) AND Y3=K(I,2) THEN 5190\n5180 NEXT I:I=3\n5190 K(I,3)=0:GOTO 5430\n5210 A$=\" * \":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5280\n5260 PRINT \"STAR AT\";X3;\",\";Y3;\"ABSORBED TORPEDO ENERGY.\":GOSUB 6000:GOTO 1990\n5280 A$=\">!<\":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 4760\n5330 PRINT \"*** STARBASE DESTROYED ***\":B3=B3-1:B9=B9-1\n5360 IF B9>0 OR K9>T-T0-T9 THEN 5400\n5370 PRINT \"THAT DOES IT, CAPTAIN!!  YOU ARE HEREBY RELIEVED OF COMMAND\"\n5380 PRINT \"AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!\"\n5390 GOTO 6270\n5400 PRINT \"STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER\"\n5410 PRINT \"COURT MARTIAL!\":D0=0\n5430 Z1=X:Z2=Y:A$=\"   \":GOSUB 8670\n5470 G(Q1,Q2)=K3*100+B3*10+S3:Z(Q1,Q2)=G(Q1,Q2):GOSUB 6000:GOTO 1990\n5490 PRINT \"TORPEDO MISSED\":GOSUB 6000:GOTO 1990\n5520 REM SHIELD CONTROL\n5530 IF D(7)<0 THEN PRINT \"SHIELD CONTROL INOPERABLE\":GOTO 1990\n5560 PRINT \"ENERGY AVAILABLE =\";E+S;:INPUT\"NUMBER OF UNITS TO SHIELDS\";X\n5580 IF X<0 OR S=X THEN PRINT \"<SHIELDS UNCHANGED>\":GOTO 1990\n5590 IF X<=E+S THEN 5630\n5600 PRINT \"SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION TREASURY.'\"\n5610 PRINT \"<SHIELDS UNCHANGED>\":GOTO 1990\n5630 E=E+S-X:S=X:PRINT \"DEFLECTOR CONTROL ROOM REPORT:\"\n5660 PRINT \"  'SHIELDS NOW AT\";INT(S);\"UNITS PER YOUR COMMAND.'\":GOTO 1990\n5680 REM DAMAGE CONTROL\n5690 IF D(6)>=0 THEN 5910\n5700 PRINT \"DAMAGE CONTROL REPORT NOT AVAILABLE\":IF D0=0 THEN 1990\n5720 D3=0:FOR I=1TO8:IF D(I)<0 THEN D3=D3+.1\n5760 NEXT I:IF D3=0 THEN 1990\n5780 PRINT:D3=D3+D4:IF D3>=1 THEN D3=.9\n5810 PRINT \"TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;\"\n5820 PRINT \"ESTIMATED TIME TO REPAIR:\";.01*INT(100*D3);\"STARDATES\"\n5840 INPUT \"WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)\";A$\n5860 IF A$<>\"Y\" THEN 1990\n5870 FOR I=1TO8:IF D(I)<0 THEN D(I)=0\n5890 NEXT I:T=T+D3+.1\n5910 PRINT:PRINT \"DEVICE             STATE OF REPAIR\":FOR R1=1TO8\n5920 GOSUB 8790:PRINT G2$;LEFT$(Z$,25-LEN(G2$));INT(D(R1)*100)*.01\n5950 NEXT R1:PRINT:IF D0<>0 THEN 5720\n5980 GOTO 1990\n5990 REM KLINGONS SHOOTING\n6000 IF K3<=0 THEN RETURN\n6010 IF D0<>0 THEN PRINT \"STARBASE SHIELDS PROTECT THE ENTERPRISE\":RETURN\n6040 FOR I=1TO3:IF K(I,3)<=0 THEN 6200\n6060 H=INT((K(I,3)/FND(1))*(2+RND(1))):S=S-H:K(I,3)=K(I,3)/(3+RND(0))\n6080 PRINT H;\"UNIT HIT ON ENTERPRISE FROM SECTOR\";K(I,1);\",\";K(I,2)\n6090 IF S<=0 THEN 6240\n6100 PRINT \"      <SHIELDS DOWN TO\";S;\"UNITS>\":IF H<20 THEN 6200\n6120 IF RND(1)>.6 OR H/S<=.02 THEN 6200\n6140 R1=FNR(1):D(R1)=D(R1)-H/S-.5*RND(1):GOSUB 8790\n6170 PRINT \"DAMAGE CONTROL REPORTS \";G2$;\" DAMAGED BY THE HIT'\"\n6200 NEXT I:RETURN\n6210 REM END OF GAME\n6220 PRINT \"IT IS STARDATE\";T:GOTO 6270\n6240 PRINT:PRINT \"THE ENTERPRISE HAS BEEN DESTROYED.  THEN FEDERATION \";\n6250 PRINT \"WILL BE CONQUERED\":GOTO 6220\n6270 PRINT \"THERE WERE\";K9;\"KLINGON BATTLE CRUISERS LEFT AT\"\n6280 PRINT \"THE END OF YOUR MISSION.\"\n6290 PRINT:PRINT:IF B9=0 THEN 6360\n6310 PRINT \"THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER\"\n6320 PRINT \"FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,\"\n6330 INPUT\"LET HIM STEP FORWARD AND ENTER 'AYE'\";A$:IF A$=\"AYE\" THEN 10\n6360 END\n6370 PRINT \"CONGRULATION, CAPTAIN!  THEN LAST KLINGON BATTLE CRUISER\"\n6380 PRINT \"MENACING THE FDERATION HAS BEEN DESTROYED.\":PRINT\n6400 PRINT \"YOUR EFFICIENCY RATING IS\";1000*(K7/(T-T0))^2:GOTO 6290\n6420 REM SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE\n6430 FOR I=S1-1TOS1+1:FOR J=S2-1 TO S2+1\n6450 IF INT(I+.5)<1 OR INT(I+.5)>8 OR INT(J+.5)<1 OR INT(J+.5)>8 THEN 6540\n6490 A$=\">!<\":Z1=I:Z2=J:GOSUB 8830:IF Z3=1 THEN 6580\n6540 NEXT J:NEXT I:D0=0:GOTO 6650\n6580 D0=1:C$=\"DOCKED\":E=E0:P=P0\n6620 PRINT \"SHIELDS DROPPED FOR DOCKING PURPOSES\":S=0:GOTO 6720\n6650 IF K3>0 THEN C$=\"*RED*\":GOTO 6720\n6660 C$=\"GREEN\":IF E<E0*.1 THEN C$=\"YELLOW\"\n6720 IF D(2)>=0 THEN 6770\n6730 PRINT:PRINT \"*** SHORT RANGE SENSORS ARE OUT ***\":PRINT:RETURN\n6770 O1$=\"---------------------------------\":PRINT O1$:FOR I=1 TO 8\n6820 FOR J=(I-1)*24+1 TO (I-1)*24+22STEP3:PRINT \" \";MID$(Q$,J,3);:NEXT J\n6830 ON I GOTO 6850,6900,6960,7020,7070,7120,7180,7240\n6850 PRINT \"        STARDATE          \";INT(T*10)*.1:GOTO 7260\n6900 PRINT \"        CONDITION          \";C$:GOTO 7260\n6960 PRINT \"        QUADRANT          \";Q1;\",\";Q2:GOTO 7260\n7020 PRINT \"        SECTOR            \";S1;\",\";S2:GOTO 7260\n7070 PRINT \"        PHOTON TORPEDOES  \";INT(P):GOTO 7260\n7120 PRINT \"        TOTAL ENERGY      \";INT(E+S):GOTO 7260\n7180 PRINT \"        SHIELDS           \";INT(S):GOTO 7260\n7240 PRINT \"        KLINGONS REMAINING\";INT(K9)\n7260 NEXT I:PRINT O1$:RETURN\n7280 REM LIBRARY COMPUTER CODE\n7290 IF D(8)<0 THEN PRINT \"COMPUTER DISABLED\":GOTO 1990\n7320 INPUT\"COMPUTER ACTIVE AND AWAITING COMMAND\";A:IF A<0 THEN 1990\n7350 PRINT:H8=1:ON A+1 GOTO 7540,7900,8070,8500,8150,7400\n7360 PRINT \"FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\"\n7370 PRINT \"   0 = CUMULATIVE GALACTIC RECORD\"\n7372 PRINT \"   1 = STATUS REPORT\"\n7374 PRINT \"   2 = PHOTON TORPEDO DATA\"\n7376 PRINT \"   3 = STARBASE NAV DATA\"\n7378 PRINT \"   4 = DIRECTION/DISTANCE CALCULATOR\"\n7380 PRINT \"   5 = GALAXY 'REGION NAME' MAP\":PRINT:GOTO 7320\n7390 REM SETUP TO CHANGE CUM GAL RECORD TO GALAXY MAP\n7400 H8=0:G5=1:PRINT \"                        THE GALAXY\":GOTO 7550\n7530 REM CUM GALACTIC RECORD\n7540 REM INPUT\"DO YOU WANT A HARDCOPY? IS THE TTY ON (Y/N)\";A$\n7542 REM IF A$=\"Y\" THEN POKE1229,2:POKE1237,3:NULL1\n7543 PRINT:PRINT \"        \";\n7544 PRINT \"COMPUTER RECORD OF GALAXY FOR QUADRANT\";Q1;\",\";Q2\n7546 PRINT\n7550 PRINT \"       1     2     3     4     5     6     7     8\"\n7560 O1$=\"     ----- ----- ----- ----- ----- ----- ----- -----\"\n7570 PRINT O1$:FOR I=1 TO 8:PRINT I;:IF H8=0 THEN 7740\n7630 FOR J=1 TO 8:PRINT \"   \";:IF Z(I,J)=0 THEN PRINT \"***\";:GOTO 7720\n7700 PRINT RIGHT$(STR$(Z(I,J)+1000),3);\n7720 NEXT J:GOTO 7850\n7740 Z4=I:Z5=1:GOSUB 9030:J0=INT(15-.5*LEN(G2$)):PRINT TAB(J0);G2$;\n7800 Z5=5:GOSUB 9030:J0=INT(39-.5*LEN(G2$)):PRINT TAB(J0);G2$;\n7850 PRINT:PRINT O1$:NEXT I:PRINT:GOTO 1990\n7890 REM STATUS REPORT\n7900 PRINT \"   STATUS REPORT:\":X$=\"\":IF K9>1 THEN X$=\"S\"\n7940 PRINT \"KLINGON\";X$;\" LEFT: \";K9\n7960 PRINT \"MISSION MUST BE COMPLETED IN\";.1*INT((T0+T9-T)*10);\"STARDATES\"\n7970 X$=\"S\":IF B9<2 THEN X$=\"\":IF B9<1 THEN 8010\n7980 PRINT \"THE FEDERATION IS MAINTAINING\";B9;\"STARBASE\";X$;\" IN THE GALAXY\"\n7990 GOTO 5690\n8010 PRINT \"YOUR STUPIDITY HAS LEFT YOU ON YOUR ON IN\"\n8020 PRINT \"  THE GALAXY -- YOU HAVE NO STARBASES LEFT!\":GOTO 5690\n8060 REM TORPEDO, BASE NAV, D/D CALCULATOR\n8070 IF K3<=0 THEN 4270\n8080 X$=\"\":IF K3>1 THEN X$=\"S\"\n8090 PRINT \"FROM ENTERPRISE TO KLINGON BATTLE CRUSER\";X$\n8100 H8=0:FOR I=1 TO 3:IF K(I,3)<=0 THEN 8480\n8110 W1=K(I,1):X=K(I,2)\n8120 C1=S1:A=S2:GOTO 8220\n8150 PRINT \"DIRECTION/DISTANCE CALCULATOR:\"\n8160 PRINT \"YOU ARE AT QUADRANT \";Q1;\",\";Q2;\" SECTOR \";S1;\",\";S2\n8170 PRINT \"PLEASE ENTER\":INPUT\"  INITIAL COORDINATES (X,Y)\";C1,A\n8200 INPUT\"  FINAL COORDINATES (X,Y)\";W1,X\n8220 X=X-A:A=C1-W1:IF X<0 THEN 8350\n8250 IF A<0 THEN 8410\n8260 IF X>0 THEN 8280\n8270 IF A=0 THEN C1=5:GOTO 8290\n8280 C1=1\n8290 IF ABS(A)<=ABS(X) THEN 8330\n8310 PRINT \"DIRECTION =\";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO 8460\n8330 PRINT \"DIRECTION =\";C1+(ABS(A)/ABS(X)):GOTO 8460\n8350 IF A>0 THEN C1=3:GOTO 8420\n8360 IF X<>0 THEN C1=5:GOTO 8290\n8410 C1=7\n8420 IF ABS(A)>=ABS(X) THEN 8450\n8430 PRINT \"DIRECTION =\";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO 8460\n8450 PRINT \"DIRECTION =\";C1+(ABS(X)/ABS(A))\n8460 PRINT \"DISTANCE =\";SQR(X^2+A^2):IF H8=1 THEN 1990\n8480 NEXT I:GOTO 1990\n8500 IF B3<>0 THEN PRINT \"FROM ENTERPRISE TO STARBASE:\":W1=B4:X=B5:GOTO 8120\n8510 PRINT \"MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS\";\n8520 PRINT \" QUADRANT.'\":GOTO 1990\n8580 REM FIND EMPTY PLACE IN QUADRANT (FOR THINGS)\n8590 R1=FNR(1):R2=FNR(1):A$=\"   \":Z1=R1:Z2=R2:GOSUB 8830:IF Z3=0 THEN 8590\n8600 RETURN\n8660 REM INSERT IN STRING ARRAY FOR QUADRANT\n8670 S8=INT(Z2-.5)*3+INT(Z1-.5)*24+1\n8675 IF LEN(A$)<>3 THEN PRINT \"ERROR\":STOP\n8680 IF S8=1 THEN Q$=A$+RIGHT$(Q$,189):RETURN\n8690 IF S8=190 THEN Q$=LEFT$(Q$,189)+A$:RETURN\n8700 Q$=LEFT$(Q$,S8-1)+A$+RIGHT$(Q$,190-S8):RETURN\n8780 REM PRINTS DEVICE NAME\n8790 ON R1 GOTO 8792,8794,8796,8798,8800,8802,8804,8806\n8792 G2$=\"WARP ENGINES\":RETURN\n8794 G2$=\"SHORT RANGE SENSORS\":RETURN\n8796 G2$=\"LONG RANGE SENSORS\":RETURN\n8798 G2$=\"PHASER CONTROL\":RETURN\n8800 G2$=\"PHOTON TUBES\":RETURN\n8802 G2$=\"DAMAGE CONTROL\":RETURN\n8804 G2$=\"SHIELD CONTROL\":RETURN\n8806 G2$=\"LIBRARY-COMPUTER\":RETURN\n8820 REM STRING COMPARISON IN QUADRANT ARRAY\n8830 Z1=INT(Z1+.5):Z2=INT(Z2+.5):S8=(Z2-1)*3+(Z1-1)*24+1:Z3=0\n8890 IF MID$(Q$,S8,3)<>A$ THEN RETURN\n8900 Z3=1:RETURN\n9010 REM QUADRANT NAME IN G2$ FROM Z4,Z5 (=Q1,Q2)\n9020 REM CALL WITH G5=1 TO GET REGION NAME ONLY\n9030 IF Z5<=4 THEN ON Z4 GOTO 9040,9050,9060,9070,9080,9090,9100,9110\n9035 GOTO 9120\n9040 G2$=\"ANTARES\":GOTO 9210\n9050 G2$=\"RIGEL\":GOTO 9210\n9060 G2$=\"PROCYON\":GOTO 9210\n9070 G2$=\"VEGA\":GOTO 9210\n9080 G2$=\"CANOPUS\":GOTO 9210\n9090 G2$=\"ALTAIR\":GOTO 9210\n9100 G2$=\"SAGITTARIUS\":GOTO 9210\n9110 G2$=\"POLLUX\":GOTO 9210\n9120 ON Z4 GOTO 9130,9140,9150,9160,9170,9180,9190,9200\n9130 G2$=\"SIRIUS\":GOTO 9210\n9140 G2$=\"DENEB\":GOTO 9210\n9150 G2$=\"CAPELLA\":GOTO 9210\n9160 G2$=\"BETELGEUSE\":GOTO 9210\n9170 G2$=\"ALDEBARAN\":GOTO 9210\n9180 G2$=\"REGULUS\":GOTO 9210\n9190 G2$=\"ARCTURUS\":GOTO 9210\n9200 G2$=\"SPICA\"\n9210 IF G5<>1 THEN ON Z5 GOTO 9230,9240,9250,9260,9230,9240,9250,9260\n9220 RETURN\n9230 G2$=G2$+\" I\":RETURN\n9240 G2$=G2$+\" II\":RETURN\n9250 G2$=G2$+\" III\":RETURN\n9260 G2$=G2$+\" IV\":RETURN\n"
  },
  {
    "path": "00_Alternate_Languages/84_Super_Star_Trek/superstartrekins.bas",
    "content": "10 REM INSTRUCTIONS FOR \"SUPER STARTREK\"  MAR 5, 1978\n20 FOR I=1 TO 12:PRINT:NEXT I\n21 PRINT TAB(10);\"*************************************\"\n22 PRINT TAB(10);\"*                                   *\"\n23 PRINT TAB(10);\"*                                   *\"\n30 PRINT TAB(10);\"*      * * SUPER STAR TREK * *      *\"\n31 PRINT TAB(10);\"*                                   *\"\n32 PRINT TAB(10);\"*                                   *\"\n35 PRINT TAB(10);\"*************************************\"\n36 FOR I=1 TO 8:PRINT:NEXT I\n40 INPUT \"DO YOU NEED INSTRUCTIONS (Y/N)\";K$:IF K$=\"N\" THEN 2000\n44 PRINT\n45 REM PRINT \"TURN THE TTY ON-LINE AND HIT ANY KEY EXCEPT RETURN\"\n46 REM IF INP(1)=13 THEN 46\n50 REM POKE 1229,2:POKE 1237,3:NULL 1\n90 PRINT\"      INSTRUCTIONS FOR 'SUPER STAR TREK'\"\n100 PRINT\n110 PRINT\"1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL\"\n120 PRINT\"     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\"\n130 PRINT\"2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\"\n140 PRINT\"     LIST OF THE LEGAL COMMANDS PRINTED OUT.\"\n150 PRINT\"3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\"\n160 PRINT\"     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\"\n170 PRINT\"     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\"\n180 PRINT\"     WILL BE ABORTED\"\n190 PRINT\n270 PRINT\"     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\"\n280 PRINT\"AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\"\n290 PRINT\n300 PRINT\"     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\"\n310 PRINT\"GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\"\n320 PRINT\"\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\"\n330 PRINT\"KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\"\n340 PRINT\"PLANETS.\"\n360 PRINT\n370 PRINT\"     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\"\n380 PRINT\"OF THE STARSHIP ENTERPRISE:\"\n385 PRINT\n390 PRINT\"\\NAV\\ COMMAND = WARP ENGINE CONTROL --\"\n400 PRINT\"     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\"\n410 PRINT\"     VECTOR ARRANGEMENT AS SHOWN             . . .\"\n420 PRINT\"     INTEGER AND REAL VALUES MAY BE           ...\"\n430 PRINT\"     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\"\n440 PRINT\"     WAY BETWEEN 1 AND 2                      ...\"\n450 PRINT\"                                             . . .\"\n460 PRINT\"     VALUES MAY APPROACH 9.0, WHICH         6  7  8\"\n470 PRINT\"     ITSELF IS EQUIVALENT TO 1.0\"\n480 PRINT\"                                            COURSE\"\n490 PRINT\"     ONE WARP FACTOR IS THE SIZE OF \"\n500 PRINT\"     ONE QUADTANT.  THEREFORE, TO GET\"\n510 PRINT\"     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\"\n520 PRINT\"     USE COURSE 3, WARP FACTOR 1.\"\n530 PRINT\n540 PRINT\"\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN\"\n550 PRINT\"     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\"\n555 PRINT\n560 PRINT\"     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\"\n570 PRINT\"        <*> = YOUR STARSHIP'S POSITION\"\n580 PRINT\"        +K+ = KLINGON BATTLE CRUISER\"\n590 PRINT\"        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\"\n600 PRINT\"         *  = STAR\"\n605 PRINT\n610 PRINT\"     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\"\n620 PRINT\n640 PRINT\"\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN\"\n650 PRINT\"     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\"\n660 PRINT\"     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\"\n670 PRINT\"     THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT\"\n680 PRINT\"     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\"\n690 PRINT\"     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF\"\n700 PRINT\"     KLINGONS.\"\n705 PRINT\n706 PRINT\"     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\"\n710 PRINT\n720 PRINT\"\\PHA\\ COMMAND = PHASER CONTROL.\"\n730 PRINT\"     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY \"\n740 PRINT\"     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\"\n750 PRINT\"     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE\"\n760 PRINT\"     PHASERS TOO!)\"\n770 PRINT\n780 PRINT\"\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL\"\n790 PRINT\"     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\"\n800 PRINT\"     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\"\n810 PRINT\"     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\"\n820 PRINT\"     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO \"\n825 PRINT\"     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\"\n830 PRINT\n835 PRINT\"     THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO \"\n840 PRINT\"     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\"\n850 PRINT\n860 PRINT\"\\SHE\\ COMMAND = SHIELD CONTROL\"\n870 PRINT\"     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\"\n880 PRINT\"     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\"\n890 PRINT\"     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\"\n900 PRINT\n910 PRINT\"\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT\"\n920 PRINT\"     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\"\n930 PRINT\"     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\"\n940 PRINT\"     DAMAGED.\"\n950 PRINT\n960 PRINT\"\\COM\\ COMMAND = LIBRARY-COMPUTER\"\n970 PRINT\"     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\"\n980 PRINT\"     OPTION 0 = CUMULATIVE GALACTIC RECORD\"\n990 PRINT\"        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\"\n1000 PRINT\"        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\"\n1010 PRINT\"     OPTION 1 = STATUS REPORT\"\n1020 PRINT\"        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\"\n1030 PRINT\"        AND STARBASES REMAINING IN THE GAME.\"\n1040 PRINT\"     OPTION 2 = PHOTON TORPEDO DATA\"\n1050 PRINT\"        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\"\n1060 PRINT\"        TO ALL KLINGONS IN YOUR QUADRANT\"\n1070 PRINT\"     OPTION 3 = STARBASE NAV DATA\"\n1080 PRINT\"        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY \"\n1090 PRINT\"        STARBASE WITHIN YOUR QUADRANT\"\n1100 PRINT\"     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\"\n1110 PRINT\"        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\"\n1120 PRINT\"        DIRECTION/DISTANCE CALCULATIONS\"\n1130 PRINT\"     OPTION 5 = GALACTIC /REGION NAME/ MAP\"\n1140 PRINT\"        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR \"\n1150 PRINT\"        GALACTIC REGIONS REFERRED TO IN THE GAME.\"\n1990 REM POKE 1229,0:POKE 1237,1:NULL 0\n2000 REM PRINT:PRINT:PRINT\n2010 REM PRINT \"TURN CASSETTE PLAYER ON AND HIT ANY KEY EXCEPT RETURN\"\n2020 REM IF INP(1)=13 THEN 2020\n2030 REM PRINT\n2040 REM PRINT \"TURN CASSETTE PLAYER OFF AND \"\n2050 REM PRINT \"TYPE 'RUN' WHEN COMPUTER PRINTS 'OK'\"\n"
  },
  {
    "path": "00_Alternate_Languages/85_Synonym/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\r\n\r\nConversion to [MiniScript](https://miniscript.org).\r\n\r\nWays to play:\r\n\r\n1. Command-Line MiniScript:\r\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\r\n```\r\n\tminiscript synonym.ms\r\n```\r\n2. Mini Micro:\r\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\r\n```\r\n\tload \"synonym\"\r\n\trun\r\n```\r\n"
  },
  {
    "path": "00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms",
    "content": "words = [[\"first\", \"start\", \"beginning\", \"onset\", \"initial\"],\n[\"similar\", \"alike\", \"same\", \"like\", \"resembling\"],\n[\"model\", \"pattern\", \"prototype\", \"standard\", \"criterion\"],\n[\"small\", \"insignificant\", \"little\", \"tiny\", \"minute\"],\n[\"stop\", \"halt\", \"stay\", \"arrest\", \"check\", \"standstill\"],\n[\"house\", \"dwelling\", \"residence\", \"domicile\", \"lodging\", \"habitation\"],\n[\"pit\", \"hole\", \"hollow\", \"well\", \"gulf\", \"chasm\", \"abyss\"],\n[\"push\", \"shove\", \"thrust\", \"prod\",\"poke\",\"butt\", \"press\"],\n[\"red\", \"rouge\", \"scarlet\", \"crimson\", \"flame\", \"ruby\"],\n[\"pain\", \"suffering\", \"hurt\", \"misery\", \"distress\", \"ache\", \"discomfort\"]]\n\nwords.shuffle\n\nresponses = [\"Right\",\"Correct\",\"Fine\",\"Good!\",\"Check\"]\n\nprint \" \" * 33 + \"SYNONYM\"\nprint \" \" * 15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"A synonym of a word means another word in the English\"\nprint \"language which has the same or very nearly the same meaning.\"\nprint \"I choose a word -- you type a synonym.\"\nprint \"If you can't think a synonym, type the word 'HELP'\"\nprint \"and I will tell you a synonym.\"\nprint\n\nfor synonyms in words\n\tword = synonyms[0]\n\tsynonyms = synonyms[1:]\n\tresponses.shuffle\n\t\n\tprint\n\twhile 1\n\t\tguess = input(\"    What is a synonym of \" + word + \"? \").lower\n\t\tif guess == \"help\" then\n\t\t\tsynonyms.shuffle\n\t\t\tprint \"**** A synonym of \" + word + \" is \" + synonyms[0] + \".\"\n\t\t\tprint\n\t\telse if guess == word or synonyms.indexOf(guess) == null then\n\t\t\tprint \"    Try again.\"\n\t\telse\n\t\t\tprint responses[0]\n\t\t\tbreak\n\t\tend if\n\tend while\nend for\nprint\nprint \"Synonym drill completed.\"\n"
  },
  {
    "path": "00_Alternate_Languages/85_Synonym/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/85_Synonym/synonym.bas",
    "content": "2 PRINT TAB(33);\"SYNONYM\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 DIM R$(5),W$(10),L(30),R(30)\n20 R$(1)=\"RIGHT\": R$(2)=\"CORRECT\": R$(3)=\"FINE\": R$(4)=\"GOOD!\"\n30 R$(5)=\"CHECK\"\n70 C=0\n90 PRINT \"A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\"\n100 PRINT \"LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME\";\n110 PRINT \" MEANING.\"\n130 PRINT \"I CHOOSE A WORD -- YOU TYPE A SYNONYM.\"\n140 PRINT \"IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\"\n145 PRINT \"AND I WILL TELL YOU A SYNONYM.\": PRINT\n150 RESTORE: C=C+1: READ N\n160 IF C>N THEN 420\n170 N1=INT(RND(1)*N+1)\n174 IF R(N1)=1 THEN 170\n176 R(N1)=1\n180 FOR I=1 TO N1\n190 READ N2\n200 FOR J=1 TO N2\n210 READ W$(J)\n220 NEXT J\n230 NEXT I\n232 FOR J=1 TO N2: L(J)=J: NEXT J\n235 L(0)=N2: G=1: PRINT\n237 L(G)=L(L(0)): L(0)=N2-1: PRINT\n240 PRINT \"     WHAT IS A SYNONYM OF \";W$(G);: INPUT A$\n250 IF A$=\"HELP\" THEN 340\n260 FOR K=1 TO N2\n270 IF G=K THEN 290\n280 IF A$=W$(K) THEN 320\n290 NEXT K\n300 PRINT \"     TRY AGAIN.\": GOTO 240\n320 PRINT R$(INT(RND(1)*5+1)): GOTO 150\n340 G1=INT(RND(1)*L(0)+1)\n360 PRINT \"**** A SYNONYM OF \";W$(G);\" IS \";W$(L(G1));\".\": PRINT\n370 L(G1)=L(L(0)): L(0)=L(0)-1: GOTO 240\n420 PRINT: PRINT \"SYNONYM DRILL COMPLETED.\": GOTO 999\n500 DATA 10\n510 DATA 5,\"FIRST\",\"START\",\"BEGINNING\",\"ONSET\",\"INITIAL\"\n520 DATA 5,\"SIMILAR\",\"ALIKE\",\"SAME\",\"LIKE\",\"RESEMBLING\"\n530 DATA 5,\"MODEL\",\"PATTERN\",\"PROTOTYPE\",\"STANDARD\",\"CRITERION\"\n540 DATA 5,\"SMALL\",\"INSIGNIFICANT\",\"LITTLE\",\"TINY\",\"MINUTE\"\n550 DATA 6,\"STOP\",\"HALT\",\"STAY\",\"ARREST\",\"CHECK\",\"STANDSTILL\"\n560 DATA 6,\"HOUSE\",\"DWELLING\",\"RESIDENCE\",\"DOMICILE\",\"LODGING\"\n565 DATA \"HABITATION\"\n570 DATA 7,\"PIT\",\"HOLE\",\"HOLLOW\",\"WELL\",\"GULF\",\"CHASM\",\"ABYSS\"\n580 DATA 7,\"PUSH\",\"SHOVE\",\"THRUST\",\"PROD\",\"POKE\",\"BUTT\",\"PRESS\"\n590 DATA 6,\"RED\",\"ROUGE\",\"SCARLET\",\"CRIMSON\",\"FLAME\",\"RUBY\"\n600 DATA 7,\"PAIN\",\"SUFFERING\",\"HURT\",\"MISERY\",\"DISTRESS\",\"ACHE\"\n605 DATA \"DISCOMFORT\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/86_Target/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\r\n\r\nConversion to [MiniScript](https://miniscript.org).\r\n\r\nWays to play:\r\n\r\n1. Command-Line MiniScript:\r\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\r\n```\r\n\tminiscript target.ms\r\n```\r\n2. Mini Micro:\r\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\r\n```\r\n\tload \"target\"\r\n\trun\r\n```\r\n"
  },
  {
    "path": "00_Alternate_Languages/86_Target/MiniScript/target.ms",
    "content": "degToRad = function(n)\n\treturn n * pi / 180\nend function\n\nradToDeg = function(n)\n\treturn n * 180 / pi\nend function\n\nroundDown = function(n, r)\n\treturn floor(n / r) * r\nend function\n\ngetCoord = function(distance, radX, radZ)\n\txc = sin(radZ)*cos(radX)*distance\n\tyc = sin(radZ)*sin(radX)*distance\n\tzc = cos(radZ)*distance\n\treturn [xc,yc,zc]\nend function\n\ndistanceBetween = function (d1,d2)\n\treturn ((d1[0]-d2[0])^2 + (d1[1]-d2[1])^2 + (d1[2]-d2[2])^2)^.5\nend function\n\ncoordStr = function(coords)\n\treturn \"X = \" + round(coords[0]) +\n\t  \"   Y = \" + round(coords[1]) + \"   Z = \" + round(coords[2])\nend function\n\nprint \" \" * 33 + \"TARGET\"\nprint \" \" * 15 + \"Creative Computing   Morristown, New Jersey\"\nprint; print; print\n\nprint \"You are the weapons officer on the Starship Enterprise\"\nprint \"and this is a test to see how accurae a shot you\"\nprint \"are in a 3-dimensional range. You will be told\"\nprint \"the radian offset for the X and Z axes, the location\"\nprint \"of the target in 3-dimensional rectangular coordinates,\"\nprint \"the approximate number of degrees from the X and Z\"\nprint \"axes, and the approximate distance to the target.\"\nprint \"You will then proceed to shoot at the target until it is\"\nprint \"destroyed!\"\nprint; print\nprint \"Good luck!\"\nroundToList = [20,10,2,1]\nready = true\nwhile ready\n\tturns = -1\n\tradX = rnd * 2 * pi\n\tradZ = rnd * 2 * pi\n\tprint \"Radians from X axis = \" + radX + \"  from Z axis = \" + radZ\n\t\n\tdistance = 100000 * rnd * rnd\n\tcoords = getCoord(distance, radX, radZ)\n\t\n\tprint \"Target sighted: Approx Coordinates: \" + coordStr(coords)\n\t\n\tgameRunning = true\n\twhile gameRunning\n\t\tturns += 1\n\t\tif turns >=4 then\n\t\t\testDistance = distance\n\t\telse\n\t\t\testDistance = roundDown(distance, roundToList[turns])\n\t\tend if\n\t\t\n\t\tprint \"    Estimated Distance: \" + \testDistance\n\t\tprint\n\t\ttx = input(\"Input angle deviation from X in degrees: \").val\n\t\ttz = input(\"Input angle deviation from Z in degrees: \").val\n\t\ttdist = input(\"Input distance: \").val\n\t\tprint\n\t\tif tdist < 20 then\n\t\t\tprint \"You blew yourself up!!\"\n\t\t\tgameRunning = false\n\t\telse\n\t\t\ttx = degToRad(tx)\n\t\t\ttz = degToRad(tz)\n\t\t\t\n\t\t\tprint \"Radians from X-axis = \" + tx + \" from Z-axis = \" + tz\n\t\t\ttargeted = getCoord(tdist, tx,tz)\n\t\t\tdistBet = distanceBetween(coords, targeted)\n\t\t\tif distBet > 20 then\n\t\t\t\tdx = targeted[0] - coords[0]\n\t\t\t\tdy = targeted[1] - coords[1]\n\t\t\t\tdz = targeted[2] - coords[2]\n\t\t\t\txMsg = {false: \"Shot in front of target \", true: \"Shot behind target \"}\n\t\t\t\tprint xMsg[dx<0] + dx + \" kilometers.\"\n\t\t\t\tyMsg = {false: \"Shot to left of target \", true: \"Shot to right of target \"}\n\t\t\t\tprint yMsg[dy<0] + dy + \" kilometers.\"\n\t\t\t\tzMsg = {false: \"Shot above target \", true: \"Shot below target \"}\n\t\t\t\tprint zMsg[dz<0] + dz + \" kilometers.\"\n\t\t\t\t\n\t\t\t\tprint \"Approx position of explosion: \" + coordStr(targeted)\n\t\t\t\tprint \"    Distance from target = \" + distBet\n\t\t\t\tprint \n\t\t\t\tprint\n\t\t\t\t\n\t\t\telse\n\t\t\t\tprint\n\t\t\t\tprint \" * * * HIT * * *  Target is non-functional\"\n\t\t\t\tprint\n\t\t\t\tprint \"Distance of explosion from target was \" + distBet + \"kilometers.\"\n\t\t\t\tprint\n\t\t\t\tprint \"Mission accomplished in \" + (turns+1) + \" shots.\"\n\t\t\t\tprint\n\t\t\t\tgameRunning = false\n\t\t\tend if\n\t\tend if\n\tend while\n\tprint\n\tans = input(\"Ready for next target? \").lower\n\tready = ans and  ans[0].lower == \"y\"\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/86_Target/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/86_Target/target.bas",
    "content": "10 PRINT TAB(33);\"TARGET\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 R=1: R1=57.296: P=3.14159\n110 PRINT \"YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\"\n120 PRINT \"AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\"\n130 PRINT \"ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\"\n140 PRINT \"THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\"\n150 PRINT \"OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\"\n160 PRINT \"THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\"\n170 PRINT \"AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\"\n180 PRINT \"YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\"\n190 PRINT \"DESTROYED!\": PRINT: PRINT \"GOOD LUCK!!\":PRINT: PRINT\n220 A=RND(1)*2*P: B=RND(1)*2*P: Q=INT(A*R1): W=INT(B*R1)\n260 PRINT \"RADIANS FROM X AXIS =\";A;\"   FROM Z AXIS =\";B\n280 P1=100000*RND(1)+RND(1): X=SIN(B)*COS(A)*P1: Y=SIN(B)*SIN(A)*P1\n290 Z=COS(B)*P1\n340 PRINT \"TARGET SIGHTED: APPROXIMATE COORDINATES:  X=\";X;\"  Y=\";Y;\"  Z=\";Z\n345 R=R+1: IF R>5 THEN 390\n350 ON R GOTO 355,360,365,370,375\n355 P3=INT(P1*.05)*20: GOTO 390\n360 P3=INT(P1*.1)*10: GOTO 390\n365 P3=INT(P1*.5)*2: GOTO 390\n370 P3=INT(P1): GOTO 390\n375 P3=P1\n390 PRINT \"     ESTIMATED DISTANCE:\";P3\n400 PRINT:PRINT \"INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE\";\n405 INPUT A1,B1,P2\n410 PRINT: IF P2<20 THEN PRINT \"YOU BLEW YOURSELF UP!!\": GOTO 580\n420 A1=A1/R1: B1=B1/R1: PRINT \"RADIANS FROM X AXIS =\";A1;\"  \";\n425 PRINT \"FROM Z AXIS =\";B1\n480 X1=P2*SIN(B1)*COS(A1): Y1=P2*SIN(B1)*SIN(A1): Z1=P2*COS(B1)\n510 D=((X1-X)^2+(Y1-Y)^2+(Z1-Z)^2)^(1/2)\n520 IF D>20 THEN 670\n530 PRINT: PRINT \" * * * HIT * * *   TARGET IS NON-FUNCTIONAL\": PRINT\n550 PRINT \"DISTANCE OF EXPLOSION FROM TARGET WAS\";D;\"KILOMETERS.\"\n570 PRINT: PRINT \"MISSION ACCOMPLISHED IN \";R;\" SHOTS.\"\n580 R=0: FOR I=1 TO 5: PRINT: NEXT I: PRINT \"NEXT TARGET...\": PRINT\n590 GOTO 220\n670 X2=X1-X: Y2=Y1-Y: Z2=Z1-Z: IF X2<0 THEN 730\n710 PRINT \"SHOT IN FRONT OF TARGET\";X2;\"KILOMETERS.\": GOTO 740\n730 PRINT \"SHOT BEHIND TARGET\";-X2;\"KILOMETERS.\"\n740 IF Y2<0 THEN 770\n750 PRINT \"SHOT TO LEFT OF TARGET\";Y2;\"KILOMETERS.\": GOTO 780\n770 PRINT \"SHOT TO RIGHT OF TARGET\";-Y2;\"KILOMETERS.\"\n780 IF Z2<0 THEN 810\n790 PRINT \"SHOT ABOVE TARGET\";Z2;\"KILOMETERS.\": GOTO 820\n810 PRINT \"SHOT BELOW TARGET\";-Z2;\"KILOMETERS.\"\n820 PRINT \"APPROX POSITION OF EXPLOSION:  X=\";X1;\"   Y=\";Y1;\"   Z=\";Z1\n830 PRINT \"     DISTANCE FROM TARGET =\";D: PRINT: PRINT: PRINT: GOTO 345\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/3dplot.bas",
    "content": "1 PRINT TAB(32);\"3D PLOT\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n5 DEF FNA(Z)=30*EXP(-Z*Z/100)\n100 PRINT\n110 FOR X=-30 TO 30 STEP 1.5\n120 L=0\n130 Y1=5*INT(SQR(900-X*X)/5)\n140 FOR Y=Y1 TO -Y1 STEP -5\n150 Z=INT(25+FNA(SQR(X*X+Y*Y))-.7*Y)\n160 IF Z<=L THEN 190\n170 L=Z\n180 PRINT TAB(Z);\"*\";\n190 NEXT Y\n200 PRINT\n210 NEXT X\n300 END\n"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms",
    "content": "// 3dPlot\n//\n// Converted from BASIC to MiniScript by Joe Strout\n\nprint \" \"*32 + \"3D PLOT\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\ne = 2.71828\n\nfna = function(z)\n\treturn 30 * e^(-z*z/100)\nend function\n\nfor x in range(-30, 30, 1.5)\n\tlastZ = 0\n\ty1 = 5 * floor(sqrt(900-x*x)/5)\n\tfor y in range(y1, -y1, -5)\n\t\tz = floor(25+fna(sqrt(x*x+y*y))-.7*y)\n\t\tif z > lastZ then\n\t\t\tprint \" \"*(z-lastZ) + \"*\", \"\"\n\t\t\tlastZ = z\n\t\tend if\n\tend for\n\tprint\n\twait 0.1  // (optional)\nend for\n"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript number.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"number\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/d/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -dip1000 -run threedeeplot.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n\n## On rounding floating point values to integer values\n\nThe D equivalent of Basic `INT` is [`floor`](https://dlang.org/phobos/std_math_rounding.html#.floor),\nwhich rounds towards negative infinity. If you change occurrences of `floor` to\n[`lrint`](https://dlang.org/phobos/std_math_rounding.html#.lrint), you'll see that the plots show a bit more detail,\nas is done in the bonus below.\n\n## Bonus: Self-writing programs\n\nWith a small modification to the source, the program can be extended to **plot a random function**, and **print its formula**.\n\n```shell\nrdmd -dip1000 threedeeplot_random.d\n```\n(`rdmd` caches the executable, which results in speedy execution when the source does not change.)\n\n### Example output\n```\n                                    3D Plot\n              (After Creative Computing  Morristown, New Jersey)\n\n\n                           f(z) = 30 * sin(z / 10.0)\n\n                             *\n                      *      *    * *\n                *         *      *    * *\n                    *         *      *    * *\n            *           *        *       *   *  *\n               *           *         *      *   *  *\n                  *           *         *     *    * **\n       *             *           *        *      *   *  *\n         *              *           *       *     *   *  **\n            *              *          *       *    *   *  * *\n              *              *          *      *   *   *  *  *\n                *              *          *     *  *  *   *   **\n                  *              *         *    * *  *   *    * *\n   *                *             *        *    ** *    *     * *\n    *                *             *        *  **     *      *   *\n     *                 *            *       * *     *       *    *\n      *                 *            *      * *   *         *    *\n       *                *             *     ** *           *     **\n        *                *            *     **            *      **\n        *                *            *     *            *       **\n        *                *            *     *            *       **\n        *                *            *     *            *       **\n        *                *            *     **            *      **\n       *                *             *     ** *           *     **\n      *                 *            *      * *   *         *    *\n     *                 *            *       * *     *       *    *\n    *                *             *        *  **     *      *   *\n   *                *             *        *    ** *    *     * *\n                  *              *         *    * *  *   *    * *\n                *              *          *     *  *  *   *   **\n              *              *          *      *   *   *  *  *\n            *              *          *       *    *   *  * *\n         *              *           *       *     *   *  **\n       *             *           *        *      *   *  *\n                  *           *         *     *    * **\n               *           *         *      *   *  *\n            *           *        *       *   *  *\n                    *         *      *    * *\n                *         *      *    * *\n                      *      *    * *\n                             *\n```\n\n### Breakdown of differences\n\nHave a look at the relevant differences between `threedeeplot.d` and `threedeeplot_random.d`.\nThis is the original function with the single expression that is evaluated for the plot:\n```d\n    static float fna(float z)\n    {\n        return 30.0 * exp(-z * z / 100.0);\n    }\n```\nHere `static` means that the nested function does not need acces to its enclosing scope.\n\nNow, by inserting the following:\n```d\n    enum functions = [\"30.0 * exp(-z * z / 100.0)\",\n                      \"sqrt(900.01 - z * z) * .9 - 2\",\n                      \"30 * (cos(z / 16.0) + .5)\",\n                      \"30 - 30 * sin(z / 18.0)\",\n                      \"30 * exp(-cos(z / 16.0)) - 30\",\n                      \"30 * sin(z / 10.0)\"];\n\n    size_t index = uniform(0, functions.length);\n    writeln(center(\"f(z) = \" ~ functions[index], width), \"\\n\");\n```\nand changing the implementation of `fna` to\n```d\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            static foreach (i, f; functions)\n                case i:\n                    mixin(\"return \" ~ f ~ \";\");\n        }\n    }\n```\nwe unlock some very special abilities of D. Let's break it down:\n\n```d\n    enum functions = [\"30.0 * exp(-z * z / 100.0)\", /*...*/];\n```\nThis defines an array of strings, each containing a mathematical expression. Due to the `enum` keyword, this is an\narray that really only exists at compile-time.\n\n```d\n    size_t index = uniform(0, functions.length);\n```\nThis defines a random index into the array. `functions.length` is evaluated at compile-time, due to D's compile-time\nfunction evaluation (CTFE).\n\n```d\n    writeln(center(\"f(z) = \" ~ functions[index], width), \"\\n\");\n```\nUnmistakenly, this prints the formula centered on a line. What happens behind the scenes is that `functions` (which\nonly existed at compile-time before now) is pasted in, so that an instance of that array actually exists at run-time\nat this spot, and is instantly indexed.\n\n```d\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            // ...\n        }\n    }\n```\n`static` has been dropped from the nested function because we want to evaluate `index` inside it. The function contains\nan ordinary `switch`, with `final` providing some extra robustness. It disallows a `default` case and produces an error\nwhen the switch doesn't handle all cases. The `switch` body is where the magic happens and consists of these three\nlines:\n```d\n            static foreach (i, f; functions)\n                case i:\n                    mixin(\"return \" ~ f ~ \";\");\n```\nThe `static foreach` iterates over `functions` at compile-time, producing one `case` for every element in `functions`.\n`mixin` takes a string, which is constructed at compile-time, and pastes it right into the source.\n\nIn effect, the implementation of `float fna(float z)` unrolls itself into\n```d\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            case 0:\n                return 30.0 * exp(-z * z / 100.0);\n            case 1:\n                return sqrt(900.01 - z * z) * .9 - 2;\n            case 2:\n                return 30 * (cos(z / 16.0) + .5);\n            case 3:\n                return 30 - 30 * sin(z / 18.0);\n            case 4:\n                return 30 * exp(-cos(z / 16.0)) - 30;\n            case 5:\n                return 30 * sin(z / 10.0)\";\n        }\n    }\n```\n\nSo if you feel like adding another function, all you need to do is append it to the `functions` array, and the rest of\nthe program *rewrites itself...*\n"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/d/threedeeplot.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std.stdio, std.string, std.math, std.range, std.conv, std.algorithm;\n\nvoid main()\n{\n    enum width = 80;\n    writeln(center(\"3D Plot\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\\n\", width));\n\n    static float fna(float z)\n    {\n        return 30.0 * exp(-z * z / 100.0);\n    }\n\n    char[] row;\n\n    for (float x = -30.0; x <= 30.0; x += 1.5)\n    {\n        size_t max_z = 0L;\n        auto y1 = 5 * floor((sqrt(900 - x * x)) / 5.0);\n        for (float y = y1; y >= -y1; y -= 5)\n        {\n            auto z = to!size_t(max(0, floor(25 + fna(sqrt(x * x + y * y)) - .7 * y)));\n            if (z > max_z) // Visible\n            {\n                max_z = z;\n                if (z + 1 > row.length) // row needs to grow\n                    row ~= ' '.repeat(z + 1 - row.length).array;\n                row[z] = '*';\n            }\n        }\n        writeln(row);\n        row = null;\n    }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/87_3-D_Plot/d/threedeeplot_random.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std.stdio, std.string, std.math, std.range, std.conv, std.random, std.algorithm;\n\nvoid main()\n{\n    enum width = 80;\n    writeln(center(\"3D Plot\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\", width));\n\n    enum functions = [\"30.0 * exp(-z * z / 100.0)\",\n                      \"sqrt(900.01 - z * z) * .9 - 2\",\n                      \"30 * (cos(z / 16.0) + .5)\",\n                      \"30 - 30 * sin(z / 18.0)\",\n                      \"30 * exp(-cos(z / 16.0)) - 30\",\n                      \"30 * sin(z / 10.0)\"];\n\n    size_t index = uniform(0, functions.length);\n    writeln(center(\"f(z) = \" ~ functions[index], width), \"\\n\");\n\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            static foreach (i, f; functions)\n                case i:\n                    mixin(\"return \" ~ f ~ \";\");\n        }\n    }\n\n    char[] row;\n\n    for (float x = -30.0; x <= 30.0; x += 1.5)\n    {\n        size_t max_z = 0L;\n        auto y1 = 5 * lrint((sqrt(900 - x * x)) / 5.0);\n        for (float y = y1; y >= -y1; y -= 5)\n        {\n            auto z = to!size_t(max(0, lrint(25 + fna(sqrt(x * x + y * y)) - .7 * y)));\n            if (z > max_z) // Visible\n            {\n                max_z = z;\n                if (z + 1 > row.length) // row needs to grow\n                    row ~= ' '.repeat(z + 1 - row.length).array;\n                row[z] = '*';\n            }\n        }\n        writeln(row);\n        row = null;\n    }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript qubit.ms\n```\n\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"qubit\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms",
    "content": "print \" \"*33 + \"QUBIC\"\nprint \" \"*15 + \"Creative Computing  Morristown  New Jersey\"\nprint; print; print\n\ngetYesNo = function(prompt)\n\twhile true\n\t\tyn = input(prompt + \"? \").lower + \" \"\n\t\tif yn[0] == \"y\" then return \"yes\"\n\t\tif yn[0] == \"n\" then return \"no\"\n\t\tprint \"Incorrect answer.  Please type 'yes' or 'no'\"\n\tend while\nend function\n\n// Data defining \"lines\" as sets of board indexes which form 4-in-a-row:\nma = [null,\n          [null, 1,2,3,4],    // 1\n          [null, 5,6,7,8],    // 2\n          [null, 9,10,11,12], // 3\n          [null, 13,14,15,16],    // 4\n          [null, 17,18,19,20],    // 5\n          [null, 21,22,23,24],    // 6\n          [null, 25,26,27,28],    // 7\n          [null, 29,30,31,32],    // 8\n          [null, 33,34,35,36],    // 9\n          [null, 37,38,39,40],    // 10\n          [null, 41,42,43,44],    // 11\n          [null, 45,46,47,48],    // 12\n          [null, 49,50,51,52],    // 13\n          [null, 53,54,55,56],    // 14\n          [null, 57,58,59,60],    // 15\n          [null, 61,62,63,64],    // 16\n          [null, 1,17,33,49], // 17\n          [null, 5,21,37,53],    // 18\n          [null, 9,25,41,57],   // 19\n          [null, 13,29,45,61], // 20\n          [null, 2,18,34,50], // 21\n          [null, 6,22,38,54],    // 22\n          [null, 10,26,42,58],  // 23\n          [null, 14,30,46,62],   // 24\n          [null, 3,19,35,51], // 25\n          [null, 7,23,39,55],    // 26\n          [null, 11,27,43,59],  // 27\n          [null, 15,31,47,63], // 28\n          [null, 4,20,36,52], // 29\n          [null, 8,24,40,56], // 30\n          [null, 12,28,44,60],    // 31\n          [null, 16,32,48,64],    // 32\n          [null, 1,5,9,13],   // 33\n          [null, 17,21,25,29],    // 34\n          [null, 33,37,41,45],    // 35\n          [null, 49,53,57,61],    // 36\n          [null, 2,6,10,14],  // 37\n          [null, 18,22,26,30],    // 38\n          [null, 34,38,42,46],    // 39\n          [null, 50,54,58,62],    // 40\n          [null, 3,7,11,15],  // 41\n          [null, 19,23,27,31],    // 42\n          [null, 35,39,43,47],    // 43\n          [null, 51,55,59,63],    // 44\n          [null, 4,8,12,16],  // 45\n          [null, 20,24,28,32],    // 46\n          [null, 36,40,44,48],    // 47\n          [null, 52,56,60,64],    // 48\n          [null, 1,6,11,16],  // 49\n          [null, 17,22,27,32],    // 50\n          [null, 33,38,43,48],    // 51\n          [null, 49,54,59,64],    // 52\n          [null, 13,10,7,4],  // 53\n          [null, 29,26,23,20],    // 54\n          [null, 45,42,39,36],    // 55\n          [null, 61,58,55,52],    // 56\n          [null, 1,21,41,61], // 57\n          [null, 2,22,42,62], // 58\n          [null, 3,23,43,63], // 59\n          [null, 4,24,44,64], // 60\n          [null, 49,37,25,13],    // 61\n          [null, 50,38,26,14],    // 62\n          [null, 51,39,27,15],    // 63\n          [null, 52,40,28,16],    // 64\n          [null, 1,18,35,52], // 65\n          [null, 5,22,39,56], // 66\n          [null, 9,26,43,60], // 67\n          [null, 13,30,47,64],    // 68\n          [null, 49,34,19,4], // 69\n          [null, 53,38,23,8], // 70\n          [null, 57,42,27,12],    // 71\n          [null, 61,46,31,16],    // 72\n          [null, 1,22,43,64], // 73\n          [null, 16,27,38,49],    // 74\n          [null, 4,23,42,61], // 75\n          [null, 13,26,39,52]] // 76\n          \n// \"opening book\", i.e. spots that are generally good to hold if available\nya = [null, 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43]\n\nshowBoard = function\n\tfor i in range(1,9); print; end for\n\tfor i in range(1, 4)\n\t\tprint\n\t\tfor j in range(1, 4)\n\t\t\tstr = \"   \" * j\n\t\t\tfor k in range(1, 4)\n\t\t\t\tq = 16 * i + 4 * j + k - 20\n\t\t\t\tif xa[q] == 5 then\n\t\t\t\t\tstr += \"(M)\"\n\t\t\t\telse if xa[q] == 1 then\n\t\t\t\t\tstr += \"(Y)\"\n\t\t\t\telse\n\t\t\t\t\tstr += \"( )\"\n\t\t\t\tend if\n\t\t\t\tstr += \"      \"\n\t\t\tend for\n\t\t\tprint str\n\t\t\t// print\t(makes display too tall for the screen)\n\t\tend for\n\t\tprint\n\tend for\nend function\n\nclearFractions = function\n\tfor i in range(1, 64)\n\t\tif xa[i] == 1/8 then xa[i] = 0\n\tend for\nend function\n\ncheckForLines = function\n\tfor s in range(1, 76)\n\t\tj1 = ma[s][1];\n\t\tj2 = ma[s][2];\n\t\tj3 = ma[s][3];\n\t\tj4 = ma[s][4];\n\t\tla[s] = xa[j1] + xa[j2] + xa[j3] + xa[j4]\n\tend for\nend function\n\ndoPlayerMove = function\n\tclearFractions\n\twhile true\n\t\tprint\n\t\tinp = input(\"Your move? \")\n\t\tif inp == \"0\" then\n\t\t\tshowBoard\n\t\t\tcontinue\n\t\tend if\n\t\tif inp == \"1\" then exit\n\t\tok = true\n\t\tif inp.len != 3 then\n\t\t\tok = false\n\t\telse\n\t\t\ti = inp[0].val\n\t\t\tj = inp[1].val\n\t\t\tk = inp[2].val\n\t\t\tok = (0 < i < 5) and (0 < j < 5) and (0 < k < 5)\n\t\tend if\n\t\tif not ok then\n\t\t\tprint \"Incorrect move, retype it--\"\n\t\telse\n\t\t\tm = 16 * i + 4 * j + k - 20\n\t\t\tif xa[m] != 0 then\n\t\t\t\tprint \"That square is used, try again.\"\n\t\t\telse\n\t\t\t\txa[m] = 1\n\t\t\t\tbreak\n\t\t\tend if\n\t\tend if\n\tend while\nend function\n\nselectMove = function(lineIndex, valueToReplace)\n    if lineIndex % 4 <= 1 then a = 1 else a = 2\n    for j in range(a, 5 - a, 5 - 2 * a)\n        if xa[ma[lineIndex][j]] == valueToReplace then\n\t\t\txa[ma[lineIndex][j]] = 5\n\t\t\tm = ma[lineIndex][j]\n\t\t\tprint \"Machine takes \" + squareName(m)\n\t\t\treturn true\n        end if\n    end for\n    return false\nend function\n\ndoComputerMove = function\n\t// look for lines with two M's and two blanks; add 1/8 to the blank spots\n\tfor i in range(1, 76)\n\t\tla[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]]\n\t\tl = la[i]\n\t\tif l == 10 then\n\t\t\tfor j in range(1, 4)\n\t\t\t\tif (xa[ma[i][j]] == 0) then xa[ma[i][j]] = 1/8\n\t\t\tend for\n\t\tend if\n\tend for\n\t// ...and if we now find lines containing 4 such spots, or 1 M and 3 such spots,\n\t// then pick one of those spots for our move\n\tcheckForLines\n\tfor i in range(1, 76)\n\t\tif la[i] == 4/8 or la[i] == 5 + 3/8 then\n\t\t\tselectMove i, 1/8\n\t\t\treturn true\n\t\tend if\n\tend for\n\n\t// now look for lines containing 2 Y's, and mark (with 1/8) the blank spots\n\tclearFractions\n\tfor i in range(1, 76)\n\t\tla[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]]\n\t\tl = la[i]\n\t\tif l == 2 then\n\t\t\tfor j in range(1, 4)\n\t\t\t\tif (xa[ma[i][j]] == 0) then xa[ma[i][j]] = 1 / 8\n\t\t\tend for\n\t\tend if\n\tend for\n\t// ...and again, if we find 4 such spots in a row, or 1 player move plus\n\t// 3 marked spots, then pick one of those\n\tcheckForLines\n\tfor i in range(1, 76)\n\t\tif la[i] == 4/8  or la[i] == 1 + 3/8 then\n\t\t\tselectMove 1/8\n\t\t\treturn true\n\t\tend if\n\tend for\n\n\t// do mysterious stuff that depends on the order of lines in ma\n\t// in ways I don't understand\n\tfor k in range(1, 18)\n\t\tp = 0\n\t\tfor i in range(4 * k - 3, 4 * k)\n\t\t\tfor j in range(1, 4)\n\t\t\t\tp += xa[ma[i][j]]\n\t\t\tend for\n\t\tend for\n\t\tif p == 4 or p == 9 then\n\t\t\tfor i in range(4 * k - 3, 4 * k)\n\t\t\t\tif selectMove(1/8) then return true\n\t\t\tend for\n\t\t\ts = 0\n\t\tend if\n\tend for\n\n\t// look for certain \"good\" spots in our ya array that are still available\n\tclearFractions\n\tfound = false\n\tfor z in range(1, 17)\n\t\tif xa[ya[z]] == 0 then\n\t\t\tfound = true\n\t\t\tbreak\n\t\tend if\n\tend for\n\tif not found then\n\t\t// getting desperate, look for any open spot\n\t\tfor i in range(1, 64)\n\t\t\tif xa[i] == 0 then\n\t\t\t\txa[i] = 5\n\t\t\t\tprint \"Machine likes \" + squareName(i)\n\t\t\t\treturn true\n\t\t\tend if\n\t\tend for\n\t\tprint \"The game is a draw.\"\n\t\treturn false\n\tend if\n\tm = ya[z]\n\txa[m] = 5\n\tprint \"Machine moves to \" + squareName(m)\n\treturn true\nend function\n\nsquareName = function(m)\n\tk1 = floor((m - 1) / 16) + 1\n\tj2 = m - 16 * (k1 - 1)\n\tk2 = floor((j2 - 1) / 4) + 1\n\tk3 = m - (k1 - 1) * 16 - (k2 - 1) * 4\n\treturn str(k1) + k2 + k3\nend function\n\ndoOneGame = function\n\tglobals.xa = [null] + [0] * 64\t// board state\n\tglobals.la = [null] + [0] * 76\t// line data\n\tskipFirst = getYesNo(\"Do you want to move first\") == \"no\"\n\twhile true\n\t\tif skipFirst then\n\t\t\tskipFirst = false\n\t\telse\n\t\t\tdoPlayerMove\n\t\tend if\n\t\tcheckForLines\n\t\tmachineDone = false\n\t\t// take three passes over the straight lines in the board\n\t\tfor j in range(1, 3)\n\t\t\tfor i in range(1, 76)\n\t\t\t\t// first pass: check for player win\n\t\t\t\tif j == 1 then\n\t\t\t\t\tif la[i] != 4 then continue;\n\t\t\t\t\tprint \"You win as follows\" + \" (line \" + i + \")\"\n\t\t\t\t\tfor j in range(1, 4)\n\t\t\t\t\t\tprint squareName(ma[i][j])\n\t\t\t\t\tend for\n\t\t\t\t\treturn\n\t\t\t\tend if\n\t\t\t\t// second pass: check for machine able to win\n\t\t\t\tif j == 2 then\n\t\t\t\t\tif la[i] != 15 then continue;\n\t\t\t\t\tfor j in range(1, 4)\n\t\t\t\t\t\tm = ma[i][j]\n\t\t\t\t\t\tif (xa[m] != 0) then continue;\n\t\t\t\t\t\txa[m] = 5\n\t\t\t\t\t\tbreak\n\t\t\t\t\tend for\n\t\t\t\t\tprint \"Machine moves to \" + squareName(m) + \", and wins as follows\"\n\t\t\t\t\tfor j in range(1, 4)\n\t\t\t\t\t\tprint squareName(ma[i][j])\n\t\t\t\t\tend for\n\t\t\t\t\treturn\n\t\t\t\tend if\n\t\t\t\t// third pass: check for player about to win\n\t\t\t\tif j == 3 then\n\t\t\t\t\tif la[i] != 3 then continue\n\t\t\t\t\tfor j in range(1, 4)\n\t\t\t\t\t\tm = ma[i][j]\n\t\t\t\t\t\tif xa[m] != 0 then continue\n\t\t\t\t\t\txa[m] = 5\n\t\t\t\t\t\tprint \"Nice try, machine moves to \" + squareName(m)\n\t\t\t\t\t\tmachineDone = true\n\t\t\t\t\tend for\n\t\t\t\t\tbreak\n\t\t\t\tend if\n\t\t\tend for\n\t\tend for\n\t\tif (machineDone) then continue\n\n\t\tif not doComputerMove then break\n\tend while\nend function\n\n\n// Main program\nif getYesNo(\"Do you want instructions\") == \"yes\" then\n\tprint\n\tprint \"The game is tic-tac-toe in a 4 x 4 x 4 cube.\"\n\tprint \"Each move is indicated by a 3 digit number, with each\"\n\tprint \"digit between 1 and 4 inclusive.  The digits indicate the\"\n\tprint \"level, row, and column, respectively, of the occupied\"\n\tprint \"place.  \"\n\tprint\n\tprint \"To print the playing board, type 0 (zero) as your move.\"\n\tprint \"The program will print the board with your moves indi-\"\n\tprint \"cated with a (Y), the machine's moves with an (M), and\"\n\tprint \"unused squares with a ( ).\" // \"output is on paper.\"\n\tprint\n\tprint \"To stop the program run, type 1 as your move.\"\n\tprint\n\tprint\nend if\nwhile true\n\tdoOneGame\n\tprint\n\tif getYesNo(\"Do you want to try another game\") == \"no\" then break\nend while\n\n\n\n"
  },
  {
    "path": "00_Alternate_Languages/88_3-D_Tic-Tac-Toe/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/88_3-D_Tic-Tac-Toe/qubit.bas",
    "content": "50 PRINT CHR$(26):REM WIDTH 80\n100 PRINT TAB(33);\"QUBIC\":PRINT\n110 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n120 PRINT:PRINT:PRINT\n210 PRINT \"DO YOU WANT INSTRUCTIONS\";\n220 INPUT C$\n230 IF LEFT$(C$,1)=\"N\" THEN 315\n240 IF LEFT$(C$,1)=\"Y\" THEN 265\n250 PRINT \"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'\";\n260 GOTO 220\n265 PRINT\n270 PRINT \"THE GAME IS TIC-TAC-TOE IN A 4 X 4 X 4 CUBE.\"\n280 PRINT \"EACH MOVE IS INDICATED BY A 3 DIGIT NUMBER, WITH EACH\"\n290 PRINT \"DIGIT BETWEEN 1 AND 4 INCLUSIVE.  THE DIGITS INDICATE THE\"\n300 PRINT \"LEVEL, ROW, AND COLUMN, RESPECTIVELY, OF THE OCCUPIED\"\n305 PRINT \"PLACE.  \"\n306 PRINT\n307 PRINT \"TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE.\"\n308 PRINT \"THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-\"\n309 PRINT \"CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND\"\n310 PRINT \"UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER.\"\n311 PRINT\n312 PRINT \"TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE.\"\n313 PRINT:PRINT\n315 DIM X(64),L(76),M(76,4),Y(16)\n320 FOR I = 1 TO 16\n330 READ Y(I)\n340 NEXT I\n350 FOR I=1 TO 76\n360 FOR J = 1 TO 4\n370 READ M(I,J)\n380 NEXT J\n390 NEXT I\n400 FOR I = 1 TO 64\n410 LET X (I) =0\n420 NEXT I\n430 LET Z=1\n440 PRINT \"DO YOU WANT TO MOVE FIRST\";\n450 INPUT S$\n460 IF LEFT$(S$,1)=\"N\" THEN 630\n470 IF LEFT$(S$,1)=\"Y\" THEN 500\n480 PRINT \"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'.\";\n490 GOTO 450\n500 PRINT \" \"\n510 PRINT \"YOUR MOVE\";\n520 INPUT J1\n521 IF J1=1 THEN 2770\n522 IF J1<>0 THEN 525\n523 GOSUB 2550\n524 GOTO 500\n525 IF J1<111 THEN 2750\n526 IF J1>444 THEN 2750\n530 GOSUB 2500\n540 LET K1=INT(J1/100)\n550 LET J2=(J1-K1*100)\n560 LET K2=INT(J2/10)\n570 LET K3= J1 - K1*100 -K2*10\n580 LET M=16*K1+4*K2+K3-20\n590 IF X(M)=0 THEN 620\n600 PRINT \"THAT SQUARE IS USED, TRY AGAIN.\"\n610 GOTO 500\n620 LET X(M)=1\n630 GOSUB 1640\n640 J=1\n650 I=1\n660 IF J=1 THEN 720\n670 IF J=2 THEN 790\n680 IF J=3 THEN 930\n690 I=I+1: IF I<=76 THEN 660\n700 J=J+1: IF J<=3 THEN 650\n710 GOTO 1300\n720 IF L(I)<>4 THEN 690\n730 PRINT \"YOU WIN AS FOLLOWS\";\n740 FOR J=1 TO 4\n750 LET M=M(I,J)\n760 GOSUB 1570\n770 NEXT J\n780 GOTO 1490\n790 IF L(I)<>15 THEN 690\n800 FOR J=1 TO 4\n810 LET M=M(I,J)\n820 IF X(M)<>0 THEN 860\n830 LET X(M)=5\n840 PRINT \"MACHINE MOVES TO\";\n850 GOSUB 1570\n860 NEXT J\n870 PRINT \", AND WINS AS FOLLOWS\"\n880 FOR J=1 TO 4\n890 LET M=M(I,J)\n900 GOSUB 1570\n910 NEXT J\n920 GOTO 1490\n930 IF L(I)<>3 THEN 690\n940 PRINT \"NICE TRY. MACHINE MOVES TO\";\n950 FOR J=1 TO 4\n960 LET M=M(I,J)\n970 IF X(M)<>0 THEN 1010\n980 LET X(M)=5\n990 GOSUB 1570\n1000 GOTO 500\n1010 NEXT J\n1020 GOTO 1300\n1030 I=1\n1040 LET L(I)=X(M(I,1))+X(M(I,2))+X(M(I,3))+X(M(I,4))\n1050 LET L = L(I)\n1060 IF L <2 THEN 1130\n1070 IF L>=3 THEN 1130\n1080 IF L>2 THEN 2230\n1090 FOR J = 1 TO 4\n1100 IF X(M(I,J))<>0 THEN 1120\n1110 LET X(M(I,J))=1/8\n1120 NEXT J\n1130 I=I+1: IF I<=76 THEN 1040\n1140 GOSUB 1640\n1150 I=1\n1160 IF L(I)=1/2 THEN 2360\n1170 IF L(I)=1+3/8 THEN 2360\n1180 I=I+1: IF I<=76 THEN 1160\n1190 GOTO 1830\n1200 LET Z = 1\n1210 IF X(Y(Z))=0 THEN 1250\n1220 LET Z=Z+1\n1230 IF Z<>17 THEN 1210\n1240 GOTO 1720\n1250 LET M=Y(Z)\n1260 LET X(M)=5\n1270 PRINT \"MACHINE MOVES TO\";\n1280 GOSUB 1570\n1290 GOTO 500\n1300 LET X=X\n1310 I=1\n1320 LET L(I)=X(M(I,1))+X(M(I,2))+X(M(I,3))+X(M(I,4))\n1330 LET L=L(I)\n1340 IF L<10 THEN 1410\n1350 IF L>=11 THEN 1410\n1360 IF L>10 THEN 2230\n1370 FOR J=1 TO 4\n1380 IF X(M(I,J))<>0 THEN 1400\n1390 LET X(M(I,J))=1/8\n1400 NEXT J\n1410 I=I+1: IF I<=76 THEN 1320\n1420 GOSUB 1640\n1430 I=1\n1440 IF L(I)=.5 THEN 2360\n1450 IF L(I)=5+3/8 THEN 2360\n1460 I=I+1: IF I<=76 THEN 1440\n1470 GOSUB 2500\n1480 GOTO 1030\n1490 PRINT \" \"\n1500 PRINT \"DO YOU WANT TO TRY ANOTHER GAME\";\n1510 INPUT X$\n1520 IF LEFT$(X$,1)=\"Y\" THEN 400\n1530 IF LEFT$(X$,1)=\"N\" THEN 1560\n1540 PRINT \"INCORRECT ANSWER. PLEASE TYPE 'YES' OR 'NO'\";\n1550 GOTO 1510\n1560 END\n1570 LET K1=INT((M-1)/16)+1\n1580 LET J2=M-16*(K1-1)\n1590 LET K2=INT((J2-1)/4)+1\n1600 LET K3=M-(K1-1)*16-(K2-1)*4\n1610 LET M=K1*100+K2*10+K3\n1620 PRINT M;\n1630 RETURN\n1640 FOR S=1 TO 76\n1650 LET J1 = M(S,1)\n1660 LET J2=M(S,2)\n1670 LET J3=M(S,3)\n1680 LET J4=M(S,4)\n1690 LET L(S)=X(J1)+X(J2)+X(J3)+X(J4)\n1700 NEXT S\n1710 RETURN\n1720 FOR I=1 TO 64\n1730 IF X(I)<>0 THEN 1800\n1740 LET X(I)=5\n1750 LET M=I\n1760 PRINT \"MACHINE LIKES\";\n1770 GOSUB 1570\n1780 PRINT \" \"\n1790 GOTO 500\n1800 NEXT I\n1810 PRINT \"THE GAME IS A DRAW.\"\n1820 GOTO 1490\n1830 FOR K=1 TO 18\n1840 LET P=0\n1850 FOR I=4*K-3 TO 4*K\n1860 FOR J=1 TO 4\n1870 LET P=P+X(M(I,J))\n1880 NEXT J\n1890 NEXT I\n1900 IF P<4 THEN 1940\n1910 IF P<5 THEN 1970\n1920 IF P<9 THEN 1940\n1930 IF P<10 THEN 1970\n1940 NEXT K\n1950 GOSUB 2500\n1960 GOTO 1200\n1970 LET S=1/8\n1980 FOR I=4*K-3 TO 4*K\n1990 GOTO 2370\n2000 NEXT I\n2010 LET S=0\n2020 GOTO 1980\n2030 DATA 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43\n2040 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20\n2050 DATA 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38\n2060 DATA 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56\n2070 DATA 57,58,59,60,61,62,63,64\n2080 DATA 1,17,33,49,5,21,37,53,9,25,41,57,13,29,45,61\n2090 DATA 2,18,34,50,6,22,38,54,10,26,42,58,14,30,46,62\n2100 DATA 3,19,35,51,7,23,39,55,11,27,43,59,15,31,47,63\n2110 DATA 4,20,36,52,8,24,40,56,12,28,44,60,16,32,48,64\n2120 DATA 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61\n2130 DATA 2,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62\n2140 DATA 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63\n2150 DATA 4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64\n2160 DATA 1,6,11,16,17,22,27,32,33,38,43,48,49,54,59,64\n2170 DATA 13,10,7,4,29,26,23,20,45,42,39,36,61,58,55,52\n2180 DATA 1,21,41,61,2,22,42,62,3,23,43,63,4,24,44,64\n2190 DATA 49,37,25,13,50,38,26,14,51,39,27,15,52,40,28,16\n2200 DATA 1,18,35,52,5,22,39,56,9,26,43,60,13,30,47,64\n2210 DATA 49,34,19,4,53,38,23,8,57,42,27,12,61,46,31,16\n2220 DATA 1,22,43,64,16,27,38,49,4,23,42,61,13,26,39,52\n2230 FOR J=1 TO 4\n2240 IF X(M(I,J))<>1/8 THEN 2330\n2250 LET X(M(I,J))=5\n2260 IF L(I)<5 THEN 2290\n2270 PRINT \"LET'S SEE YOU GET OUT OF THIS:  MACHINE MOVES TO\";\n2280 GOTO 2300\n2290 PRINT \"YOU FOX.  JUST IN THE NICK OF TIME, MACHINE MOVES TO\";\n2300 LET M=M(I,J)\n2310 GOSUB 1570\n2320 GOTO 500\n2330 NEXT J\n2340 PRINT \"MACHINE CONCEDES THIS GAME.\"\n2350 GOTO 1490\n2360 LET S=1/8\n2370 IF I-INT(I/4)*4>1 THEN 2400\n2380 LET A=1\n2390 GOTO 2410\n2400 LET A=2\n2410 FOR J=A TO 5-A STEP 5-2*A\n2420 IF X(M(I,J))=S THEN 2450\n2430 NEXT J\n2440 GOTO 2000\n2450 LET X(M(I,J))=5\n2460 LET M=M(I,J)\n2470 PRINT \"MACHINE TAKES\";\n2480 GOSUB 1570\n2490 GOTO 500\n2500 FOR I=1 TO 64\n2510 IF X(I)<>1/8 THEN 2530\n2520 LET X(I)=0\n2530 NEXT I\n2540 RETURN\n2550 FOR XX=1 TO 9:PRINT:NEXT:FOR I=1 TO 4\n2560 FOR J=1 TO 4\n2562 FOR I1=1 TO J\n2564 PRINT\"   \";\n2566 NEXT I1\n2570 FOR K=1 TO 4\n2600 LET Q=16*I+4*J+K-20\n2610 IF X(Q)<>O THEN 2630\n2620 PRINT\"( )      \";\n2630 IF X(Q)<>5 THEN 2650\n2640 PRINT\"(M)      \";\n2650 IF X(Q)<>1 THEN 2660\n2655 PRINT\"(Y)      \";\n2660 IF X(Q)<>1/8 THEN 2670\n2665 PRINT\"( )      \";\n2670 NEXT K\n2680 PRINT\n2690 PRINT\n2700 NEXT J\n2710 PRINT\n2720 PRINT\n2730 NEXT I\n2735 REM PRINT CHR$(12)\n2740 RETURN\n2750 PRINT\"INCORRECT MOVE, RETYPE IT--\";\n2760 GOTO 520\n2770 END\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\r\n\r\nConversion to [MiniScript](https://miniscript.org).\r\n\r\nWays to play:\r\n\r\n1. Command-Line MiniScript:\r\nDownload for your system from <https://miniscript.org/cmdline/>, install, and then run the program with a command such as:\r\n\r\n```\r\n miniscript tictactoe.ms\r\n```\r\n\r\n2. Mini Micro:\r\nDownload Mini Micro from <https://miniscript.org/MiniMicro/>, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\r\n\r\n```\r\n load \"tictactoe\"\r\n run\r\n```\r\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms",
    "content": "// This program plays Tic Tac Toe\n// The machine goes first and the way this is set up\n// there's no way the human player can win. At best\n// it will be a draw.\ncomputerNext = function(x)\n\treturn x - 8 * floor((x - 1) / 8)\nend function\n\nprint \" \" * 30 + \"TIC TAC TOE\"\nprint \" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint; print; print\n\nprint \"The game board is numbered:\"\nprint\nprint \"1 2 3\"\nprint \"8 9 4\"\nprint \"7 6 5\"\nprint\n\nwhile true\n\tcomputer = 9\n\tgameOver = false\n\t// MOVE ONE line 240 in original\n\t// Computer always moves first and takes the center\n\tprint \"Computer moves \" + computer\n\tplayer = input(\"Your move? \").val\n\tplayerFirstMove = player\n\t\n\t// MOVE TWO line 280\n\t// Computer's 2nd move - always the next space clockwise\n\t// from the player's\n\tcomputer = computerNext(player + 1)\n\tcanWinAt = computerNext(computer+4)\n\tprint \"Computer moves \" + computer\n\tplayer = input(\"Your move? \").val\n\t\n\t// MOVE THREE line 300\n\t// Computer has two consecutive cells. This includes the\n\t// middle so, to complete this 3-in-a-row, get the opposite\n\t// value of comp's last move - which is four cells clockwise away.\n\t\n\tif player != canWinAt then\n\t\tcomputer = canWinAt\n\t\tprint \"Computer moves \" + computer\n\t\tprint \"... and wins ********\"\n\t\tgameOver = true\n\telse\n\t\t// Blocked - so two cells away from comp's last move\n\t\t// line 360\n\t\tcomputer = computerNext(computer + 2)\n\t\tprint \"Computer moves \" + computer\n\tend if\n\t\n\tif gameOver == false then\n\t\tcanWinAt = computerNext(computer+4)\n\t\tplayer = input(\"Your move? \").val\n\t\t\n\t\t// MOVE FOUR - line 400\n\t\tif player != canWinAt then\n\t\t\tcomputer = canWinAt\n\t\t\tprint \"Computer moves \" + computer\n\t\t\tprint \"... and wins ********\"\n\t\t\tgameOver = true\n\t\telse\n\t\t\t// Foiled again! - line 450\n\t\t\tif playerFirstMove % 2 == 0 then\n\t\t\t\tcomputer = computerNext(computer + 7)\n\t\t\t\tprint \"Computer moves \" + computer\n\t\t\t\tprint \"... and wins ********\"\n\t\t\t\tgameOver = true\n\t\t\telse // line 500\n\t\t\t\tcomputer = computerNext(computer + 3)\n\t\t\t\tprint \"Computer moves \" + computer\n\t\t\tend if\n\t\tend if\n\tend if\n\t\n\tif gameOver == false then\n\t\t// line 520\n\t\tplayer = input(\"Your move? \").val\n\t\tif player != computerNext(computer + 4) then\n\t\t\tcomputer = computerNext(computer + 4)\n\t\telse\n\t\t\tcomputer = computerNext(computer + 6)\n\t\tend if\n\t\tprint \"Computer moves \" + computer\n\t\tprint \"The game is a draw.\"\n\tend if\n\tprint\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms",
    "content": "solutions = [[0,1,2],[3,4,5],[6,7,8]]\nsolutions += [[0,3,6],[1,4,7],[2,5,8]]\nsolutions += [[0,4,8],[2,4,6]]\n\nTicTacToe = {}\nTicTacToe.grid = (\" \" * 9).split(\"\")\nTicTacToe.markers = {true: \"X\",false:\"O\"}\nTicTacToe.AI = \"X\"\nTicTacToe.human = \"O\"\nTicTacToe.next = \"X\"\nTicTacToe.lastMove = -1\n\nTicTacToe.show = function\n\tprint \" \" + self.grid[0:3].join(\" ! \")\n\tprint \"---+---+---\"\n\tprint \" \" + self.grid[3:6].join(\" ! \")\n\tprint \"---+---+---\"\n\tprint \" \" + self.grid[6:].join(\" ! \")\n\tprint\n\tprint\nend function\n\nTicTacToe.set = function(player, pos)\n\tif self.grid[pos] != \" \" then\n\t\treturn false\n\tend if\n\tself.grid[pos] = player\n\tself.lastMove = pos\n\treturn true\nend function\n\nTicTacToe.setMarkers = function(mark)\n\tself.human = self.markers[mark == \"X\"]\n\tself.AI = self.markers[mark == \"O\"]\nend function\n\nTicTacToe.getWinner = function\n\tfor mark in self.markers.values\n\t\tfor solution in solutions\n\t\t\tcnt = 0\n\t\t\tfor i in solution\n\t\t\t\tcnt += (self.grid[i] == mark)\n\t\t\tend for\n\t\t\tif cnt == 3 then return mark\n\t\tend for\n\tend for\n\treturn null\nend function\n\nTicTacToe.potentialWins = function\n\tpotential = {\"X\": [], \"O\": []}\n\tfor mark in self.markers.values\n\t\tfor solution in solutions\n\t\t\tcnt = 0\n\t\t\temptyCells = [] \n\t\t\tfor i in solution\n\t\t\t\tcnt += (self.grid[i] == mark)\n\t\t\t\tif self.grid[i] == \" \" then emptyCells.push(i)\n\t\t\tend for \n\t\t\tif cnt == 2 and emptyCells.len == 1 then potential[mark].push(emptyCells[0])\n\t\tend for\n\tend for\n\treturn potential\nend function\n\nTicTacToe.moveAvailable = function\n\treturn self.grid.indexOf(\" \") != null\nend function\n\nTicTacToe.selectAI = function\n\tif self.grid[4] == \" \" then return 4\n\t\n\tpotential = self.potentialWins\n\t\n\tAIWins = potential[self.AI]\n\tif AIWins.len >0 then return AIWins[0]\n\t\n\tHumanWins = potential[self.human]\n\t\n\tif HumanWins.len > 0 then return HumanWins[0]\n\t\n\tif [1,3,5,7].indexOf(self.lastMove) != null then\n\t\tfor corner in [8,6,2,0]\n\t\t\tif self.grid[corner] == \" \" then\n\t\t\t\tself.grid[corner] = self.AI\n\t\t\t\tpotential = self.potentialWins\n\t\t\t\tself.grid[corner] = \" \"\n\t\t\t\tAIWins = potential[self.AI]\n\t\t\t\tif AIWins.len > 0 then return corner\n\t\t\tend if\n\t\tend for\n\telse\n\t\tfor side in [1,3,5,7]\n\t\t\tif self.grid[side] == \" \" then\n\t\t\t\tself.grid[side] = self.AI\n\t\t\t\tpotential = self.potentialWins\n\t\t\t\tself.grid[side] = \" \"\n\t\t\t\tAIWins = potential[self.AI]\n\t\t\t\tif AIWins.len > 0 then return side\n\t\t\tend if\n\t\tend for\n\tend if\n\tfor ix in range(0,8)\n\t\tif self.grid[ix] == \" \" then return ix\n\tend for\n\t\n\treturn null\t\t\nend function\n\nprint \" \" * 15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\nprint \"The board is numbered.\"\nprint; print; print\nprint \" 1 2 3\"\nprint \" 4 5 6\"\nprint \" 7 8 9\"\nprint\nans = input(\"Do you want to 'X' or 'O'? \")\nif ans.upper != \"X\" then ans = \"O\"\nTicTacToe.setMarkers(ans.upper)\nwinner = null\nprint\nwhile TicTacToe.moveAvailable and winner == null\n\t\n\tif TicTacToe.next == TicTacToe.AI then\n\t\tmove = TicTacToe.selectAI\n\t\tTicTacToe.set(TicTacToe.AI, move)\n\t\tTicTacToe.next = TicTacToe.human\n\t\tprint \"The computer moves to...\"\n\telse\n\t\tmove = input(\"Where do you move? \").val\n\t\tif move < 1 or move > 9 then\n\t\t\tprint \"Thanks for the game.\"\n\t\t\texit\n\t\telse if not TicTacToe.set(TicTacToe.human, move-1) then\n\t\t\tprint \"That square is occupied.\"\n\t\t\tprint\n\t\t\tcontinue\n\t\telse\n\t\t\tTicTacToe.next = TicTacToe.AI\n\t\tend if\n\tend if\n\t\n\tTicTacToe.show\n\twinner = TicTacToe.getWinner\nend while\n\nif winner == null then\n\tprint \"It's a draw. Thank you.\"\nelse if winner == TicTacToe.AI then\n\tprint \"I win, turkey!!\"\nelse \n\tprint \"You beat me! Good game!\"\nend if\n\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/go/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/go/src/tictactoe1.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\nfunc main() {\n\t// Print text on the screen with 30 spaces before text\n\tfmt.Printf(\"%30s\\n\", \"TIC TAC TOE\")\n\t// Print text on screen with 15 spaces before text\n\t// And print three lines break on screen\n\tfmt.Printf(\"%15s\\n\\n\\n\\n\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n\t// THIS PROGRAM PLAYS TIC TAC TOE\n\tfmt.Printf(\"THE GAME BOARD IS NUMBERED:\\n\\n\")\n\tfmt.Println(\"1  2  3\")\n\tfmt.Println(\"8  9  4\")\n\tfmt.Println(\"7  6  5\")\n\n\t// Main program\n\tfor {\n\t\tvar (\n\t\t\ta, b, c, d, e int\n\t\t\tp, q, r, s    int\n\t\t)\n\t\ta = 9\n\t\tfmt.Printf(\"\\n\\n\")\n\t\t// THE MACHINE GOES FIRST\n\t\tcomputerMoves(a)\n\t\tp = readYourMove()\n\t\tb = move(p + 1)\n\t\tcomputerMoves(b)\n\t\tq = readYourMove()\n\t\tif q == move(b+4) {\n\t\t\tc = move(b + 2)\n\t\t\tcomputerMoves(c)\n\t\t\tr = readYourMove()\n\t\t\tif r == move(c+4) {\n\t\t\t\tif p%2 != 0 {\n\t\t\t\t\td = move(c + 3)\n\t\t\t\t\tcomputerMoves(d)\n\t\t\t\t\ts = readYourMove()\n\t\t\t\t\tif s == move(d+4) {\n\t\t\t\t\t\te = move(d + 6)\n\t\t\t\t\t\tcomputerMoves(e)\n\t\t\t\t\t\tfmt.Println(\"THE GAME IS A DRAW.\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\te = move(d + 4)\n\t\t\t\t\t\tcomputerMoves(e)\n\t\t\t\t\t\tfmt.Println(\"AND WINS ********\")\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\td = move(c + 7)\n\t\t\t\t\tcomputerMoves(d)\n\t\t\t\t\tfmt.Println(\"AND WINS ********\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\td = move(c + 4)\n\t\t\t\tcomputerMoves(d)\n\t\t\t\tfmt.Println(\"AND WINS ********\")\n\t\t\t}\n\t\t} else {\n\t\t\tc = move(b + 4)\n\t\t\tcomputerMoves(c)\n\t\t\tfmt.Println(\"AND WINS ********\")\n\t\t}\n\t}\n}\nfunc computerMoves(move int) {\n\tfmt.Printf(\"COMPUTER MOVES %v\\n\", move)\n}\n\nfunc readYourMove() int {\n\tfor {\n\t\tfmt.Printf(\"YOUR MOVE?\")\n\t\tvar input string\n\t\tfmt.Scan(&input)\n\t\tnumber, err := strconv.Atoi(input)\n\t\tif err == nil {\n\t\t\treturn number\n\t\t}\n\t}\n}\n\nfunc move(number int) int {\n\treturn number - 8*(int)((number-1)/8)\n}\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/pascal/tictactoe1.pas",
    "content": "program tictactoe1;\nvar\n    a, b, c, d, e: integer;\n\tp, q, r, s: integer;\nprocedure computerMoves(m: integer);\nbegin\n\twrite('COMPUTER MOVES ');\n\twriteln(m);\nend;\n\nfunction readYourMove() : integer;\nvar number: integer;\nbegin\n    write('YOUR MOVE?');\n\treadln(number);\n\treadYourMove := number;\nend;\n\nfunction move(number: integer): integer;\nbegin\n\tmove := number - 8 * trunc((number - 1) / 8);\nend;\n\nfunction padLeft(m: string; n: integer): string;\nvar tmp: string;\nbegin\n    tmp := '';\n    repeat\n        tmp := tmp + ' ';\n        n := n - 1;\n    until n = 0;\n    tmp := tmp + m;\n    padLeft := tmp;\nend;\n\nbegin\n    writeln(padLeft('TIC TAC TOE', 30));\n    writeln(padLeft('CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY', 15));\n    writeln('');\n    writeln('');\n    writeln('');\n    writeln('THE GAME BOARD IS NUMBERED:');\n    writeln('');\n    writeln('1  2  3');\n    writeln('8  9  4');\n    writeln('7  6  5');\n    while(true) do\n    begin\n        writeln('');\n        writeln('');\n        a := 9;\n        computerMoves(a);\n        p := readYourMove();\n    \tb := move(p + 1);\n    \tcomputerMoves(b);\n    \tq := readYourMove();\n    \tif (q = move(b + 4)) then\n    \tbegin\n    \t\tc := move(b + 2);\n    \t\tcomputerMoves(c);\n    \t\tr := readYourMove();\n    \t\tif (r = move(c + 4)) then\n    \t\tbegin\n    \t\t\tif (p mod 2 <> 0) then\n    \t\t\tbegin\n    \t\t\t\td := move(c + 3);\n    \t\t\t\tcomputerMoves(d);\n    \t\t\t\ts := readYourMove();\n    \t\t\t\tif (s = move(d + 4)) then\n    \t\t\t\tbegin\n    \t\t\t\t\te := move(d + 6);\n    \t\t\t\t\tcomputerMoves(e);\n    \t\t\t\t\twriteln('THE GAME IS A DRAW.');\n    \t\t\t\tend\n    \t\t\t\telse\n    \t\t\t\tbegin\n    \t\t\t\t\te := move(d + 4);\n    \t\t\t\t\tcomputerMoves(e);\n    \t\t            writeln('AND WINS ********');\n    \t\t\t\tend\n    \t\t\tend\n    \t\t\telse\n    \t\t\tbegin\n    \t\t\t\td := move(c + 7);\n    \t\t\t\tcomputerMoves(d);\n    \t\t        writeln('AND WINS ********');\n    \t\t\tend\n\t\t\tend\n    \t\telse\n    \t\tbegin\n    \t\t\td := move(c + 4);\n    \t\t\tcomputerMoves(d);\n    \t\twriteln('AND WINS ********');\n    \t\tend\n\t\tend\n    \telse\n    \tbegin\n    \t\tc := move(b + 4);\n    \t\tcomputerMoves(c);\n    \t\twriteln('AND WINS ********');\n    \tend;\n    end;\nend.\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe1.bas",
    "content": "10 PRINT TAB(30);\"TIC TAC TOE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n50 REM\n100 REM   THIS PROGRAM PLAYS TIC TAC TOE\n110 REM   THE MACHINE GOES FIRST\n120 PRINT \"THE GAME BOARD IS NUMBERED:\": PRINT\n130 PRINT \"1  2  3\": PRINT \"8  9  4\": PRINT \"7  6  5\"\n140 PRINT\n150 REM\n160 REM\n170 REM\n180 DEF FNM(X)=X-8*INT((X-1)/8)\n190 REM\n200 REM  MAIN PROGRAM\n210 PRINT\n220 PRINT\n230 A=9\n240 M=A\n250 GOSUB 650\n260 P=M\n270 B=FNM(P+1)\n280 M=B\n290 GOSUB 650\n300 Q=M\n310 IF Q=FNM(B+4) THEN 360\n320 C=FNM(B+4)\n330 M=C\n340 GOSUB 700\n350 GOTO 730\n360 C=FNM(B+2)\n370 M=C\n380 GOSUB 650\n390 R=M\n400 IF R=FNM(C+4) THEN 450\n410 D=FNM(C+4)\n420 M=D\n430 GOSUB 700\n440 GOTO 730\n450 IF P/2<>INT(P/2) THEN 500\n460 D=FNM(C+7)\n470 M=D\n480 GOSUB 700\n490 GOTO 730\n500 D=FNM(C+3)\n510 M=D\n520 GOSUB 650\n530 S=M\n540 IF S=FNM(D+4) THEN 590\n550 E=FNM(D+4)\n560 M=E\n570 GOSUB 700\n580 REM\n590 E=FNM(D+6)\n600 M=E\n610 GOSUB 700\n620 PRINT \"THE GAME IS A DRAW.\"\n630 GOTO 210\n640 REM\n650 GOSUB 700\n660 PRINT \"YOUR MOVE\";\n670 INPUT M\n680 RETURN\n700 PRINT \"COMPUTER MOVES\";M\n710 RETURN\n720 REM\n730 PRINT \"AND WINS ********\"\n740 GOTO 210\n750 END\n"
  },
  {
    "path": "00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe2.bas",
    "content": "2 PRINT TAB(30);\"TIC-TAC-TOE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n8 PRINT \"THE BOARD IS NUMBERED:\"\n10 PRINT \" 1  2  3\"\n12 PRINT \" 4  5  6\"\n14 PRINT \" 7  8  9\"\n16 PRINT:PRINT:PRINT\n20 DIM S(9)\n50 INPUT\"DO YOU WANT 'X' OR 'O'\";C$\n55 IF C$=\"X\"THEN 475\n60 P$=\"O\":Q$=\"X\"\n100 G=-1:H=1:IF S(5)<>0 THEN 103\n102 S(5)=-1:GOTO 195\n103 IF S(5)<>1 THEN 106\n104 IF S(1)<>0 THEN 110\n105 S(1)=-1:GOTO 195\n106 IF S(2)=1 AND S(1)=0 THEN 181\n107 IF S(4)=1 AND S(1)=0 THEN 181\n108 IF S(6)=1 AND S(9)=0 THEN 189\n109 IF S(8)=1 AND S(9)=0 THEN 189\n110 IF G=1 THEN 112\n111 GOTO 118\n112 J=3*INT((M-1)/3)+1\n113 IF 3*INT((M-1)/3)+1=M THEN K=1\n114 IF 3*INT((M-1)/3)+2=M THEN K=2\n115 IF 3*INT((M-1)/3)+3=M THEN K=3\n116 GOTO 120\n118 FOR J=1 TO 7 STEP 3:FOR K=1 TO 3\n120 IF S(J)<>G THEN 130\n122 IF S(J+2)<>G THEN 135\n126 IF S(J+1)<>0 THEN 150\n128 S(J+1)=-1:GOTO 195\n130 IF S(J)=H THEN 150\n131 IF S(J+2)<>G THEN 150\n132 IF S(J+1)<>G THEN 150\n133 S(J)=-1:GOTO 195\n135 IF S(J+2)<>0 THEN 150\n136 IF S(J+1)<>G THEN 150\n138 S(J+2)=-1:GOTO 195\n150 IF S(K)<>G THEN 160\n152 IF S(K+6)<>G THEN 165\n156 IF S(K+3)<>0 THEN 170\n158 S(K+3)=-1:GOTO 195\n160 IF S(K)=H THEN 170\n161 IF S(K+6)<>G THEN 170\n162 IF S(K+3)<>G THEN 170\n163 S(K)=-1:GOTO 195\n165 IF S(K+6)<>0 THEN 170\n166 IF S(K+3)<>G THEN 170\n168 S(K+6)=-1:GOTO 195\n170 GOTO 450\n171 IF S(3)=G AND S(7)=0 THEN 187\n172 IF S(9)=G AND S(1)=0 THEN 181\n173 IF S(7)=G AND S(3)=0 THEN 183\n174 IF S(9)=0 AND S(1)=G THEN 189\n175 IF G=-1 THEN G=1:H=-1:GOTO 110\n176 IF S(9)=1 AND S(3)=0 THEN 182\n177 FOR I=2 TO 9:IF S(I)<>0 THEN 179\n178 S(I)=-1:GOTO 195\n179 NEXT I\n181 S(1)=-1:GOTO 195\n182 IF S(1)=1 THEN 177\n183 S(3)=-1:GOTO 195\n187 S(7)=-1:GOTO 195\n189 S(9)=-1\n195 PRINT:PRINT\"THE COMPUTER MOVES TO...\"\n202 GOSUB 1000\n205 GOTO 500\n450 IF G=1 THEN 465\n455 IF J=7 AND K=3 THEN 465\n460 NEXT K,J\n465 IF S(5)=G THEN 171\n467 GOTO 175\n475 P$=\"X\":Q$=\"O\"\n500 PRINT:INPUT\"WHERE DO YOU MOVE\";M\n502 IF M=0 THEN PRINT\"THANKS FOR THE GAME.\":GOTO 2000\n503 IF M>9 THEN 506\n505 IF S(M)=0 THEN 510\n506 PRINT\"THAT SQUARE IS OCCUPIED.\":PRINT:PRINT:GOTO 500\n510 G=1:S(M)=1\n520 GOSUB 1000\n530 GOTO 100\n1000 PRINT:FOR I=1 TO 9:PRINT\" \";:IF S(I)<>-1 THEN 1014\n1012 PRINT Q$\" \";:GOTO 1020\n1014 IF S(I)<>0 THEN 1018\n1016 PRINT\"  \";:GOTO 1020\n1018 PRINT P$\" \";\n1020 IF I<>3 AND I<>6 THEN 1050\n1030 PRINT:PRINT\"---+---+---\"\n1040 GOTO 1080\n1050 IF I=9 THEN 1080\n1060 PRINT\"!\";\n1080 NEXT I:PRINT:PRINT:PRINT\n1095 FOR I=1 TO 7 STEP 3\n1100 IF S(I)<>S(I+1)THEN 1115\n1105 IF S(I)<>S(I+2)THEN 1115\n1110 IF S(I)=-1 THEN 1350\n1112 IF S(I)=1 THEN 1200\n1115 NEXT I:FOR I=1 TO 3:IF S(I)<>S(I+3)THEN 1150\n1130 IF S(I)<>S(I+6)THEN 1150\n1135 IF S(I)=-1 THEN 1350\n1137 IF S(I)=1 THEN 1200\n1150 NEXT I:FOR I=1 TO 9:IF S(I)=0 THEN 1155\n1152 NEXT I:GOTO 1400\n1155 IF S(5)<>G THEN 1170\n1160 IF S(1)=G AND S(9)=G THEN 1180\n1165 IF S(3)=G AND S(7)=G THEN 1180\n1170 RETURN\n1180 IF G=-1 THEN 1350\n1200 PRINT\"YOU BEAT ME!! GOOD GAME.\":GOTO 2000\n1350 PRINT\"I WIN, TURKEY!!!\":GOTO 2000\n1400 PRINT\"IT'S A DRAW. THANK YOU.\"\n2000 END\n"
  },
  {
    "path": "00_Alternate_Languages/90_Tower/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\r\n\r\nConversion to [MiniScript](https://miniscript.org).\r\n\r\nWays to play:\r\n\r\n1. Command-Line MiniScript:\r\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\r\n```\r\n\tminiscript tower.ms\r\n```\r\n\r\n2. Mini Micro:\r\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\r\n```\r\n\tload \"tower\"\r\n\trun\r\n```\r\n"
  },
  {
    "path": "00_Alternate_Languages/90_Tower/MiniScript/tower.ms",
    "content": "kInvalidDisk = 100\nkNotTopDisk = 200\nkNotTower = 300\nkGameOver = 300\n\nTower = {\"disks\": []}\nTower.init = function\n\tnoob = new Tower\n\tnoob.disks = []\n\treturn noob\nend function\n\nTower.height = function\n\treturn self.disks.len\nend function\n\nTower.top = function\n\tif self.height == 0 then return 100\n\treturn self.disks[-1]\nend function\n\nGame = {}\nGame.towers = []\nGame.numOfDisks = 0\nGame.rangeOfDisks = []\nGame.selectedDisk = 0\nGame.selectedDiskOn = 0\nGame.selectedTower = 0\nGame.inputErrors = 0\nGame.turns = 0\n\nGame.display = function\n\tprint\n\tfor r in range(7,1)\n\t\trowstr = \"\"\n\t\tfor tower in self.towers\n\t\t\tif r > tower.height then\n\t\t\t\trowstr += \" \" * 12 + \"#\" + \" \" * 7\n\t\t\telse\n\t\t\t\tspaces = (15 - tower.disks[r-1])/2\n\t\t\t\tdisks = \" \" * 4 + tower.disks[r-1]\n\t\t\t\trowstr += disks[-5:] + \" \" * spaces\n\t\t\t\trowstr += \"#\" * tower.disks[r-1]\n\t\t\t\trowstr += \" \" * spaces\n\t\t\tend if\n\t\t\trowstr += \" \"\n\t\tend for\n\t\tprint rowstr\n\tend for\n\trowstr = (\" \" * 5 + \"=\" * 15 + \" \") * 3\n\tprint rowstr\n\tprint\nend function\n\nGame.init = function(num)\n\tif num < 1 or num > 7 then\n\t\tself.inputErrors += 1\n\t\treturn false\n\tend if\n\tGame.towers = []\n\tfor i in range(0,2)\n\t\tGame.towers.push(Tower.init)\n\tend for\n\t\n\tfirst = self.towers[0]\n\tfirst.disks = range(15, 17 - num * 2, -2)\n\tself.numOfDisks = num\n\tself.rangeOfDisks = range(17 -num * 2, 15, 2)\n\t\n\t// This game doesn't like to be bothered\n\t// and keeps track of how many incorrect inputs\n\t// are made before it stops the game\n\tself.inputErrors = 0\n\tself.turns = 0\n\treturn true\nend function\n\nGame.diskStatus = function\n\tn = self.selectedDisk\n\tif self.rangeOfDisks.indexOf(n) == null then\n\t\tself.inputErrors +=1\n\t\treturn kInvalidDisk\n\tend if\n\tself.inputErrors = 0\n\tfor i in range(0, self.towers.len - 1)\n\t\tif self.towers[i].top == n then\n\t\t\tself.selectedDiskOn = i\n\t\t\tself.inputErrors = 0\n\t\t\treturn i\n\t\tend if\n\tend for\n\treturn kNotTopDisk\nend function\n\nGame.pickDisk = function\n\tself.selectedDisk = input(\"Which disk would you like to move? \").val\n\treturn self.diskStatus\nend function\n\nGame.pickTower = function\n\tself.selectedTower = input(\"Place disk on which needle? \").val - 1\n\tif not(0<= self.selectedTower and self.selectedTower <= 2) then\n\t\tself.inputErrors += 1\n\t\treturn kNotTower\n\tend if\n\treturn self.selectedTower\nend function\n\nGame.doneWithYou = function\n\treturn self.inputErrors >= 2\nend function\n\nGame.isFinish = function\n\treturn self.towers[0].disks.len == 0 and self.towers[1].disks.len == 0\nend function\n\nGame.move = function\n\tprint \"Take turn # \" + (self.turns + 1)\n\tstatus = -1\n\tself.inputErrors = 0\n\twhile 1\n\t\tstatus = self.pickDisk\n\t\tif 0 <= status and status <= 2 then break\n\t\tif status == kInvalidDisk and self.doneWithYou then\n\t\t\tprint \"Stop wasting my time. Go bother someone else.\"\n\t\t\texit\n\t\telse if status == kInvalidDisk then\n\t\t\tmsg = \"Illegal entry ... you may only type \"\n\t\t\tmsg += self.rangeOfDisks[0:-1].join(\",\") + \" \"\n\t\t\tif self.rangeOfDisks.len > 1 then\n\t\t\t\tmsg += \"or \"\n\t\t\tend if\n\t\t\tmsg += \"15\"\n\t\t\tprint msg\n\t\telse if status == kNotTopDisk then\n\t\t\tprint \"That disk is below another. Make another choice.\"\n\t\tend if\n\tend while\n\t\n\tself.inputErrors = 0\n\twhile 1\n\t\tstatus = self.pickTower\n\t\tif 0 <= status and status <= 2 then break\n\t\tif status == kNotTower and self.doneWithYou then\n\t\t\tprint \"I tried to warn you. But you wouldn't listen.\"\n\t\t\tprint \"Bye bye, big shot.\"\n\t\t\texit\n\t\telse if status == kNotTower then\n\t\t\tprint \"I'll assume you hit the wrong key this time. But watch it,\"\n\t\t\tprint \"I only allow one mistake.\"\n\t\tend if\n\tend while\n\t\n\tif self.selectedDisk > self.towers[self.selectedTower].top then\n\t\tprint \"You can't place a larger disk on a top of a smaller one,\"\n\t\tprint \"it may crush it!\"\n\telse\n\t\tn=self.towers[self.selectedDiskOn].disks.pop\n\t\tself.towers[self.selectedTower].disks.push(n)\n\t\tself.turns += 1\n\t\tself.inputErrors = 0\n\tend if\nend function\n\n\nprint \" \" * 33 + \"TOWERS\"\nprint \" \" * 15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print\nprint \"You must transfer the disks from the left to the right\"\nprint \"tower, one at a time, never putting a larger disk on a\"\nprint \"smaller disk.\"\nprint\n\nans = \"Y\"\nwhile ans[0].upper == \"Y\"\n\twhile 1\n\t\tdisks = input(\"How many disks do you want to move (7 is MAX)? \").val\n\t\tstatus = Game.init(disks)\n\t\tif status == false and Game.doneWithYou then\n\t\t\tprint \"All right, wise guy, if you can't play the game right, I'll\"\n\t\t\tprint \"take my puzzle and go home. So long.\"\n\t\t\texit\n\t\telse if not status then\n\t\t\tprint \"Sorry, but I can't do that job for you\"\n\t\telse\n\t\t\tbreak\n\t\tend if\n\tend while\n\t\n\twhile not Game.isFinish\n\t\tGame.display\n\t\t\n\t\tGame.move\n\tend while\n\tGame.display\n\tprint \"Congratulations!\"\n\tprint \"You performed the task in \" + Game.turns + \" moves.\"\n\tprint\n\tans = input(\"Play again (Yes or No)? \") + \" \"\nend while\nprint\nprint \"Thanks for the game!\"\n"
  },
  {
    "path": "00_Alternate_Languages/90_Tower/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/90_Tower/tower.bas",
    "content": "10 PRINT TAB(33);\"TOWERS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n90 PRINT\n100 REM*** INITIALIZE\n110 DIM T(7,3)\n120 E=0\n130 FOR D=1 TO 7\n140 FOR N=1 TO 3\n150 T(D,N)=0\n160 NEXT N\n170 NEXT D\n180 PRINT \"TOWERS OF HANOI PUZZLE.\": PRINT\n200 PRINT \"YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT\"\n205 PRINT \"TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A\"\n210 PRINT \"SMALLER DISK.\": PRINT\n215 INPUT \"HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)\";S\n220 PRINT\n230 M=0\n240 FOR Q=1 TO 7\n250 IF Q=S THEN 350\n260 NEXT Q\n270 E=E+1\n280 IF E>2 THEN 310\n290 PRINT \"SORRY, BUT I CAN'T DO THAT JOB FOR YOU.\": GOTO 215\n310 PRINT \"ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL\"\n320 PRINT \"JUST TAKE MY PUZZLE AND GO HOME.  SO LONG.\": STOP\n340 REM *** STORE DISKS FROM SMALLEST TO LARGEST\n350 PRINT \"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\"\n355 PRINT \"3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\"\n360 PRINT \"7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\"\n365 PRINT \"2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\"\n370 PRINT \"THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\"\n375 PRINT \"ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\"\n380 PRINT \"START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\"\n385 PRINT \"TO NEEDLE 3.\"\n390 PRINT: PRINT \"GOOD LUCK!\": PRINT\n400 Y=7: D=15\n420 FOR X=S TO 1 STEP -1\n430 T(Y,1)=D: D=D-2: Y=Y-1\n460 NEXT X\n470 GOSUB 1230\n480 PRINT \"WHICH DISK WOULD YOU LIKE TO MOVE\";:E=0\n500 INPUT D\n510 IF (D-3)*(D-5)*(D-7)*(D-9)*(D-11)*(D-13)*(D-15)=0 THEN 580\n520 PRINT \"ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\"\n530 E=E+1: IF E>1 THEN 560\n550 GOTO 500\n560 PRINT \"STOP WASTING MY TIME.  GO BOTHER SOMEONE ELSE.\": STOP\n580 REM *** CHECK IF REQUESTED DISK IS BELOW ANOTHER\n590 FOR R=1 TO 7\n600 FOR C=1 TO 3\n610 IF T(R,C)=D THEN 640\n620 NEXT C: NEXT R\n640 FOR Q=R TO 1 STEP -1\n645 IF T(Q,C)=0 THEN 660\n650 IF T(Q,C)<D THEN 680\n660 NEXT Q\n670 GOTO 700\n680 PRINT \"THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\"\n690 GOTO 480\n700 E=0\n705 INPUT \"PLACE DISK ON WHICH NEEDLE\";N\n730 IF (N-1)*(N-2)*(N-3)=0 THEN 800\n735 E=E+1\n740 IF E>1 THEN 780\n750 PRINT \"I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME.  BUT WATCH IT,\"\n760 PRINT \"I ONLY ALLOW ONE MISTAKE.\": GOTO 705\n780 PRINT \"I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\"\n790 PRINT \"BYE BYE, BIG SHOT.\":STOP\n800 FOR R=1 TO 7\n810 IF T(R,N)<>0 THEN 840\n820 NEXT R\n830 GOTO 880\n835 REM *** CHECK IF DISK TO BE PLACED ON A LARGER ONE\n840 IF D<T(R,N) THEN 880\n850 PRINT \"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,\"\n860 PRINT \"IT MIGHT CRUSH IT!\": PRINT \"NOW THEN, \";:GOTO 480\n875 REM *** MOVE RELOCATED DISK\n880 FOR V=1 TO 7: FOR W=1 TO 3\n900 IF T(V,W)=D THEN 930\n910 NEXT W: NEXT V\n925 REM *** LOCATE EMPTY SPACE ON NEEDLE N\n930 FOR U=1 TO 7\n940 IF T(U,N)<>0 THEN 970\n950 NEXT U\n960 U=7: GOTO 980\n965 REM *** MOVE DISK AND SET OLD LOCATION TO 0\n970 U=U-1\n980 T(U,N)=T(V,W): T(V,W)=0\n995 REM *** PRINT OUT CURRENT STATUS\n1000 GOSUB 1230\n1018 REM *** CHECK IF DONE\n1020 M=M+1\n1030 FOR R=1 TO 7: FOR C=1 TO 2\n1050 IF T(R,C)<>0 THEN 1090\n1060 NEXT C: NEXT R\n1080 GOTO 1120\n1090 IF M<=128 THEN 480\n1100 PRINT \"SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN\"\n1110 PRINT \"128 MOVES.\": STOP\n1120 IF M<>2^S-1 THEN 1140\n1130 PRINT:PRINT \"CONGRATULATIONS!!\":PRINT\n1140 PRINT \"YOU HAVE PERFORMED THE TASK IN\";M;\"MOVES.\"\n1150 PRINT: PRINT \"TRY AGAIN (YES OR NO)\";: INPUT A$\n1160 IF A$=\"NO\" THEN 1390\n1170 IF A$=\"YES\" THEN 90\n1180 PRINT: PRINT \"'YES' OR 'NO' PLEASE\";: INPUT A$: GOTO 1160\n1230 REM *** PRINT SUBROUTINE\n1240 FOR K=1 TO 7\n1250 Z=10\n1260 FOR J=1 TO 3\n1270 IF T(K,J)=0 THEN 1330\n1280 PRINT TAB(Z-INT(T(K,J)/2));\n1290 FOR V=1 TO T(K,J)\n1300 PRINT \"*\";\n1310 NEXT V\n1320 GOTO 1340\n1330 PRINT TAB(Z);\"*\";\n1340 Z=Z+21\n1350 NEXT J\n1360 PRINT\n1370 NEXT K\n1380 RETURN\n1390 PRINT: PRINT \"THANKS FOR THE GAME!\": PRINT: END\n"
  },
  {
    "path": "00_Alternate_Languages/91_Train/D/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://dlang.org)."
  },
  {
    "path": "00_Alternate_Languages/91_Train/D/train.d",
    "content": "import std.stdio;\nimport std.random : uniform;\n\nfloat abs(float num) {\n    if(num<0){\n        return num*-1;\n    }\n\n    return num;\n}\n\nvoid main() {\n    \n    writeln(\"\\nTIME - SPEED DISTANCE EXERCISE\");\n\n    bool keep_playing = true;\n    float error_margin = 5.0;\n\n    while(keep_playing){\n        int car_speed = uniform!\"[]\"(40,65);       //Random number between 40 and 65\n        int delta_time = uniform!\"(]\"(4,20);       //Between 5 and 20\n        int train_speed = uniform!\"[)\"(20,40);     //Between 20 and 39; This is the default if not specified: uniform(x,y)\n\n        writeln(\"\\nA CAR TRAVELING AT \", car_speed, \" MPH CAN MAKE A CERTAIN TRIP IN \", delta_time,\n                \" HOURS LESS THAN A TRAIN TRAVELING AT \", train_speed, \"MPH.\" );\n        \n        float input;\n        write(\"HOW LONG DOES THE TRIP TAKE BY CAR? \");\n        readf!\"%f\\n\"(input);\n\n        float car_time = cast(float)delta_time * train_speed / (car_speed - train_speed);\n        int percent = cast(int)( abs(car_time-input) * 100 / car_time + .5);\n\n        if(percent > error_margin){\n            writeln(\"SORRY. YOU WERE OFF BY \", percent, \" PERCENT.\");\n        }else{\n            writeln(\"GOOD! ANSWER WITHIN \", percent, \" PERCENT.\");\n        }\n        writeln(\"CORRECT ANSWER IS \", car_time, \" HOURS.\");\n\n        string answer;\n        write(\"\\nANOTHER PROBLEM (YES OR NO)? \");\n        readf!\"%s\\n\"(answer);\n\n        if( !(answer == \"YES\" || answer == \"Y\" || answer == \"yes\" || answer == \"y\") ){\n            keep_playing = false;\n        }\n    }\n\n}"
  },
  {
    "path": "00_Alternate_Languages/91_Train/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n0. \"Try-It!\" page on the web:\nGo to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of train.ms, and click the \"Run Script\" button.\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript train.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"train\"\n\trun\n```\n"
  },
  {
    "path": "00_Alternate_Languages/91_Train/MiniScript/train.ms",
    "content": "// TRAIN\n//\n// Converted from BASIC to MiniScript by Ryushinaka and Joe Strout\n\nwhile true\n\tprint \"TRAIN\"\n\tprint \"CREATIVE COMPUTER  MORRISTOWN, NEW JERSEY\"\n\tprint \"\"\n\tprint \"TIME - SPEED DISTANCE EXERCISE\"\n\t\n\tcarSpeed = floor(25*rnd + 40)\n\tdifference = floor(15*rnd + 5)\n\ttrainSpeed = floor(19*rnd + 20)\n\tprint \" A car traveling \" + carSpeed + \" MPH can make a certain trip in\"\n\tprint difference + \" hours less than a train traveling at \" + trainSpeed + \" MPH.\"\n\tanswer = input(\"How long does the trip take by car? \").val\n\tcarTime = difference*trainSpeed/(carSpeed-trainSpeed)\n\terror = round(abs((carTime-answer)*100/answer))\n\tif error < 5 then\n\t\tprint \"GOOD! Answer within \" + error + \" PERCENT.\"\n\telse\n\t\tprint \"Sorry. You were off by \" + floor(error) + \" percent.\"\n\t\tprint \"Correct answer is \" + round(carTime, 1) + \" hours.\"\n\tend if\n\t\n\tanswer = input(\"Another problem (YES or NO)? \")\n\tif not answer or answer[0].upper != \"Y\" then break\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/91_Train/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/91_Train/nim/train.nim",
    "content": "import std/[random,strutils]\n\nvar\n  carSpeed, diff, err, guess, trainSpeed, carTime: int\n  stillplaying: bool = true\n\nrandomize() # Seed the random number generator\n\n# Return a tuple that'll be carSpeed, diff, trainSpeed\nproc randomNumbers(): (int,int,int) =\n  result = (rand(41..65), rand(6..20), rand(21..39))\n\n# Do we want to play again?\nproc tryAgain(): bool =\n  echo \"ANOTHER PROBLEM (YES OR NO)\"\n  var answer = readLine(stdin).normalize()\n  result = (answer == \"y\") or (answer == \"yes\")\n\necho spaces(33), \"TRAIN\"\necho spaces(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\necho \"\\n\"\necho \"TIME - SPEED DISTANCE EXERCISE\"\n\nwhile stillplaying:\n  echo \"\"\n  (carSpeed, diff, trainSpeed) = randomNumbers() # Get random numbers for prompt\n  echo \"A CAR TRAVELING \", carSpeed, \" MPH CAN MAKE A CERTAIN TRIP IN\"\n  echo diff, \" HOURS LESS THAN A TRAIN TRAVELING AT \", trainSpeed, \" MPH.\"\n  echo \"HOW LONG DOES THE TRIP TAKE BY CAR?\"\n  guess = readLine(stdin).parseInt() # Get guess\n  carTime = (diff * trainSpeed / (carSpeed - trainSpeed)).toInt() # Calculate answer\n  err = (((carTime - guess) * 100) / guess).toInt().abs() # Calculate error to an absolute value\n  if err > 5: # Error within 5%?\n    echo \"SORRY.  YOU WERE OFF BY \", err, \" PERCENT.\"\n  else:\n    echo \"GOOD! ANSWER WITHIN \", err, \" PERCENT.\"\n  echo \"CORRECT ANSWER IS \", carTime, \" HOURS.\"\n  stillplaying = tryAgain()\n"
  },
  {
    "path": "00_Alternate_Languages/91_Train/train.bas",
    "content": "1 PRINT TAB(33);\"TRAIN\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT: PRINT: PRINT\n4 PRINT \"TIME - SPEED DISTANCE EXERCISE\": PRINT\n10 C=INT(25*RND(1))+40\n15 D=INT(15*RND(1))+5\n20 T=INT(19*RND(1))+20\n25 PRINT \" A CAR TRAVELING\";C;\"MPH CAN MAKE A CERTAIN TRIP IN\"\n30 PRINT D;\"HOURS LESS THAN A TRAIN TRAVELING AT\";T;\"MPH.\"\n35 PRINT \"HOW LONG DOES THE TRIP TAKE BY CAR\";\n40 INPUT A\n45 V=D*T/(C-T)\n50 E=INT(ABS((V-A)*100/A)+.5)\n55 IF E>5 THEN 70\n60 PRINT \"GOOD! ANSWER WITHIN\";E;\"PERCENT.\"\n65 GOTO 80\n70 PRINT \"SORRY.  YOU WERE OFF BY\";E;\"PERCENT.\"\n80 PRINT \"CORRECT ANSWER IS\";V;\"HOURS.\"\n90 PRINT\n95 PRINT \"ANOTHER PROBLEM (YES OR NO)\";\n100 INPUT A$\n105 PRINT\n110 IF A$=\"YES\" THEN 10\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/92_Trap/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript trap.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"trap\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/92_Trap/MiniScript/trap.ms",
    "content": "// TRAP\n// STEVE ULLMAN, 8-1-72\n// Ported to MiniScript by Ryushinaka and Joe Strout, 2023\n\nprint \" \"*34 + \"TRAP\"\nprint \" \"*15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint \n\n// constants:\nG = 6    // number of guesses\nN = 100  // range of numbers\n\n// Get a yes/no (or at least y/n) response from the user.\naskYesNo = function(prompt)\n\twhile true\n\t\tanswer = input(prompt).lower[:1]\n\t\tif answer == \"y\" or answer == \"n\" then return answer\n\tend while\nend function\n\nif askYesNo(\"Instructions? \") == \"y\" then\n\tprint \"I am thinking of a number between 1 and \" + N\n\tprint \"Try to guess my number. On each guess, \"\n\tprint \"you are to enter 2 numbers, trying to trap\"\n\tprint \"my number between the two numbers. I will\"\n\tprint \"tell you if you have trapped my number, if my\"\n\tprint \"number is larger than your two numbers, or if\"\n\tprint \"my number is smaller than your two numbers.\"\n\tprint \"If you want to guess one single number, type\"\n\tprint \"your guess for both your trap numbers.\"\n\tprint \"You get \" + G + \" guesses to get my number.\"\n\tprint\nend if\n\ndoOneGame = function\n\tcomputers_number = ceil(N*rnd)\n\t\n\tfor Q in range(1,G)\t\n\t\tprint \"\"\n\t\twhile true\n\t\t\tguess = input(\"Guess #\" + Q + \": \").replace(\" \",\"\")\n\t\t\tguess = guess.split(\",\")\n\t\t\tif guess.len == 2 then break\n\t\t\tprint \"Enter your guess like: 30,40\"\n\t\tend while\n\t\tA = guess[0].val\n\t\tB = guess[1].val\n\t\t\n\t\tif A == computers_number and B == computers_number then\n\t\t\tprint \"You got it!!!\"\n\t\t\treturn\n\t\telse if A <= computers_number and B >= computers_number then\n\t\t\tprint \"You have trapped my number.\"\n\t\telse if A > computers_number and B > computers_number then\n\t\t\tprint \"My number is smaller than your trap numbers.\"\t\t\t\t\n\t\telse if A < computers_number and B < computers_number then\n\t\t\tprint \"My number is larger than your trap numbers.\"\n\t\tend if\n\tend for\n\tprint \"Sorry, that's \" + G + \" guesses. The number was \" + computers_number\nend function\n\n// main loop\nwhile true\n\tprint\n\tdoOneGame\n\tprint\n\tif askYesNo(\"Try Again? \") == \"n\" then break\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/92_Trap/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/92_Trap/trap.bas",
    "content": "1 PRINT TAB(34);\"TRAP\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n10 G=6\n20 N=100\n30 REM-TRAP\n40 REM-STEVE ULLMAN, 8-1-72\n50 PRINT \"INSTRUCTIONS\";\n60 INPUT Z$\n70 IF LEFT$(Z$,1)<>\"Y\" THEN 180\n80 PRINT \"I AM THINKING OF A NUMBER BETWEEN 1 AND\";N\n90 PRINT \"TRY TO GUESS MY NUMBER. ON EACH GUESS,\"\n100 PRINT \"YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\"\n110 PRINT \"MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\"\n120 PRINT \"TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\"\n130 PRINT \"NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\"\n140 PRINT \"MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\"\n150 PRINT \"IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\"\n160 PRINT \"YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\"\n170 PRINT \"YOU GET\";G;\"GUESSES TO GET MY NUMBER.\"\n180 X=INT(N*RND(1))+1\n190 FOR Q=1 TO G\n200 PRINT\n210 PRINT \"GUESS #\";Q;\n220 INPUT A,B\n230 IF A=B AND X=A THEN 400\n240 IF A <= B THEN 260\n250 GOSUB 360\n260 IF A <= X AND X <= B THEN 320\n270 IF X<A THEN 300\n280 PRINT \"MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\"\n290 GOTO 330\n300 PRINT \"MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\"\n310 GOTO 330\n320 PRINT \"YOU HAVE TRAPPED MY NUMBER.\"\n330 NEXT Q\n340 PRINT \"SORRY, THAT'S\";G;\"GUESSES. THE NUMBER WAS\";X\n345 PRINT\n350 GOTO 410\n360 R=A\n370 A=B\n380 B=R\n390 RETURN\n400 PRINT \"YOU GOT IT!!!\"\n410 PRINT\n420 PRINT \"TRY AGAIN.\"\n430 PRINT\n440 GOTO 180\n450 END\n"
  },
  {
    "path": "00_Alternate_Languages/93_23_Matches/23matches.bas",
    "content": "20 PRINT TAB(31);\"23 MATCHES\"\n30 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n40 PRINT:PRINT:PRINT\n80 PRINT \" THIS IS A GAME CALLED '23 MATCHES'.\"\n90 PRINT\n100 PRINT \"WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\"\n110 PRINT \"MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\"\n120 PRINT \"THE LAST MATCH.\"\n130 PRINT\n140 PRINT \"LET'S FLIP A COIN TO SEE WHO GOES FIRST.\"\n150 PRINT \"IF IT COMES UP HEADS, I WILL WIN THE TOSS.\"\n155 PRINT\n160 REM\n165 N = 23\n170 Q = INT(2*RND(5))\n180 IF Q = 1 THEN 210\n190 PRINT \"TAILS! YOU GO FIRST. \"\n195 PRINT\n200 GOTO 300\n210 PRINT \"HEADS! I WIN! HA! HA!\"\n220 PRINT \"PREPARE TO LOSE, MEATBALL-NOSE!!\"\n230 PRINT\n250 PRINT \"I TAKE 2 MATCHES\"\n260 N = N -2\n270 PRINT \"THE NUMBER OF MATCHES IS NOW\" N\n280 PRINT\n290 PRINT \"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\"\n300 PRINT \"HOW MANY DO YOU WISH TO REMOVE\",\n310 INPUT K\n320 IF K > 3 THEN 430\n330 IF K <= 0 THEN 430\n340 N = N - K\n350 PRINT \"THERE ARE NOW\";N;\"MATCHES REMAINING.\"\n351 IF N = 4 THEN 381\n352 IF N = 3 THEN 383\n353 IF N = 2 THEN 385\n360 IF N <= 1 THEN  530\n370 Z = 4 - K\n372 GOTO 390\n380 PRINT\n381 Z = 3\n382 GOTO 390\n383 Z = 2\n384 GOTO 390\n385 Z = 1\n390 PRINT \"MY TURN ! I REMOVE\" Z \"MATCHES\"\n400 N = N - Z\n410 IF N <= 1 THEN 470\n420 GOTO 270\n430 PRINT \"VERY FUNNY! DUMMY!\"\n440 PRINT \"DO YOU WANT TO PLAY OR GOOF AROUND?\"\n450 PRINT \"NOW, HOW MANY MATCHES DO YOU WANT\",\n460 GOTO 310\n470 PRINT\n480 PRINT\"YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\"\n490 PRINT \"HA ! HA ! I BEAT YOU !!!\"\n500 PRINT\n510 PRINT \"GOOD BYE LOSER!\"\n520 GOTO 560\n530 PRINT \"YOU WON, FLOPPY EARS !\"\n540 PRINT \"THINK YOU'RE PRETTY SMART !\"\n550 PRINT \"LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\"\n560 STOP\n570 END\n"
  },
  {
    "path": "00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms",
    "content": "print \" \"*31 + \"23 MATCHES\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"This is a game called '23 Matches'.\"\nprint\nprint \"When it is your turn, you may take one, two, or three\"\nprint \"matches. The object of the game is not to have to take\"\nprint \"the last match.\"\nprint\nprint \"Let's flip a coin to see who goes first.\"\nprint \"If it comes up heads, I will win the toss.\"\nprint\nmatches = 23\nhumanTurn = floor(rnd * 2)\n\nif humanTurn then\n\tprint \"Tails! You go first.\"\n\tprompt = \"How many do you wish to remove? \"\nelse\n\tprint \"Heads! I win! Ha! Ha!\"\n\tprint \"Prepare to lose, meatball-nose!!\"\nend if\n\nchoice = 2\nwhile matches > 0\n\tif humanTurn then\n\t\tif matches < 23 then print \"Your turn -- you may take 1, 2 or 3 matches.\"\n\t\tprompt = \"How many do you wish to remove? \"\n\t\tchoice = 0\n\t\tif matches == 1 then choice = 1\n\t\twhile choice == 0\n\t\t\tchoice = input(prompt).val\n\t\t\tif choice < 1 or choice > 3 or choice > matches then\n\t\t\t\tchoice = 0\n\t\t\t\tprint \"Very funny! Dummy!\"\n\t\t\t\tprint \"Do you want to play or goof around?\"\n\t\t\t\tprompt = \"Now, how many matches do you want? \"\n\t\t\tend if\n\t\tend while\n\t\tmatches = matches - choice\n\t\tif matches == 0 then\n\t\t\tprint \"You poor boob! You took the last match! I gotcha!!\"\n\t\t\tprint \"Ha ! Ha ! I beat you !!\"\n\t\t\tprint\n\t\t\tprint \"Good bye loser!\"\n\t\telse\n\t\t\tprint \"There are now \" + matches + \" matches remaining.\"\n\t\t\tprint\n\t\tend if\n\telse\n\t\tchoice_comp = 4 - choice\n\t\tif matches == 1 then\n\t\t\tchoice_comp = 1\n\t\telse if 1 < matches and matches < 4 then\n\t\t\tchoice_comp = matches - 1\n\t\tend if\n\t\tmatches = matches - choice_comp\n\t\tif matches == 0 then\n\t\t\tprint \"You won, floppy ears!\"\n\t\t\tprint \"Think you're pretty smart!\"\n\t\t\tprint \"Let's play again and I'll blow your shoes off!!\"\n\t\telse\n\t\t\tprint \"My turn! I remove \" + choice_comp + \" matches\"\n\t\t\tprint \"The number of matches is now \" + matches\n\t\t\tprint\n\t\tend if\n\tend if\n\thumanTurn = not humanTurn\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/93_23_Matches/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\r\n\r\nConversion to [MiniScript](https://miniscript.org).\r\n\r\nWays to play:\r\n\r\n1. Command-Line MiniScript:\r\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\r\n```\r\n\tminiscript 23matches.ms\r\n```\r\n\r\n2. Mini Micro:\r\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\r\n```\r\n\tload \"23matches\"\r\n\trun\r\n```\r\n"
  },
  {
    "path": "00_Alternate_Languages/93_23_Matches/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/94_War/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n\n```\n\tminiscript war.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n\n```\n\tload \"war\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/94_War/MiniScript/war.ms",
    "content": "print \" \"*33 + \"WAR\"\r\nprint \" \"*15 + \"CREATIVE COMPUTER  MORRISTOWN, NEW JERSEY\"\r\nprint; print; print\r\n\r\nprint \"This is the card game of War.  Each card is given by SUIT-#\"\r\nprint \"as S-7 for Spade 7.\"\r\n\r\n// Get a yes/no (or at least y/n) response from the user.\r\naskYesNo = function(prompt)\r\n\twhile true\r\n\t\tanswer = input(prompt + \"? \").lower[:1]\r\n\t\tif answer == \"y\" or answer == \"n\" then return answer\r\n\t\tprint \"Answer yes or no, please.\"\r\n\tend while\r\nend function\r\n\r\nif askYesNo(\"Do you want directions\") == \"y\" then\r\n\tprint \"The computer gives you and it a 'card'.  The higher card\"\r\n\tprint \"(numerically) wins.  The game ends when you choose not to\"\r\n\tprint \"continue or when you have finished the pack.\"\r\nend if\r\nprint\r\nprint\r\n\r\ncardValues = \"2 3 4 5 6 7 8 9 10 J Q K A\".split\r\ndeck = []\r\nfor suits in \"SHCD\"\r\n\tfor value in cardValues\r\n\t\tdeck.push suits + \"-\" + value\r\n\tend for\r\nend for\r\ndeck.shuffle\r\n\r\nplayerScore = 0\r\ncomputerScore = 0\r\n\r\nwhile true\r\n\tm1 = deck.pop\r\n\tm2 = deck.pop\r\n\tprint \"You: \" + m1 + \"; Computer: \" + m2\r\n\tn1 = cardValues.indexOf(m1[2:])\r\n\tn2 = cardValues.indexOf(m2[2:])\r\n\tif n1 > n2 then\r\n\t\tplayerScore += 1\r\n\t\tprint \"You win. You have \" + playerScore + \" and the computer has \" + computerScore\r\n\telse if n2 > n1 then\r\n\t\tcomputerScore += 1\r\n\t\tprint \"The computer wins!!! You have \" + playerScore + \" and the computer has \" + computerScore\r\n\telse\r\n\t\tprint \"Tie.  No score change.\"\r\n\tend if\r\n\tif not deck then break\r\n\tif askYesNo(\"Do you want to continue\") == \"n\" then break\r\nend while\r\n\r\nif not deck then\r\n\tprint\r\n\tprint\r\n\tprint \"We have run out of cards.  Final score: You: \" + playerScore + \r\n\t  \"  The computer: \" + computerScore\r\n\tprint\r\nend if\r\nprint \"Thanks for playing.  It was fun.\"\r\nprint\r\n\t\t"
  },
  {
    "path": "00_Alternate_Languages/94_War/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/94_War/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "00_Alternate_Languages/94_War/d/README.md",
    "content": "﻿Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -preview=dip1000 -run war.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n\n## Specialties explained\n\nThis game code contains some specialties that you might want to know more about. Here goes.\n\n### Suits\n\nMost modern consoles are capable of displaying more than just ASCII, and so I have chosen to display the actual ♠, ♥, ♦\nand ♣ instead of substituting them by letters like the BASIC original did. Only the Windows console needs a nudge in\nthe right direction with these instructions:\n```d\nSetConsoleOutputCP(CP_UTF8); // Set code page\nSetConsoleOutputCP(GetACP);  // Restore the default\n```\nInstead of cluttering the `main()` function with these lesser important details, we can move them into a\n[module constructor and module destructor](https://dlang.org/spec/module.html#staticorder), which run before and after\n`main()` respectively. And because order of declaration is irrelevant in a D module, we can push those all the way\ndown to the bottom of the file. This is of course only necessary on Windows (and won't even work anywhere else) so\nwe'll need to wrap this in a `version (Windows)` conditional code block:\n```d\nversion (Windows)\n{\n    import core.sys.windows.windows;\n\n    shared static this() @trusted\n    {\n        SetConsoleOutputCP(CP_UTF8);\n    }\n\n    shared static ~this() @trusted\n    {\n        SetConsoleOutputCP(GetACP);\n    }\n}\n```\nAlthough it doesn't matter much in this single-threaded program, the `shared` attribute makes that these\nconstructors/destructors are run once per program invocation; non-shared module constructors and module destructors are\nrun for every thread. The `@trusted` annotation is necessary because these are system API calls; The compiler cannot\ncheck these for memory-safety, and so we must indicate that we have reviewed the safety manually.\n\n### Uniform Function Call Syntax\n\nIn case you wonder why this line works:\n```d\nif (\"Do you want instructions?\".yes)\n    // ...\n```\nthen it is because this is equivalent to\n```d\nif (yes(\"Do you want instructions?\"))\n    // ...\n```\nwhere `yes()` is a Boolean function that is defined below `main()`. This is made possible by the language feature that\nis called [uniform function call syntax (UFCS)](https://dlang.org/spec/function.html#pseudo-member). UFCS works by\npassing what is in front of the dot as the first parameter to the function, and it was invented to make it possible to\ncall free functions on objects as if they were member functions. UFCS can also be used to obtain a more natural order\nof function calls, such as this line inside `yes()`:\n```d\nreturn trustedReadln.strip.toLower.startsWith(\"y\");\n```\nwhich reads easier than the equivalent\n```d\nreturn startsWith(toLower(strip(trustedReadln())), \"y\");\n```\n\n### Type a lot or not?\n\nIt would have been straight forward to define the `cards` array explicitly like so:\n```d\nconst cards = [\"2♠\", \"2♥\", \"2♦\", \"2♣\", \"3♠\", \"3♥\", \"3♦\", \"3♣\",\n               \"4♠\", \"4♥\", \"4♦\", \"4♣\", \"5♠\", \"5♥\", \"5♦\", \"5♣\",\n               \"6♠\", \"6♥\", \"6♦\", \"6♣\", \"7♠\", \"7♥\", \"7♦\", \"7♣\",\n               \"8♠\", \"8♥\", \"8♦\", \"8♣\", \"9♠\", \"9♥\", \"9♦\", \"9♣\",\n               \"10♠\", \"10♥\", \"10♦\", \"10♣\", \"J♥\", \"J♦\", \"J♣\", \"J♣\",\n               \"Q♠\", \"Q♥\", \"Q♦\", \"Q♣\", \"K♠\", \"K♥\", \"K♦\", \"K♣\",\n               \"A♠\", \"A♥\", \"A♦\", \"A♣\"];\n```\nbut that's tedious, difficult to spot errors in (*can you?*) and looks like something a computer can automate. Indeed\nit can:\n```d\nstatic const cards = cartesianProduct([\"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\"],\n                                      [\"♠\", \"♥\", \"♦\", \"♣\"]).map!(a => a.expand.only.join).array;\n```\nThe function [`cartesianProduct`](https://dlang.org/phobos/std_algorithm_setops.html#cartesianProduct) takes two\nranges, like the horizontal and vertical headers of a spreadsheet, and fills the table with the combinations that form\nthe coordinates of the cells. But the output of that function is in the form of an array of\n[`Tuple`](https://dlang.org/phobos/std_typecons.html#Tuple)s, which looks like `[Tuple!(string, string)(\"2\", \"♠\"),\nTuple!(string, string)(\"2\", \"♥\"), ... etc]`. [`map`](https://dlang.org/phobos/std_algorithm_iteration.html#map)\ncomes to the rescue, converting each Tuple to a string, by calling\n[`expand`](https://dlang.org/phobos/std_typecons.html#.Tuple.expand), then\n[`only`](https://dlang.org/phobos/std_range.html#only) and then [`join`](https://dlang.org/phobos/std_array.html#join)\non them. The result is a lazily evaluated range of strings. Finally,\n[`array`](https://dlang.org/phobos/std_array.html#array) turns the range into a random access array. The `static`\nattribute makes that all this is performed at compile-time, so the result is exactly the same as the manually entered\ndata, but without the typo's.\n\n### Shuffle the cards or not?\n\nThe original BASIC code works with a constant array of cards, ordered by increasing numerical value, and indexing it\nwith indices that have been shuffled. This is efficient because in comparing who wins, the indices can be compared\ndirectly, since a higher index correlates to a card with a higher numerical value (when divided by the number of suits,\n4). Some of the other reimplementations in other languages have been written in a lesser efficient way by shuffling the\narray of cards itself. This then requires the use of a lookup table or searching for equality in an auxiliary array\nwhen comparing cards.\n\nI find the original more elegant, so that's what you see here:\n```d\nconst indices = iota(0, cards.length).array.randomShuffle;\n```\n[`iota`](https://dlang.org/phobos/std_range.html#iota) produces a range of integers, in this case starting at 0 and\nincreasing up to the number of cards in the deck (exclusive). [`array`](https://dlang.org/phobos/std_array.html#array)\nturns the range into an array, so that [`randomShuffle`](https://dlang.org/phobos/std_random.html#randomShuffle) can\ndo its work.\n"
  },
  {
    "path": "00_Alternate_Languages/94_War/d/war.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std;\n\nvoid main()\n{\n    enum width = 50;\n    writeln(center(\"War\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\", width));\n    writeln(wrap(\"This is the card game of war.  Each card is given by suit-# \" ~\n                 \"as 7♠ for seven of spades.  \", width));\n\n    if (\"Do you want instructions?\".yes)\n        writeln(\"\\n\", wrap(\"The computer gives you and it a 'card'.  The higher card \" ~\n                           \"(numerically) wins.  The game ends when you choose not to \" ~\n                           \"continue or when you have finished the pack.\\n\", width));\n\n    static const cards = cartesianProduct([\"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\"],\n                                          [\"♠\", \"♥\", \"♦\", \"♣\"]).map!(a => a.expand.only.join).array;\n    const indices = iota(0, cards.length).array.randomShuffle;\n    int yourScore = 0, compScore = 0, i = 0;\n    while (i < indices.length)\n    {\n        size_t your = indices[i++], comp = indices[i++];\n        writeln(\"\\nYou: \", cards[your].leftJustify(9), \"Computer: \", cards[comp]);\n        your /= 4; comp /= 4;\n        if (your == comp)\n            writeln(\"Tie. No score change.\");\n        else if (your < comp)\n            writeln(\"The computer wins!!! You have \", yourScore,\n                    \" and the computer has \", ++compScore, \".\");\n        else\n            writeln(\"You win. You have \", ++yourScore,\n                    \" and the computer has \", compScore, \".\");\n        if (i == indices.length)\n            writeln(\"\\nWe have run out of cards. Final score: You: \", yourScore,\n                    \", the computer: \", compScore, \".\");\n        else if (!\"Do you want to continue?\".yes)\n            break;\n    }\n    writeln(\"\\nThanks for playing. It was fun.\");\n}\n\n/// Returns whether question was answered positively.\nbool yes(string question)\n{\n    writef!\"%s \"(question);\n    try\n        return trustedReadln.strip.toLower.startsWith(\"y\");\n    catch (Exception)   // readln throws on I/O and Unicode errors, which we handle here.\n        return false;\n}\n\n/** An @trusted wrapper around readln.\n*\n* This is the only function that formally requires manual review for memory-safety.\n* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)\n* which would remove the need to have any @trusted code in this program.\n*/\nstring trustedReadln() @trusted\n{\n    return readln;\n}\n\nversion (Windows)\n{\n    // Make the Windows console do a better job at printing UTF-8 strings,\n    // and restore the default upon termination.\n\n    import core.sys.windows.windows;\n\n    shared static this() @trusted\n    {\n        SetConsoleOutputCP(CP_UTF8);\n    }\n\n    shared static ~this() @trusted\n    {\n        SetConsoleOutputCP(GetACP);\n    }\n}\n"
  },
  {
    "path": "00_Alternate_Languages/94_War/war.bas",
    "content": "10 PRINT TAB(33);\"WAR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 PRINT \"THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#\"\n110 PRINT \"AS S-7 FOR SPADE 7.  \";\n120 PRINT \"DO YOU WANT DIRECTIONS\";\n130 INPUT B$\n140 IF B$=\"NO\" THEN 210\n150 IF B$=\"YES\" THEN 180\n160 PRINT \"YES OR NO, PLEASE.  \";\n170 GOTO 120\n180 PRINT \"THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD\"\n190 PRINT \"(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO\"\n200 PRINT \"CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\"\n210 PRINT\n220 PRINT\n230 DIM A$(52),L(54)\n240 FOR I=1 TO 52\n250 READ A$(I)\n260 NEXT I\n270 REM\n280 FOR J=1 TO 52\n290 LET L(J)=INT(52*RND(1))+1\n295 IF J=1 THEN 350\n300 FOR K=1 TO J-1\n310 IF L(K)<>L(J) THEN 340\n320 REM\n330 GOTO 290\n340 NEXT K\n350 NEXT J\n360 P=P+1\n370 M1=L(P)\n380 P=P+1\n390 M2=L(P)\n400 PRINT\n420 PRINT \"YOU: \";A$(M1),\"COMPUTER: \";A$(M2)\n430 N1=INT((M1-.5)/4)\n440 N2=INT((M2-.5)/4)\n450 IF N1>=N2 THEN 490\n460 A1=A1+1\n470 PRINT \"THE COMPUTER WINS!!! YOU HAVE\";B1;\"AND THE COMPUTER HAS\";A1\n480 GOTO 540\n490 IF N1=N2 THEN 530\n500 B1=B1+1\n510 PRINT \"YOU WIN. YOU HAVE\";B1;\"AND THE COMPUTER HAS\";A1\n520 GOTO 540\n530 PRINT \"TIE.  NO SCORE CHANGE.\"\n540 IF L(P+1)=0 THEN 610\n550 PRINT \"DO YOU WANT TO CONTINUE\";\n560 INPUT V$\n570 IF V$=\"YES\" THEN 360\n580 IF V$=\"NO\" THEN 650\n590 PRINT \"YES OR NO, PLEASE.  \";\n600 GOTO 540\n610 PRINT\n620 PRINT\n630 PRINT \"WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: \";B1;\n640 PRINT \"  THE COMPUTER: \";A1:PRINT\n650 PRINT \"THANKS FOR PLAYING.  IT WAS FUN.\"\n655 PRINT\n660 DATA \"S-2\",\"H-2\",\"C-2\",\"D-2\",\"S-3\",\"H-3\",\"C-3\",\"D-3\"\n670 DATA \"S-4\",\"H-4\",\"C-4\",\"D-4\",\"S-5\",\"H-5\",\"C-5\",\"D-5\"\n680 DATA \"S-6\",\"H-6\",\"C-6\",\"D-6\",\"S-7\",\"H-7\",\"C-7\",\"D-7\"\n690 DATA \"S-8\",\"H-8\",\"C-8\",\"D-8\",\"S-9\",\"H-9\",\"C-9\",\"D-9\"\n700 DATA \"S-10\",\"H-10\",\"C-10\",\"D-10\",\"S-J\",\"H-J\",\"C-J\",\"D-J\"\n710 DATA \"S-Q\",\"H-Q\",\"C-Q\",\"D-Q\",\"S-K\",\"H-K\",\"C-K\",\"D-K\"\n720 DATA \"S-A\",\"H-A\",\"C-A\",\"D-A\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/95_Weekday/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript weekday.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"weekday\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms",
    "content": "TAB = char(9)\n\nAge = {\"m\": 0, \"d\": 0, \"y\": 0}\nAge.init = function(m,d,y)\n\tnoob = new Age\n\tnoob.m = m;noob.d = d;noob.y = y\n\treturn noob\nend function\n\nAge.sub = function(a)\n\tm1 = self.m; d1 = self.d; y1 = self.y\n\td1 = d1 - a.d\n\tif d1 < 0 then\n\t\td1 = d1 + 30\n\t\tm1 = m1 - 1\n\tend if\n\tm1 = m1 - a.m\n\tif m1 < 0then\n\t\tm1 = m1 + 12\n\t\ty1 = y1 - 1\n\tend if\n\ty1 = y1 - a.y\n\treturn Age.init(m1,d1,y1)\nend function\n\nAge.multiply = function(multiplier)\n\tageInDays = self.y *365 + self.m * 30 + self.d + floor(self.m / 2)\n\tnewAge = ageInDays * multiplier\n\tyears = floor(newAge/ 365)\n\tleftover = newAge % 365\n\tmonths = floor(leftover / 30)\n\tdays = floor(leftover % 30)\n\treturn Age.init(months, days, years)\nend function\n\nDate = {\"m\": null, \"d\": null, \"y\": null}\n\n// the number of days between the 1st of one month to the next\nDate.daysPerMonth = [0,31,28,31,30,31,30, 31,31,30,31,30]\nDate.dayNames = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\",\n\"Thursday\", \"Friday\", \"Saturday\"]\n\nDate.init = function(dt)\n\td = dt.split(\",\")\n\tif d.len != 3 then return\n\tnoob = new Date\n\tnoob.m = d[0].val\n\tnoob.d = d[1].val\n\tnoob.y = d[2].val\n\treturn noob\nend function\n\nDate.diff = function(mdy)\n\tdday = self.d - mdy.d\n\tdmonth = self.m - mdy.m\n\tif dday < 0 then\n\t\tdmonth -= 1\n\t\tdday += 30\n\tend if\n\t\n\tdyear = self.y - mdy.y\n\tif dmonth <0 then\n\t\tdyear -= 1\n\t\tdmonth += 12\n\tend if\n\treturn Age.init(dmonth, dday, dyear)\nend function\n\nDate._isLeapYear = function\n\treturn (self.y % 4 == 0 and self.y % 100 != 0) or self.y % 400 == 0\nend function\n\nDate.value = function\n\t//Not accepting dates Jan 1st 1583 this because the\n\t//transistion to Gregorian calendar occurred in 1582.\n\t\n\t//calculating days since the end of 1582\n\tyears = self.y - 1583\n\tdays = years * 365 + self._leapYears + Date.daysPerMonth[:self.m].sum + self.d\n\treturn days // returns 1 for 1,1,1583\nend function\n\nDate.dayOfWeek = function\n\t// 1,1,1583 is a Saturday\n\t// Date.value calculates a value of 1 for that date\n\treturn (self.value + 5) % 7\nend function\n\nDate.weekday = function\n\treturn Date.dayNames[self.dayOfWeek]\nend function\n\n// get # of lear yeaps since the change to Gregorian\nDate._leapYears = function\n\tly = floor((self.y - 1580) / 4)\n\t\n\t//exclude centuries\n\tcenturies = floor((self.y - 1500) / 100)\n\t\n\t//unless centuries divisible by 400\n\tcenturies400 = floor((self.y - 1200) / 400) \n\tly = ly - centuries + centuries400\n\t\n\tif self._isLeapYear and self.m < 3 then ly -= 1\n\treturn ly\nend function\n\nprint \" \"*32 + \"WEEKDAY\"\nprint \" \"*15 + \"Creative Computing  Morristown, New Jersey\"\nprint; print; print\n\nprint \"WEEKDAY is a computer demonstration that\"\nprint \"gives facts about a date of interest to you.\"\nprint\n\nmdy = input(\"Enter today's date in the form: 3,24,1979? \")\ntoday = Date.init(mdy)\n\n\nmdy = input(\"Enter day of birth (or other day of interest)? \")\ndob = Date.init(mdy)\n\nprint\nif dob.y < 1583 then\n\tprint \"Not prepared to give day of the week prior to 1583\"\n\texit\nend if\n\nverb = \" was a \"\nif today.value < dob.value then verb= \" will be a \"\nif today.value == dob.value then verb = \" is a \"\n\nif dob.d == 13 and dob.weekday == \"Friday\" then\n\tendMsg = \" The Thirteenth--Beware!\"\nelse\n\tendMsg = \".\"\nend if\nprint dob.m + \"/\" + dob.d + \"/\" + dob.y + verb + dob.weekday + endMsg\n\nage = today.diff(dob)\n\ntotalAge = Age.init(age.m,age.d,age.y)\nif verb == \" was a \" then\n\tif dob.d == today.d and dob.m == today.m then print \"***HAPPY BIRTHDAY***\"\n\t\n\tlines= [[\"\", \"YEARS\", \"MONTHS\", \"DAYS\"]]\n\tlines.push([\"\", \"-----\", \"------\", \"----\"])\n\tlines.push([\"Your age (if birthdate)\", age.y,age.m, age.d])\n\t\n\tspent = age.multiply(.35)\n\tlines.push([\"You have slept\", spent.y,spent.m, spent.d])\n\ttotalAge = totalAge.sub(spent)\n\t\n\tspent = age.multiply(.17)\n\tlines.push([\"You have eaten\", spent.y,spent.m, spent.d])\n\ttotalAge = totalAge.sub(spent)\n\t\n\tif totalAge.y <= 3 then\n\t\tphrase = \"You have played\"\n\telse if totalAge.y <= 9 then\n\t\tphrase = \"You have played/studied\"\n\telse\n\t\tphrase = \"You have worked/played\"\n\tend if\n\t\n\tspent = age.multiply(.23)\n\tlines.push([phrase, spent.y,spent.m, spent.d])\t\n\ttotalAge = totalAge.sub(spent)\n\t\n\trelaxed = totalAge\n\tlines.push([\"You have relaxed\", relaxed.y, relaxed.m, relaxed.d])\n\tfor line in lines\n\t\tcol0 = (\" \" * 25 + line[0])[-25:]\n\t\tcol1 = (line[1] + \" \" * 6)[:6]\n\t\tcol2 = (line[2] + \" \" * 7)[:7]\n\t\tcol3 = (line[3] + \" \" * 5)[:5]\n\t\tprint (col0+\" \" + col1+col2+col3)\n\tend for\nend if\n\nprint\nprint \" \"*16 + \"***  You may retire in \" + (dob.y + 65) + \"  ***\"\n"
  },
  {
    "path": "00_Alternate_Languages/95_Weekday/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/95_Weekday/weekday.bas",
    "content": "10 PRINT TAB(32);\"WEEKDAY\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"WEEKDAY IS A COMPUTER DEMONSTRATION THAT\"\n110 PRINT\"GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\"\n120 PRINT\n130 PRINT \"ENTER TODAY'S DATE IN THE FORM: 3,24,1979  \";\n140 INPUT M1,D1,Y1\n150 REM THIS PROGRAM DETERMINES THE DAY OF THE WEEK\n160 REM  FOR A DATE AFTER 1582\n170 DEF FNA(A)=INT(A/4)\n180 DIM T(12)\n190 DEF FNB(A)=INT(A/7)\n200 REM SPACE OUTPUT AND READ IN INITIAL VALUES FOR MONTHS.\n210 FOR I= 1 TO 12\n220 READ T(I)\n230 NEXT I\n240 PRINT\"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)\";\n250 INPUT M,D,Y\n260 PRINT\n270 LET I1 = INT((Y-1500)/100)\n280 REM TEST FOR DATE BEFORE CURRENT CALENDAR.\n290 IF Y-1582 <0 THEN 1300\n300 LET A = I1*5+(I1+3)/4\n310 LET I2=INT(A-FNB(A)*7)\n320 LET Y2=INT(Y/100)\n330 LET Y3 =INT(Y-Y2*100)\n340 LET A =Y3/4+Y3+D+T(M)+I2\n350 LET B=INT(A-FNB(A)*7)+1\n360 IF M > 2 THEN 470\n370 IF Y3 = 0 THEN 440\n380 LET T1=INT(Y-FNA(Y)*4)\n390 IF T1 <> 0 THEN 470\n400 IF B<>0 THEN 420\n410 LET B=6\n420 LET B = B-1\n430 GOTO 470\n440 LET A = I1-1\n450 LET T1=INT(A-FNA(A)*4)\n460 IF T1 = 0 THEN 400\n470 IF B <>0 THEN 490\n480 LET B = 7\n490 IF (Y1*12+M1)*31+D1<(Y*12+M)*31+D THEN 550\n500 IF (Y1*12+M1)*31+D1=(Y*12+M)*31+D THEN 530\n510 PRINT M;\"/\";D;\"/\";Y;\" WAS A \";\n520 GOTO 570\n530 PRINT M;\"/\";D;\"/\";Y;\" IS A \";\n540 GOTO 570\n550 PRINT M;\"/\";D;\"/\";Y;\" WILL BE A \";\n560 REM PRINT THE DAY OF THE WEEK THE DATE FALLS ON.\n570 IF B <>1 THEN 590\n580 PRINT \"SUNDAY.\"\n590 IF B<>2 THEN 610\n600 PRINT \"MONDAY.\"\n610 IF B<>3 THEN 630\n620 PRINT \"TUESDAY.\"\n630 IF B<>4 THEN 650\n640 PRINT \"WEDNESDAY.\"\n650 IF B<>5 THEN 670\n660 PRINT \"THURSDAY.\"\n670 IF B<>6 THEN 690\n680 GOTO 1250\n690 IF B<>7 THEN 710\n700 PRINT \"SATURDAY.\"\n710 IF (Y1*12+M1)*31+D1=(Y*12+M)*31+D THEN 1120\n720 LET I5=Y1-Y\n730 PRINT\n740 LET I6=M1-M\n750 LET I7=D1-D\n760 IF I7>=0 THEN 790\n770 LET I6= I6-1\n780 LET I7=I7+30\n790 IF I6>=0 THEN 820\n800 LET I5=I5-1\n810 LET I6=I6+12\n820 IF I5<0 THEN 1310\n830 IF I7 <> 0 THEN 850\n835 IF I6 <> 0 THEN 850\n840 PRINT\"***HAPPY BIRTHDAY***\"\n850 PRINT \" \",\" \",\"YEARS\",\"MONTHS\",\"DAYS\"\n855 PRINT \" \",\" \",\"-----\",\"------\",\"----\"\n860 PRINT \"YOUR AGE (IF BIRTHDATE) \",I5,I6,I7\n870 LET A8 = (I5*365)+(I6*30)+I7+INT(I6/2)\n880 LET K5 = I5\n890 LET K6 = I6\n900 LET K7 = I7\n910 REM CALCULATE RETIREMENT DATE.\n920 LET E = Y+65\n930 REM CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS.\n940 LET F = .35\n950 PRINT \"YOU HAVE SLEPT \",\n960 GOSUB 1370\n970 LET F = .17\n980 PRINT \"YOU HAVE EATEN \",\n990 GOSUB 1370\n1000 LET F = .23\n1010 IF K5 > 3 THEN 1040\n1020 PRINT \"YOU HAVE PLAYED\",\n1030 GOTO 1080\n1040 IF K5 > 9 THEN 1070\n1050 PRINT \"YOU HAVE PLAYED/STUDIED\",\n1060 GOTO  1080\n1070 PRINT \"YOU HAVE WORKED/PLAYED\",\n1080 GOSUB 1370\n1085 GOTO 1530\n1090 PRINT \"YOU HAVE RELAXED \",K5,K6,K7\n1100 PRINT\n1110 PRINT TAB(16);\"***  YOU MAY RETIRE IN\";E;\" ***\"\n1120 PRINT\n1140 PRINT\n1200 PRINT\n1210 PRINT\n1220 PRINT\n1230 PRINT\n1240 END\n1250 IF D=13 THEN 1280\n1260 PRINT \"FRIDAY.\"\n1270 GOTO 710\n1280 PRINT \"FRIDAY THE THIRTEENTH---BEWARE!\"\n1290 GOTO 710\n1300 PRINT \"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII. \"\n1310 GOTO 1140\n1320 REM TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS.\n1330 DATA 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5\n1340 REM THIS IS THE CURRENT DATE USED IN THE CALCULATIONS.\n1350 REM THIS IS THE DATE TO BE CALCULATED ON.\n1360 REM CALCULATE TIME IN YEARS, MONTHS, AND DAYS\n1370 LET K1=INT(F*A8)\n1380 LET I5 = INT(K1/365)\n1390 LET K1 = K1- (I5*365)\n1400 LET I6 = INT(K1/30)\n1410 LET I7 = K1 -(I6*30)\n1420 LET K5 = K5-I5\n1430 LET K6 =K6-I6\n1440 LET K7 = K7-I7\n1450 IF K7>=0 THEN 1480\n1460 LET K7=K7+30\n1470 LET K6=K6-1\n1480 IF K6>0 THEN 1510\n1490 LET K6=K6+12\n1500 LET K5=K5-1\n1510 PRINT I5,I6,I7\n1520 RETURN\n1530 IF K6=12 THEN 1550\n1540 GOTO 1090\n1550 LET K5=K5+1\n1560 LET K6=0\n1570 GOTO 1090\n1580 REM\n1590 END\n"
  },
  {
    "path": "00_Alternate_Languages/96_Word/MiniScript/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).\n\nConversion to [MiniScript](https://miniscript.org).\n\nWays to play:\n\n1. Command-Line MiniScript:\nDownload for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:\n```\n\tminiscript word.ms\n```\n2. Mini Micro:\nDownload Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose \"Mount Folder...\"  Select the folder containing the MiniScript program and this README file.  Then, at the Mini Micro command prompt, enter:\n```\n\tload \"word\"\n\trun\n```"
  },
  {
    "path": "00_Alternate_Languages/96_Word/MiniScript/word.ms",
    "content": "words = [\"dinky\", \"smoke\", \"water\", \"grass\", \"train\", \"might\", \n         \"first\", \"candy\", \"champ\", \"would\", \"clump\", \"dopey\"]\n\nplayGame = function\n\tsecret = words[rnd * words.len]\n\tguesses = 0\n\texact = [\"-\"]*5\n\t\n\tprint \"You are starting a new game...\"\n\twhile true\n\t\tguess = \"\"\n\t\twhile guess == \"\"\n\t\t\tprint\n\t\t\tguess = input(\"Guess a five letter word. \").lower\n\t\t\tif guess == \"?\" then break\n\t\t\tif guess.len != 5 then\n\t\t\t\tguess = \"\"\n\t\t\t\tprint \"You must guess a five letter word. Try again.\"\n\t\t\tend if\n\t\tend while\n\t\tguesses += 1\n\t\t\n\t\tif guess == \"?\" then\n\t\t\tprint \"The secret word is \" + secret\n\t\t\tbreak\n\t\telse\n\t\t\tcommon = \"\"\n\t\t\tfor i in range(0, 4)\n\t\t\t\tif secret.indexOf(guess[i]) != null then\n\t\t\t\t\tcommon += guess[i]\n\t\t\t\t\tif secret[i] == guess[i] then\n\t\t\t\t\t\texact[i] = guess[i]\n\t\t\t\t\tend if\n\t\t\t\tend if\n\t\t\tend for\n\t\t\tprint \"There were \" + common.len + \" matches and the common letters were...\" + common\n\t\t\tprint \"From the exact letter matches, you know\"+\".\"*16 + exact.join(\"\")\n\t\t\t\n\t\t\tif secret == guess or secret == exact.join(\"\") then\n\t\t\t\tprint \"You have guessed the word. It took \" + guesses + \" guesses!\"\n\t\t\t\tbreak\n\t\t\telse if common.len < 2 then\n\t\t\t\tprint\n\t\t\t\tprint \"If you give up, type '?' for your next guess.\"\n\t\t\tend if\n\t\tend if\n\tend while\nend function\n\nprint \" \" * 33 + \"WORD\"\nprint \" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\nprint\nprint \"I am thinking of a word -- you guess it. I will give you\"\nprint \"clues to help you get it. Good luck!\"\nprint\n\nplaying = \"y\"\nwhile playing == \"y\"\n\tplayGame\n\tprint\n\tplaying = input(\"Want to play again? \") + \" \"\n\tplaying = playing[0].lower\nend while\n"
  },
  {
    "path": "00_Alternate_Languages/96_Word/README.md",
    "content": "Please refer to the `readme.md` in the parent folder. \n\nEach subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nWe welcome additional ports, but these additional ports are for educational purposes only."
  },
  {
    "path": "00_Alternate_Languages/96_Word/word.bas",
    "content": "2 PRINT TAB(33);\"WORD\"\n3 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n4 PRINT: PRINT: PRINT\n5 DIM S(7),A(7),L(7),D(7),P(7)\n10 PRINT \"I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\"\n15 PRINT \"CLUES TO HELP YOU GET IT.  GOOD LUCK!!\": PRINT: PRINT\n20 REM\n30 PRINT: PRINT: PRINT \"YOU ARE STARTING A NEW GAME...\"\n35 RESTORE\n40 READ N\n50 C=INT(RND(1)*N+1)\n60 FOR I=1 TO C\n70 READ S$\n80 NEXT I\n90 G=0\n95 S(0)=LEN(S$)\n100 FOR I=1 TO LEN(S$): S(I)=ASC(MID$(S$,I,1)): NEXT I\n110 FOR I=1 TO 5\n120 A(I)=45\n130 NEXT I\n140 FOR J=1 TO 5\n144 P(J)=0\n146 NEXT J\n150 PRINT \"GUESS A FIVE LETTER WORD\";\n160 INPUT L$\n170 G=G+1\n172 IF S$=L$ THEN 500\n173 FOR I=1 TO 7: P(I)=0: NEXT I\n175 L(0)=LEN(L$)\n180 FOR I=1 TO LEN(L$): L(I)=ASC(MID$(L$,I,1)): NEXT I\n190 IF L(1)=63 THEN 300\n200 IF L(0)<>5 THEN 400\n205 M=0: Q=1\n210 FOR I=1 TO 5\n220 FOR J=1 TO 5\n230 IF S(I)<>L(J) THEN 260\n231 P(Q)=L(J)\n232 Q=Q+1\n233 IF I<>J THEN 250\n240 A(J)=L(J)\n250 M=M+1\n260 NEXT J\n265 NEXT I\n270 A(0)=5\n272 P(0)=M\n275 A$=\"\": FOR I=1 TO A(0): A$=A$+CHR$(A(I)): NEXT I\n277 P$=\"\": FOR I=1 TO P(0): P$=P$+CHR$(P(I)): NEXT I\n280 PRINT \"THERE WERE\";M;\"MATCHES AND THE COMMON LETTERS WERE...\";P$\n285 PRINT \"FROM THE EXACT LETTER MATCHES, YOU KNOW................\";A$\n286 IF A$=S$ THEN 500\n287 IF M>1 THEN 289\n288 PRINT: PRINT \"IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\"\n289 PRINT\n290 GOTO 150\n300 S$=\"\": FOR I=1 TO 7: S$=S$+CHR$(S(I)): NEXT I\n310 PRINT \"THE SECRET WORD IS \";S$: PRINT\n320 GOTO 30\n400 PRINT \"YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\"\n410 PRINT: G=G-1: GOTO 150\n500 PRINT \"YOU HAVE GUESSED THE WORD.  IT TOOK\";G;\"GUESSES!\": PRINT\n510 INPUT \"WANT TO PLAY AGAIN\";Q$\n520 IF Q$=\"YES\" THEN 30\n530 DATA 12,\"DINKY\",\"SMOKE\",\"WATER\",\"GRASS\",\"TRAIN\",\"MIGHT\",\"FIRST\"\n540 DATA \"CANDY\",\"CHAMP\",\"WOULD\",\"CLUMP\",\"DOPEY\"\n999 END\n"
  },
  {
    "path": "00_Alternate_Languages/README.md",
    "content": "#### Alternate Languages\n\nThis folder contains implementations of each program in alternate languages which are _not_ one of the agreed upon 10 languages.\n\nImplementations here are NOT bound to these three criteria:\n\n1. Popular (by TIOBE index)\n2. Memory safe\n3. Generally considered a 'scripting' language\n\nSo for example, (here only) C or PASCAL are allowed. Please still remain faithful to original look-and-feel (console applications).\nTry to keep your code portable (unless it is not possible, and then be very explicit about this limitation in your\nREADME and your folder naming).\n\nWe welcome additional ports in whatever language you prefer, but these additional ports are for educational purposes only, and do not count towards the donation total at the end of the project.\n"
  },
  {
    "path": "00_Common/BASIC_Tests/InputTest.bas",
    "content": "10 INPUT \"Enter 3 numbers\";A,B,C\n20 PRINT \"You entered: \";A;B;C\n30 PRINT \"--------------------------\"\n40 GOTO 10\n"
  },
  {
    "path": "00_Common/BASIC_Tests/OutputTest.bas",
    "content": "10 A=1: B=-2: C=0.7: D=123456789: E=-0.0000000001\n20 PRINT \"|\";A;\"|\";B;\"|\";C;\"|\";D;\"|\";E;\"|\"\n"
  },
  {
    "path": "00_Common/BASIC_Tests/RndTest.bas",
    "content": "10 PRINT \"1: \";RND(1);RND(1);RND(0);RND(0);RND(1)\n20 PRINT \"2: \";RND(-2);RND(1);RND(1);RND(1)\n30 PRINT \"3: \";RND(-5);RND(1);RND(1);RND(1)\n40 PRINT \"4: \";RND(-2);RND(1);RND(1);RND(1)\n"
  },
  {
    "path": "00_Common/README.md",
    "content": "# Common Library\n\n## Purpose\n\nThe primary purpose of this library is to implement common behaviours of the BASIC interpreter that impact gameplay, to\nfree coders porting the games to concentrate on the explicit game logic.\n\nThe behaviours implemented by this library are:\n\n* Complex interactions involved in text input.\n* Formatting of number in text output.\n* Behaviour of the BASIC `RND(float)` PRNG function.\n\nA secondary purpose is to provide common services that, with dependency injection, would allow a ported game to be\ndriven programmatically to permit full-game acceptance tests to be written.\n\nThe library is **NOT** intended to be:\n\n* a repository for common game logic that is implemented in the BASIC code of the games; or\n* a DSL allowing the BASIC code to be compiled in a different language environment with minimal changes. This implies\n  that implementations of the above behaviours should use method names, etc, that are idiomatic of the specific\n  language's normal routines for that behaviour.\n\n## Text Input\n\nThe behaviour of the BASIC interpreter when accepting text input from the user is a major element of the original\ngameplay experience that is seen to be valuable to maintain. This behaviour is complex and non-trivial to implement, and\nis better implemented once for other developers to use so they can concentrate on the explicit game logic.\n\nThe text input/output behaviour can be investigated using a basic program such as:\n\n**`BASIC_Tests/InputTest.bas`**\n\n```basic\n10 INPUT \"Enter 3 numbers\";A,B,C\n20 PRINT \"You entered: \";A;B;C\n30 PRINT \"--------------------------\"\n40 GOTO 10\n```\n\nThe following transcript shows the use of this program, and some interesting behaviours of the BASIC interpreter INPUT\nroutine. There are some other behaviours which can be seen in the unit tests for the C# library implementation.\n\n```dos\nEnter 3 numbers? -1,2,3.141             <-- multiple numbers are separated by commas\nYou entered: -1  2  3.141\n--------------------------\nEnter 3 numbers? 1                      <-- ... or entered on separate lines\n?? 2\n?? 3\nYou entered:  1  2  3\n--------------------------\nEnter 3 numbers? 1,2                    <-- ... or both\n?? 3\nYou entered:  1  2  3\n--------------------------\nEnter 3 numbers? 1,-2,3,4               <-- Extra input is ignore with a warning\n!EXTRA INPUT IGNORED\nYou entered:  1 -2  3\n--------------------------\nEnter 3 numbers?   5  , 6.7, -8   ,10   <-- Whitespace around values is ignored\n!EXTRA INPUT IGNORED\nYou entered:  5  6.7 -8\n--------------------------\nEnter 3 numbers? abcd,e,f               <-- Non-numeric entries must be retried\n!NUMBER EXPECTED - RETRY INPUT LINE\n? 1,2,abc                               <-- A single non-numeric invalidates the whole line\n!NUMBER EXPECTED - RETRY INPUT LINE\n? 1de,2.3f,10k,abcde                    <-- ... except for trailing non-digit chars  and extra input\n!EXTRA INPUT IGNORED\nYou entered:  1  2.3  10\n--------------------------\nEnter 3 numbers? 1,\"2,3\",4              <-- Double-quotes enclose a single parsed value\nYou entered:  1  2  4\n--------------------------\nEnter 3 numbers? 1,2,\"3                 <-- An unmatched double-quote crashes the interpreter\nvintbas.exe: Mismatched inputbuf in inputVars\nCallStack (from HasCallStack):\n  error, called at src\\Language\\VintageBasic\\Interpreter.hs:436:21 in main:Language.VintageBasic.Interpreter\n```\n\nI propose to ignore this last behaviour - the interpreter crash - and instead treat the end of the input line as the end\nof a quoted value.  There are some additional behaviours to those shown above which can be seen in the unit tests for\nthe C# implementation of the library.\n\nNote also that BASIC numeric variables store a single-precision floating point value, so numeric input functions should\nreturn a value of that type.\n\n### Implementation Notes\n\nThe usage of the `INPUT` command in the BASIC code of the games was analysed, with the variables used designated as\n`num`, for a numeric variable (eg. `M1`), or `str`, for a string variable (eg. `C$`). The result of this usage analysis\nacross all game programs is:\n\nVariable number and type|Count\n---|---\nstr|137\nstr  str|2\nnum|187\nnum  num|27\nnum  num  num|7\nnum  num  num  num|1\nnum  num  num  num  num  num  num  num  num  num|1\n\nThe usage count is interesting, but not important. What is important is the variable type and number for each usage.\nImplementers if the above behaviours do not need to cater for mixed variable types in their input routines (although the\nBASIC interpreter does support this). Input routines also need to cater only for 1 or 2 string values, and 1, 2, 3, 4,\nor 10 numeric values.\n\n## Numbers in Text Output\n\nAs seen in the transcript above, the BASIC interpreter has some particular rules for formatting numbers in text output.\nNegative numbers are printed with a leading negative sign (`-`) and a trailing space. Positive numbers are printed also\nwith the trailing space, but with a leading space in place of the sign character.\n\nAdditional formatting rules can be seen by running this program:\n\n**`BASIC_Tests/OutputTest.bas`**\n\n```basic\n10 A=1: B=-2: C=0.7: D=123456789: E=-0.0000000001\n20 PRINT \"|\";A;\"|\";B;\"|\";C;\"|\";D;\"|\";E;\"|\"\n```\n\nThe output is:\n\n```dos\n| 1 |-2 | .7 | 1.2345679E+8 |-1.E-10 |\n```\n\nThis clearly shows the leading and trailing spaces, but also shows that:\n\n* numbers without an integer component are printed without a leading zero to the left of the decimal place;\n* numbers above and below a certain magnitude are printed in scientific notation.\n\n<!-- markdownlint-disable MD024 -->\n### Implementation Notes\n<!-- markdownlint-enable MD024 -->\n\nI think the important piece of this number formatting behaviour, in terms of its impact on replicating the text output\nof the original games, is the leading and trailing spaces. This should be the minimum behaviour supported for numeric\noutput. Additional formatting behaviours may be investigated and supported by library implementers as they choose.\n\n## The BASIC `RND(float)` function\n\nThe [Vintage BASIC documentation](http://vintage-basic.net/downloads/Vintage_BASIC_Users_Guide.html) describes the\nbehaviour of the `RND(float)` function:\n\n> Psuedorandom number generator. The behavior is different depending on the value passed. If the value is positive, the\n> result will be a new random value between 0 and 1 (including 0 but not 1). If the value is zero, the result will be a\n> repeat of the last random number generated. If the value is negative, it will be rounded down to the nearest integer\n> and used to reseed the random number generator. Pseudorandom sequences can be repeated by reseeding with the same\n> number.\n\nThis behaviour can be shown by the program:\n\n**`BASIC_Tests/RndTest.bas`**\n\n```basic\n10 PRINT \"1: \";RND(1);RND(1);RND(0);RND(0);RND(1)\n20 PRINT \"2: \";RND(-2);RND(1);RND(1);RND(1)\n30 PRINT \"3: \";RND(-5);RND(1);RND(1);RND(1)\n40 PRINT \"4: \";RND(-2);RND(1);RND(1);RND(1)\n```\n\nThe output of this program is:\n\n```dos\n1:  .97369444  .44256502  .44256502  .44256502  .28549057    <-- Repeated values due to RND(0)\n2:  .4986506  4.4510484E-2  .96231  .35997057\n3:  .8113741  .13687313  6.1034977E-2  .7874807\n4:  .4986506  4.4510484E-2  .96231  .35997057                <-- Same sequence as line 2 due to same seed\n```\n\n<!-- markdownlint-disable MD024 -->\n### Implementation Notes\n<!-- markdownlint-enable MD024 -->\n\nWhile the BASIC `RND(x)` function always returns a number between 0 (inclusive) and 1 (exclusive) for positive non-zero\nvalues of `x`, game porters would find it convenient for the library to include functions returning a random float or\ninteger in a range from an inclusive minimum to an exclusive maximum.\n\nAs one of the games, \"Football\", makes use of `RND(0)` with different scaling applied than the previous use of `RND(1)`,\na common library implementation should always generate a value between 0 and 1, and scale that for a function with a\nrange, so that a call to the equivalent of the `RND(0)` function can return the previous value between 0 and 1.\n"
  },
  {
    "path": "00_Common/dotnet/Directory.Build.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <Nullable>enable</Nullable>\n    <LangVersion>10.0</LangVersion>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/Games.Common.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/ConsoleIO.cs",
    "content": "using System;\n\nnamespace Games.Common.IO;\n\n/// <summary>\n/// An implementation of <see cref=\"IReadWrite\" /> with input begin read for STDIN and output being written to\n/// STDOUT.\n/// </summary>\npublic sealed class ConsoleIO : TextIO\n{\n    public ConsoleIO()\n        : base(Console.In, Console.Out)\n    {\n    }\n\n    public override char ReadCharacter() => Console.ReadKey(intercept: true).KeyChar;\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/IReadWrite.cs",
    "content": "using Games.Common.Numbers;\n\nnamespace Games.Common.IO;\n\n/// <summary>\n/// Provides for input and output of strings and numbers.\n/// </summary>\npublic interface IReadWrite\n{\n    /// <summary>\n    /// Reads a character from input.\n    /// </summary>\n    /// <returns>The character read.</returns>\n    char ReadCharacter();\n\n    /// <summary>\n    /// Reads a <see cref=\"float\" /> value from input.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the value.</param>\n    /// <returns>A <see cref=\"float\" />, being the value entered.</returns>\n    float ReadNumber(string prompt);\n\n    /// <summary>\n    /// Reads 2 <see cref=\"float\" /> values from input.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the values.</param>\n    /// <returns>A <see cref=\"ValueTuple{float, float}\" />, being the values entered.</returns>\n    (float, float) Read2Numbers(string prompt);\n\n    /// <summary>\n    /// Reads 3 <see cref=\"float\" /> values from input.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the values.</param>\n    /// <returns>A <see cref=\"ValueTuple{float, float, float}\" />, being the values entered.</returns>\n    (float, float, float) Read3Numbers(string prompt);\n\n    /// <summary>\n    /// Reads 4 <see cref=\"float\" /> values from input.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the values.</param>\n    /// <returns>A <see cref=\"ValueTuple{float, float, float, float}\" />, being the values entered.</returns>\n    (float, float, float, float) Read4Numbers(string prompt);\n\n    /// <summary>\n    /// Read numbers from input to fill an array.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the values.</param>\n    /// <param name=\"values\">A <see cref=\"float[]\" /> to be filled with values from input.</param>\n    void ReadNumbers(string prompt, float[] values);\n\n    /// <summary>\n    /// Reads a <see cref=\"string\" /> value from input.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the value.</param>\n    /// <returns>A <see cref=\"string\" />, being the value entered.</returns>\n    string ReadString(string prompt);\n\n    /// <summary>\n    /// Reads 2 <see cref=\"string\" /> values from input.\n    /// </summary>\n    /// <param name=\"prompt\">The text to display to prompt for the values.</param>\n    /// <returns>A <see cref=\"ValueTuple{string, string}\" />, being the values entered.</returns>\n    (string, string) Read2Strings(string prompt);\n\n    /// <summary>\n    /// Writes a <see cref=\"string\" /> to output.\n    /// </summary>\n    /// <param name=\"message\">The <see cref=\"string\" /> to be written.</param>\n    void Write(string message);\n\n    /// <summary>\n    /// Writes a <see cref=\"string\" /> to output, followed by a new-line.\n    /// </summary>\n    /// <param name=\"message\">The <see cref=\"string\" /> to be written.</param>\n    void WriteLine(string message = \"\");\n\n    /// <summary>\n    /// Writes a <see cref=\"Number\" /> to output.\n    /// </summary>\n    /// <param name=\"value\">The <see cref=\"Number\" /> to be written.</param>\n    void Write(Number value);\n\n    /// <summary>\n    /// Writes a <see cref=\"Number\" /> to output.\n    /// </summary>\n    /// <param name=\"value\">The <see cref=\"Number\" /> to be written.</param>\n    void WriteLine(Number value);\n\n    /// <summary>\n    /// Writes an <see cref=\"object\" /> to output.\n    /// </summary>\n    /// <param name=\"value\">The <see cref=\"object\" /> to be written.</param>\n    void Write(object value);\n\n    /// <summary>\n    /// Writes an <see cref=\"object\" /> to output.\n    /// </summary>\n    /// <param name=\"value\">The <see cref=\"object\" /> to be written.</param>\n    void WriteLine(object value);\n\n    /// <summary>\n    /// Writes a formatted string to output.\n    /// </summary>\n    /// <param name=\"format\">The format <see cref=\"string\" /> to be written.</param>\n    /// <param name=\"value\">The values to be inserted into the format.</param>\n    void Write(string format, params object[] values);\n\n    /// <summary>\n    /// Writes a formatted string to output followed by a new-line.\n    /// </summary>\n    /// <param name=\"format\">The format <see cref=\"string\" /> to be written.</param>\n    /// <param name=\"value\">The values to be inserted into the format.</param>\n    void WriteLine(string format, params object[] values);\n\n    /// <summary>\n    /// Writes the contents of a <see cref=\"Stream\" /> to output.\n    /// </summary>\n    /// <param name=\"stream\">The <see cref=\"Stream\" /> to be written.</param>\n    void Write(Stream stream, bool keepOpen = false);\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/InsufficientInputException.cs",
    "content": "namespace Games.Common.IO;\n\npublic class InsufficientInputException : Exception\n{\n    public InsufficientInputException()\n        : base(\"Insufficient input was supplied\")\n    {\n    }\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/Strings.cs",
    "content": "namespace Games.Common.IO;\n\ninternal static class Strings\n{\n    internal const string NumberExpected = \"!Number expected - retry input line\";\n    internal const string ExtraInput = \"!Extra input ignored\";\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/TextIO.cs",
    "content": "using Games.Common.Numbers;\n\nnamespace Games.Common.IO;\n\n/// <inheritdoc />\n/// <summary>\n/// Implements <see cref=\"IReadWrite\" /> with input read from a <see cref=\"TextReader\" /> and output written to a\n/// <see cref=\"TextWriter\" />.\n/// </summary>\n/// <remarks>\n/// This implementation reproduces the Vintage BASIC input experience, prompting multiple times when partial input\n/// supplied, rejecting non-numeric input as needed, warning about extra input being ignored, etc.\n/// </remarks>\npublic class TextIO : IReadWrite\n{\n    private readonly TextReader _input;\n    private readonly TextWriter _output;\n    private readonly TokenReader _stringTokenReader;\n    private readonly TokenReader _numberTokenReader;\n\n    public TextIO(TextReader input, TextWriter output)\n    {\n        _input = input ?? throw new ArgumentNullException(nameof(input));\n        _output = output ?? throw new ArgumentNullException(nameof(output));\n        _stringTokenReader = TokenReader.ForStrings(this);\n        _numberTokenReader = TokenReader.ForNumbers(this);\n    }\n\n    public virtual char ReadCharacter()\n    {\n        while(true)\n        {\n            var ch = _input.Read();\n            if (ch != -1) { return (char)ch; }\n        }\n    }\n\n    public float ReadNumber(string prompt) => ReadNumbers(prompt, 1)[0];\n\n    public (float, float) Read2Numbers(string prompt)\n    {\n        var numbers = ReadNumbers(prompt, 2);\n        return (numbers[0], numbers[1]);\n    }\n\n    public (float, float, float) Read3Numbers(string prompt)\n    {\n        var numbers = ReadNumbers(prompt, 3);\n        return (numbers[0], numbers[1], numbers[2]);\n    }\n\n    public (float, float, float, float) Read4Numbers(string prompt)\n    {\n        var numbers = ReadNumbers(prompt, 4);\n        return (numbers[0], numbers[1], numbers[2], numbers[3]);\n    }\n\n    public void ReadNumbers(string prompt, float[] values)\n    {\n        if (values.Length == 0)\n        {\n            throw new ArgumentException($\"'{nameof(values)}' must have a non-zero length.\", nameof(values));\n        }\n\n        var numbers = _numberTokenReader.ReadTokens(prompt, (uint)values.Length).Select(t => t.Number).ToArray();\n        numbers.CopyTo(values.AsSpan());\n    }\n\n    private IReadOnlyList<float> ReadNumbers(string prompt, uint quantity) =>\n        (quantity > 0)\n            ? _numberTokenReader.ReadTokens(prompt, quantity).Select(t => t.Number).ToList()\n            : throw new ArgumentOutOfRangeException(\n                nameof(quantity),\n                $\"'{nameof(quantity)}' must be greater than zero.\");\n\n    public string ReadString(string prompt)\n    {\n        return ReadStrings(prompt, 1)[0];\n    }\n\n    public (string, string) Read2Strings(string prompt)\n    {\n        var values = ReadStrings(prompt, 2);\n        return (values[0], values[1]);\n    }\n\n    private IReadOnlyList<string> ReadStrings(string prompt, uint quantityRequired) =>\n        _stringTokenReader.ReadTokens(prompt, quantityRequired).Select(t => t.String).ToList();\n\n    internal string ReadLine(string prompt)\n    {\n        Write(prompt + \"? \");\n        return _input.ReadLine() ?? throw new InsufficientInputException();\n    }\n\n    public void Write(string value) => _output.Write(value);\n\n    public void WriteLine(string value = \"\") => _output.WriteLine(value);\n\n    public void Write(Number value) => _output.Write(value.ToString());\n\n    public void WriteLine(Number value) => _output.WriteLine(value.ToString());\n\n    public void Write(object value) => _output.Write(value.ToString());\n\n    public void WriteLine(object value) => _output.WriteLine(value.ToString());\n\n    public void Write(string format, params object[] values) => _output.Write(format, values);\n\n    public void WriteLine(string format, params object[] values) => _output.WriteLine(format, values);\n\n    public void Write(Stream stream, bool keepOpen = false)\n    {\n        using var reader = new StreamReader(stream);\n        while (!reader.EndOfStream)\n        {\n            _output.WriteLine(reader.ReadLine());\n        }\n\n        if (!keepOpen) { stream?.Dispose(); }\n    }\n\n    private string GetString(float value) => value < 0 ? $\"{value} \" : $\" {value} \";\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/Token.cs",
    "content": "using System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Games.Common.IO;\n\ninternal class Token\n{\n    private static readonly Regex _numberPattern = new(@\"^[+\\-]?\\d*(\\.\\d*)?([eE][+\\-]?\\d*)?\");\n\n    internal Token(string value)\n    {\n        String = value;\n\n        var match = _numberPattern.Match(String);\n\n        IsNumber = float.TryParse(match.Value, out var number);\n        Number = (IsNumber, number) switch\n        {\n            (false, _) => float.NaN,\n            (true, float.PositiveInfinity) => float.MaxValue,\n            (true, float.NegativeInfinity) => float.MinValue,\n            (true, _) => number\n        };\n    }\n\n    public string String { get; }\n    public bool IsNumber { get; }\n    public float Number { get; }\n\n    public override string ToString() => String;\n\n    internal class Builder\n    {\n        private readonly StringBuilder _builder = new();\n        private bool _isQuoted;\n        private int _trailingWhiteSpaceCount;\n\n        public Builder Append(char character)\n        {\n            _builder.Append(character);\n\n            _trailingWhiteSpaceCount = char.IsWhiteSpace(character) ? _trailingWhiteSpaceCount + 1 : 0;\n\n            return this;\n        }\n\n        public Builder SetIsQuoted()\n        {\n            _isQuoted = true;\n            return this;\n        }\n\n        public Token Build()\n        {\n            if (!_isQuoted) { _builder.Length -= _trailingWhiteSpaceCount; }\n            return new Token(_builder.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/TokenReader.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing static Games.Common.IO.Strings;\n\nnamespace Games.Common.IO;\n\n/// <summary>\n/// Reads from input and assembles a given number of values, or tokens, possibly over a number of input lines.\n/// </summary>\ninternal class TokenReader\n{\n    private readonly TextIO _io;\n    private readonly Predicate<Token> _isTokenValid;\n\n    private TokenReader(TextIO io, Predicate<Token> isTokenValid)\n    {\n        _io = io;\n        _isTokenValid = isTokenValid ?? (t => true);\n    }\n\n    /// <summary>\n    /// Creates a <see cref=\"TokenReader\" /> which reads string tokens.\n    /// </summary>\n    /// <param name=\"io\">A <see cref=\"TextIO\" /> instance.</param>\n    /// <returns>The new <see cref=\"TokenReader\" /> instance.</returns>\n    public static TokenReader ForStrings(TextIO io) => new(io, t => true);\n\n    /// <summary>\n    /// Creates a <see cref=\"TokenReader\" /> which reads tokens and validates that they can be parsed as numbers.\n    /// </summary>\n    /// <param name=\"io\">A <see cref=\"TextIO\" /> instance.</param>\n    /// <returns>The new <see cref=\"TokenReader\" /> instance.</returns>\n    public static TokenReader ForNumbers(TextIO io) => new(io, t => t.IsNumber);\n\n    /// <summary>\n    /// Reads valid tokens from one or more input lines and builds a list with the required quantity.\n    /// </summary>\n    /// <param name=\"prompt\">The string used to prompt the user for input.</param>\n    /// <param name=\"quantityNeeded\">The number of tokens required.</param>\n    /// <returns>The sequence of tokens read.</returns>\n    public IEnumerable<Token> ReadTokens(string prompt, uint quantityNeeded)\n    {\n        if (quantityNeeded == 0)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(quantityNeeded),\n                $\"'{nameof(quantityNeeded)}' must be greater than zero.\");\n        }\n\n        var tokens = new List<Token>();\n\n        while (tokens.Count < quantityNeeded)\n        {\n            tokens.AddRange(ReadValidTokens(prompt, quantityNeeded - (uint)tokens.Count));\n            prompt = \"?\";\n        }\n\n        return tokens;\n    }\n\n    /// <summary>\n    /// Reads a line of tokens, up to <paramref name=\"maxCount\" />, and rejects the line if any are invalid.\n    /// </summary>\n    /// <param name=\"prompt\">The string used to prompt the user for input.</param>\n    /// <param name=\"maxCount\">The maximum number of tokens to read.</param>\n    /// <returns>The sequence of tokens read.</returns>\n    private IEnumerable<Token> ReadValidTokens(string prompt, uint maxCount)\n    {\n        while (true)\n        {\n            var tokensValid = true;\n            var tokens = new List<Token>();\n            foreach (var token in ReadLineOfTokens(prompt, maxCount))\n            {\n                if (!_isTokenValid(token))\n                {\n                    _io.WriteLine(NumberExpected);\n                    tokensValid = false;\n                    prompt = \"\";\n                    break;\n                }\n\n                tokens.Add(token);\n            }\n\n            if (tokensValid) { return tokens; }\n        }\n    }\n\n    /// <summary>\n    /// Lazily reads up to <paramref name=\"maxCount\" /> tokens from an input line.\n    /// </summary>\n    /// <param name=\"prompt\">The string used to prompt the user for input.</param>\n    /// <param name=\"maxCount\">The maximum number of tokens to read.</param>\n    /// <returns></returns>\n    private IEnumerable<Token> ReadLineOfTokens(string prompt, uint maxCount)\n    {\n        var tokenCount = 0;\n\n        foreach (var token in Tokenizer.ParseTokens(_io.ReadLine(prompt)))\n        {\n            if (++tokenCount > maxCount)\n            {\n                _io.WriteLine(ExtraInput);\n                break;\n            }\n\n            yield return token;\n        }\n    }\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/IO/Tokenizer.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Games.Common.IO;\n\n/// <summary>\n/// A simple state machine which parses tokens from a line of input.\n/// </summary>\ninternal class Tokenizer\n{\n    private const char Quote = '\"';\n    private const char Separator = ',';\n\n    private readonly Queue<char> _characters;\n\n    private Tokenizer(string input) => _characters = new Queue<char>(input);\n\n    public static IEnumerable<Token> ParseTokens(string input)\n    {\n        if (input is null) { throw new ArgumentNullException(nameof(input)); }\n\n        return new Tokenizer(input).ParseTokens();\n    }\n\n    private IEnumerable<Token> ParseTokens()\n    {\n        while (true)\n        {\n            var (token, isLastToken) = Consume(_characters);\n            yield return token;\n\n            if (isLastToken) { break; }\n        }\n    }\n\n    public (Token, bool) Consume(Queue<char> characters)\n    {\n        var tokenBuilder = new Token.Builder();\n        var state = ITokenizerState.LookForStartOfToken;\n\n        while (characters.TryDequeue(out var character))\n        {\n            (state, tokenBuilder) = state.Consume(character, tokenBuilder);\n            if (state is AtEndOfTokenState) { return (tokenBuilder.Build(), false); }\n        }\n\n        return (tokenBuilder.Build(), true);\n    }\n\n    private interface ITokenizerState\n    {\n        public static ITokenizerState LookForStartOfToken { get; } = new LookForStartOfTokenState();\n\n        (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder);\n    }\n\n    private struct LookForStartOfTokenState : ITokenizerState\n    {\n        public (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder) =>\n            character switch\n            {\n                Separator => (new AtEndOfTokenState(), tokenBuilder),\n                Quote => (new InQuotedTokenState(), tokenBuilder.SetIsQuoted()),\n                _ when char.IsWhiteSpace(character) => (this, tokenBuilder),\n                _ => (new InTokenState(), tokenBuilder.Append(character))\n            };\n    }\n\n    private struct InTokenState : ITokenizerState\n    {\n        public (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder) =>\n            character == Separator\n                ? (new AtEndOfTokenState(), tokenBuilder)\n                : (this, tokenBuilder.Append(character));\n    }\n\n    private struct InQuotedTokenState : ITokenizerState\n    {\n        public (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder) =>\n            character == Quote\n                ? (new ExpectSeparatorState(), tokenBuilder)\n                : (this, tokenBuilder.Append(character));\n    }\n\n    private struct ExpectSeparatorState : ITokenizerState\n    {\n        public (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder) =>\n            character == Separator\n                ? (new AtEndOfTokenState(), tokenBuilder)\n                : (new IgnoreRestOfLineState(), tokenBuilder);\n    }\n\n    private struct IgnoreRestOfLineState : ITokenizerState\n    {\n        public (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder) =>\n            (this, tokenBuilder);\n    }\n\n    private struct AtEndOfTokenState : ITokenizerState\n    {\n        public (ITokenizerState, Token.Builder) Consume(char character, Token.Builder tokenBuilder) =>\n            throw new InvalidOperationException();\n    }\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/Numbers/Number.cs",
    "content": "namespace Games.Common.Numbers;\n\n/// <summary>\n/// A single-precision floating-point number with string formatting equivalent to the BASIC interpreter.\n/// </summary>\npublic struct Number\n{\n    private readonly float _value;\n\n    public Number (float value)\n    {\n        _value = value;\n    }\n\n    public static implicit operator float(Number value) => value._value;\n\n    public static implicit operator Number(float value) => new Number(value);\n\n    public override string ToString() => _value < 0 ? $\"{_value} \" : $\" {_value} \";\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/Randomness/IRandom.cs",
    "content": "namespace Games.Common.Randomness;\n\n/// <summary>\n/// Provides access to a random number generator\n/// </summary>\npublic interface IRandom\n{\n    /// <summary>\n    /// Gets a random <see cref=\"float\" /> such that 0 &lt;= n &lt; 1.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    float NextFloat();\n\n    /// <summary>\n    /// Gets the <see cref=\"float\" /> returned by the previous call to <see cref=\"NextFloat\" />.\n    /// </summary>\n    /// <returns>The previous random number.</returns>\n    float PreviousFloat();\n\n    /// <summary>\n    /// Reseeds the random number generator.\n    /// </summary>\n    /// <param name=\"seed\">The seed.</param>\n    void Reseed(int seed);\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/Randomness/IRandomExtensions.cs",
    "content": "using System;\n\nnamespace Games.Common.Randomness;\n\n/// <summary>\n/// Provides extension methods to <see cref=\"IRandom\" /> providing random numbers in a given range.\n/// </summary>\n/// <value></value>\npublic static class IRandomExtensions\n{\n    /// <summary>\n    /// Gets a random <see cref=\"float\" /> such that 0 &lt;= n &lt; exclusiveMaximum.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static float NextFloat(this IRandom random, float exclusiveMaximum) =>\n        Scale(random.NextFloat(), exclusiveMaximum);\n\n    /// <summary>\n    /// Gets a random <see cref=\"float\" /> such that inclusiveMinimum &lt;= n &lt; exclusiveMaximum.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static float NextFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum) =>\n        Scale(random.NextFloat(), inclusiveMinimum, exclusiveMaximum);\n\n    /// <summary>\n    /// Gets a random <see cref=\"int\" /> such that 0 &lt;= n &lt; exclusiveMaximum.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static int Next(this IRandom random, int exclusiveMaximum) => ToInt(random.NextFloat(exclusiveMaximum));\n\n    /// <summary>\n    /// Gets a random <see cref=\"int\" /> such that inclusiveMinimum &lt;= n &lt; exclusiveMaximum.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static int Next(this IRandom random, int inclusiveMinimum, int exclusiveMaximum) =>\n        ToInt(random.NextFloat(inclusiveMinimum, exclusiveMaximum));\n\n    /// <summary>\n    /// Gets the previous unscaled <see cref=\"float\" /> (between 0 and 1) scaled to a new range:\n    /// 0 &lt;= x &lt; <paramref name=\"exclusiveMaximum\" />.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static float PreviousFloat(this IRandom random, float exclusiveMaximum) =>\n        Scale(random.PreviousFloat(), exclusiveMaximum);\n\n    /// <summary>\n    /// Gets the previous unscaled <see cref=\"float\" /> (between 0 and 1) scaled to a new range:\n    /// <paramref name=\"inclusiveMinimum\" /> &lt;= n &lt; <paramref name=\"exclusiveMaximum\" />.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static float PreviousFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum) =>\n        Scale(random.PreviousFloat(), inclusiveMinimum, exclusiveMaximum);\n\n    /// <summary>\n    /// Gets the previous unscaled <see cref=\"float\" /> (between 0 and 1) scaled to an <see cref=\"int\" /> in a new\n    /// range: 0 &lt;= n &lt; <paramref name=\"exclusiveMaximum\" />.\n    /// </summary>\n    /// <returns>The random number.</returns>\n    public static int Previous(this IRandom random, int exclusiveMaximum) =>\n        ToInt(random.PreviousFloat(exclusiveMaximum));\n\n    /// <summary>\n    /// Gets the previous unscaled <see cref=\"float\" /> (between 0 and 1) scaled to an <see cref=\"int\" /> in a new\n    /// range: <paramref name=\"inclusiveMinimum\" /> &lt;= n &lt; <paramref name=\"exclusiveMaximum\" />.\n    /// <returns>The random number.</returns>\n    public static int Previous(this IRandom random, int inclusiveMinimum, int exclusiveMaximum) =>\n        ToInt(random.PreviousFloat(inclusiveMinimum, exclusiveMaximum));\n\n    private static float Scale(float zeroToOne, float exclusiveMaximum)\n    {\n        if (exclusiveMaximum <= 0)\n        {\n            throw new ArgumentOutOfRangeException(nameof(exclusiveMaximum), \"Must be greater than 0.\");\n        }\n\n        return Scale(zeroToOne, 0, exclusiveMaximum);\n    }\n\n    private static float Scale(float zeroToOne, float inclusiveMinimum, float exclusiveMaximum)\n    {\n        if (exclusiveMaximum <= inclusiveMinimum)\n        {\n            throw new ArgumentOutOfRangeException(nameof(exclusiveMaximum), \"Must be greater than inclusiveMinimum.\");\n        }\n\n        var range = exclusiveMaximum - inclusiveMinimum;\n        return zeroToOne * range + inclusiveMinimum;\n    }\n\n    private static int ToInt(float value) => (int)Math.Floor(value);\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/Randomness/RandomNumberGenerator.cs",
    "content": "using System;\n\nnamespace Games.Common.Randomness;\n\n/// <inheritdoc />\npublic class RandomNumberGenerator : IRandom\n{\n    private Random _random;\n    private float _previous;\n\n    public RandomNumberGenerator()\n    {\n        // The BASIC RNG is seeded based on time with a 1 second resolution\n        _random = new Random((int)(DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond));\n    }\n\n    public float NextFloat() => _previous = (float)_random.NextDouble();\n\n    public float PreviousFloat() => _previous;\n\n    public void Reseed(int seed) => _random = new Random(seed);\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common/_InternalsVisibleTo.cs",
    "content": "using System.Runtime.CompilerServices;\n\n[assembly:InternalsVisibleTo(\"Games.Common.Test\")]\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.Test/Games.Common.Test.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FluentAssertions\" Version=\"6.4.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.11.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.3\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"3.1.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.Test/IO/TextIOTests/NumberFormatTests.cs",
    "content": "using System;\nusing System.IO;\nusing FluentAssertions;\nusing Xunit;\n\nnamespace Games.Common.IO.TextIOTests;\n\npublic class NumberFormatTests\n{\n    [Theory]\n    [MemberData(nameof(WriteFloatTestCases))]\n    public void Write_Float_FormatsNumberSameAsBasic(float value, string basicString)\n    {\n        var outputWriter = new StringWriter();\n        var io = new TextIO(new StringReader(\"\"), outputWriter);\n\n        io.Write(value);\n\n        outputWriter.ToString().Should().BeEquivalentTo(basicString);\n    }\n\n    [Theory]\n    [MemberData(nameof(WriteFloatTestCases))]\n    public void WriteLine_Float_FormatsNumberSameAsBasic(float value, string basicString)\n    {\n        var outputWriter = new StringWriter();\n        var io = new TextIO(new StringReader(\"\"), outputWriter);\n\n        io.WriteLine(value);\n\n        outputWriter.ToString().Should().BeEquivalentTo(basicString + Environment.NewLine);\n    }\n\n    public static TheoryData<float, string> WriteFloatTestCases()\n        => new()\n        {\n            { 1000F, \" 1000 \" },\n            { 3.1415927F, \" 3.1415927 \" },\n            { 1F, \" 1 \" },\n            { 0F, \" 0 \" },\n            { -1F, \"-1 \" },\n            { -3.1415927F, \"-3.1415927 \" },\n            { -1000F, \"-1000 \" },\n        };\n\n    [Theory]\n    [MemberData(nameof(WriteIntTestCases))]\n    public void Write_Int_FormatsNumberSameAsBasic(int value, string basicString)\n    {\n        var outputWriter = new StringWriter();\n        var io = new TextIO(new StringReader(\"\"), outputWriter);\n\n        io.Write(value);\n\n        outputWriter.ToString().Should().BeEquivalentTo(basicString);\n    }\n\n    [Theory]\n    [MemberData(nameof(WriteIntTestCases))]\n    public void WriteLine_Int_FormatsNumberSameAsBasic(int value, string basicString)\n    {\n        var outputWriter = new StringWriter();\n        var io = new TextIO(new StringReader(\"\"), outputWriter);\n\n        io.WriteLine(value);\n\n        outputWriter.ToString().Should().BeEquivalentTo(basicString + Environment.NewLine);\n    }\n\n    public static TheoryData<int, string> WriteIntTestCases()\n        => new()\n        {\n            { 1000, \" 1000 \" },\n            { 1, \" 1 \" },\n            { 0, \" 0 \" },\n            { -1, \"-1 \" },\n            { -1000, \"-1000 \" },\n        };\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.Test/IO/TextIOTests/ReadMethodTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing FluentAssertions;\nusing FluentAssertions.Execution;\nusing Xunit;\n\nusing TwoStrings = System.ValueTuple<string, string>;\nusing TwoNumbers = System.ValueTuple<float, float>;\nusing ThreeNumbers = System.ValueTuple<float, float, float>;\nusing FourNumbers = System.ValueTuple<float, float, float, float>;\n\nusing static System.Environment;\nusing static Games.Common.IO.Strings;\n\nnamespace Games.Common.IO.TextIOTests;\n\npublic class ReadMethodTests\n{\n    [Theory]\n    [MemberData(nameof(ReadStringTestCases))]\n    [MemberData(nameof(Read2StringsTestCases))]\n    [MemberData(nameof(ReadNumberTestCases))]\n    [MemberData(nameof(Read2NumbersTestCases))]\n    [MemberData(nameof(Read3NumbersTestCases))]\n    [MemberData(nameof(Read4NumbersTestCases))]\n    [MemberData(nameof(ReadNumbersTestCases))]\n    public void ReadingValuesHasExpectedPromptsAndResults<T>(\n        Func<IReadWrite, T> read,\n        string input,\n        string expectedOutput,\n        T expectedResult)\n    {\n        var inputReader = new StringReader(input + Environment.NewLine);\n        var outputWriter = new StringWriter();\n        var io = new TextIO(inputReader, outputWriter);\n\n        var result = read.Invoke(io);\n        var output = outputWriter.ToString();\n\n        using var _ = new AssertionScope();\n        output.Should().Be(expectedOutput);\n        result.Should().BeEquivalentTo(expectedResult);\n    }\n\n    [Fact]\n    public void ReadNumbers_ArrayEmpty_ThrowsArgumentException()\n    {\n        var io = new TextIO(new StringReader(\"\"), new StringWriter());\n\n        Action readNumbers = () => io.ReadNumbers(\"foo\", Array.Empty<float>());\n\n        readNumbers.Should().Throw<ArgumentException>()\n            .WithMessage(\"'values' must have a non-zero length.*\")\n            .WithParameterName(\"values\");\n    }\n\n    public static TheoryData<Func<IReadWrite, string>, string, string, string> ReadStringTestCases()\n    {\n        static Func<IReadWrite, string> ReadString(string prompt) => io => io.ReadString(prompt);\n\n        return new()\n        {\n            { ReadString(\"Name\"), \"\", \"Name? \", \"\" },\n            { ReadString(\"prompt\"), \" foo  ,bar\", $\"prompt? {ExtraInput}{NewLine}\", \"foo\" }\n        };\n    }\n\n    public static TheoryData<Func<IReadWrite, TwoStrings>, string, string, TwoStrings> Read2StringsTestCases()\n    {\n        static Func<IReadWrite, TwoStrings> Read2Strings(string prompt) => io => io.Read2Strings(prompt);\n\n        return new()\n        {\n            { Read2Strings(\"2 strings\"), \",\", \"2 strings? \", (\"\", \"\") },\n            {\n                Read2Strings(\"Input please\"),\n                $\"{NewLine}x,y\",\n                $\"Input please? ?? {ExtraInput}{NewLine}\",\n                (\"\", \"x\")\n            }\n        };\n    }\n\n    public static TheoryData<Func<IReadWrite, float>, string, string, float> ReadNumberTestCases()\n    {\n        static Func<IReadWrite, float> ReadNumber(string prompt) => io => io.ReadNumber(prompt);\n\n        return new()\n        {\n            { ReadNumber(\"Age\"), $\"{NewLine}42,\", $\"Age? {NumberExpected}{NewLine}? {ExtraInput}{NewLine}\", 42 },\n            { ReadNumber(\"Guess\"), \"3,4,5\", $\"Guess? {ExtraInput}{NewLine}\", 3 }\n        };\n    }\n\n    public static TheoryData<Func<IReadWrite, TwoNumbers>, string, string, TwoNumbers> Read2NumbersTestCases()\n    {\n        static Func<IReadWrite, TwoNumbers> Read2Numbers(string prompt) => io => io.Read2Numbers(prompt);\n\n        return new()\n        {\n            { Read2Numbers(\"Point\"), \"3,4,5\", $\"Point? {ExtraInput}{NewLine}\", (3, 4) },\n            {\n                Read2Numbers(\"Foo\"),\n                $\"x,4,5{NewLine}4,5,x\",\n                $\"Foo? {NumberExpected}{NewLine}? {ExtraInput}{NewLine}\",\n                (4, 5)\n            }\n        };\n    }\n\n    public static TheoryData<Func<IReadWrite, ThreeNumbers>, string, string, ThreeNumbers> Read3NumbersTestCases()\n    {\n        static Func<IReadWrite, ThreeNumbers> Read3Numbers(string prompt) => io => io.Read3Numbers(prompt);\n\n        return new()\n        {\n            { Read3Numbers(\"Point\"), \"3.2, 4.3, 5.4, 6.5\", $\"Point? {ExtraInput}{NewLine}\", (3.2F, 4.3F, 5.4F) },\n            {\n                Read3Numbers(\"Bar\"),\n                $\"x,4,5{NewLine}4,5,x{NewLine}6,7,8,y\",\n                $\"Bar? {NumberExpected}{NewLine}? {NumberExpected}{NewLine}? {ExtraInput}{NewLine}\",\n                (6, 7, 8)\n            }\n        };\n    }\n\n    public static TheoryData<Func<IReadWrite, FourNumbers>, string, string, FourNumbers> Read4NumbersTestCases()\n    {\n        static Func<IReadWrite, FourNumbers> Read4Numbers(string prompt) => io => io.Read4Numbers(prompt);\n\n        return new()\n        {\n            { Read4Numbers(\"Point\"), \"3,4,5,6,7\", $\"Point? {ExtraInput}{NewLine}\", (3, 4, 5, 6) },\n            {\n                Read4Numbers(\"Baz\"),\n                $\"x,4,5,6{NewLine} 4, 5 , 6,7  ,x\",\n                $\"Baz? {NumberExpected}{NewLine}? {ExtraInput}{NewLine}\",\n                (4, 5, 6, 7)\n            }\n        };\n    }\n\n    public static TheoryData<Func<IReadWrite, IReadOnlyList<float>>, string, string, float[]> ReadNumbersTestCases()\n    {\n        static Func<IReadWrite, IReadOnlyList<float>> ReadNumbers(string prompt) =>\n            io =>\n            {\n                var numbers = new float[6];\n                io.ReadNumbers(prompt, numbers);\n                return numbers;\n            };\n\n        return new()\n        {\n            { ReadNumbers(\"Primes\"), \"2, 3, 5, 7, 11, 13\", $\"Primes? \", new float[] { 2, 3, 5, 7, 11, 13 } },\n            {\n                ReadNumbers(\"Qux\"),\n                $\"42{NewLine}3.141, 2.718{NewLine}3.0e8, 6.02e23{NewLine}9.11E-28\",\n                $\"Qux? ?? ?? ?? \",\n                new[] { 42, 3.141F, 2.718F, 3.0e8F, 6.02e23F, 9.11E-28F }\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.Test/IO/TokenReaderTests.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing FluentAssertions;\nusing FluentAssertions.Execution;\nusing Xunit;\n\nusing static System.Environment;\nusing static Games.Common.IO.Strings;\n\nnamespace Games.Common.IO;\n\npublic class TokenReaderTests\n{\n    private readonly StringWriter _outputWriter;\n\n    public TokenReaderTests()\n    {\n        _outputWriter = new StringWriter();\n    }\n\n    [Fact]\n    public void ReadTokens_QuantityNeededZero_ThrowsArgumentException()\n    {\n        var sut = TokenReader.ForStrings(new TextIO(new StringReader(\"\"), _outputWriter));\n\n        Action readTokens = () => sut.ReadTokens(\"\", 0);\n\n        readTokens.Should().Throw<ArgumentOutOfRangeException>()\n            .WithMessage(\"'quantityNeeded' must be greater than zero.*\")\n            .WithParameterName(\"quantityNeeded\");\n    }\n\n\n    [Theory]\n    [MemberData(nameof(ReadTokensTestCases))]\n    public void ReadTokens_ReadingValuesHasExpectedPromptsAndResults(\n        string prompt,\n        uint tokenCount,\n        string input,\n        string expectedOutput,\n        string[] expectedResult)\n    {\n        var sut = TokenReader.ForStrings(new TextIO(new StringReader(input + NewLine), _outputWriter));\n\n        var result = sut.ReadTokens(prompt, tokenCount);\n        var output = _outputWriter.ToString();\n\n        using var _ = new AssertionScope();\n        output.Should().Be(expectedOutput);\n        result.Select(t => t.String).Should().BeEquivalentTo(expectedResult);\n    }\n\n    [Theory]\n    [MemberData(nameof(ReadNumericTokensTestCases))]\n    public void ReadTokens_Numeric_ReadingValuesHasExpectedPromptsAndResults(\n        string prompt,\n        uint tokenCount,\n        string input,\n        string expectedOutput,\n        float[] expectedResult)\n    {\n        var sut = TokenReader.ForNumbers(new TextIO(new StringReader(input + NewLine), _outputWriter));\n\n        var result = sut.ReadTokens(prompt, tokenCount);\n        var output = _outputWriter.ToString();\n\n        using var _ = new AssertionScope();\n        output.Should().Be(expectedOutput);\n        result.Select(t => t.Number).Should().BeEquivalentTo(expectedResult);\n    }\n\n    public static TheoryData<string, uint, string, string, string[]> ReadTokensTestCases()\n    {\n        return new()\n        {\n            { \"Name\", 1, \"Bill\", \"Name? \", new[] { \"Bill\" } },\n            { \"Names\", 2, \" Bill , Bloggs \", \"Names? \", new[] { \"Bill\", \"Bloggs\" } },\n            { \"Names\", 2, $\" Bill{NewLine}Bloggs \", \"Names? ?? \", new[] { \"Bill\", \"Bloggs\" } },\n            {\n                \"Foo\",\n                6,\n                $\"1,2{NewLine}\\\" a,b \\\"{NewLine},\\\"\\\"c,d{NewLine}d\\\"x,e,f\",\n                $\"Foo? ?? ?? ?? {ExtraInput}{NewLine}\",\n                new[] { \"1\", \"2\", \" a,b \", \"\", \"\", \"d\\\"x\" }\n            }\n        };\n    }\n\n    public static TheoryData<string, uint, string, string, float[]> ReadNumericTokensTestCases()\n    {\n        return new()\n        {\n            { \"Age\", 1, \"23\", \"Age? \", new[] { 23F } },\n            { \"Constants\", 2, \" 3.141 , 2.71 \", \"Constants? \", new[] { 3.141F, 2.71F } },\n            { \"Answer\", 1, $\"Forty-two{NewLine}42 \", $\"Answer? {NumberExpected}{NewLine}? \", new[] { 42F } },\n            {\n                \"Foo\",\n                6,\n                $\"1,2{NewLine}\\\" a,b \\\"{NewLine}3, 4  {NewLine}5.6,7,a, b\",\n                $\"Foo? ?? {NumberExpected}{NewLine}? ?? {ExtraInput}{NewLine}\",\n                new[] { 1, 2, 3, 4, 5.6F, 7 }\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.Test/IO/TokenTests.cs",
    "content": "using FluentAssertions;\nusing Xunit;\n\nnamespace Games.Common.IO;\n\npublic class TokenTests\n{\n    [Theory]\n    [MemberData(nameof(TokenTestCases))]\n    public void Ctor_PopulatesProperties(string value, bool isNumber, float number)\n    {\n        var expected = new { String = value, IsNumber = isNumber, Number = number };\n\n        var token = new Token(value);\n\n        token.Should().BeEquivalentTo(expected);\n    }\n\n    public static TheoryData<string, bool, float> TokenTestCases() => new()\n    {\n        { \"\", false, float.NaN },\n        { \"abcde\", false, float.NaN },\n        { \"123  \", true, 123 },\n        { \"+42  \", true, 42 },\n        { \"-42  \", true, -42 },\n        { \"+3.14159  \", true, 3.14159F },\n        { \"-3.14159  \", true, -3.14159F },\n        { \"   123\", false, float.NaN },\n        { \"1.2e4\", true, 12000 },\n        { \"2.3e-5\", true, 0.000023F },\n        { \"1e100\", true, float.MaxValue },\n        { \"-1E100\", true, float.MinValue },\n        { \"1E-100\", true, 0 },\n        { \"-1e-100\", true, 0 },\n        { \"100abc\", true, 100 },\n        { \"1,2,3\", true, 1 },\n        { \"42,a,b\", true, 42 },\n        { \"1.2.3\", true, 1.2F },\n        { \"12e.5\", false, float.NaN },\n        { \"12e0.5\", true, 12 }\n    };\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.Test/IO/TokenizerTests.cs",
    "content": "using System.Linq;\nusing FluentAssertions;\nusing Xunit;\n\nnamespace Games.Common.IO;\n\npublic class TokenizerTests\n{\n    [Theory]\n    [MemberData(nameof(TokenizerTestCases))]\n    public void ParseTokens_SplitsStringIntoExpectedTokens(string input, string[] expected)\n    {\n        var result = Tokenizer.ParseTokens(input);\n\n        result.Select(t => t.ToString()).Should().BeEquivalentTo(expected);\n    }\n\n    public static TheoryData<string, string[]> TokenizerTestCases() => new()\n    {\n        { \"\", new[] { \"\" } },\n        { \"aBc\", new[] { \"aBc\" } },\n        { \"  Foo   \", new[] { \"Foo\" } },\n        { \"  \\\" Foo  \\\"  \", new[] { \" Foo  \" } },\n        { \"  \\\" Foo    \", new[] { \" Foo    \" } },\n        { \"\\\"\\\"abc\", new[] { \"\" } },\n        { \"a\\\"\\\"bc\", new[] { \"a\\\"\\\"bc\" } },\n        { \"\\\"\\\"\", new[] { \"\" } },\n        { \",\", new[] { \"\", \"\" } },\n        { \" foo  ,bar\", new[] { \"foo\", \"bar\" } },\n        { \"\\\"a\\\"bc,de\", new[] { \"a\" } },\n        { \"a\\\"b,\\\" c,d\\\", f ,,g\", new[] { \"a\\\"b\", \" c,d\", \"f\", \"\", \"g\" } }\n    };\n}\n"
  },
  {
    "path": "00_Common/dotnet/Games.Common.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Games.Common\", \"Games.Common\\Games.Common.csproj\", \"{005F2A3E-4E45-418B-8D19-E735B3BD4535}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Games.Common.Test\", \"Games.Common.Test\\Games.Common.Test.csproj\", \"{8369DA66-0414-4A14-B5BE-73B0159498A2}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{005F2A3E-4E45-418B-8D19-E735B3BD4535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{005F2A3E-4E45-418B-8D19-E735B3BD4535}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{005F2A3E-4E45-418B-8D19-E735B3BD4535}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{005F2A3E-4E45-418B-8D19-E735B3BD4535}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8369DA66-0414-4A14-B5BE-73B0159498A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8369DA66-0414-4A14-B5BE-73B0159498A2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8369DA66-0414-4A14-B5BE-73B0159498A2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8369DA66-0414-4A14-B5BE-73B0159498A2}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "00_Common/dotnet/README.md",
    "content": "# Games.Common\n\nThis is the common library for C# and VB.Net ports of the games.\n\n## Overview\n\n### Game Input/Output\n\n* `TextIO` is the main class which manages text input and output for a game. It take a `TextReader` and a `TextWriter` in\nits constructor so it can be wired up in unit tests to test gameplay scenarios.\n* `ConsoleIO` derives from `TextIO` and binds it to `System.Console.In` and `System.Console.Out`.\n* `IReadWrite` is an interface implemented by `TextIO` which may be useful in some test scenarios.\n\n```csharp\npublic interface IReadWrite\n{\n    // Reads a float value from input.\n    float ReadNumber(string prompt);\n\n    // Reads 2 float values from input.\n    (float, float) Read2Numbers(string prompt);\n\n    // Reads 3 float values from input.\n    (float, float, float) Read3Numbers(string prompt);\n\n    // Reads 4 float values from input.\n    (float, float, float, float) Read4Numbers(string prompt);\n\n    // Read numbers from input to fill an array.\n    void ReadNumbers(string prompt, float[] values);\n\n    // Reads a string value from input.\n    string ReadString(string prompt);\n\n    // Reads 2 string values from input.\n    (string, string) Read2Strings(string prompt);\n\n    // Writes a string to output.\n    void Write(string message);\n\n    // Writes a string to output, followed by a new-line.\n    void WriteLine(string message = \"\");\n\n    // Writes a float to output, formatted per the BASIC interpreter, with leading and trailing spaces.\n    void Write(float value);\n\n    // Writes a float to output, formatted per the BASIC interpreter, with leading and trailing spaces,\n    // followed by a new-line.\n    void WriteLine(float value);\n\n    // Writes the contents of a Stream to output.\n    void Write(Stream stream);}\n```\n\n### Random Number Generation\n\n* `IRandom` is an interface that provides basic methods that parallel the 3 uses of BASIC's `RND(float)` function.\n* `RandomNumberGenerator` is an implementation of `IRandom` built around `System.Random`.\n* `IRandomExtensions` provides convenience extension methods for obtaining random numbers as `int` and also within a\n  given range.\n\n```csharp\npublic interface IRandom\n{\n    // Like RND(1), gets a random float such that 0 <= n < 1.\n    float NextFloat();\n\n    // Like RND(0), Gets the float returned by the previous call to NextFloat.\n    float PreviousFloat();\n\n    // Like RND(-x), Reseeds the random number generator.\n    void Reseed(int seed);\n}\n```\n\nExtension methods on `IRandom`:\n\n```csharp\n// Gets a random float such that 0 <= n < exclusiveMaximum.\nfloat NextFloat(this IRandom random, float exclusiveMaximum);\n\n// Gets a random float such that inclusiveMinimum <= n < exclusiveMaximum.\nfloat NextFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum);\n\n// Gets a random int such that 0 <= n < exclusiveMaximum.\nint Next(this IRandom random, int exclusiveMaximum);\n\n// Gets a random int such that inclusiveMinimum <= n < exclusiveMaximum.\nint Next(this IRandom random, int inclusiveMinimum, int exclusiveMaximum);\n\n// Gets the previous unscaled float (between 0 and 1) scaled to a new range:\n// 0 <= x < exclusiveMaximum.\nfloat PreviousFloat(this IRandom random, float exclusiveMaximum);\n\n// Gets the previous unscaled float (between 0 and 1) scaled to a new range:\n// inclusiveMinimum <= n < exclusiveMaximum.\nfloat PreviousFloat(this IRandom random, float inclusiveMinimum, float exclusiveMaximum);\n\n// Gets the previous unscaled float (between 0 and 1) scaled to an int in a new range:\n// 0 <= n < exclusiveMaximum.\nint Previous(this IRandom random, int exclusiveMaximum);\n\n// Gets the previous unscaled float (between 0 and 1) scaled to an int in a new range:\n// inclusiveMinimum <= n < exclusiveMaximum.\nint Previous(this IRandom random, int inclusiveMinimum, int exclusiveMaximum);\n```\n\n## C\\# Usage\n\n### Add Project Reference\n\nAdd the `Games.Common` project as a reference to the game project. For example, here's the reference from the C\\# port\nof `86_Target`:\n\n```xml\n<ItemGroup>\n  <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n</ItemGroup>\n```\n\n### C# Game Input/Output usage\n\nA game can be encapsulated in a class which takes a `TextIO` instance in it's constructor:\n\n```csharp\npublic class Game\n{\n    private readonly TextIO _io;\n\n    public Game(TextIO io) => _io = io;\n\n    public void Play()\n    {\n        var name = _io.ReadString(\"What is your name\");\n        var (cats, dogs) = _io.Read2Number($\"Hello, {name}, how many pets do you have (cats, dogs)\");\n        _io.WriteLine($\"So, {cats + dogs} pets in total, huh?\");\n    }\n}\n```\n\nThen the entry point of the game program would look something like:\n\n```csharp\nvar game = new Game(new ConsoleIO());\ngame.Play();\n```\n\n### C# Random Number Generator usage\n\n```csharp\nvar io = new ConsoleIO();\nvar rng = new RandomNumberGenerator();\nio.WriteLine(rng.NextFloat());           // 0.1234, for example\nio.WriteLine(rng.NextFloat());           // 0.6, for example\nio.WriteLine(rng.PreviousFloat());       // 0.6, repeats previous\nio.WriteLine(rng.PreviousFloat(0, 10));  // 6,   repeats previous value, but scaled to new range\n```\n\n### C# Unit Test usage\n\n`TextIO` can be initialised with a `StringReader` and `StringWriter` to enable testing. For example, given the `Game`\nclass above:\n\n```csharp\nvar reader = new StringReader(\"Joe Bloggs\\r\\n4\\n\\r5\");\nvar writer = new StringWriter();\nvar game = new Game(new TextIO(reader, writer))\n\ngame.Play();\n\nwriter.ToString().Should().BeEquivalentTo(\n    \"What is your name? Hello, Joe Bloggs, how many pets do you have (cats, dogs)? ?? So, 9 pets in total, huh?\");\n```\n\nNote the lack of line breaks in the expected output, because during game play the line breaks come from the text input.\n\nOf course, `IReadWrite` can also be mocked for simple test scenarios.\n\n## VB.Net Usage\n\n*To be provided*\n"
  },
  {
    "path": "00_Common/javascript/WebTerminal/HtmlTerminal.css",
    "content": ":root {\n    --terminal-font: 1rem \"Lucida Console\", \"Courier New\", monospace;\n    --background-color: transparent;\n    --text-color: var(--text);\n    --prompt-char: '$ ';\n    --cursor-char: '_';\n}\n\n/* Basic terminal style.\n * If you wan t to overwrite them use custom properties (variables). \n */\n.terminal {\n    display: block;\n    font: var(--terminal-font);\n    background-color: var(--background-color);\n    color: var(--text-color);\n\n    overflow-y: scroll;\n    width: 100%;\n    max-width: 640px;\n    margin: 0 auto;\n}\n\n/* The terminal consits of multiple \"line\" elements\n * Because sometimes we want to add a simulates \"prompt\" at the end of a line\n * we need to make it an \"inline\" element and handle line-breaks \n * by adding <br> elements */\n.terminal pre.line {\n    display: inline-block;\n    font: var(--terminal-font);\n    margin: 0;\n    padding: 0;\n}\n\n/* The \"terminal\" has one \"prompt\" input-element. */\n@keyframes prompt-blink {\n    100% {\n        opacity: 0;\n    }\n}\n.terminal #prompt {\n    display: inline-block;\n}\n.terminal #prompt:before {\n    display: inline-block;\n    content: var(--prompt-char);\n    font: var(--terminal-font);\n}\n.terminal #prompt:after {\n    display: inline-block;\n    content: var(--cursor-char);\n    background: var(--text);\n    animation: prompt-blink 1s steps(2) infinite;\n    width: 0.75rem;\n    opacity: 1;\n}\n.terminal input#prompt {\n    text-transform: uppercase;\n    background: none;\n    border: none;\n    outline: none;\n    caret-color: var(--text);\n    color: var(--text);\n    font: var(--terminal-font);\n}\n\n\n/* Terminal scrollbar */\n::-webkit-scrollbar {\n    width: 3px;\n    height: 3px;\n}\n::-webkit-scrollbar-track {\n    background: var(--background-color);\n}\n::-webkit-scrollbar-thumb {\n    background: var(--text-color); \n}\n"
  },
  {
    "path": "00_Common/javascript/WebTerminal/HtmlTerminal.js",
    "content": "/**\n * @class HtmlTerminal\n * \n * This class is a very basic implementation of a \"terminal\" in the browser.\n * It provides simple functions like \"write\" and an \"input\" Callback.\n * \n * @license AGPL-2.0\n * @author Alexaner Wunschik <https://github.com/mojoaxel>\n */\nclass HtmlTerminal {\n\n  /**\n   * Input callback.\n   * If the prompt is activated by calling the input function\n   * a callback is defined. If this member is not set this means\n   * the prompt is not active.\n   * \n   * @private\n   * @type {function}\n   */\n  #inputCallback = undefined;\n\n  /**\n   * A html element to show a \"prompt\".\n   * \n   * @private\n   * @type {HTMLElement}\n   */\n  #$prompt;\n  \n  /**\n   * Constructor\n   * Creates a basic terminal simulation on the provided HTMLElement.\n   * \n   * @param {HTMLElement} $output - a dom element\n   */\n  constructor($output) {\n    // Store the output DOM element in a local variable.\n    this.$output = $output;\n\n    // Clear terminal.\n    this.clear();\n\n    // Add the call \"terminal\" to the $output element.\n    this.$output.classList.add('terminal');\n\n    // Create a prompt element.\n    // This element gets added if input is needed.\n    this.#$prompt = document.createElement(\"input\");\n    this.#$prompt.setAttribute(\"id\", \"prompt\");\n    this.#$prompt.setAttribute(\"type\", \"text\");\n    this.#$prompt.setAttribute(\"length\", \"50\");\n    this.#$prompt.addEventListener(\"keydown\", this.#handleKey.bind(this));\n\n    // Force focus on the promt on each click.\n    // This is needed for mobile support.\n    document.body.addEventListener('click', () => {\n      this.#$prompt.focus();\n    });\n  }\n\n  /**\n   * Creates a new HTMLElement with the given text content.\n   * This element than gets added to the $output as a new \"line\".\n   * \n   * @private\n   * @memberof MinimalTerminal\n   * @param {String} text - text that should be displayed in the new \"line\".\n   * @returns {HTMLElement} return a new DOM Element <pre class=\"line\"></pre>\n   */\n  #newLine(text) {\n    const $lineNode = document.createElement(\"pre\");\n    $lineNode.classList.add(\"line\");\n    $lineNode.innerText = text;\n    return $lineNode;\n  }\n\n  /**\n   * TODO\n   * \n   * @private\n   * @param {*} e \n   */\n  #handleKey(e) {\n    // if no input-callback is defined just return\n    if (!this.#inputCallback) {\n      return;\n    }\n\n    if (e.keyCode == 13) {\n      const text = this.#$prompt.value;\n      this.#$prompt.value = '';\n      this.#$prompt.remove();\n      this.#inputCallback(text + '\\n');\n    }\n  }\n\n  /**\n   * Clear the terminal.\n   * Remove all lines.\n   * \n   * @public\n   */\n  clear() {\n    this.$output.innerText = \"\";\n  }\n\n  /**\n   * Create a new div and add html content.\n   * \n   * @public\n   * @param {*} htmlContent \n   */\n  inserHtml(htmlContent) {\n    const $htmlNode = document.createElement(\"div\");\n    $htmlNode.innerHTML = htmlContent;\n    this.$output.appendChild($htmlNode);\n    document.body.scrollTo(0, document.body.scrollHeight);\n  }\n\n  /**\n   * Write a text to the terminal.\n   * By default there is no linebreak at the end of a new line\n   * except the line ensd with a \"\\n\".\n   * If the given text has multible linebreaks, multibe lines are inserted.\n   * \n   * @public\n   * @param {string} text \n   */\n  write(text) {\n    if (!text || text.length <= 0) {\n      // empty line\n      this.$output.appendChild(document.createElement(\"br\"));\n    } else if (text.endsWith(\"\\n\")) {\n      // single line with linebrank\n      const $lineNode = this.#newLine(text);\n      this.$output.appendChild(this.#newLine(text));\n      this.$output.appendChild(document.createElement(\"br\"));\n    } else if (text.includes(\"\\n\")) {\n      // multible lines\n      const lines = text.split(\"\\n\");\n      lines.forEach((line) => {\n        this.write(line);\n      });\n    } else {\n      // single line\n      this.$output.appendChild(this.#newLine(text));\n    }\n\n    // scroll to the buttom of the page\n    document.body.scrollTo(0, document.body.scrollHeight);\n  }\n\n  /**\n   * Like \"write\" but with a newline at the end.\n   * \n   * @public\n   * @param {*} text \n   */\n  writeln(text) {\n    this.write(text + \"\\n\");\n  }\n\n  /**\n   * Query from user input.\n   * This is done by adding a input-element at the end of the terminal,\n   * that showes a prompt and a blinking cursor.\n   * If a key is pressed the input is added to the prompt element.\n   * The input ends with a linebreak.\n   * \n   * @public\n   * @param {*} callback \n   */\n  input(callback) {\n    // show prompt with a blinking prompt\n    this.#inputCallback = callback;\n    this.$output.appendChild(this.#$prompt);\n    this.#$prompt.focus();\n  }\n}\n"
  },
  {
    "path": "00_Common/javascript/WebTerminal/terminal.html",
    "content": "<html>\n  <head>\n    <title>Minimal node.js terminal</title>\n    <meta name=\"viewport\" content=\"width=640, initial-scale=1\">\n    <link\n      rel=\"stylesheet\"\n      href=\"../../../00_Utilities/javascript/style_terminal.css\"\n    />\n    <link rel=\"stylesheet\" href=\"HtmlTerminal.css\" />\n    <style>\n      header {\n        position: sticky;\n        top: 0;\n        left: 0;\n        right: 0;\n        border-bottom: 1px solid var(--text);\n        padding: 0.25rem 0.5rem;\n        margin: 0;\n        margin-bottom: 1rem;\n        background: black;\n        display: flex;\n        justify-content: space-between;\n      }\n      header h1 {\n        font-size: small;\n        color: var(--text),\n      }\n      header div {\n        font-size: small;\n      }\n    </style>\n  </head>\n  <body>\n    <header>\n      <h1><a href=\"../../../\">BASIC Computer Games</a></h1>\n    </header>\n    <main id=\"output\"></main>\n    <script src=\"HtmlTerminal.js\" type=\"text/javascript\"></script>\n    <script>\n      const $output = document.getElementById(\"output\");\n      const term = new HtmlTerminal($output);\n\n      function getGameScriptFromHash() {\n        const hash = window.location.hash;\n\n        // if no game-script was provided redirect to the overview.\n        if (!hash) {\n          // show error message and link back to the index.html\n          console.debug(\"[HtmlTerminal] No game script found!\");\n          term.writeln(`no game script found :-(\\n`);\n          term.inserHtml(`<a href=\"/\">>> Back to game overview!</a>`);\n          return;\n        }\n\n        // remove the hash\n        const gameFile = hash.replace(\"#\", \"\");\n        return gameFile;\n      }\n\n      function addGitHubLink(gameFile) {\n        const gameFolder = gameFile.split(\"/\")[0];\n\n        $gitHubLink = document.createElement(\"a\");\n        $gitHubLink.href = `https://github.com/coding-horror/basic-computer-games/tree/main/${gameFolder}`;\n        $gitHubLink.innerText = `show source-code`;\n\n        var $gitHubBanner = document.createElement(\"div\");\n        $gitHubBanner.classList.add(\"githublink\");\n        $gitHubBanner.appendChild($gitHubLink);\n\n        const $header = document.getElementsByTagName('header')[0];\n        $header.append($gitHubBanner);\n      }\n\n      function loadGameScript(gameFile) {\n        // clear terminal\n        term.clear();\n\n        // load game-script\n        console.debug(\"[HtmlTerminal] Game script found: \", gameFile);\n        const gameScript = `../../../${gameFile}`;\n        var $scriptTag = document.createElement(\"script\");\n        $scriptTag.async = \"async\";\n        $scriptTag.type = \"module\";\n        $scriptTag.src = gameScript;\n        $scriptTag.onerror = () => {\n          term.clear();\n          term.writeln(`Error loading game-script \"${gameFile}\" :-(\\n`);\n          term.inserHtml(`<a href=\"/\">>> Back to game overview!</a>`);\n        };\n        $scriptTag.addEventListener(\"load\", function () {\n          console.log(\"[HtmlTerminal] Game script loaded!\");\n        });\n        document.body.append($scriptTag);\n      }\n\n      /**\n       * Determine how much chars will fit in each terminal line.\n       */\n      function getOutputColumns($element) {\n        \n        const fontWidth = 10; //TODO: this width could be measured but it may be complicated!\n        const columnWidth = Math.trunc($element.clientWidth / fontWidth);\n        console.warn(`[terminal] document.body.clientWidth:${$element.clientWidth} fontsize:${fontWidth} columnWidth:${columnWidth}`);\n        return columnWidth;\n      }\n\n      /* Redirect stdin/stdout to the HtmlTerminal.\n       * This is VERY hacky and should never be done in a serious project!\n       * We can use this here because we know what we are doing and...\n       * ...it's just simple games ;-) */\n      window.process = {\n        stdout: {\n          write: (t) => term.write(t),\n          columns: getOutputColumns($output)\n        },\n        stdin: {\n          on: (event, callback) => term.input(callback),\n        },\n        exit: (code) => {},\n      };\n\n      // let's play 🚀\n      const gameFile = getGameScriptFromHash();\n      addGitHubLink(gameFile);\n      loadGameScript(gameFile);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "00_Common/javascript/WebTerminal/terminal_tests.mjs",
    "content": "#!/usr/bin/env node\n\nimport { print, println, tab, input } from '../common.mjs';\n\nasync function main() {\n  println(tab(30), \"Minimal node.js terminal emulator\");\n  println();\n  println(tab(0), \"tab 0\");\n  println(tab(5), \"tab 5\");\n  println(tab(10), \"tab 10\");\n  println(tab(15), \"tab 15\");\n  println(tab(20), \"tab 20\");\n  println(tab(25), \"tab 25\");\n  println();\n  println(\"1234567890\", \" _ \", \"ABCDEFGHIJKLMNOPRSTUVWXYZ\");\n  println();\n  print(\"\\nHallo\"); print(\" \"); print(\"Welt!\\n\");\n  println(\"\");\n  println(\"Line 1\\nLine 2\\nLine 3\\nLine 4\");\n  println(\"----------------------------------------------\");\n\n  const value = await input(\"input\");\n  println(`input value was \"${value}\"`);\n\n  println(\"End of script\");\n\n  // 320 END\n  process.exit(0);\n}\nmain();\n"
  },
  {
    "path": "00_Common/javascript/common.mjs",
    "content": "/**\n * Print multible strings to the terminal.\n * Strings get concatinated (add together) without any space betweent them.\n * There will be no newline at the end!\n * If you want a linebrak at the end use `println`.\n * \n * This function is normally used if you want to put something on the screen \n * and later add some content to the same line.\n * For normal output (similar to `console.log`) use `println`!\n * \n * @param  {...string} messages - the strings to print to the terminal.\n */\nexport function print(...messages) {\n\tprocess.stdout.write(messages.join(\"\"));\n}\n\n/**\n * Add multible strings as a new line to the terminal.\n * Strings get concatinated (add together) without any space betweent them.\n * There will be a newline at the end!\n * If you want the terminal to stay active on the current line use `print`.\n * \n * @param  {...any} messages - the strings to print to the terminal.\n */\nexport function println(...messages) {\n\tprocess.stdout.write(messages.join(\"\") + \"\\n\");\n}\n\n/**\n * Create an empty string with a given length\n * \n * @param {number} length - the length of the string in space-characters.\n * @returns {string} returns a string containing only ampty spaces with a length of `count`.\n */\nexport function tab(length) {\n\treturn \" \".repeat(length);\n}\n\n/**\n * Read input from the keyboard and return it as a string.\n * TODO: to would be very helpfull to only allow a certain class of input (numbers, letters)\n * TODO: also we could convert all inputs to uppercase (where it makes sence).\n * \n * @param {string=''} message - a message or question to print befor the input.\n * @returns {Promise<string>} - returns the entered text as a string\n * @async \n */\nexport async function input(message = '') {\n\t/* First we need to print the mesage\n\t * We append a space by default to seperate the message from the imput.\n\t * TODO: If the message already contains a space at the end this is not needed! */\n\tprocess.stdout.write(message + ' ');\n\t\n\treturn new Promise(resolve => {\n\t\tprocess.stdin.on('data', (input) => {\n\t\t\t/* onData returns a Buffer.\n\t\t\t * First we need to convert it into a string. */\n\t\t\tconst data = input.toString();\n\n\t\t\t/* add input to terminal\n\t\t\t * The data should end with a newline! */\n\t\t\tprocess.stdout.write(data);\n\n\t\t\t/* The result fo onData is a string ending with an `\\n`.\n\t\t\t * We just need the actual content so let's remove the newline at the end: */\n\t\t\tconst content = data.endsWith('\\n') ? data.slice(0, -1) : data;\n\n\t\t\tresolve(content);\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/.editorconfig",
    "content": "root = true\n\n\n[*.{cs,vb}]\nindent_size = 4\nindent_style = space\nend_of_line = crlf\ninsert_final_newline = true\n\ndotnet_separate_import_directive_groups = false\ndotnet_sort_system_directives_first = false\n\ndotnet_style_qualification_for_event = false:suggestion\ndotnet_style_qualification_for_field = false:suggestion\ndotnet_style_qualification_for_method = false:suggestion\ndotnet_style_qualification_for_property = false:suggestion\n\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\ndotnet_style_predefined_type_for_member_access = true:suggestion\n\ndotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent\ndotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent\ndotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent\ndotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent\n\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:silent\n\ndotnet_style_coalesce_expression = true:suggestion\ndotnet_style_collection_initializer = true:suggestion\ndotnet_style_explicit_tuple_names = true:suggestion\ndotnet_style_null_propagation = true:suggestion\ndotnet_style_object_initializer = true:suggestion\ndotnet_style_operator_placement_when_wrapping = end_of_line\ndotnet_style_prefer_auto_properties = true:suggestion\ndotnet_style_prefer_compound_assignment = true:suggestion\ndotnet_style_prefer_conditional_expression_over_assignment = true:suggestion\ndotnet_style_prefer_conditional_expression_over_return = true:suggestion\ndotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion\ndotnet_style_prefer_inferred_tuple_names = true:suggestion\ndotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion\ndotnet_style_prefer_simplified_boolean_expressions = true:suggestion\ndotnet_style_prefer_simplified_interpolation = true:suggestion\n\n\n# Naming rules\n\ndotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion\ndotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface\ndotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i\n\ndotnet_naming_rule.types_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.types_should_be_pascal_case.symbols = types\ndotnet_naming_rule.types_should_be_pascal_case.style = pascal_case\n\ndotnet_naming_rule.non_private_members_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.non_private_members_should_be_pascal_case.symbols = non_private_members\ndotnet_naming_rule.non_private_members_should_be_pascal_case.style = pascal_case\n\ndotnet_naming_rule.private_members_should_be_pascal_case.severity = suggestion\ndotnet_naming_rule.private_members_should_be_pascal_case.symbols = private_members\ndotnet_naming_rule.private_members_should_be_pascal_case.style = camel_case\n\n\n# Symbols for use with naming rules\n\ndotnet_naming_symbols.interface.applicable_kinds = interface\ndotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.interface.required_modifiers =\n\ndotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum, delegate\ndotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected\ndotnet_naming_symbols.types.required_modifiers =\n\ndotnet_naming_symbols.non_private_members.applicable_kinds = property, method, field, event\ndotnet_naming_symbols.non_private_members.applicable_accessibilities = public, internal, protected, protected_internal, private_protected\n\ndotnet_naming_symbols.private_members.applicable_kinds = property, method, field, event\ndotnet_naming_symbols.private_members.applicable_accessibilities = private\n\n\n# Naming styles\n\ndotnet_naming_style.pascal_case.required_prefix =\ndotnet_naming_style.pascal_case.required_suffix =\ndotnet_naming_style.pascal_case.word_separator =\ndotnet_naming_style.pascal_case.capitalization = pascal_case\n\ndotnet_naming_style.begins_with_i.required_prefix = I\ndotnet_naming_style.begins_with_i.required_suffix =\ndotnet_naming_style.begins_with_i.word_separator =\ndotnet_naming_style.begins_with_i.capitalization = pascal_case\n\ndotnet_naming_style.camel_case.required_prefix =\ndotnet_naming_style.camel_case.required_suffix =\ndotnet_naming_style.camel_case.word_separator =\ndotnet_naming_style.camel_case.capitalization = camel_case\n\n\n[*.cs]\ncsharp_new_line_before_catch = false\ncsharp_new_line_before_else = false\ncsharp_new_line_before_finally = false\ncsharp_new_line_before_members_in_anonymous_types = true\ncsharp_new_line_before_members_in_object_initializers = true\ncsharp_new_line_before_open_brace = none\ncsharp_new_line_between_query_expression_clauses = true\n\ncsharp_indent_block_contents = true\ncsharp_indent_braces = false\ncsharp_indent_case_contents = true\ncsharp_indent_case_contents_when_block = true\ncsharp_indent_labels = one_less_than_current\ncsharp_indent_switch_labels = true\n\ncsharp_space_after_cast = false\ncsharp_space_after_colon_in_inheritance_clause = true\ncsharp_space_after_comma = true\ncsharp_space_after_dot = false\ncsharp_space_after_keywords_in_control_flow_statements = true\ncsharp_space_after_semicolon_in_for_statement = true\ncsharp_space_around_binary_operators = before_and_after\ncsharp_space_around_declaration_statements = false\ncsharp_space_before_colon_in_inheritance_clause = true\ncsharp_space_before_comma = false\ncsharp_space_before_dot = false\ncsharp_space_before_open_square_brackets = false\ncsharp_space_before_semicolon_in_for_statement = false\ncsharp_space_between_empty_square_brackets = false\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\ncsharp_space_between_method_call_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\ncsharp_space_between_method_declaration_name_and_open_parenthesis = false\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\ncsharp_space_between_parentheses = false\ncsharp_space_between_square_brackets = false\n\ncsharp_preserve_single_line_blocks = true\ncsharp_preserve_single_line_statements = true\n\ncsharp_prefer_braces = true:warning\n\ncsharp_style_expression_bodied_constructors = true:suggestion\ncsharp_style_expression_bodied_methods = true:suggestion\ncsharp_style_expression_bodied_properties = true:suggestion\n\ncsharp_prefer_simple_default_expression = true:suggestion\ndotnet_style_prefer_inferred_tuple_names = true:suggestion\n\ncsharp_style_var_elsewhere = true:suggestion\ncsharp_style_var_for_built_in_types = true:suggestion\ncsharp_style_var_when_type_is_apparent = true:suggestion\n\ncsharp_preferred_modifier_order = internal,protected,public,private,static,readonly,abstract,override,sealed,virtual:suggestion\n\ncsharp_style_pattern_matching_over_is_with_cast_check = true:suggestion\ncsharp_style_pattern_matching_over_as_with_null_check = true:suggestion\ncsharp_style_inlined_variable_declaration = true:suggestion\ncsharp_style_deconstructed_variable_declaration = true:suggestion\ncsharp_style_pattern_local_over_anonymous_function = true:suggestion\ncsharp_style_throw_expression = true:suggestion\ncsharp_style_conditional_delegate_call = true:suggestion\n\n\n[*.vb]\nvisual_basic_preferred_modifier_order = partial,default,private,protected,public,friend,notoverridable,overridable,mustoverride,overloads,overrides,mustinherit,notinheritable,static,shared,shadows,readonly,writeonly,dim,const,withevents,widening,narrowing,custom,async,iterator:silent\nvisual_basic_style_unused_value_assignment_preference = unused_local_variable:suggestion\nvisual_basic_style_unused_value_expression_statement_preference = unused_local_variable:silent\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing static System.IO.Path;\n\nnamespace DotnetUtils;\n\npublic static class Extensions {\n    public static IEnumerable<TResult> SelectT<T1, T2, TResult>(this IEnumerable<(T1, T2)> src, Func<T1, T2, TResult> selector) =>\n        src.Select(x => selector(x.Item1, x.Item2));\n    public static IEnumerable<TResult> SelectT<T1, T2, T3, TResult>(this IEnumerable<(T1, T2, T3)> src, Func<T1, T2, T3, TResult> selector) =>\n        src.Select(x => selector(x.Item1, x.Item2, x.Item3));\n    public static IEnumerable<(T1, T2, int)> WithIndex<T1, T2>(this IEnumerable<(T1, T2)> src) => src.Select((x, index) => (x.Item1, x.Item2, index));\n\n    public static bool None<T>(this IEnumerable<T> src, Func<T, bool>? predicate = null) =>\n        predicate is null ?\n            !src.Any() :\n            !src.Any(predicate);\n\n    public static bool IsNullOrWhitespace([NotNullWhen(false)] this string? s) => string.IsNullOrWhiteSpace(s);\n\n    [return: NotNullIfNotNull(\"path\")]\n    public static string? RelativePath(this string? path, string? rootPath) {\n        if (\n            path.IsNullOrWhitespace() ||\n            rootPath.IsNullOrWhitespace()\n        ) { return path; }\n\n        path = path.TrimEnd('\\\\'); // remove trailing backslash, if present\n        return GetRelativePath(rootPath, path.TrimEnd('\\\\'));\n    }\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/Functions.cs",
    "content": "﻿using System.Xml.Linq;\nusing static System.Console;\n\nnamespace DotnetUtils;\n\npublic static class Functions {\n    public static string? getValue(string path, params string[] names) {\n        if (names.Length == 0) { throw new InvalidOperationException(); }\n        var parent = XDocument.Load(path).Element(\"Project\")?.Element(\"PropertyGroup\");\n        return getValue(parent, names);\n    }\n\n    public static string? getValue(XElement? parent, params string[] names) {\n        if (names.Length == 0) { throw new InvalidOperationException(); }\n        XElement? elem = null;\n        foreach (var name in names) {\n            elem = parent?.Element(name);\n            if (elem != null) { break; }\n        }\n        return elem?.Value;\n    }\n\n    public static int getChoice(int maxValue) => getChoice(0, maxValue);\n\n    public static int getChoice(int minValue, int maxValue) {\n        int result;\n        do {\n            Write(\"? \");\n        } while (!int.TryParse(ReadLine(), out result) || result < minValue || result > maxValue);\n        //WriteLine();\n        return result;\n    }\n\n\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/Globals.cs",
    "content": "﻿namespace DotnetUtils;\n\npublic static class Globals {\n    public static readonly Dictionary<string, (string codefileExtension, string projExtension)> LangData = new() {\n        { \"csharp\", (\"cs\", \"csproj\") },\n        { \"vbnet\", (\"vb\", \"vbproj\") }\n    };\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/Methods.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace DotnetUtils;\n\npublic static class Methods {\n    public static ProcessResult RunProcess(string filename, string arguments) {\n        var process = new Process() {\n            StartInfo = {\n                FileName = filename,\n                Arguments = arguments,\n                UseShellExecute = false,\n                CreateNoWindow = true,\n                RedirectStandardOutput = true,\n                RedirectStandardError = true,\n            },\n            EnableRaisingEvents = true\n        };\n        return RunProcess(process);\n    }\n\n    public static ProcessResult RunProcess(Process process, string input = \"\") {\n        var (output, error) = (\"\", \"\");\n        var (redirectOut, redirectErr) = (\n            process.StartInfo.RedirectStandardOutput,\n            process.StartInfo.RedirectStandardError\n        );\n        if (redirectOut) {\n            process.OutputDataReceived += (s, ea) => output += ea.Data + \"\\n\";\n        }\n        if (redirectErr) {\n            process.ErrorDataReceived += (s, ea) => error += ea.Data + \"\\n\";\n        }\n\n        if (!process.Start()) {\n            throw new InvalidOperationException();\n        };\n\n        if (redirectOut) { process.BeginOutputReadLine(); }\n        if (redirectErr) { process.BeginErrorReadLine(); }\n        if (!string.IsNullOrEmpty(input)) {\n            process.StandardInput.WriteLine(input);\n            process.StandardInput.Close();\n        }\n        process.WaitForExit();\n        return new ProcessResult(process.ExitCode, output, error);\n    }\n\n    public static Task<ProcessResult> RunProcessAsync(Process process, string input = \"\") {\n        var tcs = new TaskCompletionSource<ProcessResult>();\n        var (output, error) = (\"\", \"\");\n        var (redirectOut, redirectErr) = (\n            process.StartInfo.RedirectStandardOutput,\n            process.StartInfo.RedirectStandardError\n        );\n\n        process.Exited += (s, e) => tcs.SetResult(new ProcessResult(process.ExitCode, output, error));\n\n        if (redirectOut) {\n            process.OutputDataReceived += (s, ea) => output += ea.Data + \"\\n\";\n        }\n        if (redirectErr) {\n            process.ErrorDataReceived += (s, ea) => error += ea.Data + \"\\n\";\n        }\n\n        if (!process.Start()) {\n            // what happens to the Exited event if process doesn't start successfully?\n            throw new InvalidOperationException();\n        }\n\n        if (redirectOut) { process.BeginOutputReadLine(); }\n        if (redirectErr) { process.BeginErrorReadLine(); }\n        if (!string.IsNullOrEmpty(input)) {\n            process.StandardInput.WriteLine(input);\n            process.StandardInput.Close();\n        }\n\n        return tcs.Task;\n    }\n}\n\npublic sealed record ProcessResult(int ExitCode, string StdOut, string StdErr) {\n    public override string? ToString() =>\n        StdOut +\n        (StdOut is not (null or \"\") && ExitCode > 0 ? \"\\n\" : \"\") +\n        (ExitCode != 0 ?\n            $\"{ExitCode}\\n{StdErr}\" :\n            \"\");\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs",
    "content": "﻿using static System.IO.Directory;\nusing static System.IO.Path;\nusing static DotnetUtils.Globals;\n\nnamespace DotnetUtils;\n\npublic record PortInfo(\n    string GamePath, string FolderName, int Index, string GameName,\n    string LangPath, string Lang, string Ext, string ProjExt,\n    string[] CodeFiles, string[] Slns, string[] Projs\n) {\n\n    private static readonly EnumerationOptions enumerationOptions = new() {\n        RecurseSubdirectories = true,\n        MatchType = MatchType.Simple,\n        MatchCasing = MatchCasing.CaseInsensitive\n    };\n\n    // .NET namespaces cannot have a digit as the first character\n    // For games whose name starts with a digit, we map the name to a specific string\n    private static readonly Dictionary<string, string> specialGameNames = new() {\n        { \"3-D_Plot\", \"Plot\" },\n        { \"3-D_Tic-Tac-Toe\", \"ThreeDTicTacToe\" },\n        { \"23_Matches\", \"TwentyThreeMatches\"}\n    };\n\n    public static PortInfo? Create(string gamePath, string langKeyword) {\n        var folderName = GetFileName(gamePath);\n        var parts = folderName.Split('_', 2);\n\n        if (parts.Length <= 1) { return null; }\n\n        var (index, gameName) = (\n            int.TryParse(parts[0], out var n) && n > 0 ? // ignore utilities folder\n                n :\n                (int?)null,\n            specialGameNames.TryGetValue(parts[1], out var specialName) ?\n                specialName :\n                parts[1].Replace(\"_\", \"\").Replace(\"-\", \"\")\n        );\n\n        if (index is null || gameName is null) { return null; }\n\n        var (ext, projExt) = LangData[langKeyword];\n        var langPath = Combine(gamePath, langKeyword);\n        var codeFiles =\n            GetFiles(langPath, $\"*.{ext}\", enumerationOptions)\n                .Where(x => !x.Contains(\"\\\\bin\\\\\") && !x.Contains(\"\\\\obj\\\\\"))\n                .ToArray();\n\n        return new PortInfo(\n            gamePath, folderName, index.Value, gameName,\n            langPath, langKeyword, ext, projExt,\n            codeFiles,\n            GetFiles(langPath, \"*.sln\", enumerationOptions),\n            GetFiles(langPath, $\"*.{projExt}\", enumerationOptions)\n        );\n    }\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs",
    "content": "﻿using System.Reflection;\nusing static System.IO.Directory;\nusing static DotnetUtils.Globals;\n\nnamespace DotnetUtils;\n\npublic static class PortInfos {\n    public static readonly string Root;\n\n    static PortInfos() {\n        Root = GetParent(Assembly.GetEntryAssembly()!.Location)!.FullName;\n        Root = Root[..Root.IndexOf(@\"\\00_Utilities\")];\n\n        Get = GetDirectories(Root)\n            .SelectMany(gamePath => LangData.Keys.Select(keyword => (gamePath, keyword)))\n            .SelectT((gamePath, keyword) => PortInfo.Create(gamePath, keyword))\n            .Where(x => x is not null)\n            .ToArray()!;\n    }\n\n    public static readonly PortInfo[] Get;\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils/Program.cs",
    "content": "﻿using System.Xml.Linq;\nusing DotnetUtils;\nusing static System.Console;\nusing static System.IO.Path;\nusing static DotnetUtils.Methods;\nusing static DotnetUtils.Functions;\n\nvar infos = PortInfos.Get;\n\nvar actions = new (Action action, string description)[] {\n    (printInfos, \"Output information -- solution, project, and code files\"),\n    (missingSln, \"Output missing sln\"),\n    (unexpectedSlnName, \"Output misnamed sln\"),\n    (multipleSlns, \"Output multiple sln files\"),\n    (missingProj, \"Output missing project file\"),\n    (unexpectedProjName, \"Output misnamed project files\"),\n    (multipleProjs, \"Output multiple project files\"),\n    (checkProjects, \"Check .csproj/.vbproj files for target framework, nullability etc.\"),\n    (checkExecutableProject, \"Check that there is at least one executable project per port\"),\n    (noCodeFiles, \"Output ports without any code files\"),\n    (printPortInfo, \"Print info about a single port\"),\n\n    (generateMissingSlns, \"Generate solution files when missing\"),\n    (generateMissingProjs, \"Generate project files when missing\")\n};\n\nforeach (var (_, description, index) in actions.WithIndex()) {\n    WriteLine($\"{index}: {description}\");\n}\n\nWriteLine();\n\nactions[getChoice(actions.Length - 1)].action();\n\nvoid printSlns(PortInfo pi) {\n    switch (pi.Slns.Length) {\n        case 0:\n            WriteLine(\"No sln\");\n            break;\n        case 1:\n            WriteLine($\"Solution: {pi.Slns[0].RelativePath(pi.LangPath)}\");\n            break;\n        case > 1:\n            WriteLine(\"Solutions:\");\n            foreach (var sln in pi.Slns) {\n                Write(sln.RelativePath(pi.LangPath));\n                WriteLine();\n            }\n            break;\n    }\n}\n\nvoid printProjs(PortInfo pi) {\n    switch (pi.Projs.Length) {\n        case 0:\n            WriteLine(\"No project\");\n            break;\n        case 1:\n            WriteLine($\"Project: {pi.Projs[0].RelativePath(pi.LangPath)}\");\n            break;\n        case > 1:\n            WriteLine(\"Projects:\");\n            foreach (var proj in pi.Projs) {\n                Write(proj.RelativePath(pi.LangPath));\n                WriteLine();\n            }\n            break;\n    }\n}\n\nvoid printInfos() {\n    foreach (var item in infos) {\n        WriteLine(item.LangPath);\n        WriteLine();\n\n        printSlns(item);\n        WriteLine();\n\n        printProjs(item);\n        WriteLine();\n\n        // get code files\n        foreach (var file in item.CodeFiles) {\n            WriteLine(file.RelativePath(item.LangPath));\n        }\n        WriteLine(new string('-', 50));\n    }\n}\n\nvoid missingSln() {\n    var data = infos.Where(x => x.Slns.None()).ToArray();\n    foreach (var item in data) {\n        WriteLine(item.LangPath);\n    }\n    WriteLine();\n    WriteLine($\"Count: {data.Length}\");\n}\n\nvoid unexpectedSlnName() {\n    var counter = 0;\n    foreach (var item in infos) {\n        if (item.Slns.None()) { continue; }\n\n        var expectedSlnName = $\"{item.GameName}.sln\";\n        if (item.Slns.Contains(Combine(item.LangPath, expectedSlnName), StringComparer.InvariantCultureIgnoreCase)) { continue; }\n\n        counter += 1;\n        WriteLine(item.LangPath);\n        WriteLine($\"Expected: {expectedSlnName}\");\n\n        printSlns(item);\n\n        WriteLine();\n    }\n    WriteLine($\"Count: {counter}\");\n}\n\nvoid multipleSlns() {\n    var data = infos.Where(x => x.Slns.Length > 1).ToArray();\n    foreach (var item in data) {\n        WriteLine(item.LangPath);\n        printSlns(item);\n    }\n    WriteLine();\n    WriteLine($\"Count: {data.Length}\");\n}\n\nvoid missingProj() {\n    var data = infos.Where(x => x.Projs.None()).ToArray();\n    foreach (var item in data) {\n        WriteLine(item.LangPath);\n    }\n    WriteLine();\n    WriteLine($\"Count: {data.Length}\");\n}\n\nvoid unexpectedProjName() {\n    var counter = 0;\n    foreach (var item in infos) {\n        if (item.Projs.None()) { continue; }\n\n        var expectedProjName = $\"{item.GameName}.{item.ProjExt}\";\n        if (item.Projs.Contains(Combine(item.LangPath, expectedProjName))) { continue; }\n\n        counter += 1;\n        WriteLine(item.LangPath);\n        WriteLine($\"Expected: {expectedProjName}\");\n\n        printProjs(item);\n\n        WriteLine();\n    }\n    WriteLine($\"Count: {counter}\");\n}\n\nvoid multipleProjs() {\n    var data = infos.Where(x => x.Projs.Length > 1).ToArray();\n    foreach (var item in data) {\n        WriteLine(item.LangPath);\n        WriteLine();\n        printProjs(item);\n    }\n    WriteLine();\n    WriteLine($\"Count: {data.Length}\");\n}\n\nvoid generateMissingSlns() {\n    foreach (var item in infos.Where(x => x.Slns.None())) {\n        var result = RunProcess(\"dotnet\", $\"new sln -n {item.GameName} -o {item.LangPath}\");\n        WriteLine(result);\n\n        var slnFullPath = Combine(item.LangPath, $\"{item.GameName}.sln\");\n        foreach (var proj in item.Projs) {\n            result = RunProcess(\"dotnet\", $\"sln {slnFullPath} add {proj}\");\n            WriteLine(result);\n        }\n    }\n}\n\nvoid generateMissingProjs() {\n    foreach (var item in infos.Where(x => x.Projs.None())) {\n        // We can't use the dotnet command to create a new project using the built-in console template, because part of that template\n        // is a Program.cs / Program.vb file. If there already are code files, there's no need to add a new empty one; and\n        // if there's already such a file, it might try to overwrite it.\n\n        var projText = item.Lang switch {\n            \"csharp\" => @\"<Project Sdk=\"\"Microsoft.NET.Sdk\"\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n\",\n            \"vbnet\" => @$\"<Project Sdk=\"\"Microsoft.NET.Sdk\"\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>{item.GameName}</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n\",\n            _ => throw new InvalidOperationException()\n        };\n        var projFullPath = Combine(item.LangPath, $\"{item.GameName}.{item.ProjExt}\");\n        File.WriteAllText(projFullPath, projText);\n\n        if (item.Slns.Length == 1) {\n            var result = RunProcess(\"dotnet\", $\"sln {item.Slns[0]} add {projFullPath}\");\n            WriteLine(result);\n        }\n    }\n}\n\nvoid checkProjects() {\n    foreach (var info in infos) {\n        WriteLine(info.LangPath);\n        printProjectWarnings(info);\n    }\n}\n\nvoid printProjectWarnings(PortInfo info) {\n    foreach (var proj in info.Projs) {\n        var warnings = new List<string>();\n        var parent = XDocument.Load(proj).Element(\"Project\")?.Element(\"PropertyGroup\");\n\n        var (\n            framework,\n            nullable,\n            implicitUsing,\n            rootNamespace,\n            langVersion,\n            optionStrict\n        ) = (\n            getValue(parent, \"TargetFramework\", \"TargetFrameworks\"),\n            getValue(parent, \"Nullable\"),\n            getValue(parent, \"ImplicitUsings\"),\n            getValue(parent, \"RootNamespace\"),\n            getValue(parent, \"LangVersion\"),\n            getValue(parent, \"OptionStrict\")\n        );\n\n        if (framework != \"net6.0\") {\n            warnings.Add($\"Target: {framework}\");\n        }\n\n        if (info.Lang == \"csharp\") {\n            if (nullable != \"enable\") {\n                warnings.Add($\"Nullable: {nullable}\");\n            }\n            if (implicitUsing != \"enable\") {\n                warnings.Add($\"ImplicitUsings: {implicitUsing}\");\n            }\n            if (rootNamespace != null && rootNamespace != info.GameName) {\n                warnings.Add($\"RootNamespace: {rootNamespace}\");\n            }\n            if (langVersion != \"10\") {\n                warnings.Add($\"LangVersion: {langVersion}\");\n            }\n        }\n\n        if (info.Lang == \"vbnet\") {\n            if (rootNamespace != info.GameName) {\n                warnings.Add($\"RootNamespace: {rootNamespace}\");\n            }\n            if (langVersion != \"16.9\") {\n                warnings.Add($\"LangVersion: {langVersion}\");\n            }\n            if (optionStrict != \"On\") {\n                warnings.Add($\"OptionStrict: {optionStrict}\");\n            }\n        }\n\n        if (warnings.Any()) {\n            WriteLine(proj.RelativePath(info.LangPath));\n            WriteLine(string.Join(\"\\n\", warnings));\n            WriteLine();\n        }\n    }\n}\n\nvoid checkExecutableProject() {\n    foreach (var item in infos) {\n        if (item.Projs.All(proj => getValue(proj, \"OutputType\") != \"Exe\")) {\n            WriteLine($\"{item.LangPath}\");\n        }\n    }\n}\n\nvoid noCodeFiles() {\n    var qry = infos\n        .Where(x => x.CodeFiles.None())\n        .OrderBy(x => x.Lang);\n    foreach (var item in qry) {\n        WriteLine(item.LangPath);\n    }\n}\n\nvoid tryBuild() {\n    // if has code files, try to build\n}\n\nvoid printPortInfo() {\n    // prompt for port number\n    Write(\"Enter number from 1 to 96 \");\n    var index = getChoice(1, 96);\n\n    Write(\"Enter 0 for C#, 1 for VB \");\n    var lang = getChoice(1) switch {\n        0 => \"csharp\",\n        1 => \"vbnet\",\n        _ => throw new InvalidOperationException()\n    };\n\n    WriteLine();\n\n    var info = infos.Single(x => x.Index == index && x.Lang == lang);\n\n    WriteLine(info.LangPath);\n    WriteLine(new string('-', 50));\n\n    // print solutions\n    printSlns(info);\n\n    // mismatched solution name/location? (expected x)\n    var expectedSlnName = Combine(info.LangPath, $\"{info.GameName}.sln\");\n    if (!info.Slns.Contains(expectedSlnName)) {\n        WriteLine($\"Expected name/path: {expectedSlnName.RelativePath(info.LangPath)}\");\n    }\n\n    // has executable project?\n    if (info.Projs.All(proj => getValue(proj, \"OutputType\") != \"Exe\")) {\n        WriteLine(\"No executable project\");\n    }\n\n    WriteLine();\n\n    // print projects\n    printProjs(info);\n\n    // mimsatched project name/location? (expected x)\n    var expectedProjName = Combine(info.LangPath, $\"{info.GameName}.{info.ProjExt}\");\n    if (info.Projs.Length < 2 && !info.Projs.Contains(expectedProjName)) {\n        WriteLine($\"Expected name/path: {expectedProjName.RelativePath(info.LangPath)}\");\n    }\n\n    WriteLine();\n\n    // verify project properties\n    printProjectWarnings(info);\n\n    WriteLine(\"Code files:\");\n\n    // list code files\n    foreach (var codeFile in info.CodeFiles) {\n        WriteLine(codeFile.RelativePath(info.LangPath));\n    }\n\n    // try build\n}\n"
  },
  {
    "path": "00_Utilities/DotnetUtils/DotnetUtils.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DotnetUtils\", \"DotnetUtils\\DotnetUtils.csproj\", \"{BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {30FCF56E-4E83-42F8-AB43-A52C86C7C9B4}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "00_Utilities/README.md",
    "content": "#### Utilities\n\nThese are global helper / utility programs to assist us in maintaining all the ports. "
  },
  {
    "path": "00_Utilities/TODO.md",
    "content": "# TODO list\n game                          | C# | Java | JS | Kotlin | Lua | Perl | Python | Ruby | Rust | VB.NET\n------------------------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---\n01_Acey_Ducey                  | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n[02_Amazing](../02_Amazing)    | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅\n[03_Animal](../03_Animal)      | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[04_Awari](../04_Awari)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[05_Bagels](../05_Bagels)      | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[06_Banner](../06_Banner)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅\n[07_Basketball](../07_Basketball) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[08_Batnum](../08_Batnum)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅\n[09_Battle](../09_Battle)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️\n[10_Blackjack](../10_Blackjack) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️\n[11_Bombardment](../11_Bombardment) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[12_Bombs_Away](../12_Bombs_Away) | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[13_Bounce](../13_Bounce)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[14_Bowling](../14_Bowling)    | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[15_Boxing](../15_Boxing)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[16_Bug](../16_Bug)            | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️\n[17_Bullfight](../17_Bullfight) | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[18_Bullseye](../18_Bullseye)  | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[19_Bunny](../19_Bunny)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[20_Buzzword](../20_Buzzword)  | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[21_Calendar](../21_Calendar)  | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[22_Change](../22_Change)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[23_Checkers](../23_Checkers)  | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[24_Chemist](../24_Chemist)    | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[25_Chief](../25_Chief)        | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[26_Chomp](../26_Chomp)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[27_Civil_War](../27_Civil_War) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[28_Combat](../28_Combat)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[29_Craps](../29_Craps)        | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[30_Cube](../30_Cube)          | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️\n[31_Depth_Charge](../31_Depth_Charge) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[32_Diamond](../32_Diamond)    | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[33_Dice](../33_Dice)          | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅\n[34_Digits](../34_Digits)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[35_Even_Wins](../35_Even_Wins) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[36_Flip_Flop](../36_Flip_Flop) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[37_Football](../37_Football)  | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[38_Fur_Trader](../38_Fur_Trader) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[39_Golf](../39_Golf)          | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[40_Gomoko](../40_Gomoko)      | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[41_Guess](../41_Guess)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[42_Gunner](../42_Gunner)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[43_Hammurabi](../43_Hammurabi) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[44_Hangman](../44_Hangman)    | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[45_Hello](../45_Hello)        | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[46_Hexapawn](../46_Hexapawn)  | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[47_Hi-Lo](../47_Hi-Lo)        | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[48_High_IQ](../48_High_IQ)    | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[49_Hockey](../49_Hockey)      | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[50_Horserace](../50_Horserace) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️\n[51_Hurkle](../51_Hurkle)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[52_Kinema](../52_Kinema)      | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[53_King](../53_King)          | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️\n[54_Letter](../54_Letter)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[55_Life](../55_Life)          | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[56_Life_for_Two](../56_Life_for_Two) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[57_Literature_Quiz](../57_Literature_Quiz) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[58_Love](../58_Love)          | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[59_Lunar_LEM_Rocket](../59_Lunar_LEM_Rocket) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️\n[60_Mastermind](../60_Mastermind) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[61_Math_Dice](../61_Math_Dice) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[62_Mugwump](../62_Mugwump)    | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[63_Name](../63_Name)          | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[64_Nicomachus](../64_Nicomachus) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[65_Nim](../65_Nim)            | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️\n[66_Number](../66_Number)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[67_One_Check](../67_One_Check) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[68_Orbit](../68_Orbit)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[69_Pizza](../69_Pizza)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[70_Poetry](../70_Poetry)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[71_Poker](../71_Poker)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️\n[72_Queen](../72_Queen)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[73_Reverse](../73_Reverse)    | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅\n[74_Rock_Scissors_Paper](../74_Rock_Scissors_Paper) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[75_Roulette](../75_Roulette)  | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[76_Russian_Roulette](../76_Russian_Roulette) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[77_Salvo](../77_Salvo)        | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[78_Sine_Wave](../78_Sine_Wave) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[79_Slalom](../79_Slalom)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[80_Slots](../80_Slots)        | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[81_Splat](../81_Splat)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[82_Stars](../82_Stars)        | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[83_Stock_Market](../83_Stock_Market) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[84_Super_Star_Trek](../84_Super_Star_Trek) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️\n[85_Synonym](../85_Synonym)    | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[86_Target](../86_Target)      | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️\n[87_3-D_Plot](../87_3-D_Plot)  | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️\n[88_3-D_Tic-Tac-Toe](../88_3-D_Tic-Tac-Toe) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️\n[89_Tic-Tac-Toe](../89_Tic-Tac-Toe) | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[90_Tower](../90_Tower)        | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[91_Train](../91_Train)        | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[92_Trap](../92_Trap)          | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[93_23_Matches](../93_23_Matches) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[94_War](../94_War)            | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️\n[95_Weekday](../95_Weekday)    | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️\n[96_Word](../96_Word)          | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅\n------------------------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---\nSum of 96                      | 79 | 83 | 96 | 9 | 16 | 75 | 95 | 51 | 58 | 7\n"
  },
  {
    "path": "00_Utilities/VintageBASIC.xml",
    "content": "<NotepadPlus>\n    <UserLang name=\"Vintage BASIC\" ext=\"bas\" udlVersion=\"2.1\">\n        <Settings>\n            <Global caseIgnored=\"no\" allowFoldOfComments=\"no\" foldCompact=\"no\" forcePureLC=\"0\" decimalSeparator=\"0\" />\n            <Prefix Keywords1=\"no\" Keywords2=\"no\" Keywords3=\"no\" Keywords4=\"no\" Keywords5=\"no\" Keywords6=\"no\" Keywords7=\"no\" Keywords8=\"no\" />\n        </Settings>\n        <KeywordLists>\n            <Keywords name=\"Comments\">00REM 01 02 03 04</Keywords>\n            <Keywords name=\"Numbers, prefix1\"></Keywords>\n            <Keywords name=\"Numbers, prefix2\"></Keywords>\n            <Keywords name=\"Numbers, extras1\"></Keywords>\n            <Keywords name=\"Numbers, extras2\"></Keywords>\n            <Keywords name=\"Numbers, suffix1\"></Keywords>\n            <Keywords name=\"Numbers, suffix2\"></Keywords>\n            <Keywords name=\"Numbers, range\"></Keywords>\n            <Keywords name=\"Operators1\">- + ^ * / = &lt;&gt; &lt; &gt; &lt;= &gt;=</Keywords>\n            <Keywords name=\"Operators2\"></Keywords>\n            <Keywords name=\"Folders in code1, open\"></Keywords>\n            <Keywords name=\"Folders in code1, middle\"></Keywords>\n            <Keywords name=\"Folders in code1, close\"></Keywords>\n            <Keywords name=\"Folders in code2, open\"></Keywords>\n            <Keywords name=\"Folders in code2, middle\"></Keywords>\n            <Keywords name=\"Folders in code2, close\"></Keywords>\n            <Keywords name=\"Folders in comment, open\"></Keywords>\n            <Keywords name=\"Folders in comment, middle\"></Keywords>\n            <Keywords name=\"Folders in comment, close\"></Keywords>\n            <Keywords name=\"Keywords1\">DATA DEF FN DIM END FOR GOSUB GOTO IF THEN INPUT LET NEXT ON PRINT RANDOMIZE REM RESTORE RETURN STOP TO</Keywords>\n            <Keywords name=\"Keywords2\">ABS ASC ATN CHR$ COS EXP INT LEFT$ LEN LOG MID$ RIGHT$ RND SGN SIN SPC SQR STR TAB TAN VAL</Keywords>\n            <Keywords name=\"Keywords3\">NOT AND OR</Keywords>\n            <Keywords name=\"Keywords4\"></Keywords>\n            <Keywords name=\"Keywords5\"></Keywords>\n            <Keywords name=\"Keywords6\"></Keywords>\n            <Keywords name=\"Keywords7\"></Keywords>\n            <Keywords name=\"Keywords8\"></Keywords>\n            <Keywords name=\"Delimiters\">00&quot; 01 02&quot; 03( 04 05) 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>\n        </KeywordLists>\n        <Styles>\n            <WordsStyle name=\"DEFAULT\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"Courier New\" fontStyle=\"0\" fontSize=\"14\" nesting=\"0\" />\n            <WordsStyle name=\"COMMENTS\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"LINE COMMENTS\" fgColor=\"00FF00\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"NUMBERS\" fgColor=\"FF0000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS1\" fgColor=\"8000FF\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS2\" fgColor=\"0080C0\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS3\" fgColor=\"800000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS4\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS5\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS6\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS7\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS8\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"OPERATORS\" fgColor=\"800000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"FOLDER IN CODE1\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"FOLDER IN CODE2\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"FOLDER IN COMMENT\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS1\" fgColor=\"0000FF\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS2\" fgColor=\"FF8040\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS3\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS4\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS5\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS6\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS7\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS8\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontStyle=\"0\" nesting=\"0\" />\n        </Styles>\n    </UserLang>\n</NotepadPlus>\n"
  },
  {
    "path": "00_Utilities/bas2perl.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nmy $Mode= lc($ARGV[0]);  #trace #convert\nmy $File= $ARGV[1];\nmy $LN= \"Line\";\nmy $Pedantic= 0;\nmy $Indent= 0;\n\nmy %Vars;  # num | str | anm | ast\nmy @Data;\nmy %Code;\nopen(FH, $File);\nwhile (my $Line = <FH>) {\n\tchomp $Line;\n\tmy $Space= index($Line, \" \");\n\tmy $Key= substr($Line, 0, $Space);\n\tmy $Code= substr($Line, $Space+1);\n\t$Code{$Key}=$Code;\n\t}\nclose(FH);\n\n\nforeach my $Lin (sort  {$a<=>$b} keys %Code) {\n\tif ($Mode eq \"trace\") { print \"==> $Lin $Code{$Lin}\\n\"; }\n\tmy $Ret= &PROCLINE($Code{$Lin});\n\tif ($Mode eq \"trace\") { print \"   $Ret\\n\"; }\n\t$Code{$Lin}= $Ret;\n\t}\n\n\nif ($Mode eq \"convert\") {\n\t$Code{'0.1'}= \"#!/usr/bin/perl\";\n\t$Code{'0.2'}= \"#use strict;\";\n\t$Code{'0.3'}= \"# Automatic converted by bas2perl.pl\";\n\t$Code{'0.4'}= \"\";\n\tforeach my $Lin (sort  {$a<=>$b} keys %Code) {\n\t\tprint \"$Code{$Lin}\\n\";\n\t\t}\n\t}\n\n\tif (@Data) { &DATAIL(); }\n\tprint \"\\n\\n\\n\";\n\n\nexit;\n\n\nsub PROCLINE {\n\tmy ($Line)= @_;\n\tmy @Sente= &SMARPLIT($Line, \":\", \"\\\"\");\n\n\tmy $Perl;\n\tforeach my $Sen (@Sente) {\n\t\tmy $Flag=0;\n\t\tif ($Pedantic==0) {\n\t\t\t#REM: Resolves some ugly syntaxis...\n\t\t\t$Sen=~ s/\\bPRINT\"/PRINT \"/g;\t\t\t# PRINT\"Hello\"\n\t\t\t$Sen=~ s/\"([A-Z])\\$/\"; $1\\$/g;\t\t# PRINT \"Hello \"N$\n\t\t\t}\n\t\t$Sen= &TRIM($Sen);\n\t\tif ($Sen>0) { $Sen= \"GOTO $Sen\"; }\n\t\tif ($Sen=~ /^DATA\\b/) { $Sen= &DATA($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^DIM\\b/) { $Sen= &DIM($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^END\\b/) { $Sen= &ENDD($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^FOR\\b/) { $Sen= &FOR($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^GOTO\\b/) { $Sen= &GOTO($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^GOSUB\\b/) { $Sen= &GOSUB($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^IF\\b/) { $Sen= &IF($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^INPUT\\b/) { $Sen= &INPUT($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^NEXT\\b/) { $Sen= &NEXT($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^ON\\b/ && $Sen=~ / GOTO /) { $Sen= &ONGOTO($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^PRINT\\b/) { $Sen= &PRINT($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^READ\\b/) { $Sen= &READ($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^REM\\b/) { $Sen= &REM($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^RETURN\\b/) { $Sen= &RETURN($Sen); $Flag=1; }\n\t\tif ($Sen=~ /^STOP\\b/) { $Sen= &ENDD($Sen); $Flag=1; }\n\t\tif ($Flag==0) { $Sen= &FORMULA($Sen); } # LET\n\t\t$Sen.=\";\";\n\t\t$Sen=~ s/\\{;$/\\{/g;\n\t\t$Sen=~ s/\\};$/\\}/g;\n\t\t$Perl.= \"$Sen \";\n\t\t}\n\t$Perl= &TRIM($Perl);\n\tmy $Adj= 0;\n\tif ($Perl=~ /^for\\b/) { $Adj--; }\n\tif ($Perl eq \"}\") { $Adj++; }\n\t$Perl= \"\\t\"x ($Indent+$Adj) . $Perl;\n\treturn $Perl;\n\t}\n\n\n\n####################\n# BASIC STATEMENTS #\n####################\n\nsub DATA {\n\tmy ($Str)= @_;\n\t$Str=~ s/DATA //;\n\tpush @Data, $Str;\n\treturn \"# TO DATA SEGMENT\";\n\t}\n\n\nsub DIM {\n\tmy ($Str)= @_;\n\t$Str=~ s/DIM //;\n\tmy @Parts= split(/\\,(?![^\\(]*\\))/, $Str);\n\tmy $Out;\n\tforeach my $Par (@Parts) {\n\t\tmy $Type= $Par=~ /\\$/ ? \"ast\" : \"anm\";\n\t\t$Par=~ s/\\$//g;\n\t\t$Par=~ s/\\(.*\\)//;\n\t\t$Vars{$Par}= \"anm\";\n\t\t$Out.= \"my \\@$Par; \";\n\t\t}\n\tchop $Out;\n\tchop $Out;\n\treturn $Out;\n\t}\n\n\nsub ENDD {\n\treturn \"exit\";\n\t}\n\n\nsub FOR {\n\tmy ($Str)= @_;\n\t$Str=~ s/= /=/g;\n\tmy @Parts= split(\" \", $Str);\n\t$Parts[1]= &FORMULA($Parts[1]);\n\tmy $Var=substr($Parts[1],0,index($Parts[1],\"=\"));\n\t$Parts[3]= \"$Var<=\".&FORMULA($Parts[3]);\n\tif ($Parts[5]<0) { $Parts[3]=~ s/</>/; }\n \t$Parts[5]= $Parts[5] eq \"\" ? \"$Var++\" : \"$Var+=\".&FORMULA($Parts[5]);\n\t$Str= \"for ($Parts[1]; $Parts[3]; $Parts[5]) {\";\n\t$Indent++;\n\treturn $Str;\n\t}\n\n\nsub GOTO {\n\t# The birth of spaguetti code!\n\t# Dijkstra would not like this...\n\tmy ($Str)= @_;\n\tmy @Parts= split(\" \", $Str);\n\tmy $Label= \"$LN$Parts[1]\";\n\t$Str= lc($Parts[0]).\" $Label\";\n\t$Code{($Parts[1]-.2)}=\"\";\n\t$Code{($Parts[1]-.1)}=\"$Label:\";\n\treturn $Str;\n\t}\n\n\nsub GOSUB {\n\tmy ($Str)= @_;\n\tmy @Parts= split(\" \", $Str);\n\tmy $Label= \"$LN$Parts[1]\";\n\t$Str= \"\\&$Label()\";\n\t$Code{($Parts[1]-.2)}=\"\";\n\t$Code{($Parts[1]-.1)}=\"sub $Label {\";\n\treturn $Str;\n\t}\n\n\nsub IF {\n\tmy ($Str)= @_;\n\t$Str=~ s/^IF //g;\n\tmy @Parts= split(\" THEN \", $Str);\n\t$Parts[0]= &FORMULA($Parts[0], 1);\n\t$Parts[1]= &PROCLINE($Parts[1]);\n\tmy $Str= \"if ($Parts[0]) { $Parts[1] }\";\n\treturn $Str;\n\t}\n\n\nsub INPUT {\n\tmy ($Str)= @_;\n\t$Str=~ s/INPUT //;\n\t$Str=~ s/\"(.*)\"//g;\n\n\tmy $Txt= qq|print \"$1\\? \"; |;\n\n\tmy @Parts= split(/,/, $Str);\n\tmy @Multi;\n\tforeach my $Par (@Parts) {\n\t\tmy $Type= \"num\";\n\t\tif ($Par=~ /\\$/) {\n\t\t\t$Type= \"str\";\n\t\t\t$Par=~ s/\\$//g;\n\t\t\t}\n\t\tif ($Par=~ /\\(/) {\n\t\t\tif ($Type eq \"num\") { $Type= \"anm\"; }\n\t\t\tif ($Type eq \"str\") { $Type= \"ast\"; }\n\t\t\t$Par=~ s/\\(/\\[/g;\n\t\t\t$Par=~ s/\\)/\\]/g;\n\t\t\t}\n\t\t$Par=~ s/\\;//g;\n\t\tpush @Multi, \"\\$$Par\";\n\n\t\tmy $Name= $Par;\n\t\t$Name=~ s/\\[.*\\]//;\n\t\t$Vars{$Name}= $Type;\n\t\t}\n\n\t$Str= join(\",\", @Multi);\n\n\tmy $Spl= \"\";\n\tif (scalar @Parts>1) {\n\t\t$Spl= \"; ($Str)= split(/,/, \\$Inp_)\";\n\t\t$Str= \"\\$Inp_\";\n\t\t}\n\tmy $Inp= qq|chomp($Str = uc(<STDIN>))$Spl|;\n\n\n\tif ($Str=~ /,/) {\n\t\t$Str= \"\\$$Str\";\n\t\t$Str=~ s/,/,\\$/g;\n\t\t$Str= \"Inp\";\n\t\t}\n\treturn $Txt.$Inp;\n\t}\n\n\nsub NEXT {\n\t$Indent--;\n\treturn \"}\";\n\t}\n\n\nsub ONGOTO {\n\t# Base 1, if not match it will be skipped.\n\tmy ($Str)= @_;\n\tmy @Parts= split(\" \", $Str);\n\tmy $Var= $Parts[1];\n\tmy @Lines= split(\",\", $Parts[3]);\n\tmy $Count=0;\n\tmy $Text;\n\tforeach my $Lin (@Lines) {\n\t\t$Count++;\n\t\tmy $This= \"\\telsif (\\$$Var==$Count) \";\n\t\tif ($Count==1) { $This= \"if (\\$$Var==1) \"; }\n\n\t\tmy $Goto= &GOTO(\"GOTO $Lin\");\n\t\t$This.=\"{ $Goto; }\\n\";\n\t\t$Text.= $This;\n\t\t}\n\treturn $Text;\n\t}\n\n\nsub PRINT {\n\tmy ($Str)= @_;\n\tif ($Str eq \"PRINT\") { return 'print \"\\n\"' };\n\t$Str=~ s/^PRINT //;\n\n\tmy $Enter= 1;\n\tif ($Str=~ /;$/) { $Enter= 0; }\n\n\tmy @Parts= &SMARPLIT($Str, \";\", \"\\\"\");\n\n\tmy @Out;\n\tforeach my $Par (@Parts) {\n\t\tif ($Par=~ /\"/) {\n\t\t\tpush @Out, $Par;\n\t\t\tnext;\n\t\t\t}\n\n\t\tif ($Par=~ /TAB\\((.*?)\\)/) {\n\t\t\tpush @Out, \"' 'x\".&FORMULA($1).\" \";\n\t\t\tnext;\n\t\t\t}\n\n\t\t$Par= &FORMULA($Par);\n\t\tpush @Out, $Par;\n\t\t}\n\n\tmy $Out= join(\". \", @Out);\n\tif ($Enter) { $Out.= qq|. \"\\\\n\"|; }\n\treturn \"print \".$Out;\n\t}\n\n\nsub READ {\n\tmy ($Str)= @_;\n\t$Str=~ s/READ //;\n\t$Str= &FORMULA($Str);\n\t$Str.=\"= <DATA>; chomp($Str)\";\n\treturn $Str;\n\t}\n\n\nsub REM {\n\tmy ($Str)= @_;\n\treturn \"#\".$Str;\n\t}\n\n\nsub RETURN {\n\treturn \"return; }\";\n\t}\n\n\n\n###########\n# HELPERS #\n###########\n\nsub TRIM {\n\tmy ($Str)= @_;\n\t#$Str=~ s/\\s+/ /g;\n\t$Str=~ s/^\\s+//;\n\t$Str=~ s/\\s+$//;\n\treturn $Str;\n\t}\n\n\nsub DATAIL {\n\tprint \"\\n\\n\\n\";\n\tprint \"__DATA__\\n\";\n\tforeach my $Dat (@Data) {\n\t\t$Dat=~ s/\"//g;\n\t\t$Dat=~ s/,/\\n/g;\n\t\tprint \"$Dat\\n\";\n\t\t}\n\t}\n\n\nsub FORMULA {\n\tmy ($Str, $Cond)= @_;\n\t$Str=~ s/\\$//g;\n\t$Str=~ s/ABS\\(/abs\\(/g;\n\t$Str=~ s/COS\\(/cos\\(/g;\n\t$Str=~ s/LEN\\(/length\\(/g;\n\t$Str=~ s/INT\\(/int\\(/g;\n\t$Str=~ s/MID\\$?\\(/substr\\(/g;\n\t$Str=~ s/RND\\(/rand\\(/g;\n\t$Str=~ s/SIN\\(/sin\\(/g;\n\t$Str=~ s/SQR\\(/sqr\\(/g;\n\t$Str=~ s/(\\b[A-Z][0-9]?\\b)/\\$$&/g;\n\n\t#==> Check for arrays...\n\tforeach my $Key (keys %Vars) {\n\t\tif ($Vars{$Key}!~ /^a/) { next; }\n\t\t$Str=~ s/\\$$Key\\((.*?)\\)/\\$$Key\\[$1\\]/g;\n\t\t}\n\n\tif ($Cond==1) {\n\t\t$Str=~ s/<>/ ne /g;\n\t\t$Str=~ s/=/ eq /g;\n\t\t}\n\treturn $Str;\n\t}\n\n\nsub SMARPLIT {\n\tmy ($Str, $Sep, $Nin)= @_;\n\tmy @Parts;\n\tmy $Text= \"\";\n\tmy $Flag= 0;\n\tmy $Prev;\n\tforeach my $Char (split('', $Str)) {\n\t\tif ($Char eq $Nin) { $Flag= !$Flag; }\n\t\tif ($Char eq $Sep && $Flag==0) {\n\t\t\tpush @Parts, &TRIM($Text);\n\t\t\t$Text= \"\";\n\t\t\tnext;\n\t\t\t}\n\t\t$Prev= $Char;\n\t\t$Text.= $Char;\n\t\t}\n\tif ($Text) { push @Parts, &TRIM($Text); }\n\treturn @Parts;\n\t}\n"
  },
  {
    "path": "00_Utilities/build-index.js",
    "content": "#!/usr/bin/env node\n/**\n * This script creates an \"index.html\" file in the root of the directory.\n * \n * Call this from the root of the project with \n *  `node ./00_Utilities/build-index.js`\n * \n * @author Alexander Wunschik <https://github.com/mojoaxel>\n */\n\nconst fs = require('fs');\nconst path = require('path');\n\nconst TITLE = 'BASIC Computer Games';\nconst JAVASCRIPT_FOLDER = 'javascript';\nconst IGNORE_FOLDERS_START_WITH = ['.', '00_', 'buildJvm', 'Sudoku'];\nconst IGNORE_FILES = [\n\t// \"84 Super Star Trek\"  has it's own node/js implementation (using xterm)\n\t'cli.mjs', 'superstartrek.mjs'\n];\n\nfunction createGameLinks(game) {\n\tconst creatFileLink = (file, name = path.basename(file)) => {\n\t\tif (file.endsWith('.html')) {\n\t\t\treturn `\n\t\t\t\t<li><a href=\"${file}\">${name.replace('.html', '')}</a></li>\n\t\t\t`;\n\t\t} else if (file.endsWith('.mjs')) {\n\t\t\treturn `\n\t\t\t\t<li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#${file}\">${name.replace('.mjs', '')} (node.js)</a></li>\n\t\t\t`;\n\t\t} else {\n\t\t\tthrow new Error(`Unknown file-type found: ${file}`);\n\t\t}\n\t}\n\n\tif (game.files.length > 1) {\n\t\tconst entries = game.files.map(file => {\n\t\t\treturn creatFileLink(file);\n\t\t});\n\t\treturn `\n\t\t\t<li>\n\t\t\t\t<span>${game.name}</span>\n\t\t\t\t<ul>${entries.map(e => `\\t\\t\\t${e}`).join('\\n')}</ul>\n\t\t\t</li>\n\t\t`;\n\t} else {\n\t\treturn creatFileLink(game.files[0], game.name);\n\t}\n}\n\nfunction createIndexHtml(title, games) {\n\tconst listEntries = games.map(game => \n\t\tcreateGameLinks(game)\n\t).map(entry => `\\t\\t\\t${entry}`).join('\\n');\n\n\tconst head = `\n\t\t<head>\n\t\t\t<meta charset=\"UTF-8\">\n\t\t\t<title>${title}</title>\n\t\t\t<link rel=\"stylesheet\" href=\"./00_Utilities/javascript/style_terminal.css\" />\n\t\t</head>\n\t`;\n\n\tconst body = `\n\t\t<body>\n\t\t\t<article id=\"output\">\n\t\t\t\t<header>\n\t\t\t\t\t<h1>${title}</h1>\n\t\t\t\t</header>\n\t\t\t\t<main>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t${listEntries}\n\t\t\t\t\t</ul>\n\t\t\t\t</main>\n\t\t\t</article>\n\t\t</body>\n\t`;\n\n\treturn `\n\t\t<!DOCTYPE html>\n\t\t<html lang=\"en\">\n\t\t${head}\n\t\t${body}\n\t\t</html>\n\t`.trim().replace(/\\s\\s+/g, '');\n}\n\nfunction findJSFilesInFolder(folder) {\n\t// filter folders that do not include a subfolder called \"javascript\"\n\tconst hasJavascript = fs.existsSync(`${folder}/${JAVASCRIPT_FOLDER}`);\n\tif (!hasJavascript) {\n\t\tthrow new Error(`Game \"${folder}\" is missing a javascript folder`);\n\t}\n\n\t// get all files in the javascript folder\n\tconst files = fs.readdirSync(`${folder}/${JAVASCRIPT_FOLDER}`);\n\n\t// filter files only allow .html files\n\tconst htmlFiles = files.filter(file => file.endsWith('.html'));\n\tconst mjsFiles = files.filter(file => file.endsWith('.mjs'));\n\tconst entries = [\n\t\t...htmlFiles,\n\t\t...mjsFiles\n\t].filter(file => !IGNORE_FILES.includes(file));\n\n\tif (entries.length == 0) {\n\t\tthrow new Error(`Game \"${folder}\" is missing a HTML or node.js file in the folder \"${folder}/${JAVASCRIPT_FOLDER}\"`);\n\t}\n\n\treturn entries.map(file => path.join(folder, JAVASCRIPT_FOLDER, file));\n}\n\nfunction main() {\n\t// Get the list of all folders in the current director\n\tlet folders = fs.readdirSync(process.cwd());\n\n\t// filter files only allow folders\n\tfolders = folders.filter(folder => fs.statSync(folder).isDirectory());\n\n\t// filter out the folders that start with a dot or 00_\n\tfolders = folders.filter(folder => {\n\t\treturn !IGNORE_FOLDERS_START_WITH.some(ignore => folder.startsWith(ignore));\n\t});\n\n\t// sort the folders alphabetically (by number)\n\tfolders = folders.sort();\n\n\t// get name and javascript file from folder\n\tconst games = folders.map(folder => {\n\t\tconst name = folder.replace('_', ' ');\n\t\tlet files;\n\t\t\n\t\ttry {\n\t\t\tfiles = findJSFilesInFolder(folder);\n\t\t} catch (error) {\n\t\t\tconsole.warn(`Game \"${name}\" is missing a javascript implementation: ${error.message}`);\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\tname,\n\t\t\tfiles\n\t\t}\n\t}).filter(game => game !== null);\n\n\t// create a index.html file with a list of all games\n\tconst htmlContent = createIndexHtml(TITLE, games);\n\tfs.writeFileSync('index.html', htmlContent);\n\tconsole.log(`index.html successfully created!`);\n}\n\nmain();"
  },
  {
    "path": "00_Utilities/find-missing-implementations.js",
    "content": "/**\n * Program to find games that are missing solutions in a given language\n *\n * Scan each game folder, check for a folder for each language, and also make\n * sure there's at least one file of the expected extension and not just a\n * readme or something\n */\n\nconst fs = require(\"fs\");\nconst glob = require(\"glob\");\n\n// relative path to the repository root\nconst ROOT_PATH = \"../.\";\n\nconst languages = [\n  { name: \"csharp\", extension: \"cs\" },\n  { name: \"java\", extension: \"java\" },\n  { name: \"javascript\", extension: \"html\" },\n  { name: \"kotlin\", extension: \"kt\" },\n  { name: \"lua\", extension: \"lua\" },\n  { name: \"pascal\", extension: \"pas\" },\n  { name: \"perl\", extension: \"pl\" },\n  { name: \"python\", extension: \"py\" },\n  { name: \"ruby\", extension: \"rb\" },\n  { name: \"rust\", extension: \"rs\" },\n  { name: \"vbnet\", extension: \"vb\" },\n];\n\nconst getFilesRecursive = async (path, extension) => {\n  return new Promise((resolve, reject) => {\n    glob(`${path}/**/*.${extension}`, (err, matches) => {\n      if (err) {\n        reject(err);\n      }\n      resolve(matches);\n    });\n  });\n};\n\nconst getPuzzleFolders = () => {\n  return fs\n    .readdirSync(ROOT_PATH, { withFileTypes: true })\n    .filter((dirEntry) => dirEntry.isDirectory())\n    .filter(\n      (dirEntry) =>\n        ![\".git\", \"node_modules\", \"00_Utilities\"].includes(dirEntry.name)\n    )\n    .map((dirEntry) => dirEntry.name);\n};\n\n(async () => {\n  let missingGames = {};\n  let missingLanguageCounts = {};\n  languages.forEach((l) => (missingLanguageCounts[l.name] = 0));\n  const puzzles = getPuzzleFolders();\n  for (const puzzle of puzzles) {\n    for (const { name: language, extension } of languages) {\n      const files = await getFilesRecursive(\n        `${ROOT_PATH}/${puzzle}/${language}`,\n        extension\n      );\n      if (files.length === 0) {\n        if (!missingGames[puzzle]) missingGames[puzzle] = [];\n\n        missingGames[puzzle].push(language);\n        missingLanguageCounts[language]++;\n      }\n    }\n  }\n  const missingCount = Object.values(missingGames).flat().length;\n  if (missingCount === 0) {\n    console.log(\"All games have solutions for all languages\");\n  } else {\n    console.log(`Missing ${missingCount} implementations:`);\n\n    Object.entries(missingGames).forEach(\n      ([p, ls]) => (missingGames[p] = ls.join(\", \"))\n    );\n\n    console.log(`\\nMissing languages by game:`);\n    console.table(missingGames);\n    console.log(`\\nBy language:`);\n    console.table(missingLanguageCounts);\n  }\n})();\n\nreturn;\n"
  },
  {
    "path": "00_Utilities/find-unimplemented.js",
    "content": "/**\n * Program to show unimplemented games by language, optionally filtered by\n * language\n *\n * Usage: node find-unimplemented.js [[[lang1] lang2] ...]\n *\n * Adapted from find-missing-implementtion.js\n */\n\nconst fs = require(\"fs\");\nconst glob = require(\"glob\");\n\n// relative path to the repository root\nconst ROOT_PATH = \"../.\";\n\nlet languages = [\n  { name: \"csharp\", extension: \"cs\" },\n  { name: \"java\", extension: \"java\" },\n  { name: \"javascript\", extension: \"html\" },\n  { name: \"kotlin\", extension: \"kt\" },\n  { name: \"lua\", extension: \"lua\" },\n  { name: \"pascal\", extension: \"pas\" },\n  { name: \"perl\", extension: \"pl\" },\n  { name: \"python\", extension: \"py\" },\n  { name: \"ruby\", extension: \"rb\" },\n  { name: \"vbnet\", extension: \"vb\" },\n  { name: \"rust\", extension: \"rs\" },\n];\n\nconst getFilesRecursive = async (path, extension) => {\n  return new Promise((resolve, reject) => {\n    glob(`${path}/**/*.${extension}`, (err, matches) => {\n      if (err) {\n        reject(err);\n      }\n      resolve(matches);\n    });\n  });\n};\n\nconst getPuzzleFolders = () => {\n  return fs\n    .readdirSync(ROOT_PATH, { withFileTypes: true })\n    .filter((dirEntry) => dirEntry.isDirectory())\n    .filter(\n      (dirEntry) =>\n        ![\".git\", \"node_modules\", \"00_Utilities\", \"buildJvm\"].includes(dirEntry.name)\n    )\n    .map((dirEntry) => dirEntry.name);\n};\n\n(async () => {\n  const result = {};\n  if (process.argv.length > 2) {\n    languages = languages.filter((language) => process.argv.slice(2).includes(language.name));\n  }\n  for (const { name: language } of languages) {\n    result[language] = [];\n  }\n\n  const puzzleFolders = getPuzzleFolders();\n  for (const puzzleFolder of puzzleFolders) {\n    for (const { name: language, extension } of languages) {\n      const files = await getFilesRecursive(\n        `${ROOT_PATH}/${puzzleFolder}/${language}`, extension\n      );\n      if (files.length === 0) {\n        result[language].push(puzzleFolder);\n      }\n    }\n  }\n  console.log('Unimplementation by language:')\n  console.dir(result);\n})();\n\nreturn;\n"
  },
  {
    "path": "00_Utilities/javascript/style_terminal.css",
    "content": "/**\n * Old school terminal style\n *\n * @see https://codepen.io/cvan/pen/Zarmry\n * @see http://aleclownes.com/2017/02/01/crt-display.html\n */\n\n /* define the main color theme */\n:root {\n  --background: rgb(1, 24, 1);\n  --text: rgb(51, 251, 51);\n  --input: yellow;\n  --font: 600 1rem/1.3 Consolas, Andale Mono, monospace;\n}\n\n/* reset some styles */\n* {\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n}\nhtml {\n  font-size: 16px;\n}\n\nheader {\n  margin-bottom: 2rem;\n}\n\nbody {\n  background-color: var(--background);\n  color: var(--text);\n  font: var(--font);\n  margin: 0;\n}\n\n#output {\n  padding: 1rem;\n}\n\n/* format input fields */\n/* TODO: a simple blinking cursor would even better than this! */\ninput {\n  display: inline-block;\n  position: relative;\n  caret-color: var(--input);\n  background: none;\n  border: none;\n  outline: none;\n  border-bottom: 1px solid var(--input);\n  border-style: none none dashed none;\n  color: var(--input);\n  font: 900 1rem/1.3 Consolas, Andale Mono, monospace;\n  animation: textShadow 1.6s infinite;\n  text-transform: uppercase;\n}\n\n/* format the link list */\nul {\n  margin: 0;\n  list-style: none;\n}\nli {\n  margin: 0;\n}\n/* format the sub-lists */\nul > li > ul {\n  margin-left: 1.75rem;\n}\nul > li > ul > li::before {\n  content: \"├── \";\n}\nul > li > ul > li:last-child::before {\n  content: \"└── \";\n}\n\n/* overwrite the default (blue) link styles */\na, a:visited {\n  color: var(--text);\n  text-decoration: none;\n}\na:hover {\n  text-decoration: underline;\n}\n\n/* add all the face flicker effects (only on desktop) */\n@media not screen and (max-width: 960px) and (prefers-reduced-motion) {\n  main {\n    padding: 3rem;\n  }\n  #output::before {\n    content: \" \";\n    display: block;\n    position: fixed;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));\n    z-index: 2;\n    background-size: 100% 2px, 3px 100%;\n    pointer-events: none;\n  }\n  #output::after {\n    content: \" \";\n    display: block;\n    position: fixed;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    background: rgba(18, 16, 16, 0.1);\n    opacity: 0;\n    z-index: 2;\n    pointer-events: none;\n  }\n}"
  },
  {
    "path": "00_Utilities/jvmTestUtils/kotlin/test/ConsoleTest.kt",
    "content": "package com.pcholt.console.testutils\n\nimport com.google.common.truth.Truth\nimport org.junit.Rule\nimport org.junit.contrib.java.lang.system.SystemOutRule\nimport org.junit.contrib.java.lang.system.TextFromStandardInputStream\n\nabstract class ConsoleTest {\n    @get:Rule\n    val inputRule = TextFromStandardInputStream.emptyStandardInputStream()\n\n    @get:Rule\n    val systemOutRule = SystemOutRule().enableLog()\n\n    val regexInputCommand = \"\\\\{(.*)}\".toRegex()\n\n    fun assertConversation(conversation: String, runMain: () -> Unit) {\n\n        inputRule.provideLines(*regexInputCommand\n            .findAll(conversation)\n            .map { it.groupValues[1] }\n            .toList().toTypedArray())\n\n        runMain()\n\n        Truth.assertThat(\n            systemOutRule.log.trimWhiteSpace()\n        )\n            .isEqualTo(\n                regexInputCommand\n                    .replace(conversation, \"\").trimWhiteSpace()\n            )\n    }\n\n    private fun String.trimWhiteSpace() =\n        replace(\"[\\\\s]+\".toRegex(), \" \")\n}\n"
  },
  {
    "path": "00_Utilities/markdown_todo.py",
    "content": "import os\nfrom typing import Dict, List\n\n\ndef has_implementation(lang: str, file_list: List[str], subdir_list: List[str]) -> bool:\n    if lang == \"csharp\":\n        return any(file.endswith(\".cs\") for file in file_list)\n    elif lang == \"vbnet\":\n        return any(file.endswith(\".vb\") for file in file_list)\n    else:\n        return len(file_list) > 1 or len(subdir_list) > 0\n\n\ndef get_data(checklist_orig: List[str], root_dir: str = \"..\") -> List[List[str]]:\n    \"\"\"\n\n    Parameters\n    ----------\n    root_dir : str\n        The root directory you want to start from.\n    \"\"\"\n    lang_pos: Dict[str, int] = {\n        lang: i for i, lang in enumerate(checklist_orig[1:], start=1)\n    }\n    strings_done: List[List[str]] = []\n\n    ignore_folders = [\n        \".git\",\n        \"00_Utilities\",\n        \".github\",\n        \".mypy_cache\",\n        \".pytest_cache\",\n        \"00_Alternate_Languages\",\n        \"00_Common\",\n        \"buildJvm\",\n        \"htmlcov\",\n    ]\n\n    prev_game = \"\"\n\n    empty_boxes = [\"⬜️\" for _ in checklist_orig]\n    checklist = empty_boxes[:]\n\n    for dir_name, subdir_list, file_list in sorted(os.walk(root_dir)):\n        # split_dir[1] is the game\n        # split_dir[2] is the language\n        split_dir = dir_name.split(os.path.sep)\n\n        if len(split_dir) == 2 and split_dir[1] not in ignore_folders:\n            if prev_game == \"\":\n                prev_game = split_dir[1]\n                checklist[0] = f\"{split_dir[1]:<30}\"\n\n            if prev_game != split_dir[1]:\n                # it's a new dir\n                strings_done.append(checklist)\n                checklist = [\n                    f\"{f'[{split_dir[1]}](../{split_dir[1]})':<30}\",\n                ] + empty_boxes[1:]\n                prev_game = split_dir[1]\n        elif (\n            len(split_dir) == 3 and split_dir[1] != \".git\" and split_dir[2] in lang_pos\n        ):\n            out = (\n                \"✅\"\n                if has_implementation(split_dir[2], file_list, subdir_list)\n                else \"⬜️\"\n            )\n            if split_dir[2] not in lang_pos or lang_pos[split_dir[2]] >= len(checklist):\n                print(f\"Could not find {split_dir[2]}: {dir_name}\")\n                checklist[lang_pos[split_dir[2]]] = \"⬜️\"\n                continue\n            checklist[lang_pos[split_dir[2]]] = out\n    return strings_done\n\n\ndef write_file(path: str, languages: List[str], strings_done: List[List[str]]) -> None:\n    dashes_arr = [\"---\"] * (len(languages) + 1)\n    dashes_arr[0] = \"-\" * 30\n    dashes = \" | \".join(dashes_arr)\n    write_string = f\"# TODO list\\n {'game':<30}| {' | '.join(languages)}\\n{dashes}\\n\"\n    sorted_strings = list(\n        map(lambda l: \" | \".join(l) + \"\\n\", sorted(strings_done, key=lambda x: x[0]))\n    )\n    write_string += \"\".join(sorted_strings)\n    write_string += f\"{dashes}\\n\"\n    language_indices = range(1, len(languages) + 1)\n    nb_games = len(strings_done)\n    write_string += (\n        f\"{f'Sum of {nb_games}':<30} | \"\n        + \" | \".join(\n            [\n                f\"{sum(row[lang] == '✅' for row in strings_done)}\"\n                for lang in language_indices\n            ]\n        )\n        + \"\\n\"\n    )\n\n    with open(path, \"w\", encoding=\"utf-8\") as f:\n        f.write(write_string)\n\n\nif __name__ == \"__main__\":\n    languages = {\n        \"csharp\": \"C#\",\n        \"java\": \"Java\",\n        \"javascript\": \"JS\",\n        \"kotlin\": \"Kotlin\",\n        \"lua\": \"Lua\",\n        \"perl\": \"Perl\",\n        \"python\": \"Python\",\n        \"ruby\": \"Ruby\",\n        \"rust\": \"Rust\",\n        \"vbnet\": \"VB.NET\",\n    }\n    strings_done = get_data([\"game\"] + list(languages.keys()))\n    write_file(\"TODO.md\", list(languages.values()), strings_done)\n"
  },
  {
    "path": "00_Utilities/markdown_todo_rust/Cargo.toml",
    "content": "[package]\nname = \"markdown_todo_rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "00_Utilities/markdown_todo_rust/src/main.rs",
    "content": "use std::ffi::OsStr;\nuse std::{fs, io};\nuse std::fs::metadata;\nuse std::path::{Path, PathBuf};\n/**\n * todo list generator for this repository, coded in rust\n *\n * @author Anthony Rubick\n */\n\n//DATA\nconst ROOT_DIR: &str = \"../../\";\nconst LANGUAGES: [(&str,&str); 10] = [ //first element of tuple is the language name, second element is the file extension\n    (\"csharp\", \"cs\"),\n    (\"java\", \"java\"),\n    (\"javascript\", \"html\"),\n    (\"kotlin\", \"kt\"),\n    (\"lua\", \"lua\"),\n    (\"perl\", \"pl\"),\n    (\"python\", \"py\"),\n    (\"ruby\", \"rb\"),\n    (\"rust\", \"rs\"),\n    (\"vbnet\", \"vb\")\n];\nconst OUTPUT_PATH: &str = \"../../todo.md\";\n\nfn main() {\n    //DATA\n    let mut root_folders:Vec<PathBuf>;\n    let mut output_string: String = String::new();\n    let format_game_first: bool;\n    let ingore: [PathBuf;5] = [\n        PathBuf::from(r\"../../.git\"),\n        PathBuf::from(r\"../../.github\"),\n        PathBuf::from(r\"../../00_Alternate_Languages\"),\n        PathBuf::from(r\"../../00_Utilities\"),\n        PathBuf::from(r\"../../00_Common\"),\n    ]; //folders to ignore\n\n    //print welcome message\n    println!(\"\n                             Markdown TODO list maker\n               by Anthony Rubick for the basic-computer-games repo\n\n\n    \");\n\n\n    //ask user how they want the todo list formatted\n    format_game_first = get_yn_from_user(\"\\n\\t---====FORMATS====---\\ngame first:\\n\\tGame\\n\\t\\tLanguage ✅/⬜️\\n\\nlang first:\\n\\tLanguage\\n\\t\\tGame ✅/⬜️\\n\\nmake todo list using the game first format? (y/n | default No) \");\n\n    //get all folders in ROOT_DIR\n    root_folders = Vec::new();\n    match fs::read_dir(ROOT_DIR) {\n        Err(why) => {\n            println!(\"! {:?}\", why.kind());\n            panic!(\"error\");\n        },\n        Ok(paths) => {\n            for path in paths {\n                let full_path = path.unwrap().path();\n                if metadata(&full_path).unwrap().is_dir() {\n                    root_folders.push(full_path);\n                }\n            }\n        },\n    }\n\n    //for i in root_folders {println!(\"> {:?}\", &i);}\n\n    //for all folders, search for the languages and extensions\n    root_folders = root_folders.into_iter().filter(|path| {\n        //not one of the ignored folders\n        !ingore.contains(path)\n    }).collect();\n    root_folders.sort();\n\n    //create todo list\n    if format_game_first {\n        //being forming output string\n        // for every game\n        //      every language + ✅/⬜️\n        for g in root_folders.into_iter() {\n            //DATA\n            let mut num_done:u8 = 0; //number of languages implemented\n            let mut total:u8 = 0; //number of languages\n\n            let game = g.clone().into_os_string().into_string().unwrap().chars().filter(|c| !(*c=='.' || *c=='/')).collect::<String>();//get the game name\n\n\n            //find all the lanuages the game is coded in\n            let languages_list_for_game = {\n                let mut s:String = String::new();\n                //every language + ✅/⬜️\n                LANGUAGES.iter().for_each(|lang| {\n                    s+=\"- \";\n                    s += lang.0;\n                    // + ✅/⬜️\n                    let paths:Vec<_> = list_files(&g).into_iter().map(|path| path.into_os_string().into_string().unwrap()).collect();\n                    let paths:Vec<String> = paths.into_iter().filter_map(|s| {\n                        match  Path::new(s.as_str()).extension().and_then(OsStr::to_str) {\n                            None => None,\n                            Some(s) => Some(s.to_string()),\n                        }\n                    }).collect(); //get all the extensions\n                    if paths.into_iter().any(|f| f.eq(lang.1)) {//list_files(&game).iter().map(|path| path.into_os_string().into_string().unwrap()).any(|s| LANGUAGES.iter().map(|tup| Some(tup.1)).collect::<Vec<_>>().contains(&s.split('.').next())) {\n                        s+=\"✅\";\n                        num_done += 1; //increment number done\n                    } else {\n                        s += \"⬜️\";  \n                    }\n                    total += 1; //increment total\n\n                    s += \"\\n\";\n                });\n                s\n            };\n\n            //format message\n            output_string += format!(\n                \"### {}\\t{}\\n\\n{}\\n\", //message format\n                game,\n                format!(\"coded in {}/{} languages\", num_done, total),\n                languages_list_for_game,\n            ).as_str();\n        }\n\n        //print the whole list\n        println!(\"\\n\\n{}\", output_string);\n    }\n    else {\n        //figure out what langauges the user wants printed\n\n        //print language - extension table\n        println!(\"\\n\\t---====LANGUAGES TO PRINT====---\\na complete todo list will be output to todo-list.md\\n\");\n        print_lang_extension_table();\n\n        //prompt user to input the file extensions of the languages they want the todo-lists for printed to console\n        //parse input for valid languages, store them in langs_to_print\n        let langs_to_print = get_str_from_user(\"\\nenter the file extensions, from the table above,\\nfor the languages you want printed to standard output\\nFile extensions: (separated by spaces)\")\n        .chars().filter(|c| c.is_ascii_alphabetic() || c.is_whitespace()).collect::<String>();//filter out everything but ascii letters and spaces\n        let langs_to_print: Vec<_> = langs_to_print.split(' ')//create an iterator with all the words\n        .filter(|s| LANGUAGES.iter().any(|tup| tup.1.eq_ignore_ascii_case(*s))) //filter out words that aren't valid extensions (in languages)\n        .collect(); //collect words into vector\n        println!(\"\\nwill print: {:#?}\\n\\n\", langs_to_print);\n\n\n        //being forming output string\n        // for every language\n        //      every game + ✅/⬜️\n        for lang in LANGUAGES.iter() {\n            //DATA\n            let mut num_done = 0;\n            let mut total = 0;\n            let games_list_for_language = { //list\n                //DATA\n                let mut s:String = String::new();\n\n                //go through every game and check if it's coded in the language\n                for g in (&root_folders).into_iter() {\n                    //data\n                    let game = g.clone();\n                    let game_name = game.into_os_string().into_string().unwrap().chars().filter(|c| !(*c=='.' || *c=='/')).collect::<String>(); //get the game name\n                    let paths:Vec<_> = list_files(g).into_iter().map(|path| path.into_os_string().into_string().unwrap()).collect(); //all subpaths of game\n                    let paths:Vec<String> = paths.into_iter().filter_map(|s| {\n                        match  Path::new(s.as_str()).extension().and_then(OsStr::to_str) {\n                            None => None,\n                            Some(s) => Some(s.to_string()),\n                        }\n                    }).collect(); //get all the extensions\n\n                    //add game name\n                    s+=\"- \";\n                    s+= game_name.as_str();\n\n                    //every game + ✅/⬜️\n                    if paths.into_iter().any(|f| f.eq(lang.1)) {\n                        s+=\"✅\";\n                        num_done += 1; //increment num done\n                    } else {\n                        s += \"⬜️\";\n                    }\n                    total += 1; //increment total\n                    \n                    //new line\n                    s += \"\\n\";\n                }\n\n                //print desired languages only, what's output to std_out, also not markdown formatted\n                if langs_to_print.contains(&lang.1) {\n                    print!(\"###  {}\\t{}  ###\\n{}\\n\\n\", lang.0, format!(\"{}/{} games ported\", num_done, total), s);\n                }\n                s\n            };\n\n            //format message, what's output to the file\n            output_string += format!(\n                \"### {}\\t{}\\n\\n{}\\n\\n\", //message format\n                lang.0, //language\n                format!(\"{}/{} games ported\", num_done, total),//number done / total number\n                games_list_for_language,\n            ).as_str();\n        }\n    }\n\n    //write output to file\n    fs::write(OUTPUT_PATH, output_string).expect(\"failed to write todo list\");\n}\n\n/**\n * print language - extension table\n */\nfn print_lang_extension_table() {\n    println!(\"LANGUAGE\\tFILE EXTENSION\");\n    println!(\"========\\t==============\");\n    for tup in LANGUAGES.iter() {\n        match tup.0 {\n            \"javascript\" => println!(\"{}\\t{}\", tup.0,tup.1), //long ones\n            _ => println!(\"{}\\t\\t{}\", tup.0,tup.1),\n        };\n    }\n}\n\n/**\n * gets a string from user input\n */\nfn get_str_from_user(prompt:&str) -> String {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    println!(\"{}\",prompt);\n\n    //get input and trim whitespaces\n    io::stdin().read_line(&mut raw_input).expect(\"Failed to read input\");\n\n    //return raw input\n    return raw_input.trim().to_string();\n}\n/**\n * gets a boolean from user\n */\nfn get_yn_from_user(prompt:&str) -> bool {\n    //DATA\n    let input = get_str_from_user(prompt);\n\n    //default in case of error\n    if input.is_empty() {return false;}\n\n    //get and parse input\n    match &input[0..1] { //get first character\n        \"y\" | \"Y\" => return true,\n        _ => return false,\n    }\n}\n\n/**\n * returns a vector containing paths to all files in path and subdirectories of path\n */\nfn list_files(path: &Path) -> Vec<PathBuf> {\n    let mut vec = Vec::new();\n    _list_files(&mut vec,&path);\n    vec\n}\nfn _list_files(vec: &mut Vec<PathBuf>, path: &Path) {\n    if metadata(&path).unwrap().is_dir() {\n        let paths = fs::read_dir(&path).unwrap();\n        for path_result in paths {\n            let full_path = path_result.unwrap().path();\n            if metadata(&full_path).unwrap().is_dir() {\n                _list_files(vec, &full_path);\n            } else {\n                vec.push(full_path);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "00_Utilities/python/ci-requirements.in",
    "content": "flake8\nflake8-bugbear\nflake8-comprehensions\nflake8_implicit_str_concat\nmypy\n"
  },
  {
    "path": "00_Utilities/python/ci-requirements.txt",
    "content": "#\n# This file is autogenerated by pip-compile with python 3.10\n# To update, run:\n#\n#    pip-compile ci-requirements.in\n#\nattrs==20.3.0\n    # via\n    #   flake8-bugbear\n    #   flake8-implicit-str-concat\nflake8==4.0.1\n    # via\n    #   -r ci-requirements.in\n    #   flake8-bugbear\n    #   flake8-comprehensions\nflake8-bugbear==22.1.11\n    # via -r ci-requirements.in\nflake8-comprehensions==3.8.0\n    # via -r ci-requirements.in\nflake8-implicit-str-concat==0.2.0\n    # via -r ci-requirements.in\nmccabe==0.6.1\n    # via flake8\nmore-itertools==8.12.0\n    # via flake8-implicit-str-concat\nmypy==0.931\n    # via -r ci-requirements.in\nmypy-extensions==0.4.3\n    # via mypy\npycodestyle==2.8.0\n    # via flake8\npyflakes==2.4.0\n    # via flake8\ntomli==2.0.1\n    # via mypy\ntyping-extensions==4.1.1\n    # via mypy\n"
  },
  {
    "path": "00_Utilities/yatol.pl",
    "content": "#!/usr/bin/perl\n#YATOL: Yet Another TOdo List\nuse strict;\n\n#REM: Get list of basic files ordered by number of lines.\n#REM: This way you can do the easier ones first.\nmy @Ret=`find .. -iname '*.bas' -exec wc -l \\{\\} \\\\; | sort -h`;\n\n\nmy @Langs= qw(PL JS VB PAS RB C# JAVA PY);\nmy @Dirs= qw(perl javascript vbnet pascal ruby csharp java python);\nmy %Sum;\n\nmy $Row=25;\nmy $Tab=7;\n\nprintf(\"%-$Row\\s\", \"PATH\");\nprintf(\"%$Tab\\s\", \"BAS\");\n\nforeach my $Dir (@Langs) {\n\tprintf(\"%$Tab\\s\", $Dir);\n\t}\nprint \"\\n\";\n\nmy $Count;\nforeach my $Lin (@Ret) {\n\t$Count++;\n\tchomp $Lin;\n\tmy ($Num, $File)= split (\" \", $Lin);\n\tmy @Parts= split(/\\//, $File);\n\tmy $Base= $Parts[1];\n\n\tprintf(\"%-$Row\\s\", $Base);\n\tprintf(\"%$Tab\\s\", \"$Num\");\n\n\tforeach my $Dir (@Dirs) {\n\t\tmy $Path= \"../$Base/$Dir/\";\n\t\tmy $Ret= `ls $Path | wc -l`;\n\t\tif ($Ret>1) { printf(\"%$Tab\\s\", \"YES\"); $Sum{$Dir}++; }\n\t\t\telse { printf(\"%$Tab\\s\", \" \");}\n\t\t}\n\tprint \"\\n\";\n\t}\n\n\nprintf(\"%$Row\\s\", \"FILES:\");\nprintf(\"%$Tab\\s\", \" \");\nforeach my $Dir (@Dirs) {\n\tprintf(\"%$Tab\\s\", \"$Sum{$Dir}\");\n\t}\nprint \"\\n\";\n\nprintf(\"%$Row\\s\", \"ADVANCE:\");\nprintf(\"%$Tab\\s\", \" \");\nforeach my $Dir (@Dirs) {\n\tmy $Per= int($Sum{$Dir}/$Count*100).\"%\";\n\tprintf(\"%$Tab\\s\", \"$Per\");\n\t}\nprint \"\\n\";\n"
  },
  {
    "path": "01_Acey_Ducey/README.md",
    "content": "### Acey Ducey\n\nThis is a simulation of the Acey Ducey card game. In the game, the dealer (the computer) deals two cards face up. You have an option to bet or not to bet depending on whether or not you feel the next card dealt will have a value between the first two.\n\nYour initial money is set to $100; you may want to alter this value if you want to start with more or less than $100. The game keeps going on until you lose all your money or interrupt the program.\n\nThe original program author was Bill Palmby of Prairie View, Illinois.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=2)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=17)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- Entering a negative bet allows you to gain arbitrarily large amounts of money upon losing the round.\n\n#### Porting Notes\n\n- The assignment `N = 100` in line 100 has no effect; variable `N` is not used anywhere else in the program.\n\n#### External Links\n - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp\n - PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1\n"
  },
  {
    "path": "01_Acey_Ducey/aceyducey.bas",
    "content": "10 PRINT TAB(26);\"ACEY DUCEY CARD GAME\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n21 PRINT\n22 PRINT\n30 PRINT\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \"\n40 PRINT\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\"\n50 PRINT\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\"\n60 PRINT\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\"\n70 PRINT\"A VALUE BETWEEN THE FIRST TWO.\"\n80 PRINT\"IF YOU DO NOT WANT TO BET, INPUT A 0\"\n100 N=100\n110 Q=100\n120 PRINT \"YOU NOW HAVE \";Q;\" DOLLARS.\"\n130 PRINT\n140 GOTO 260\n210 Q=Q+M\n220 GOTO 120\n240 Q=Q-M\n250 GOTO 120\n260 PRINT\"HERE ARE YOUR NEXT TWO CARDS: \"\n270 A=INT(14*RND(1))+2\n280 IF A<2 THEN 270\n290 IF A>14 THEN 270\n300 B=INT(14*RND(1))+2\n310 IF B<2 THEN 300\n320 IF B>14 THEN 300\n330 IF A>=B THEN 270\n350 IF A<11 THEN 400\n360 IF A=11 THEN 420\n370 IF A=12 THEN 440\n380 IF A=13 THEN 460\n390 IF A=14 THEN 480\n400 PRINT A\n410 GOTO 500\n420 PRINT\"JACK\"\n430 GOTO 500\n440 PRINT\"QUEEN\"\n450 GOTO 500\n460 PRINT\"KING\"\n470 GOTO 500\n480 PRINT\"ACE\"\n500 IF B<11 THEN 550\n510 IF B=11 THEN 570\n520 IF B=12 THEN 590\n530 IF B=13 THEN 610\n540 IF B=14 THEN 630\n550 PRINT B\n560 GOTO 650\n570 PRINT\"JACK\"\n580 GOTO 650\n590 PRINT\"QUEEN\"\n600 GOTO 650\n610 PRINT\"KING\"\n620 GOTO 650\n630 PRINT\"ACE\"\n640 PRINT\n650 PRINT\n660 INPUT\"WHAT IS YOUR BET\";M\n670 IF M<>0 THEN 680\n675 PRINT\"CHICKEN!!\"\n676 PRINT\n677 GOTO 260\n680 IF M<=Q THEN 730\n690 PRINT\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\"\n700 PRINT\"YOU HAVE ONLY \";Q;\" DOLLARS TO BET.\"\n710 GOTO 650\n730 C=INT(14*RND(1))+2\n740 IF C<2 THEN 730\n750 IF C>14 THEN 730\n760 IF C<11 THEN 810\n770 IF C=11 THEN 830\n780 IF C=12 THEN 850\n790 IF C=13 THEN 870\n800 IF C=14 THEN 890\n810 PRINT C\n820 GOTO 910\n830 PRINT\"JACK\"\n840 GOTO 910\n850 PRINT\"QUEEN\"\n860 GOTO 910\n870 PRINT\"KING\"\n880 GOTO 910\n890 PRINT \"ACE\"\n900 PRINT\n910 IF C>A THEN 930\n920 GOTO 970\n930 IF C>=B THEN 970\n950 PRINT\"YOU WIN!!!\"\n960 GOTO 210\n970 PRINT\"SORRY, YOU LOSE\"\n980 IF M<Q THEN 240\n990 PRINT\n1000 PRINT\n1010 PRINT\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\"\n1015 PRINT:PRINT\n1020 INPUT\"TRY AGAIN (YES OR NO)\";A$\n1025 PRINT:PRINT\n1030 IF A$=\"YES\" THEN 110\n1040 PRINT\"O.K., HOPE YOU HAD FUN!\"\n1050 END\n"
  },
  {
    "path": "01_Acey_Ducey/csharp/AceyDucey.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "01_Acey_Ducey/csharp/AceyDucey.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30709.132\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"AceyDucey\", \"AceyDucey.csproj\", \"{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A8FE2F04-3DFE-4254-BD5B-281DC8E30B1C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {F620B340-EB7A-48C1-B12F-9D3D94AE7771}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "01_Acey_Ducey/csharp/Game.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace AceyDucey\n{\n    /// <summary>\n    /// The main class that implements all the game logic\n    /// </summary>\n    internal class Game\n    {\n        /// <summary>\n        /// Our Random number generator object\n        /// </summary>\n        private Random Rnd { get; } = new Random();\n\n        /// <summary>\n        /// A line of underscores that we'll print between turns to separate them from one another on screen\n        /// </summary>\n        private string SeparatorLine { get; } = new string('_', 70);\n\n\n        /// <summary>\n        /// Main game loop function. This will play the game endlessly until the player chooses to quit.\n        /// </summary>\n        internal void GameLoop()\n        {\n            // First display instructions to the player\n            DisplayIntroText();\n\n            // We'll loop for each game until the player decides not to continue\n            do\n            {\n                // Play a game!\n                PlayGame();\n\n                // Play again?\n            } while (TryAgain());\n        }\n\n        /// <summary>\n        /// Play the game\n        /// </summary>\n        private void PlayGame()\n        {\n            GameState state = new GameState();\n\n            // Clear the display\n            Console.Clear();\n            // Keep looping until the player has no money left\n            do\n            {\n                // Play the next turn. Pass in our state object so the turn can see the money available,\n                // can update it after the player makes a bet, and can update the turn count.\n                PlayTurn(state);\n\n                // Keep looping until the player runs out of money\n            } while (state.Money > 0);\n\n            // Looks like the player is bankrupt, let them know how they did.\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n            Console.WriteLine($\"Sorry, friend, but you blew your wad. Your game is over after {state.TurnCount} {(state.TurnCount == 1 ? \"turn\" : \"turns\")}. Your highest balance was ${state.MaxMoney}.\");\n        }\n\n\n        /// <summary>\n        /// Play a turn\n        /// </summary>\n        /// <param name=\"state\">The current game state</param>\n        private void PlayTurn(GameState state)\n        {\n            // Let the player know what's happening\n            Console.WriteLine(\"\");\n            Console.WriteLine(SeparatorLine);\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"Here are your next two cards:\");\n\n            // Generate two random cards\n            int firstCard = GetCard();\n            int secondCard = GetCard();\n\n            // If the second card is lower than the first card, swap them over\n            if (secondCard < firstCard)\n            {\n                (firstCard, secondCard) = (secondCard, firstCard);\n            }\n\n            // Display the cards\n            DisplayCard(firstCard);\n            DisplayCard(secondCard);\n\n            // Ask the player what they want to do\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n            Console.Write(\"You currently have \");\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.Write($\"${state.Money}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\". How much would you like to bet?\");\n\n            // Read the bet amount\n            int betAmount = PlayTurn_GetBetAmount(state.Money);\n\n            // Display a summary of their inpout\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"\");\n            Console.WriteLine($\"You choose to {(betAmount == 0 ? \"pass\" : $\"bet {betAmount}\")}.\");\n\n            // Generate and display the final card\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"The next card is:\");\n\n            int thirdCard = GetCard();\n            DisplayCard(thirdCard);\n            Console.WriteLine(\"\");\n\n            // Was the third card between the first two cards?\n            if (thirdCard > firstCard && thirdCard < secondCard)\n            {\n                // It was! Inform the player and add to their money\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.WriteLine(\"You win!\");\n                if (betAmount == 0)\n                {\n                    Console.WriteLine(\"(It's just a shame you chose not to bet!)\");\n                }\n                else\n                {\n                    state.Money += betAmount;\n                    // If their money exceeds the MaxMoney, update that too\n                    state.MaxMoney = Math.Max(state.Money, state.MaxMoney);\n                }\n            }\n            else\n            {\n                // Oh dear, the player lost. Let them know the bad news and take their bet from their money\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.WriteLine(\"You lose!\");\n                if (betAmount == 0)\n                {\n                    Console.WriteLine(\"(It's lucky you chose not to bet!)\");\n                }\n                else\n                {\n                    state.Money -= betAmount;\n                }\n            }\n\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write(\"You now have \");\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.Write($\"${state.Money}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\".\");\n\n            // Update the turn count now that another turn has been played\n            state.TurnCount += 1;\n\n            // Ready for the next turn...\n            Console.ForegroundColor = ConsoleColor.DarkGreen;\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"Press any key to continue...\");\n            Console.ReadKey(true);\n        }\n\n        /// <summary>\n        /// Prompt the user for their bet amount and validate their input\n        /// </summary>\n        /// <param name=\"currentMoney\">The player's current money</param>\n        /// <returns>Returns the amount the player chooses to bet</returns>\n        private int PlayTurn_GetBetAmount(int currentMoney)\n        {\n            int betAmount;\n            // Loop until the user enters a valid value\n            do\n            {\n                // Move this to a separate function...\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.Write(\"> $\");\n                string input = Console.ReadLine();\n\n                // Is this a valid number?\n                if (!int.TryParse(input, out betAmount))\n                {\n                    // No\n                    Console.ForegroundColor = ConsoleColor.Red;\n                    Console.WriteLine(\"Sorry, I didn't understand. Please enter how much you would like to bet.\");\n                    // Continue looping\n                    continue;\n                }\n\n                // If the amount between 0 and their available money?\n                if (betAmount < 0 || betAmount > currentMoney)\n                {\n                    // No\n                    Console.ForegroundColor = ConsoleColor.Red;\n                    Console.WriteLine($\"Please enter a bet amount between $0 and ${currentMoney}.\");\n                    // Continue looping\n                    continue;\n                }\n\n                // We have a valid bet, stop looping\n                break;\n            } while (true);\n\n            // Return whatever the player entered\n            return betAmount;\n        }\n\n        /// <summary>\n        /// Generate a new random card.\n        /// </summary>\n        /// <returns>Will return a value between 2 and 14, inclusive.</returns>\n        /// <remarks>Values 2 to 10 are their face values. 11 represents a Jack, 12 is a Queen, 13 a King and 14 an Ace.\n        /// Even though this is a slightly offset sequence, it allows us to perform a simple greater-than/less-than\n        /// comparison with the card values, treating an Ace as a high card.</remarks>\n        private int GetCard()\n        {\n            return Rnd.Next(2, 15);\n        }\n\n        /// <summary>\n        /// Display the card number on screen, translating values 11 through to 14 into their named equivalents.\n        /// </summary>\n        /// <param name=\"card\"></param>\n        private void DisplayCard(int card)\n        {\n            string cardText;\n            switch (card)\n            {\n                case 11:\n                    cardText = \"Jack\";\n                    break;\n                case 12:\n                    cardText = \"Queen\";\n                    break;\n                case 13:\n                    cardText = \"King\";\n                    break;\n                case 14:\n                    cardText = \"Ace\";\n                    break;\n                default:\n                    cardText = card.ToString();\n                    break;\n            }\n\n            // Format as black text on a white background\n            Console.Write(\"   \");\n            Console.BackgroundColor = ConsoleColor.White;\n            Console.ForegroundColor = ConsoleColor.Black;\n            Console.Write($\"  {cardText}  \");\n            Console.BackgroundColor = ConsoleColor.Black;\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n        }\n\n        /// <summary>\n        /// Display instructions on how to play the game and wait for the player to press a key.\n        /// </summary>\n        private void DisplayIntroText()\n        {\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"Acey Ducey Gard Game.\");\n            Console.WriteLine(\"Creating Computing, Morristown, New Jersey.\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.DarkGreen;\n            Console.WriteLine(\"Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.\");\n            Console.WriteLine(\"Modernised and converted to C# in 2021 by Adam Dawes (@AdamDawes575).\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.Gray;\n            Console.WriteLine(\"Acey Ducey is played in the following manner:\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"The dealer (computer) deals two cards, face up.\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"You have an option to bet or pass, depending on whether or not you feel the next card will have a value between the\");\n            Console.WriteLine(\"first two.\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"If the card is between, you will win your stake, otherwise you will lose it. Ace is 'high' (higher than a King).\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"If you want to pass, enter a bet amount of $0.\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"Press any key start the game.\");\n            Console.ReadKey(true);\n\n        }\n\n        /// <summary>\n        /// Prompt the player to try again, and wait for them to press Y or N.\n        /// </summary>\n        /// <returns>Returns true if the player wants to try again, false if they have finished playing.</returns>\n        private bool TryAgain()\n        {\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"Would you like to try again? (Press 'Y' for yes or 'N' for no)\");\n\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.Write(\"> \");\n\n            char pressedKey;\n            // Keep looping until we get a recognised input\n            do\n            {\n                // Read a key, don't display it on screen\n                ConsoleKeyInfo key = Console.ReadKey(true);\n                // Convert to upper-case so we don't need to care about capitalisation\n                pressedKey = Char.ToUpper(key.KeyChar);\n                // Is this a key we recognise? If not, keep looping\n            } while (pressedKey != 'Y' && pressedKey != 'N');\n            // Display the result on the screen\n            Console.WriteLine(pressedKey);\n\n            // Return true if the player pressed 'Y', false for anything else.\n            return (pressedKey == 'Y');\n        }\n\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/csharp/GameState.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace AceyDucey\n{\n    /// <summary>\n    /// The GameState class keeps track of all the game variables while the game is being played\n    /// </summary>\n    internal class GameState\n    {\n\n        /// <summary>\n        /// How much money does the player have at the moment?\n        /// </summary>\n        internal int Money { get; set; }\n\n        /// <summary>\n        /// What's the highest amount of money they had at any point in the game?\n        /// </summary>\n        internal int MaxMoney { get; set; }\n\n        /// <summary>\n        /// How many turns have they played?\n        /// </summary>\n        internal int TurnCount { get; set; }\n\n        /// <summary>\n        /// Class constructor -- initialise all values to their defaults.\n        /// </summary>\n        internal GameState()\n        {\n            // Setting Money to 100 gives the player their starting balance. Changing this will alter how much they have to begin with.\n            Money = 100;\n            MaxMoney = Money;\n            TurnCount = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Threading;\n\nnamespace AceyDucey\n{\n    /// <summary>\n    /// The application's entry point\n    /// </summary>\n    class Program\n    {\n\n        /// <summary>\n        /// This function will be called automatically when the application begins\n        /// </summary>\n        /// <param name=\"args\"></param>\n        static void Main(string[] args)\n        {\n            // Create an instance of our main Game class\n            Game game = new Game();\n\n            // Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.\n            game.GameLoop();\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) by Adam Dawes (@AdamDawes575, https://adamdawes.com).\n"
  },
  {
    "path": "01_Acey_Ducey/elixir/acey_ducey.exs",
    "content": "########################################################\n#\n# Acey Ducey\n#\n# From: BASIC Computer Games (1978)\n#       Edited by David Ahl\n#\n# \"This is a simulation of the Acey Ducey card game.\n#  In the game, the dealer (the computer) deals two\n#  cards face up.  You have an option to bet or not to\n#  bet depending on whether or not you feel the next\n#  card dealt will have a value between the first two.\n#\n# \"Your initial money is set to $100. The game keeps\n#  going on until you lose all your money or interrupt\n#  the program.\n#\n# \"The original BASIC program author was Bill Palmby\n#  of Prairie View, Illinois.\"\n#\n# To run this file:\n# > mix run acey_ducey.exs --no-mix-exs\n#\n# This uses the following techniques:\n#\n#  - The `Game` module uses a recursive `play/1` function.\n#  - The `Game` module stores the game state in a `%Game{}` struct.\n#  - The classic 52 playing card deck is set as a module attribute generated via a comprehension.\n#  - The deck is automatically shuffled when there are less than 3 cards remaining in the deck.\n#  - The initial deck defaults to an empty list which triggers a shuffle when the game begins.\n#  - The initial funds defaults to 100 but it can be explicitly set in the `%Game{}` struct.\n#  - The prompt to place a bet will automatically re-prompt when given an invalid input.\n#  - The bets are assumed to be the whole integers for simplicity.\n#\n########################################################\n\ndefmodule Game do\n  @deck for suit <- [:spades, :hearts, :clubs, :diamonds], value <- 1..13, do: {suit, value}\n\n  defstruct funds: 100, deck: []\n\n  def play(), do: play(%__MODULE__{}) # for convenience\n\n  def play(%__MODULE__{funds: funds}) when funds <= 0, do: IO.puts(\"~~~ game over ~~~\")\n  def play(%__MODULE__{deck: deck} = game) when length(deck) < 3, do: play(%{game | deck: Enum.shuffle(@deck)})\n  def play(%__MODULE__{deck: deck, funds: funds} = game) do\n    IO.gets(\"<hit enter>\\n\")\n\n    [first_card, second_card, third_card | remaining_deck] = deck\n\n    IO.puts(\"~~~ new round ~~~\")\n    IO.puts(\"first card: #{format(first_card)}\")\n    IO.puts(\"second card: #{format(second_card)}\\n\")\n    IO.puts(\"funds: $#{funds}\")\n\n    bet = prompt_to_place_bet(funds)\n    new_funds = if win?(first_card, second_card, third_card), do: funds + bet, else: funds - bet\n\n    IO.puts(\"\\nthird card: #{format(third_card)}\")\n    IO.puts(\"funds: $#{funds} => $#{new_funds}\")\n    IO.puts(\"~~~ end round ~~~\\n\")\n\n    play(%{game | deck: remaining_deck, funds: new_funds})\n  end\n\n  # re-prompt if invalid integer and/or out of bounds\n  defp prompt_to_place_bet(funds) do\n    input = IO.gets(\"place your bet: $\")\n    case Integer.parse(input) do\n      {bet, _} when bet in 0..funds -> bet\n      _ -> prompt_to_place_bet(funds)\n    end\n  end\n\n  # for a stricter win condition (non-inclusive)\n  defp win?({_, first}, {_, second}, {_, third}) do\n    [floor, ceiling] = Enum.sort([first, second])\n    (floor < third) && (third < ceiling)\n  end\n  # for a looser win condition (inclusive)\n  #defp win?({_, first}, {_, second}, {_, third}) do\n    #[_, middle, _] = Enum.sort([first, second, third])\n    #middle == third\n  #end\n\n  defp format({suit, value}) do\n    case value do\n      1 -> \"ace of #{suit}\"\n      11 -> \"prince of #{suit}\"\n      12 -> \"queen of #{suit}\"\n      13 -> \"king of #{suit}\"\n      value -> \"#{value} of #{suit}\"\n    end\n  end\nend\n\nGame.play() # equivalent to Game.play(%Game{funds: 100, deck: 100})\n"
  },
  {
    "path": "01_Acey_Ducey/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n\nTwo versions of Acey Ducey have been contributed.\n\nThe original upload supported JDK 8/JDK 11 and uses multiple files and the second uses features in JDK 17 and is implemented in a single file AceyDucey17.java.\n\nBoth are in the src folder.\n"
  },
  {
    "path": "01_Acey_Ducey/java/src/AceyDucey.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of AceyDucey\n * <p>\n * Based on the Basic game of AceyDucey here\n * https://github.com/coding-horror/basic-computer-games/blob/main/01%20Acey%20Ducey/aceyducey.bas\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class AceyDucey {\n\n    // Current amount of players cash\n    private int playerAmount;\n\n    // First drawn dealer card\n    private Card firstCard;\n\n    // Second drawn dealer card\n    private Card secondCard;\n\n    // Players drawn card\n    private Card playersCard;\n\n    // User to display game intro/instructions\n    private boolean firstTimePlaying = true;\n\n    // game state to determine if game over\n    private boolean gameOver = false;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Constant value for cards from a deck - 2 lowest, 14 (Ace) highest\n    public static final int LOW_CARD_RANGE = 2;\n    public static final int HIGH_CARD_RANGE = 14;\n\n    public AceyDucey() {\n        // Initialise players cash\n        playerAmount = 100;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    // Play again method - public method called from class invoking game\n    // If player enters YES then the game can be played again (true returned)\n    // otherwise not (false)\n    public boolean playAgain() {\n        System.out.println();\n        System.out.println(\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\");\n        System.out.println();\n        System.out.println();\n        System.out.print(\"TRY AGAIN (YES OR NO) \");\n        String playAgain = kbScanner.next().toUpperCase();\n        System.out.println();\n        System.out.println();\n        if (playAgain.equals(\"YES\")) {\n            return true;\n        } else {\n            System.out.println(\"O.K., HOPE YOU HAD FUN!\");\n            return false;\n        }\n    }\n\n    // game loop method\n\n    public void play() {\n\n        // Keep playing hands until player runs out of cash\n        do {\n            if (firstTimePlaying) {\n                intro();\n                firstTimePlaying = false;\n            }\n            displayBalance();\n            drawCards();\n            displayCards();\n            int betAmount = getBet();\n            playersCard = randomCard();\n            displayPlayerCard();\n            if (playerWon()) {\n                System.out.println(\"YOU WIN!!\");\n                playerAmount += betAmount;\n            } else {\n                System.out.println(\"SORRY, YOU LOSE\");\n                playerAmount -= betAmount;\n                // Player run out of money?\n                if (playerAmount <= 0) {\n                    gameOver = true;\n                }\n            }\n\n        } while (!gameOver); // Keep playing until player runs out of cash\n    }\n\n    // Method to determine if player won (true returned) or lost (false returned)\n    // to win a players card has to be in the range of the first and second dealer\n    // drawn cards inclusive of first and second cards.\n    private boolean playerWon() {\n        // winner\n        return (playersCard.getValue() >= firstCard.getValue())\n                && playersCard.getValue() <= secondCard.getValue();\n\n    }\n\n    private void displayPlayerCard() {\n        System.out.println(playersCard.getName());\n    }\n\n    // Get the players bet, and return the amount\n    // 0 is considered a valid bet, but better more than the player has available is not\n    // method will loop until a valid bet is entered.\n    private int getBet() {\n        boolean validBet = false;\n        int amount;\n        do {\n            System.out.print(\"WHAT IS YOUR BET \");\n            amount = kbScanner.nextInt();\n            if (amount == 0) {\n                System.out.println(\"CHICKEN!!\");\n                validBet = true;\n            } else if (amount > playerAmount) {\n                System.out.println(\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\");\n                System.out.println(\"YOU HAVE ONLY \" + playerAmount + \" DOLLARS TO BET.\");\n            } else {\n                validBet = true;\n            }\n        } while (!validBet);\n\n        return amount;\n    }\n\n    private void displayBalance() {\n        System.out.println(\"YOU NOW HAVE \" + playerAmount + \" DOLLARS.\");\n    }\n\n    private void displayCards() {\n        System.out.println(\"HERE ARE YOUR NEXT TWO CARDS: \");\n        System.out.println(firstCard.getName());\n        System.out.println(secondCard.getName());\n    }\n\n    // Draw two dealer cards, and save them for later use.\n    // ensure that the first card is a smaller value card than the second one\n    private void drawCards() {\n\n        do {\n            firstCard = randomCard();\n            secondCard = randomCard();\n        } while (firstCard.getValue() >= secondCard.getValue());\n    }\n\n    // Creates a random card\n    private Card randomCard() {\n        return new Card((int) (Math.random()\n                * (HIGH_CARD_RANGE - LOW_CARD_RANGE + 1) + LOW_CARD_RANGE));\n    }\n\n    public void intro() {\n        System.out.println(\"ACEY DUCEY CARD GAME\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println();\n        System.out.println(\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\");\n        System.out.println(\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\");\n        System.out.println(\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\");\n        System.out.println(\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\");\n        System.out.println(\"A VALUE BETWEEN THE FIRST TWO.\");\n        System.out.println(\"IF YOU DO NOT WANT TO BET, INPUT: 0\");\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/java/src/AceyDucey17.java",
    "content": "import java.util.Random;\nimport java.util.Scanner;\n\n/**\n * A modern version (JDK17) of ACEY DUCEY using post Java 8 features. Notes\n * regarding new java features or differences in the original basic\n * implementation are numbered and at the bottom of this code.\n * The goal is to recreate the exact look and feel of the original program\n * minus a large glaring bug in the original code that lets you cheat.\n */\npublic class AceyDucey17 {\n\n  public static void main(String[] args) {\n    // notes [1]\n    System.out.println(\"\"\"\n                                        ACEY DUCEY CARD GAME\n                             CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n              ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\n              THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\n              YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\n              ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\n              A VALUE BETWEEN THE FIRST TWO.\n              IF YOU DO NOT WANT TO BET, INPUT A 0\"\"\");\n\n    do {\n      playGame();\n    } while (stillInterested());\n    System.out.println(\"O.K., HOPE YOU HAD FUN!\");\n  }\n\n  public static void playGame() {\n    int cashOnHand = 100; // our only mutable variable  note [11]\n    System.out.println(\"YOU NOW HAVE  \"+ cashOnHand +\"  DOLLARS.\");// note [6]\n    while (cashOnHand > 0) {\n      System.out.println();\n      System.out.println(\"HERE ARE YOUR NEXT TWO CARDS:\");\n\n      final Card lowCard = Card.getRandomCard(2, Card.KING); //note [3]\n      System.out.println(lowCard);\n      final Card highCard = Card.getRandomCard(lowCard.rank() + 1, Card.ACE);\n      System.out.println(highCard);\n\n      final int bet = getBet(cashOnHand);\n      final int winnings = determineWinnings(lowCard,highCard,bet);\n      cashOnHand += winnings;\n      if(winnings != 0 || cashOnHand != 0){  //note [2]\n        System.out.println(\"YOU NOW HAVE  \"+ cashOnHand +\"  DOLLARS.\");//note [6]\n      }\n    }\n  }\n\n  public static int determineWinnings(Card lowCard, Card highCard, int bet){\n    if (bet <= 0) {    // note [5]\n      System.out.println(\"CHICKEN!!\");\n      return 0;\n    }\n    Card nextCard = Card.getRandomCard(2, Card.ACE);\n    System.out.println(nextCard);\n    if(nextCard.between(lowCard,highCard)){\n      System.out.println(\"YOU WIN!!!\");\n      return bet;\n    }\n    System.out.println(\"SORRY, YOU LOSE\");\n    return -bet;\n  }\n\n  public static boolean stillInterested(){\n    System.out.println();\n    System.out.println();\n    System.out.println(\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\");\n    System.out.println();\n    System.out.println();\n    System.out.print(\"TRY AGAIN (YES OR NO)? \");\n    Scanner input = new Scanner(System.in);\n    boolean playAgain = input.nextLine()\n                             .toUpperCase()\n                             .startsWith(\"Y\"); // note [9]\n    System.out.println();\n    System.out.println();\n    return playAgain;\n  }\n\n  public static int getBet(int cashOnHand){\n    int bet;\n    do{\n      System.out.println();\n      System.out.print(\"WHAT IS YOUR BET? \");\n      bet = inputNumber();\n      if (bet > cashOnHand) {\n        System.out.println(\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\");\n        System.out.println(\"YOU HAVE ONLY  \"+cashOnHand+\"  DOLLARS TO BET.\");\n      }\n    }while(bet > cashOnHand);\n    return bet;\n  }\n\n  public static int inputNumber() {\n    final Scanner input = new Scanner(System.in);\n    // set to negative to mark as not entered yet in case of input error.\n    int number = -1;\n    while (number < 0) {\n      try {\n        number = input.nextInt();\n      } catch(Exception ex) {   // note [7]\n        System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n        System.out.print(\"? \");\n        try{\n          input.nextLine();\n        }\n        catch(Exception ns_ex){ // received EOF (ctrl-d or ctrl-z if windows)\n          System.out.println(\"END OF INPUT, STOPPING PROGRAM.\");\n          System.exit(1);\n        }\n      }\n    }\n    return number;\n  }\n\n  record Card(int rank){\n    // Some constants to describe face cards.\n    public static final int JACK = 11, QUEEN = 12, KING = 13, ACE = 14;\n    private static final Random random = new Random();\n\n    public static Card getRandomCard(int from, int to){\n      return new Card(random.nextInt(from, to+1));  // note [4]\n    }\n\n    public boolean between(Card lower, Card higher){\n      return lower.rank() < this.rank() && this.rank() < higher.rank();\n    }\n\n    @Override\n    public String toString() { // note [13]\n      return switch (rank) {\n        case JACK -> \"JACK\";\n        case QUEEN -> \"QUEEN\";\n        case KING -> \"KING\";\n        case ACE -> \"ACE\\n\"; // note [10]\n        default -> \" \"+rank+\" \"; // note [6]\n      };\n    }\n  }\n\n  /*\n    Notes:\n    1. Multiline strings, a.k.a. text blocks, were added in JDK15.\n    2. The original game only displays the players balance if it changed,\n       which it does not when the player chickens out and bets zero.\n       It also doesn't display the balance when it becomes zero because it has\n       a more appropriate message: Sorry, You Lose.\n    3. To pick two cards to show, the original BASIC implementation has a\n       bug that could cause a race condition if the RND function never chose\n       a lower number first and higher number second. It loops infinitely\n       re-choosing random numbers until the condition is met of the first\n       one being lower. The logic is changed a bit here so that the first\n       card picked is anything but an ACE, the highest possible card,\n       and then the second card is between the just picked first card upto\n       and including the ACE.\n    4. Random.nextInt(origin, bound) was added in JDK17, and allows to\n       directly pick a range for a random integer to be generated. The second\n       parameter is exclusive of the range and thus why they are stated with\n       +1's to the face card.\n    5. The original BASIC implementation has a bug that allows negative value\n       bets. Since you can't bet MORE cash than you have you can always bet\n       less including a very, very large negative value. You would do this when\n       the chances of winning are slim or zero since losing a hand SUBTRACTS\n       your bet from your cash; subtracting a negative number actually ADDS\n       to your cash, potentially making you an instant billionaire.\n       This loophole is now closed.\n    6. The subtle behavior of the BASIC PRINT command causes a space to be\n       printed before all positive numbers as well as a trailing space. Any\n       place a non-face card or the players balance is printed has extra space\n       to mimic this behavior.\n    7. Errors on input were probably specific to the interpreter. This program\n       tries to match the Vintage Basic interpreter's error messages. The final\n       input.nextLine() command exists to clear the blockage of whatever\n       non-number input was entered.  But even that could fail if the user\n       types Ctrl-D (windows Ctrl-Z), signifying an EOF (end of file) and thus\n       the closing of STDIN channel. The original program on an EOF signal prints\n       \"END OF INPUT IN LINE 660\" and thus we cover it roughly the same way.\n       All of this is necessary to avoid a messy stack trace from being\n       printed as the program crashes.\n    9. The original game only accepted a full upper case \"YES\" to continue\n       playing if bankrupted. This program is more lenient and will accept\n       any input that starts with the letter 'y', uppercase or not.\n   10. The original game prints an extra blank line if the card is an ACE. There\n       is seemingly no rationale for this.\n   11. Modern java best practices are edging toward a more functional paradigm\n       and as such, mutating state is discouraged. All other variables besides\n       the cashOnHand are final and initialized only once.\n   12. Refactoring of the concept of a card is done with a record. Records were\n       introduced in JDK14. Card functionality is encapsulated in this example\n       of a record.  An enum could be a better alternative since there are\n       technically only 13 cards possible.\n   13. Switch expressions were introduced as far back as JDK12 but continue to\n       be refined for clarity, exhaustiveness. As of JDK17 pattern matching\n       for switch expressions can be accessed by enabling preview features.\n   */\n}\n"
  },
  {
    "path": "01_Acey_Ducey/java/src/AceyDuceyGame.java",
    "content": "/**\n * This class is used to invoke the game.\n *\n */\npublic class AceyDuceyGame {\n\n    public static void main(String[] args) {\n\n        boolean keepPlaying;\n        AceyDucey game = new AceyDucey();\n\n        // Keep playing game until infinity or the player loses\n        do {\n            game.play();\n            System.out.println();\n            System.out.println();\n            System.out.println();\n            keepPlaying = game.playAgain();\n        } while (keepPlaying);\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/java/src/Card.java",
    "content": "/**\n * A card from a deck - the value is between 2-14 to cover\n * cards with a face value of 2-9 and then a Jack, Queen, King, and Ace\n */\npublic class Card {\n    private int value;\n    private String name;\n\n    Card(int value) {\n        init(value);\n    }\n\n    private void init(int value) {\n        this.value = value;\n        if (value < 11) {\n            this.name = String.valueOf(value);\n        } else {\n            switch (value) {\n                case 11:\n                    this.name = \"Jack\";\n                    break;\n                case 12:\n                    this.name = \"Queen\";\n                    break;\n                case 13:\n                    this.name = \"King\";\n                    break;\n                case 14:\n                    this.name = \"Ace\";\n                    break;\n\n                default:\n                    this.name = \"Unknown\";\n            }\n        }\n    }\n\n    public int getValue() {\n        return value;\n    }\n\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/javascript/.prettierrc.json",
    "content": "{\n    \"trailingComma\": \"es5\",\n    \"tabWidth\": 4,\n    \"semi\": true,\n    \"singleQuote\": true\n}\n"
  },
  {
    "path": "01_Acey_Ducey/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "01_Acey_Ducey/javascript/aceyducey.html",
    "content": "<!DOCTYPE html>\n<head>\n<title>ACEY DUCEY</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\" style=\"font-size: 12pt\"></pre>\n<script src=\"aceyducey.js\"></script>\n</body>"
  },
  {
    "path": "01_Acey_Ducey/javascript/aceyducey.js",
    "content": "// UTILITY VARIABLES\n\n// By default:\n// — Browsers have a window object\n// — Node.js does not\n// Checking for an undefined window object is a loose check\n// to enable browser and Node.js support\nconst isRunningInBrowser = typeof window !== 'undefined';\n\n// To easily validate input strings with utility functions\nconst validLowerCaseYesStrings = ['yes', 'y'];\nconst validLowerCaseNoStrings = ['no', 'n'];\nconst validLowerCaseYesAndNoStrings = [\n    ...validLowerCaseYesStrings,\n    ...validLowerCaseNoStrings,\n];\n// UTILITY VARIABLES\n\n// Function to get a random number (card) 2-14 (ACE is 14)\nfunction getRandomCard() {\n    // In our game, the value of ACE is greater than face cards;\n    // instead of having the value of ACE be 1, we’ll have it be 14.\n    // So, we want to shift the range of random numbers from 1-13 to 2-14\n    let min = 2;\n    let max = 14;\n    // Return random integer between two values, inclusive\n    return Math.floor(Math.random() * (max - min + 1) + min);\n}\n\nfunction newGameCards() {\n    let cardOne = getRandomCard();\n    let cardTwo = getRandomCard();\n    let cardThree = getRandomCard();\n    // We want:\n    // 1. cardOne and cardTwo to be different cards\n    // 2. cardOne to be lower than cardTwo\n    // So, while cardOne is greater than or equal too cardTwo\n    // we will continue to generate random cards.\n    while (cardOne >= cardTwo) {\n        cardOne = getRandomCard();\n        cardTwo = getRandomCard();\n    }\n    return [cardOne, cardTwo, cardThree];\n}\n\n// Function to get card value\nfunction getCardValue(card) {\n    let faceOrAce = {\n        11: 'JACK',\n        12: 'QUEEN',\n        13: 'KING',\n        14: 'ACE',\n    };\n    // If card value matches a key in faceOrAce, use faceOrAce value;\n    // Else, return undefined and handle with the Nullish Coalescing Operator (??)\n    // and default to card value.\n    let cardValue = faceOrAce[card] ?? card;\n    return cardValue;\n}\n\nprint(spaces(26) + 'ACEY DUCEY CARD GAME');\nprint(spaces(15) + 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n');\nprint('ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER');\nprint('THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP');\nprint('YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING');\nprint('ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE');\nprint('A VALUE BETWEEN THE FIRST TWO.');\nprint(\"IF YOU DO NOT WANT TO BET, INPUT '0'\");\n\nmain();\n\nasync function main() {\n    let bet;\n    let availableDollars = 100;\n\n    // Loop game forever\n    while (true) {\n        let [cardOne, cardTwo, cardThree] = newGameCards();\n\n        print(`YOU NOW HAVE ${availableDollars} DOLLARS.\\n`);\n\n        print('HERE ARE YOUR NEXT TWO CARDS: ');\n        print(getCardValue(cardOne));\n        print(getCardValue(cardTwo));\n        print('');\n\n        // Loop until receiving a valid bet\n        let validBet = false;\n        while (!validBet) {\n            print('\\nWHAT IS YOUR BET? ');\n            bet = parseInt(await input(), 10);\n            let minimumRequiredBet = 0;\n            if (bet >= minimumRequiredBet) {\n                if (bet > availableDollars) {\n                    print('SORRY, MY FRIEND, BUT YOU BET TOO MUCH.');\n                    print(`YOU HAVE ONLY ${availableDollars} DOLLARS TO BET.`);\n                } else {\n                    validBet = true;\n                }\n            }\n        }\n        if (bet == 0)\n        {\n            // User chose not to bet.\n            print('CHICKEN!!');\n            print('');\n            // Don't draw a third card, draw a new set of 2 cards.\n            continue;\n        }\n\n        print('\\n\\nHERE IS THE CARD WE DREW: ');\n        print(getCardValue(cardThree));\n\n        // Determine if player won or lost\n        if (cardThree > cardOne && cardThree < cardTwo) {\n            print('YOU WIN!!!');\n            availableDollars = availableDollars + bet;\n        } else {\n            print('SORRY, YOU LOSE');\n\n            if (bet >= availableDollars) {\n                print('');\n                print('');\n                print('SORRY, FRIEND, BUT YOU BLEW YOUR WAD.');\n                print('');\n                print('');\n                print('TRY AGAIN (YES OR NO)');\n\n                let tryAgainInput = await input();\n\n                print('');\n                print('');\n\n                if (isValidYesString(tryAgainInput)) {\n                    availableDollars = 100;\n                } else {\n                    print('O.K., HOPE YOU HAD FUN!');\n                    break;\n                }\n            } else {\n                availableDollars = availableDollars - bet;\n            }\n        }\n    }\n}\n\n// UTILITY FUNCTIONS\nfunction isValidYesNoString(string) {\n    return validLowerCaseYesAndNoStrings.includes(string.toLowerCase());\n}\n\nfunction isValidYesString(string) {\n    return validLowerCaseYesStrings.includes(string.toLowerCase());\n}\n\nfunction isValidNoString(string) {\n    return validLowerCaseNoStrings.includes(string.toLowerCase());\n}\n\nfunction print(string) {\n    if (isRunningInBrowser) {\n        // Adds trailing newline to match console.log behavior\n        document\n            .getElementById('output')\n            .appendChild(document.createTextNode(string + '\\n'));\n    } else {\n        console.log(string);\n    }\n}\n\nfunction input() {\n    if (isRunningInBrowser) {\n        // Accept input from the browser DOM input\n        return new Promise((resolve) => {\n            const outputElement = document.querySelector('#output');\n            const inputElement = document.createElement('input');\n            outputElement.append(inputElement);\n            inputElement.focus();\n\n            inputElement.addEventListener('keydown', (event) => {\n                if (event.key === 'Enter') {\n                    const result = inputElement.value;\n                    inputElement.remove();\n                    print(result);\n                    print('');\n                    resolve(result);\n                }\n            });\n        });\n    } else {\n        // Accept input from the command line in Node.js\n        // See: https://nodejs.dev/learn/accept-input-from-the-command-line-in-nodejs\n        return new Promise(function (resolve) {\n            const readline = require('readline').createInterface({\n                input: process.stdin,\n                output: process.stdout,\n            });\n            readline.question('', function (input) {\n                resolve(input);\n                readline.close();\n            });\n        });\n    }\n}\n\nfunction printInline(string) {\n    if (isRunningInBrowser) {\n        document\n            .getElementById('output')\n            .appendChild(document.createTextNode(string));\n    } else {\n        process.stdout.write(string);\n    }\n}\n\nfunction spaces(numberOfSpaces) {\n    return ' '.repeat(numberOfSpaces);\n}\n\n// UTILITY FUNCTIONS\n"
  },
  {
    "path": "01_Acey_Ducey/kotlin/aceyducey.kt",
    "content": "import java.util.Random\n\nfun printCard(a: Int) {\n    if (a < 11) println(a)\n    if (a == 11) println(\"JACK\")\n    if (a == 12) println(\"QUEEN\")\n    if (a == 13) println(\"KING\")\n    if (a == 14) println(\"ACE\")\n}\n\nfun main() {\n    println(\"ACEY DUCEY CARD GAME\")\n    println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    println()\n    println()\n    println(\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \")\n    println(\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\")\n    println(\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\")\n    println(\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\")\n    println(\"A VALUE BETWEEN THE FIRST TWO.\")\n    println(\"IF YOU DO NOT WANT TO BET, INPUT A 0\")\n    var random = Random()\n    do {\n        var q = 100\n        var a : Int\n        var b : Int\n        var m : Int\n        println(\"YOU NOW HAVE \" + q + \" DOLLARS.\")\n        println()\n        do {\n            do {\n                do {\n                    println(\"HERE ARE YOUR NEXT TWO CARDS: \")\n                    do {\n                        a = random.nextInt(12) + 2\n                        b = random.nextInt(12) + 2\n                    } while (a >= b);\n                    printCard(a)\n                    printCard(b)\n                    println()\n                    println()\n                    print(\"WHAT IS YOUR BET\")\n                    m = readLine()!!.toInt()\n                    if (m == 0) {\n                        println(\"CHICKEN!!\")\n                        println()\n                    }\n                } while (m == 0);\n                if (m > q) {\n                    println(\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\")\n                    println(\"YOU HAVE ONLY \" + q + \" DOLLARS TO BET.\")\n                }\n            } while (m > q);\n            var c = random.nextInt(12) + 2\n            printCard(c)\n            println()\n            if (c > a && c < b) {\n                println(\"YOU WIN!!!\")\n                q += m\n            }\n            else {\n                println(\"SORRY, YOU LOSE\")\n                if (m < q) q -= m\n            }\n        } while (m < q);\n        println()\n        println()\n        println(\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\")\n        println()\n        println()\n        println(\"TRY AGAIN (YES OR NO)\")\n    } while (readLine() == \"YES\");\n    println(\"O.K., HOPE YOU HAD FUN!\")\n}\n"
  },
  {
    "path": "01_Acey_Ducey/lua/README.md",
    "content": "As published in Basic Computer Games (1978), as found at Annarchive:\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=17)\n\n\nConversion to Lua\n- [Lua.org](https://www.lua.org)\n"
  },
  {
    "path": "01_Acey_Ducey/lua/acey_ducey.lua",
    "content": "print [[\n            ACEY DUCEY CARD GAME\n CREATIVE COMPUTING  MORRISTOWN, NEW JERSY\n\n\n\nACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\nTHE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\nYOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\nON WHETHER OF NOT YOU FEEL THE CARD WILL HAVE\nA VALUE BETWEEN THE FIRST TWO.\nIF YOU DO NOT WANT TO BET INPUT A 0]]\n\nlocal starting_cash = 100\n\nlocal card_names = {[11] = \"JACK\", [12] = \"QUEEN\", [13] = \"KING\", [14] = \"ACE\"}\nfor i = 2, 10 do\n  card_names[i] = string.format(\" %d\", i)\nend\n\nfunction play_round(player_cash, skip_total)\n  assert(player_cash > 0, \"can't play with nothing to bet\")\n\n  if not skip_total then\n    print(string.format(\"YOU NOW HAVE %u DOLLARS\", player_cash))\n  end\n\n  print \"\\nHERE ARE YOUR NEXT TWO CARDS\"\n\n  local first_card, second_card;\n\n  repeat\n    first_card = math.random(2, 14)\n    second_card = math.random(2, 14)\n  until first_card < second_card\n\n  print(card_names[first_card])\n  print(card_names[second_card])\n  print(\"\")\n\n  local bet = get_bet(player_cash)\n\n  if bet == 0 then\n    print \"CHICKEN!!\"\n    return play_round(player_cash, \"skip total\")\n  end\n\n  local third_card = math.random(2, 14)\n  print(card_names[third_card])\n\n  if first_card < third_card and third_card < second_card then\n    print \"YOU WIN!!!\"\n    return play_round(player_cash + bet)\n  end\n\n  print \"SORRY, YOU LOSE\"\n  if bet < player_cash then\n    return play_round(player_cash - bet)\n  end\n\n  print \"SORRY, FRIEND BUT YOU BLEW YOUR WAD\"\n  io.write \"TRY AGAIN (YES OR NO)? \"\n  local keep_playing = io.read(\"l\")\n  if keep_playing:upper():match(\"%f[%a]YES%f[^%a]\") then\n    return play_round(starting_cash)\n  end\n\n  print \"OK HOPE YOU HAD FUN\"\nend\n\nfunction get_bet(player_cash)\n  assert(player_cash > 0, \"can't play with nothing to bet\")\n\n  io.write(\"WHAT IS YOUR BET? \")\n  local input = io.read(\"l\")\n  if not input then\n    print \"GOODBYE\"\n    os.exit(0)\n  end\n\n  local digits = input:match(\"(%d+)\")\n  if not digits then\n    print \"I DON'T UNDERSTAND THAT NUMBER\"\n    return get_bet(player_cash)\n  end\n\n  local bet = tonumber(digits)\n  assert(bet, \"pattern matched something that doesn't convert to number\")\n\n  if bet > player_cash then\n    print \"SORRY, MY FRIEND BUT YOU BET TOO MUCH\"\n    print(string.format(\"YOU HAVE ONLY %u DOLLARS TO BET\", player_cash))\n    return get_bet(player_cash)\n  end\n\n  assert(0 <= bet and bet <= player_cash, \"invalid bet\")\n  return bet\nend\n\nplay_round(starting_cash)\n"
  },
  {
    "path": "01_Acey_Ducey/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "01_Acey_Ducey/perl/aceyducey.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\n# The List::Util module is part of the core Perl distribution.  Using this\n# means we don't need to re-invent the wheel and create a way to shuffle\n# a list.\nuse List::Util qw(shuffle);\n\n# Rather than put in a number of print (or say) statements here, we use a\n# \"here document\".  This is very useful for long strings of text.  In this\n# case, everything between the end of the \"print\" line and the line with\n# \"END_INSTRUCTIONS\" on it will be printed verbatim.\nprint << 'END_INSTRUCTIONS';\n\nAcey-Ducey\nAdapted from Creative Computing, Morristown, New Jersey\n\n\nAcey-Ducey is played as follows. The dealer (computer) deals two cards face up.\nYou have an option to bet or not bet, depending on whether or not you feel that\nthe next card drawn will have a value between the first two.  Aces are low.\n\nBets must be in whole-dollar amounts only.\n\nIf you do not want to bet, input a 0.  If you want to quit, input a -1.\n\nEND_INSTRUCTIONS\n\nmy @cards       = ( 1 .. 13 );    # That is, Ace through King.\nmy $keepPlaying = 1;\n\nGAME:\nwhile ($keepPlaying) {\n    my $playerBalance = 100;      # The player starts with $100\n\n    HAND:\n    while (1) {\n        print \"\\nYou now have $playerBalance dollars.\\n\\n\";\n\n        # We'll create a new array that is a shuffled version of the deck.\n        my @shuffledDeck = shuffle(@cards);\n\n        # Then, by taking the two \"top cards\" off the deck, we're guaranteed\n        # that those will be unique.  This way we don't have to keep drawing\n        # if we get, say, two queens.  We sort them as we pull them to make\n        # sure that the first card is lower than the second one.\n        my ( $firstCard, $secondCard ) = sort { $a <=> $b } @shuffledDeck[ 0 .. 1 ];\n\n        print \"I drew \", nameOfCard($firstCard), \" and \", nameOfCard($secondCard), \".\\n\";\n\n        my $bet = getValidBet($playerBalance);\n        if ( $bet == 0 ) {\n            print \"Chicken!\\n\\n\";\n            next HAND;\n        }\n\n        if ( $bet < 0 ) {\n            last GAME;\n        }\n\n        # Now we re-shuffle the whole deck again and choose a third card.\n        # (Note: This is how the odds get stacked in favor of the dealer since\n        # the third card can be exactly the same as the first or second.)\n        @shuffledDeck = shuffle(@cards);\n        my $thirdCard = $shuffledDeck[0];\n\n        print \"I drew \", nameOfCard($thirdCard), \"!\\n\";\n\n        if ( ( $firstCard < $thirdCard ) && ( $thirdCard < $secondCard ) ) {\n            print \"You win!\\n\\n\";\n            $playerBalance += $bet;\n        }\n        else {\n            print \"You lose!\\n\\n\";\n            $playerBalance -= $bet;\n        }\n\n        if ( $playerBalance <= 0 ) {\n            print \"Sorry, buddy, you blew your wad!\\n\\n\";\n            last HAND;\n        }\n    }\n\n    $keepPlaying = promptUserToKeepPlaying();\n}\n\nprint \"Thanks for playing!\\n\";\n\n###############\nsub getValidBet {\n    my $maxBet = shift;\n\n    INPUT:\n    {\n        print \"\\nWhat's your bet? \";\n\n        chomp( my $input = <STDIN> );\n\n        # This regular expression will validate that the player entered an integer.\n        # The !~ match operate *negates* the match, so if the player did NOT enter\n        # an integer, they'll be given an error and prompted again.\n        if (\n            $input !~ /^        # Match the beginning of the string\n                    [+-]?    # Optional plus or minus...\n                    \\d+      # followed by one more more digits...\n                    $        # and then the end of the string\n                    /x    # The x modifier ignores whitespace in this regex...\n          )\n        {\n            print \"Sorry, numbers only!\\n\";\n            redo INPUT;\n        }\n\n        if ( $input > $maxBet ) {\n            print \"Sorry, my friend, you can't bet more money than you have.\\n\";\n            print \"You only have $maxBet dollars to spend!\\n\";\n            redo INPUT;\n        }\n\n        return $input;\n    }\n}\n\n# Since arrays in Perl are 0-based, we need to convert the value that we drew from\n# the array to its proper position in the deck.\nsub nameOfCard {\n    my $value = shift;\n\n    # Note that the Joker isn't used in this game, but since arrays in Perl are\n    # 0-based, it's useful to have something there to represent the \"0th\"\n    # position.  This way the rest of the elements match their expected values\n    # (e.g., element 1 is Ace, element 7 is 7, and element 12 is Queen).\n\n    my @cardlist = qw(Joker Ace 2 3 4 5 6 7 8 9 10 Jack Queen King);\n    return $cardlist[$value];\n}\n\nsub promptUserToKeepPlaying {\n    YESNO:\n    {\n        print \"Try again (Y/N)? \";\n\n        chomp( my $input = uc <STDIN> );\n\n        if ( $input eq 'Y' ) {\n            return 1;\n        }\n        elsif ( $input eq 'N' ) {\n            return 0;\n        }\n        else {\n            redo YESNO;\n        }\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n\nPropose using pylint and black to format python files so that it conforms to some standards\n"
  },
  {
    "path": "01_Acey_Ducey/python/acey_ducey.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nPlay the Acey-Ducey game\nhttps://www.atariarchives.org/basicgames/showpage.php?page=2\n\"\"\"\n\nimport random\n\ncards = {\n    2: \"2\",\n    3: \"3\",\n    4: \"4\",\n    5: \"5\",\n    6: \"6\",\n    7: \"7\",\n    8: \"8\",\n    9: \"9\",\n    10: \"10\",\n    11: \"Jack\",\n    12: \"Queen\",\n    13: \"King\",\n    14: \"Ace\",\n}\n\n\ndef play_game() -> None:\n    cash = 100\n    while cash > 0:\n        print(f\"You now have {cash} dollars\\n\")\n        print(\"Here are your next two cards\")\n        round_cards = list(cards.keys())  # gather cards from dictionary\n        card_a = random.choice(round_cards)  # choose a card\n        card_b = card_a  # clone the first card, so we avoid the same number for the second card\n        while (card_a == card_b):  # if the cards are the same, choose another card\n            card_b = random.choice(round_cards)\n        card_c = random.choice(round_cards)  # choose last card\n        if card_a > card_b:  # swap cards if card_a is greater than card_b\n            card_a, card_b = card_b, card_a\n        print(f\" {cards[card_a]}\")\n        print(f\" {cards[card_b]}\\n\")\n        while True:\n            try:\n                bet = int(input(\"What is your bet? \"))\n                if bet < 0:\n                    raise ValueError(\"Bet must be more than zero\")\n                if bet == 0:\n                    print(\"CHICKEN!!\\n\")\n                if bet > cash:\n                    print(\"Sorry, my friend but you bet too much\")\n                    print(f\"You only have {cash} dollars to bet\")\n                    continue\n                cash -= bet\n                break\n\n            except ValueError:\n                print(\"Please enter a positive number\")\n        print(f\" {cards[card_c]}\")\n        if bet > 0:\n            if card_a <= card_c <= card_b:\n                print(\"You win!!!\")\n                cash += bet * 2\n            else:\n                print(\"Sorry, you lose\")\n\n    print(\"Sorry, friend, but you blew your wad\")\n\n\ndef main() -> None:\n    print(\n        \"\"\"\nAcey-Ducey is played in the following manner\nThe dealer (computer) deals two cards face up\nYou have an option to bet or not bet depending\non whether or not you feel the card will have\na value between the first two.\nIf you do not want to bet, input a 0\n  \"\"\"\n    )\n    keep_playing = True\n\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"Try again? (yes or no) \").lower().startswith(\"y\")\n    print(\"Ok hope you had fun\")\n\n\nif __name__ == \"__main__\":\n    random.seed()\n    main()\n"
  },
  {
    "path": "01_Acey_Ducey/python/acey_ducey_oo.py",
    "content": "\"\"\"\nAceyDuchy\nFrom: BASIC Computer Games (1978)\n      Edited by David Ahl\n\"The original BASIC program author was Bill Palmby\n of Prairie View, Illinois.\"\nPython port by Aviyam Fischer, 2022\n\"\"\"\n\nfrom typing import List, Literal, NamedTuple, TypeAlias, get_args\nimport random\n\nSuit: TypeAlias = Literal[\"\\u2665\", \"\\u2666\", \"\\u2663\", \"\\u2660\"]\nRank: TypeAlias = Literal[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]\n\n\nclass Card(NamedTuple):\n    suit: Suit\n    rank: Rank\n\n    def __str__(self) -> str:\n        r = str(self.rank)\n        r = {\"11\": \"J\", \"12\": \"Q\", \"13\": \"K\", \"14\": \"A\"}.get(r, r)\n        return f\"{r}{self.suit}\"\n\n\nclass Deck:\n    def __init__(self) -> None:\n        self.cards: List[Card] = []\n        self.build()\n\n    def build(self) -> None:\n        for suit in get_args(Suit):\n            for rank in get_args(Rank):\n                self.cards.append(Card(suit, rank))\n\n    def shuffle(self) -> None:\n        random.shuffle(self.cards)\n\n    def deal(self) -> Card:\n        return self.cards.pop()\n\n\nclass Game:\n    def __init__(self) -> None:\n        self.deck = Deck()\n        self.deck.shuffle()\n        self.card_a = self.deck.deal()\n        self.card_b = self.deck.deal()\n        self.money = 100\n        self.not_done = True\n\n    def play(self) -> None:\n        while self.not_done:\n            while self.money > 0:\n                card_a = self.card_a\n                card_b = self.card_b\n\n                if card_a.rank > card_b.rank:\n                    card_a, card_b = card_b, card_a\n\n                if card_a.rank == card_b.rank:\n                    self.card_b = self.deck.deal()\n                    card_b = self.card_b\n\n                print(f\"You have:\\t ${self.money} \")\n                print(f\"Your cards:\\t {card_a} {card_b}\")\n\n                bet = int(input(\"What is your bet? \"))\n                player_card = self.deck.deal()\n                if 0 < bet <= self.money:\n\n                    print(f\"Your deal:\\t {player_card}\")\n                    if card_a.rank <= player_card.rank <= card_b.rank:\n                        print(\"You Win!\")\n                        self.money += bet\n                    else:\n                        print(\"You Lose!\")\n                        self.money -= bet\n                        self.not_done = False\n                else:\n                    print(\"Chicken!\")\n                    print(f\"Your deal should have been: {player_card}\")\n                    if card_a.rank < player_card.rank < card_b.rank:\n                        print(\"You could have won!\")\n                    else:\n                        print(\"You would lose, so it was wise of you to chicken out!\")\n\n                if len(self.deck.cards) <= 3:\n                    print(\"You ran out of cards. Game over.\")\n                    self.not_done = False\n                    break\n\n                self.card_a = self.deck.deal()\n                self.card_b = self.deck.deal()\n\n        if self.money == 0:\n            self.not_done = False\n\n\ndef game_loop() -> None:\n    game_over = False\n\n    while not game_over:\n        game = Game()\n        game.play()\n        print(f\"You have ${game.money} left\")\n        print(\"Would you like to play again? (y/n)\")\n        if input() == \"n\":\n            game_over = True\n\n\ndef main() -> None:\n    print(\n        \"\"\"\n    Acey Ducey is a card game where you play against the computer.\n    The Dealer(computer) will deal two cards facing up.\n    You have an option to bet or not bet depending on whether or not you\n    feel the card will have a value between the first two.\n    If you do not want to bet input a 0\n    \"\"\"\n    )\n    game_loop()\n    print(\"\\nThanks for playing!\")\n\n\nif __name__ == \"__main__\":\n    random.seed()\n    main()\n"
  },
  {
    "path": "01_Acey_Ducey/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/) by Christopher Özbek [coezbek@github](https://github.com/coezbek).\n"
  },
  {
    "path": "01_Acey_Ducey/ruby/aceyducey.rb",
    "content": "########################################################\n#\n# Acey Ducey\n#\n# From: BASIC Computer Games (1978)\n#       Edited by David Ahl\n#\n# \"This is a simulation of the Acey Ducey card game.\n#  In the game, the dealer (the computer) deals two\n#  cards face up.  You have an option to bet or not to\n#  bet depending on whether or not you feel the next\n#  card dealt will have a value between the first two.\n#\n# \"Your initial money is set to $100. The game keeps\n#  going on until you lose all your money or interrupt\n#  the program.\n#\n# \"The original BASIC program author was Bill Palmby\n#  of Prairie View, Illinois.\"\n#\n# Ruby port by Christopher Oezbek, 2021\n#\n# This uses the following techniques:\n#\n#  - The programm largely consists of a GAME LOOP,\n#    which is used to represent one round.\n#  - The Kernel function rand(Range) is used to get an\n#    Integer in the (inclusive) Range of 2 to 14.\n#  - To ensure the user enters a proper Integer\n#    via the console, an inline 'rescue' statement is\n#    used.\n#  - To capture the long text in the introduction, a\n#    squiggly HEREDOC string declaration <<~ is used.\n#\n#\n########################################################\n\nputs <<~INSTRUCTIONS\n           🂡  ACEY DUCEY CARD GAME 🂱\n   CREATIVE COMPUTING - MORRISTOWN, NEW JERSEY\n\n  ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\n  THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\n  YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\n  ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\n  A VALUE BETWEEN THE FIRST TWO.\n  IF YOU DO NOT WANT TO BET IN A ROUND, ENTER 0\nINSTRUCTIONS\n\n# The player starts with 100$\nstake = 100\n\nwhile true # Game loop\n  puts\n  puts \"YOU NOW HAVE #{stake} DOLLARS.\"\n  puts\n  puts \"HERE ARE YOUR NEXT TWO CARDS:\"\n\n  # Randomly draw two cards and make sure the first card is lower in value than the second\n  # Using array destructuring, this sorted array can be assigned to `first_card` and `second_card`\n  first_card, second_card = (2...14).to_a.shuffle.pop(2).sort\n\n  # Helper method to convert a numeric card into a String for printing\n  def card_name(card)\n    case card\n    when 11\n      \"JACK\"\n    when 12\n      \"QUEEN\"\n    when 13\n      \"KING\"\n    when 14\n      \"ACE\"\n    else\n      card\n    end\n  end\n\n  puts card_name(first_card)\n  puts card_name(second_card)\n  puts\n  puts\n\n  # Loop until the user enters something sensible\n  while true\n    puts \"WHAT IS YOUR BET? ENTER 0 IF YOU DON'T WANT TO BET (CTRL+C TO EXIT)\"\n    your_bet = Integer(gets.chomp) rescue nil\n\n    if your_bet == nil || your_bet < 0\n      puts \"PLEASE ENTER A POSITIVE NUMBER\"\n      puts\n      next\n    end\n\n    if your_bet > stake\n      puts \"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\"\n      puts \"YOU HAVE ONLY #{stake} DOLLARS TO BET.\"\n      puts\n      next\n    end\n\n    break\n  end\n\n  if your_bet == 0\n    puts \"CHICKEN!!\"\n    next\n  end\n\n  puts \"THANK YOU! YOUR BET IS #{your_bet} DOLLARS.\"\n  puts \"\"\n  puts \"THE THIRD CARD IS:\"\n  third_card = rand(2..14)\n  puts card_name(third_card)\n  puts\n\n  if first_card <= third_card && third_card <= second_card\n    puts \"YOU WIN!!!\"\n    stake += your_bet\n  else\n    puts \"SORRY, YOU LOSE\"\n    stake -= your_bet\n  end\n\n  if stake == 0\n    puts\n    puts \"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\"\n    puts\n\n    puts \"TRY AGAIN? (YES OR NO)\"\n    if gets.chomp.downcase.start_with? 'y'\n      # Reset cash to 100\n      stake = 100\n    else\n      puts \"O.K., HOPE YOU HAD FUN!\"\n      exit\n    end\n  end\nend\n"
  },
  {
    "path": "01_Acey_Ducey/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "01_Acey_Ducey/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Alex Kotov [mur4ik18@github](https://github.com/mur4ik18).\n\nFurther edits by\n\n- Berker Şal [berkersal@github](https://github.com/berkersal)\n"
  },
  {
    "path": "01_Acey_Ducey/rust/src/main.rs",
    "content": "use rand::{prelude::ThreadRng, Rng};\nuse std::{fmt, io, mem};\n\n#[derive(PartialEq, Eq, PartialOrd, Ord)]\nstruct Card(u8);\n\nimpl Card {\n    fn new_random(rng: &mut ThreadRng) -> Card {\n        Card(rng.gen_range(2..15))\n    }\n}\n\nimpl fmt::Display for Card {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(\n            f,\n            \"{}\",\n            match self.0 {\n                11 => String::from(\"JACK\"),\n                12 => String::from(\"QUEEN\"),\n                13 => String::from(\"KING\"),\n                14 => String::from(\"ACE\"),\n                otherwise => otherwise.to_string(),\n            }\n        )\n    }\n}\n\nstruct CardsPool(Card, Card, Card);\n\nimpl CardsPool {\n    fn new() -> CardsPool {\n        let mut rng = rand::thread_rng();\n        let mut first = Card::new_random(&mut rng);\n        let mut second = Card::new_random(&mut rng);\n        let third = Card::new_random(&mut rng);\n\n        if first > second {\n            mem::swap(&mut first, &mut second);\n        }\n\n        CardsPool(first, second, third)\n    }\n\n    fn is_in_win_range(&self) -> bool {\n        self.0 <= self.2 && self.2 <= self.1\n    }\n}\n\nfn main() {\n    hello();\n    // user start bank\n    let mut user_bank: u16 = 100;\n\n    loop {\n        println!(\"YOU NOW HAVE {} DOLLARS.\", &mut user_bank);\n        println!(\"\\nHERE ARE YOUR NEXT TWO CARDS:\");\n        // get new random cards\n        let cards = CardsPool::new();\n\n        println!(\"{}\", cards.0);\n        println!(\"{}\", cards.1);\n\n        let user_bet: u16 = get_bet(user_bank);\n\n        if user_bet == 0 {\n            println!(\"CHICKEN!!!\\n\");\n            continue;\n        } else {\n            println!(\"THANK YOU! YOUR BET IS {} DOLLARS.\", user_bet);\n        }\n\n        println!(\"\\nTHE THIRD CARD IS:\");\n        println!(\"{}\", cards.2);\n\n        if cards.is_in_win_range() {\n            println!(\"\\nYOU WIN!!!\");\n            user_bank += user_bet;\n        } else {\n            println!(\"\\nSORRY, YOU LOSE\");\n            user_bank -= user_bet;\n        }\n\n        if user_bank == 0 {\n            println!(\"\\nSORRY, FRIEND, BUT YOU BLEW YOUR WAD.\");\n            println!(\"\\nTRY AGAIN? (YES OR NO)\");\n            let mut input = String::new();\n            io::stdin().read_line(&mut input).expect(\"Incorrect input\");\n\n            if input.trim().to_lowercase() == \"yes\" {\n                user_bank = 100;\n                println!();\n            } else {\n                println!(\"\\nO.K., HOPE YOU HAD FUN!\");\n                break;\n            }\n        }\n    }\n}\n\nfn hello() {\n    println!(\"         🂡  ACEY DUCEY CARD GAME 🂱\");\n    println!(\"CREATIVE COMPUTING - MORRISTOWN, NEW JERSEY\");\n    println!(\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\");\n    println!(\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\");\n    println!(\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\");\n    println!(\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\");\n    println!(\"A VALUE BETWEEN THE FIRST TWO.\");\n    println!(\"IF YOU DO NOT WANT TO BET IN A ROUND, ENTER 0\");\n    println!(\"\\n\\n\");\n}\n\nfn get_bet(user_bank: u16) -> u16 {\n    loop {\n        println!(\"\\nWHAT IS YOUR BET? ENTER 0 IF YOU DON'T WANT TO BET (CTRL+C TO EXIT)\");\n        let bet: u16;\n        let mut input = String::new();\n\n        io::stdin()\n            .read_line(&mut input)\n            .expect(\"CANNOT READ INPUT!\");\n\n        match input.trim().parse::<u16>() {\n            Ok(i) => bet = i,\n            Err(e) => {\n                println!(\"CHECK YOUR INPUT! {}!\", e.to_string().to_uppercase());\n                continue;\n            }\n        };\n\n        match bet {\n            bet if bet <= user_bank => return bet,\n            _ => {\n                println!(\"\\nSORRY, MY FRIEND, BUT YOU BET TOO MUCH.\");\n                println!(\"YOU HAVE ONLY {} DOLLARS TO BET.\", user_bank);\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "01_Acey_Ducey/vbnet/AceyDucey.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{778DAE3C-4631-46EA-AA77-85C1314464D9}\") = \"AceyDucey\", \"AceyDucey.vbproj\", \"{54C05475-238D-4A82-A67B-B6C1BF2CA337}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{54C05475-238D-4A82-A67B-B6C1BF2CA337}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{54C05475-238D-4A82-A67B-B6C1BF2CA337}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{54C05475-238D-4A82-A67B-B6C1BF2CA337}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{54C05475-238D-4A82-A67B-B6C1BF2CA337}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {C01D9DAE-644C-455F-8365-E14E49074BC3}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "01_Acey_Ducey/vbnet/AceyDucey.vb",
    "content": "﻿Public Class AceyDucey\n    ''' <summary>\n    ''' Create a single instance of the Random class to be used\n    ''' throughout the program.\n    ''' </summary>\n    Private ReadOnly Property Rnd As New Random()\n\n    ''' <summary>\n    ''' Define a varaible to store the the player balance. <br/>\n    ''' Defaults to 0\n    ''' </summary>\n    ''' <remarks>\n    ''' Since <see cref=\"Integer\"/> is a value type, and no value\n    ''' has been explicitly set, the default value of the type is used.\n    ''' </remarks>\n    Private _balance As Integer\n\n    Public Sub New()\n        DisplayIntroduction()\n    End Sub\n\n    ''' <summary>\n    ''' Play multiple games of Acey Ducey until the player chooses to quit.\n    ''' </summary>\n    Public Sub Play()\n        Do\n            PlayGame()\n        Loop While TryAgain() 'Loop (play again) based on the Boolean value returned by TryAgain\n\n        Console.WriteLine(\"O.K., HOPE YOU HAD FUN!\")\n    End Sub\n\n    ''' <summary>\n    ''' Play a game of Acey Ducey, which ends when the player balance reaches 0\n    ''' </summary>\n    Private Sub PlayGame()\n        _balance = 100 'At the start of the game, set the player balance to 100\n\n        Console.WriteLine()\n        Console.WriteLine($\"YOU NOW HAVE {_balance} DOLLARS.\")\n\n        Do\n            PlayTurn()\n        Loop While _balance > 0 'Continue playing while the user has a balance\n\n        Console.WriteLine()\n        Console.WriteLine(\"SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\")\n    End Sub\n\n    ''' <summary>\n    ''' Play one turn of Acey Ducey\n    ''' </summary>\n    ''' <remarks>\n    ''' A turn consists of displaying to cards, making a wager\n    ''' and determining the result (win/lose)\n    ''' </remarks>\n    Private Sub PlayTurn()\n        Console.WriteLine()\n        Console.WriteLine(\"HERE ARE YOUR NEXT TWO CARDS: \")\n\n        Dim cards = GetOrderedCards()\n\n        For Each card In cards\n            DisplayCard(card)\n        Next\n\n        Dim wager As Integer = GetWager()\n        Dim finalCard As Integer = GetCard()\n\n        If wager = 0 Then\n            Console.WriteLine(\"CHICKEN!!\")\n            Return\n        End If\n\n        DisplayCard(finalCard)\n\n        Console.WriteLine()\n\n        '''Check if the value of the final card is between the first and second cards.\n        '''\n        '''The use of AndAlso is used to short-circuit the evaluation of the IF condition.\n        '''Short-circuiting means that both sides of the condition do not need to be\n        '''evaluated. In this case, if the left criteria returns FALSE, the right criteria\n        '''is ignored and the evaluation result is returned as FALSE.\n        '''\n        '''This works because AndAlso requires both condition to return TRUE  in order to be\n        '''evaluated as TRUE. If the first condition is FALSE we already know the evaluation result.\n        If finalCard >= cards.First() AndAlso finalCard <= cards.Last() Then\n            Console.WriteLine(\"YOU WIN!!!\")\n            _balance += wager 'Condensed version of _balance = _balance + wager\n        Else\n            Console.WriteLine(\"SORRY, YOU LOSE.\")\n            _balance -= wager 'Condensed version of _balance = _balance - wager\n        End If\n    End Sub\n\n    ''' <summary>\n    ''' Get two cards in ascending order\n    ''' </summary>\n    ''' <remarks>\n    ''' The original version generates two cards (A and B)\n    ''' If A is greater than or equal to B, both cards are regenerated.\n    ''' <br/><br/>\n    ''' This version generates the two cards, but only regenerates A\n    ''' if A is equal to B. The cards are then returned is ascending order,\n    ''' ensuring that A is less than B (maintaining the original end result)\n    ''' </remarks>\n    Private Function GetOrderedCards() As Integer()\n        '''When declaring fixed size arrays in VB.NET you declare the MAX INDEX of the array\n        '''and NOT the SIZE (number of elements) of the array.\n        '''As such, card(1) gives you and array with index 0 and index 1, which means\n        '''the array stores two elements and not one\n        Dim cards(1) As Integer\n\n        cards(0) = GetCard()\n        cards(1) = GetCard()\n\n        'Perform this action as long as the first card is equal to the second card\n        While cards(0) = cards(1)\n            cards(0) = GetCard()\n        End While\n\n        Array.Sort(cards) 'Sort the values in ascending order\n\n        Return cards\n    End Function\n\n    ''' <summary>\n    ''' Get a random number (card) ranked 2 to 14\n    ''' </summary>\n    Private Function GetCard() As Integer\n        Return Rnd.Next(2, 15)\n    End Function\n\n    ''' <summary>\n    ''' Display the face value of the card\n    ''' </summary>\n    Private Sub DisplayCard(card As Integer)\n        Dim output As String\n\n        Select Case card\n            Case 2 To 10\n                output = card.ToString()\n            Case 11\n                output = \"JACK\"\n            Case 12\n                output = \"QUEEN\"\n            Case 13\n                output = \"KING\"\n            Case 14\n                output = \"ACE\"\n            Case Else\n                Throw New ArgumentOutOfRangeException(NameOf(card), \"Value must be between 2 and 14\")\n        End Select\n\n        Console.WriteLine(output)\n    End Sub\n\n    ''' <summary>\n    ''' Prompt the user to make a bet\n    ''' </summary>\n    ''' <remarks>\n    ''' The function will not return until a valid bet is made. <br/>\n    ''' <see cref=\"Int32.TryParse(String, ByRef Integer)\"/> is used to validate that the user input is a valid <see cref=\"Integer\"/>\n    ''' </remarks>\n    Private Function GetWager() As Integer\n        Dim wager As Integer\n        Do\n            Console.WriteLine()\n            Console.Write(\"WHAT IS YOUR BET? \")\n\n            Dim input As String = Console.ReadLine()\n\n            '''Determine if the user input is an Integer\n            '''If it is an Integer, store the value in the variable wager\n            If Not Integer.TryParse(input, wager) Then\n                Console.WriteLine(\"SORRY, I DID'T QUITE GET THAT.\")\n                Continue Do 'restart the loop\n            End If\n\n            'Prevent the user from betting more than their current balance\n            If _balance < wager Then\n                Console.WriteLine(\"SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\")\n                Console.WriteLine($\"YOU HAVE ONLY {_balance} DOLLARS TO BET.\")\n                Continue Do 'restart the loop\n            End If\n\n            'Prevent the user from betting negative values\n            If wager < 0 Then\n                Console.WriteLine(\"FUNNY GUY! YOU CANNOT MAKE A NEGATIVE BET.\")\n                Continue Do 'restart the loop\n            End If\n\n            Exit Do 'If we get to this line, exit the loop as all above validations passed\n        Loop\n\n        Return wager\n    End Function\n\n    ''' <summary>\n    ''' Prompt the user to try again\n    ''' </summary>\n    ''' <remarks>\n    ''' This function will not return until a valid reponse is given\n    ''' </remarks>\n    Private Function TryAgain() As Boolean\n        Dim response As String\n        Do\n            Console.Write(\"TRY AGAIN (YES OR NO) \")\n\n            response = Console.ReadLine()\n\n            If response.Equals(\"YES\", StringComparison.OrdinalIgnoreCase) Then Return True\n            If response.Equals(\"NO\", StringComparison.OrdinalIgnoreCase) Then Return False\n\n            Console.WriteLine(\"SORRY, I DID'T QUITE GET THAT.\")\n        Loop\n    End Function\n\n    ''' <summary>\n    ''' Display the opening title and instructions\n    ''' </summary>\n    ''' <remarks>\n    ''' Refer to\n    ''' <see href=\"https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/strings/interpolated-strings\">\n    '''     Interpolated Strings\n    ''' </see> documentation for the use of $ and { } with strings\n    ''' </remarks>\n    Private Sub DisplayIntroduction()\n        Console.WriteLine($\"{Space((Console.WindowWidth \\ 2) - 10)}ACEY DUCEY CARD GAME\")\n        Console.WriteLine($\"{Space((Console.WindowWidth \\ 2) - 21)}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n        Console.WriteLine(\"\")\n        Console.WriteLine(\"\")\n        Console.WriteLine(\"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\")\n        Console.WriteLine(\"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\")\n        Console.WriteLine(\"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\")\n        Console.WriteLine(\"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\")\n        Console.WriteLine(\"A VALUE BETWEEN THE FIRST TWO.\")\n        Console.WriteLine(\"IF YOU DO NOT WANT TO BET, INPUT A 0\")\n        Console.WriteLine(\"\")\n    End Sub\nEnd Class\n"
  },
  {
    "path": "01_Acey_Ducey/vbnet/AceyDucey.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>AceyDucey</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "01_Acey_Ducey/vbnet/Program.vb",
    "content": "Imports System\n\n''' <summary>\n''' This is a modern adapation of Acey Ducey from BASIC Computer Games.\n'''\n''' The structural changes primarily consist of replacing the many GOTOs with\n''' Do/Loop constructs to force the continual execution of the program.\n'''\n''' Some modern improvements were added, primarily the inclusion of a multiple\n''' subroutines and functions, which eliminates repeated logic and reduces\n''' then need for nested loops.\n'''\n''' The archaic RND function is greatly simplified with the .NET Framework's Random class.\n'''\n''' Elementary comments are provided for non-programmers or novices.\n''' </summary>\nModule Program\n    Sub Main()\n        Call New AceyDucey().Play()\n    End Sub\nEnd Module\n"
  },
  {
    "path": "01_Acey_Ducey/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "02_Amazing/README.md",
    "content": "### Amazing\n\nThis program will print out a different maze every time it is run and guarantees only one path through. You can choose the dimensions of the maze — i.e. the number of squares wide and long.\n\nThe original program author was Jack Hauber of Windsor, Connecticut.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=3)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=18)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The input dimensions are checked for values of 1, but not for values of 0 or less.  Such inputs will cause the program to break.\n\n#### Porting Notes\n\n**2022-01-04:** patched original source in [#400](https://github.com/coding-horror/basic-computer-games/pull/400) to fix a minor bug where a generated maze may be missing an exit, particularly at small maze sizes.\n"
  },
  {
    "path": "02_Amazing/amazing.bas",
    "content": "10 PRINT TAB(28);\"AMAZING PROGRAM\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT:PRINT\n100 INPUT \"WHAT ARE YOUR WIDTH AND LENGTH\";H,V\n102 IF H<>1 AND V<>1 THEN 110\n104 PRINT \"MEANINGLESS DIMENSIONS.  TRY AGAIN.\":GOTO 100\n110 DIM W(H,V),V(H,V)\n120 PRINT\n130 PRINT\n140 PRINT\n150 PRINT\n160 Q=0:Z=0:X=INT(RND(1)*H+1)\n165 FOR I=1 TO H\n170 IF I=X THEN 173\n171 PRINT \".--\";:GOTO 180\n173 PRINT \".  \";\n180 NEXT I\n190 PRINT \".\"\n195 C=1:W(X,1)=C:C=C+1\n200 R=X:S=1:GOTO 260\n210 IF R<>H THEN 240\n215 IF S<>V THEN 230\n220 R=1:S=1:GOTO 250\n230 R=1:S=S+1:GOTO 250\n240 R=R+1\n250 IF W(R,S)=0 THEN 210\n260 IF R-1=0 THEN 530\n265 IF W(R-1,S)<>0 THEN 530\n270 IF S-1=0 THEN 390\n280 IF W(R,S-1)<>0 THEN 390\n290 IF R=H THEN 330\n300 IF W(R+1,S)<>0 THEN 330\n310 X=INT(RND(1)*3+1)\n320 ON X GOTO 790,820,860\n330 IF S<>V THEN 340\n334 IF Z=1 THEN 370\n338 Q=1:GOTO 350\n340 IF W(R,S+1)<>0 THEN 370\n350 X=INT(RND(1)*3+1)\n360 ON X GOTO 790,820,910\n370 X=INT(RND(1)*2+1)\n380 ON X GOTO 790,820\n390 IF R=H THEN 470\n400 IF W(R+1,S)<>0 THEN 470\n405 IF S<>V THEN 420\n410 IF Z=1 THEN 450\n415 Q=1:GOTO 430\n420 IF W(R,S+1)<>0 THEN 450\n430 X=INT(RND(1)*3+1)\n440 ON X GOTO 790,860,910\n450 X=INT(RND(1)*2+1)\n460 ON X GOTO 790,860\n470 IF S<>V THEN 490\n480 IF Z=1 THEN 520\n485 Q=1:GOTO 500\n490 IF W(R,S+1)<>0 THEN 520\n500 X=INT(RND(1)*2+1)\n510 ON X GOTO 790,910\n520 GOTO 790\n530 IF S-1=0 THEN 670\n540 IF W(R,S-1)<>0 THEN 670\n545 IF R=H THEN 610\n547 IF W(R+1,S)<>0 THEN 610\n550 IF S<>V THEN 560\n552 IF Z=1 THEN 590\n554 Q=1:GOTO 570\n560 IF W(R,S+1)<>0 THEN 590\n570 X=INT(RND(1)*3+1)\n580 ON X GOTO 820,860,910\n590 X=INT(RND(1)*2+1)\n600 ON X GOTO 820,860\n610 IF S<>V THEN 630\n620 IF Z=1 THEN 660\n625 Q=1:GOTO 640\n630 IF W(R,S+1)<>0 THEN 660\n640 X=INT(RND(1)*2+1)\n650 ON X GOTO 820,910\n660 GOTO 820\n670 IF R=H THEN 740\n680 IF W(R+1,S)<>0 THEN 740\n685 IF S<>V THEN 700\n690 IF Z=1 THEN 730\n695 Q=1:GOTO 710\n700 IF W(R,S+1)<>0 THEN 730\n710 X=INT(RND(1)*2+1)\n720 ON X GOTO 860,910\n730 GOTO 860\n740 IF S<>V THEN 760\n750 IF Z=1 THEN 780\n755 Q=1:GOTO 770\n760 IF W(R,S+1)<>0 THEN 780\n770 GOTO 910\n780 GOTO 1000\n790 W(R-1,S)=C\n800 C=C+1:V(R-1,S)=2:R=R-1\n810 IF C=H*V+1 THEN 1010\n815 Q=0:GOTO 260\n820 W(R,S-1)=C\n830 C=C+1\n840 V(R,S-1)=1:S=S-1:IF C=H*V+1 THEN 1010\n850 Q=0:GOTO 260\n860 W(R+1,S)=C\n870 C=C+1:IF V(R,S)=0 THEN 880\n875 V(R,S)=3:GOTO 890\n880 V(R,S)=2\n890 R=R+1\n900 IF C=H*V+1 THEN 1010\n905 GOTO 530\n910 IF Q=1 THEN 960\n920 W(R,S+1)=C:C=C+1:IF V(R,S)=0 THEN 940\n930 V(R,S)=3:GOTO 950\n940 V(R,S)=1\n950 S=S+1:IF C=H*V+1 THEN 1010\n955 GOTO 260\n960 Z=1\n970 IF V(R,S)=0 THEN 980\n975 V(R,S)=3:Q=0:GOTO 1000\n980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250\n1000 GOTO 210\n1010 IF Z=1 THEN 1015\n1011 X=INT(RND(1)*H+1)\n1012 IF V(X,V)=0 THEN 1014\n1013 V(X,V)=3: GOTO 1015\n1014 V(X,V)=1\n1015 FOR J=1 TO V\n1016 PRINT \"I\";\n1017 FOR I=1 TO H\n1018 IF V(I,J)<2 THEN 1030\n1020 PRINT \"   \";\n1021 GOTO 1040\n1030 PRINT \"  I\";\n1040 NEXT I\n1041 PRINT\n1043 FOR I=1 TO H\n1045 IF V(I,J)=0 THEN 1060\n1050 IF V(I,J)=2 THEN 1060\n1051 PRINT \":  \";\n1052 GOTO 1070\n1060 PRINT \":--\";\n1070 NEXT I\n1071 PRINT \".\"\n1072 NEXT J\n1073 END\n"
  },
  {
    "path": "02_Amazing/csharp/Amazing.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Amazing\n{\n    class AmazingGame\n    {\n        private const int FIRST_COL = 0;\n        private const int FIRST_ROW = 0;\n        private const int EXIT_UNSET = 0;\n        private const int EXIT_DOWN = 1;\n        private const int EXIT_RIGHT = 2;\n\n        private static int GetDelimitedValue(String text, int pos)\n        {\n            String[] tokens = text.Split(\",\");\n\n            int val;\n            if (Int32.TryParse(tokens[pos], out val))\n            {\n                return val;\n            }\n            return 0;\n        }\n\n        private static String Tab(int spaces)\n        {\n            return new String(' ', spaces);\n        }\n\n        public static int Random(int min, int max)\n        {\n            Random random = new Random();\n            return random.Next(max - min) + min;\n        }\n\n        public void Play()\n        {\n            Console.WriteLine(Tab(28) + \"AMAZING PROGRAM\");\n            Console.WriteLine(Tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n\n            int width = 0;\n            int length = 0;\n\n            do\n            {\n                String range = DisplayTextAndGetInput(\"WHAT ARE YOUR WIDTH AND LENGTH\");\n                if (range.IndexOf(\",\") > 0)\n                {\n                    width = GetDelimitedValue(range, 0);\n                    length = GetDelimitedValue(range, 1);\n                }\n            }\n            while (width < 1 || length < 1);\n\n            Grid grid = new Grid(length, width);\n            int enterCol = grid.SetupEntrance();\n\n            int totalWalls = width * length + 1;\n            int count = 2;\n            Cell cell = grid.StartingCell();\n\n            while (count != totalWalls)\n            {\n                List<Direction> possibleDirs = GetPossibleDirs(grid, cell);\n\n                if (possibleDirs.Count != 0)\n                {\n                    cell = SetCellExit(grid, cell, possibleDirs);\n                    cell.Count = count++;\n                }\n                else\n                {\n                    cell = grid.GetFirstUnset(cell);\n                }\n            }\n            grid.SetupExit();\n\n            WriteMaze(width, grid, enterCol);\n        }\n\n        private Cell SetCellExit(Grid grid, Cell cell, List<Direction> possibleDirs)\n        {\n            Direction direction = possibleDirs[Random(0, possibleDirs.Count)];\n            if (direction == Direction.GO_LEFT)\n            {\n                cell = grid.GetPrevCol(cell);\n                cell.ExitType = EXIT_RIGHT;\n            }\n            else if (direction == Direction.GO_UP)\n            {\n                cell = grid.GetPrevRow(cell);\n                cell.ExitType = EXIT_DOWN;\n            }\n            else if (direction == Direction.GO_RIGHT)\n            {\n                cell.ExitType = cell.ExitType + EXIT_RIGHT;\n                cell = grid.GetNextCol(cell);\n            }\n            else if (direction == Direction.GO_DOWN)\n            {\n                cell.ExitType = cell.ExitType + EXIT_DOWN;\n                cell = grid.GetNextRow(cell);\n            }\n            return cell;\n        }\n\n        private void WriteMaze(int width, Grid grid, int enterCol)\n        {\n            // top line\n            for (int i = 0; i < width; i++)\n            {\n                if (i == enterCol) Console.Write(\".  \");\n                else Console.Write(\".--\");\n            }\n            Console.WriteLine(\".\");\n\n            for (int i = 0; i < grid.Length; i++)\n            {\n                Console.Write(\"I\");\n                for (int j = 0; j < grid.Width; j++)\n                {\n                    if (grid.Cells[i,j].ExitType == EXIT_UNSET || grid.Cells[i, j].ExitType == EXIT_DOWN)\n                        Console.Write(\"  I\");\n                    else Console.Write(\"   \");\n                }\n                Console.WriteLine();\n                for (int j = 0; j < grid.Width; j++)\n                {\n                    if (grid.Cells[i,j].ExitType == EXIT_UNSET || grid.Cells[i, j].ExitType == EXIT_RIGHT)\n                        Console.Write(\":--\");\n                    else Console.Write(\":  \");\n                }\n                Console.WriteLine(\".\");\n            }\n        }\n\n        private List<Direction> GetPossibleDirs(Grid grid, Cell cell)\n        {\n            var possibleDirs = new List<Direction>();\n            foreach (var val in Enum.GetValues(typeof(Direction)))\n            {\n                possibleDirs.Add((Direction)val);\n            }\n\n            if (cell.Col == FIRST_COL || grid.IsPrevColSet(cell))\n            {\n                possibleDirs.Remove(Direction.GO_LEFT);\n            }\n            if (cell.Row == FIRST_ROW || grid.IsPrevRowSet(cell))\n            {\n                possibleDirs.Remove(Direction.GO_UP);\n            }\n            if (cell.Col == grid.LastCol || grid.IsNextColSet(cell))\n            {\n                possibleDirs.Remove(Direction.GO_RIGHT);\n            }\n            if (cell.Row == grid.LastRow || grid.IsNextRowSet(cell))\n            {\n                possibleDirs.Remove(Direction.GO_DOWN);\n            }\n            return possibleDirs;\n        }\n\n        private String DisplayTextAndGetInput(String text)\n        {\n            Console.WriteLine(text);\n            return Console.ReadLine();\n        }\n\n\n        private enum Direction\n        {\n            GO_LEFT,\n            GO_UP,\n            GO_RIGHT,\n            GO_DOWN,\n        }\n\n        public class Cell\n        {\n            public int ExitType { get; set; }\n            public int Count { get; set; }\n\n            public int Col { get; set; }\n            public int Row { get; set; }\n\n            public Cell(int row, int col)\n            {\n                ExitType = EXIT_UNSET;\n                Row = row;\n                Col = col;\n            }\n        }\n\n\n        public class Grid\n        {\n            public Cell[,] Cells { get; private set; }\n\n            public int LastCol { get; set; }\n            public int LastRow { get; set; }\n\n            public int Width { get; private set; }\n            public int Length { get; private set; }\n\n            private int enterCol;\n\n            public Grid(int length, int width)\n            {\n                LastCol = width - 1;\n                LastRow = length - 1;\n                Width = width;\n                Length = length;\n\n                Cells = new Cell[length,width];\n                for (int i = 0; i < length; i++)\n                {\n                    for (int j = 0; j < width; j++)\n                    {\n                        this.Cells[i,j] = new Cell(i, j);\n                    }\n                }\n            }\n\n            public int SetupEntrance()\n            {\n                this.enterCol = Random(0, Width);\n                Cells[0, enterCol].Count = 1;\n                return this.enterCol;\n            }\n\n            public void SetupExit()\n            {\n                int exit = Random(0, Width - 1);\n                Cells[LastRow, exit].ExitType += 1;\n            }\n\n            public Cell StartingCell()\n            {\n                return Cells[0, enterCol];\n            }\n\n            public bool IsPrevColSet(Cell cell)\n            {\n                return 0 != Cells[cell.Row, cell.Col - 1].Count;\n            }\n\n            public bool IsPrevRowSet(Cell cell)\n            {\n                return 0 != Cells[cell.Row - 1, cell.Col].Count;\n            }\n\n            public bool IsNextColSet(Cell cell)\n            {\n                return 0 != Cells[cell.Row, cell.Col + 1].Count;\n            }\n\n            public bool IsNextRowSet(Cell cell)\n            {\n                return 0 != Cells[cell.Row + 1, cell.Col].Count;\n            }\n\n            public Cell GetPrevCol(Cell cell)\n            {\n                return Cells[cell.Row, cell.Col - 1];\n            }\n\n            public Cell GetPrevRow(Cell cell)\n            {\n                return Cells[cell.Row - 1, cell.Col];\n            }\n\n            public Cell GetNextCol(Cell cell)\n            {\n                return Cells[cell.Row, cell.Col + 1];\n            }\n\n            public Cell GetNextRow(Cell cell)\n            {\n                return Cells[cell.Row + 1, cell.Col];\n            }\n\n            public Cell GetFirstUnset(Cell cell)\n            {\n                int col = cell.Col;\n                int row = cell.Row;\n                Cell newCell;\n                do\n                {\n                    if (col != this.LastCol)\n                    {\n                        col++;\n                    }\n                    else if (row != this.LastRow)\n                    {\n                        row++;\n                        col = 0;\n                    }\n                    else\n                    {\n                        row = 0;\n                        col = 0;\n                    }\n                }\n                while ((newCell = Cells[row, col]).Count == 0);\n                return newCell;\n            }\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            new AmazingGame().Play();\n        }\n    }\n}\n"
  },
  {
    "path": "02_Amazing/csharp/Amazing.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>netcoreapp3.1</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "02_Amazing/csharp/Amazing.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.808.10\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Amazing\", \"Amazing.csproj\", \"{DD3483B4-F366-493C-8BFE-BAFBFE6F3016}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{DD3483B4-F366-493C-8BFE-BAFBFE6F3016}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{DD3483B4-F366-493C-8BFE-BAFBFE6F3016}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{DD3483B4-F366-493C-8BFE-BAFBFE6F3016}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{DD3483B4-F366-493C-8BFE-BAFBFE6F3016}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {F8762606-E467-47C1-A28F-BD5C4F7BFF5A}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "02_Amazing/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "02_Amazing/java/Amazing.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Random;\nimport java.util.Scanner;\nimport static java.lang.System.in;\nimport static java.lang.System.out;\n\n/**\n * Core algorithm copied from amazing.py\n */\npublic class Amazing {\n\n    final static int FIRST_COL = 0;\n    final static int FIRST_ROW = 0;\n    final static int EXIT_UNSET = 0;\n    final static int EXIT_DOWN = 1;\n    final static int EXIT_RIGHT = 2;\n    private final Scanner kbScanner;\n    public Amazing() {\n        kbScanner = new Scanner(in);\n    }\n\n    private static int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        try {\n            return Integer.parseInt(tokens[pos]);\n        } catch (Exception ex) {\n            return 0;\n        }\n    }\n\n    private static String tab(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    public static int random(int min, int max) {\n        Random random = new Random();\n        return random.nextInt(max - min) + min;\n    }\n\n    public void play() {\n        out.println(tab(28) + \"AMAZING PROGRAM\");\n        out.println(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        out.println();\n\n        int width = 0;\n        int length = 0;\n\n        do {\n            String range = displayTextAndGetInput(\"WHAT ARE YOUR WIDTH AND LENGTH\");\n            if (range.indexOf(\",\") > 0) {\n                width = getDelimitedValue(range, 0);\n                length = getDelimitedValue(range, 1);\n            }\n        } while (width < 1 || length < 1);\n\n        Grid grid = new Grid(length, width);\n        int enterCol = grid.setupEntrance();\n\n        int totalWalls = width * length + 1;\n        int count = 2;\n        Cell cell = grid.startingCell();\n\n        while (count != totalWalls) {\n            ArrayList<Direction> possibleDirs = getPossibleDirs(grid, cell);\n\n            if (possibleDirs.size() != 0) {\n                cell = setCellExit(grid, cell, possibleDirs);\n                cell.count = count++;\n            } else {\n                cell = grid.getFirstUnset(cell);\n            }\n        }\n        grid.setupExit();\n\n        writeMaze(width, grid, enterCol);\n    }\n\n    private Cell setCellExit(Grid grid, Cell cell, ArrayList<Direction> possibleDirs) {\n        Direction direction = possibleDirs.get(random(0, possibleDirs.size()));\n        if (direction == Direction.GO_LEFT) {\n            cell = grid.getPrevCol(cell);\n            cell.exitType = EXIT_RIGHT;\n        } else if (direction == Direction.GO_UP) {\n            cell = grid.getPrevRow(cell);\n            cell.exitType = EXIT_DOWN;\n        } else if (direction == Direction.GO_RIGHT) {\n            cell.exitType = cell.exitType + EXIT_RIGHT;\n            cell = grid.getNextCol(cell);\n        } else if (direction == Direction.GO_DOWN) {\n            cell.exitType = cell.exitType + EXIT_DOWN;\n            cell = grid.getNextRow(cell);\n        }\n        return cell;\n    }\n\n    private void writeMaze(int width, Grid grid, int enterCol) {\n        // top line\n        for (int i = 0; i < width; i++) {\n            if (i == enterCol) {\n                out.print(\".  \");\n            } else {\n                out.print(\".--\");\n            }\n        }\n        out.println('.');\n\n        for (Cell[] rows : grid.cells) {\n            out.print(\"I\");\n            for (Cell cell : rows) {\n                if (cell.exitType == EXIT_UNSET || cell.exitType == EXIT_DOWN) {\n                    out.print(\"  I\");\n                } else {\n                    out.print(\"   \");\n                }\n            }\n            out.println();\n            for (Cell cell : rows) {\n                if (cell.exitType == EXIT_UNSET || cell.exitType == EXIT_RIGHT) {\n                    out.print(\":--\");\n                } else {\n                    out.print(\":  \");\n                }\n            }\n            out.println(\".\");\n        }\n    }\n\n    private ArrayList<Direction> getPossibleDirs(Grid grid, Cell cell) {\n        ArrayList<Direction> possibleDirs = new ArrayList<>(Arrays.asList(Direction.values()));\n\n        if (cell.col == FIRST_COL || grid.isPrevColSet(cell)) {\n            possibleDirs.remove(Direction.GO_LEFT);\n        }\n        if (cell.row == FIRST_ROW || grid.isPrevRowSet(cell)) {\n            possibleDirs.remove(Direction.GO_UP);\n        }\n        if (cell.col == grid.lastCol || grid.isNextColSet(cell)) {\n            possibleDirs.remove(Direction.GO_RIGHT);\n        }\n        if (cell.row == grid.lastRow || grid.isNextRowSet(cell)) {\n            possibleDirs.remove(Direction.GO_DOWN);\n        }\n        return possibleDirs;\n    }\n\n    private String displayTextAndGetInput(String text) {\n        out.print(text);\n        return kbScanner.next();\n    }\n\n    enum Direction {\n        GO_LEFT,\n        GO_UP,\n        GO_RIGHT,\n        GO_DOWN,\n    }\n\n    public static class Cell {\n        int exitType = EXIT_UNSET;\n        int count = 0;\n\n        int col;\n        int row;\n\n        public Cell(int row, int col) {\n            this.row = row;\n            this.col = col;\n        }\n    }\n\n    public static class Grid {\n        Cell[][] cells;\n\n        int lastCol;\n        int lastRow;\n\n        int width;\n        int enterCol;\n\n        public Grid(int length, int width) {\n            this.lastCol = width - 1;\n            this.lastRow = length - 1;\n            this.width = width;\n\n            this.cells = new Cell[length][width];\n            for (int i = 0; i < length; i++) {\n                this.cells[i] = new Cell[width];\n                for (int j = 0; j < width; j++) {\n                    this.cells[i][j] = new Cell(i, j);\n                }\n            }\n        }\n\n        public int setupEntrance() {\n            this.enterCol = random(0, this.width);\n            cells[0][this.enterCol].count = 1;\n            return this.enterCol;\n        }\n\n        public void setupExit() {\n            int exit = random(0, width - 1);\n            cells[lastRow][exit].exitType += 1;\n        }\n\n        public Cell startingCell() {\n            return cells[0][enterCol];\n        }\n\n        public boolean isPrevColSet(Cell cell) {\n            return 0 != cells[cell.row][cell.col - 1].count;\n        }\n\n        public boolean isPrevRowSet(Cell cell) {\n            return 0 != cells[cell.row - 1][cell.col].count;\n        }\n\n        public boolean isNextColSet(Cell cell) {\n            return 0 != cells[cell.row][cell.col + 1].count;\n        }\n\n        public boolean isNextRowSet(Cell cell) {\n            return 0 != cells[cell.row + 1][cell.col].count;\n        }\n\n        public Cell getPrevCol(Cell cell) {\n            return cells[cell.row][cell.col - 1];\n        }\n\n        public Cell getPrevRow(Cell cell) {\n            return cells[cell.row - 1][cell.col];\n        }\n\n        public Cell getNextCol(Cell cell) {\n            return cells[cell.row][cell.col + 1];\n        }\n\n        public Cell getNextRow(Cell cell) {\n            return cells[cell.row + 1][cell.col];\n        }\n\n        public Cell getFirstUnset(Cell cell) {\n            int col = cell.col;\n            int row = cell.row;\n            Cell newCell;\n            do {\n                if (col != this.lastCol) {\n                    col++;\n                } else if (row != this.lastRow) {\n                    row++;\n                    col = 0;\n                } else {\n                    row = 0;\n                    col = 0;\n                }\n            } while ((newCell = cells[row][col]).count == 0);\n            return newCell;\n        }\n    }\n}\n"
  },
  {
    "path": "02_Amazing/java/AmazingGame.java",
    "content": "public class AmazingGame {\n    public static void main(String[] args) {\n        Amazing amazing = new Amazing();\n        amazing.play();\n    }\n}\n"
  },
  {
    "path": "02_Amazing/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "02_Amazing/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "02_Amazing/javascript/amazing.html",
    "content": "<html>\n<head>\n<title>AMAZING</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"amazing.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "02_Amazing/javascript/amazing.js",
    "content": "// AMAZING\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nprint(tab(28) + \"AMAZING PROGRAM\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"FOR EXAMPLE TYPE 10,10 AND PRESS ENTER\\n\");\nprint(\"\\n\");\n\n// Main program\nasync function main()\n{\n    while (1) {\n        print(\"WHAT ARE YOUR WIDTH AND LENGTH\");\n        a = await input();\n        h = parseInt(a);\n        v2 = parseInt(a.substr(a.indexOf(\",\") + 1));\n        if (h > 1 && v2 > 1)\n            break;\n        print(\"MEANINGLESS DIMENSIONS.  TRY AGAIN.\\n\");\n    }\n    w = [];\n    v = [];\n    for (i = 1; i <= h; i++) {\n        w[i] = [];\n        v[i] = [];\n        for (j = 1; j <= v2; j++) {\n            w[i][j] = 0;\n            v[i][j] = 0;\n        }\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    q = 0;\n    z = 0;\n    x = Math.floor(Math.random() * h + 1);\n    for (i = 1; i <= h; i++) {\n        if (i == x)\n            print(\".  \");\n        else\n            print(\".--\");\n    }\n    print(\".\\n\");\n    c = 1;\n    w[x][1] = c;\n    c++;\n    r = x;\n    s = 1;\n    entry = 0;\n    while (1) {\n        if (entry == 2) {\t// Search for a non-explored cell\n            do {\n                if (r < h) {\n                    r++;\n                } else if (s < v2) {\n                    r = 1;\n                    s++;\n                } else {\n                    r = 1;\n                    s = 1;\n                }\n            } while (w[r][s] == 0) ;\n        }\n        if (entry == 0 && r - 1 > 0 && w[r - 1][s] == 0) {\t// Can go left?\n            if (s - 1 > 0 && w[r][s - 1] == 0) {\t// Can go up?\n                if (r < h && w[r + 1][s] == 0) {\t// Can go right?\n                    // Choose left/up/right\n                    x = Math.floor(Math.random() * 3 + 1);\n                } else if (s < v2) {\n                    if (w[r][s + 1] == 0) {\t// Can go down?\n                        // Choose left/up/down\n                        x = Math.floor(Math.random() * 3 + 1);\n                        if (x == 3)\n                            x = 4;\n                    } else {\n                        x = Math.floor(Math.random() * 2 + 1);\n                    }\n                } else if (z == 1) {\n                    x = Math.floor(Math.random() * 2 + 1);\n                } else {\n                    q = 1;\n                    x = Math.floor(Math.random() * 3 + 1);\n                    if (x == 3)\n                        x = 4;\n                }\n            } else if (r < h && w[r + 1][s] == 0) {\t// Can go right?\n                if (s < v2) {\n                    if (w[r][s + 1] == 0) {\t// Can go down?\n                        // Choose left/right/down\n                        x = Math.floor(Math.random() * 3 + 1);\n                    } else {\n                        x = Math.floor(Math.random() * 2 + 1);\n                    }\n                    if (x >= 2)\n                        x++;\n                } else if (z == 1) {\n                    x = Math.floor(Math.random() * 2 + 1);\n                    if (x >= 2)\n                        x++;\n                } else {\n                    q = 1;\n                    x = Math.floor(Math.random() * 3 + 1);\n                    if (x >= 2)\n                        x++;\n                }\n            } else if (s < v2) {\n                if (w[r][s + 1] == 0) {\t// Can go down?\n                    // Choose left/down\n                    x = Math.floor(Math.random() * 2 + 1);\n                    if (x == 2)\n                        x = 4;\n                } else {\n                    x = 1;\n                }\n            } else if (z == 1) {\n                x = 1;\n            } else {\n                q = 1;\n                x = Math.floor(Math.random() * 2 + 1);\n                if (x == 2)\n                    x = 4;\n            }\n        } else if (s - 1 > 0 && w[r][s - 1] == 0) {\t// Can go up?\n            if (r < h && w[r + 1][s] == 0) {\n                if (s < v2) {\n                    if (w[r][s + 1] == 0)\n                        x = Math.floor(Math.random() * 3 + 2);\n                    else\n                        x = Math.floor(Math.random() * 2 + 2);\n                } else if (z == 1) {\n                    x = Math.floor(Math.random() * 2 + 2);\n                } else {\n                    q = 1;\n                    x = Math.floor(Math.random() * 3 + 2);\n                }\n            } else if (s < v2) {\n                if (w[r][s + 1] == 0) {\n                    x = Math.floor(Math.random() * 2 + 2);\n                    if (x == 3)\n                        x = 4;\n                } else {\n                    x = 2;\n                }\n            } else if (z == 1) {\n                x = 2;\n            } else {\n                q = 1;\n                x = Math.floor(Math.random() * 2 + 2);\n                if (x == 3)\n                    x = 4;\n            }\n        } else if (r < h && w[r + 1][s] == 0) {\t// Can go right?\n            if (s < v2) {\n                if (w[r][s + 1] == 0)\n                    x = Math.floor(Math.random() * 2 + 3);\n                else\n                    x = 3;\n            } else if (z == 1) {\n                x = 3;\n            } else {\n                q = 1;\n                x = Math.floor(Math.random() * 2 + 3);\n            }\n        } else if (s < v2) {\n            if (w[r][s + 1] == 0) \t// Can go down?\n                x = 4;\n            else {\n                entry = 2;\t// Blocked!\n                continue;\n            }\n        } else if (z == 1) {\n            entry = 2;\t// Blocked!\n            continue;\n        } else {\n            q = 1;\n            x = 4;\n        }\n        if (x == 1) {\t// Left\n            w[r - 1][s] = c;\n            c++;\n            v[r - 1][s] = 2;\n            r--;\n            if (c == h * v2 + 1)\n                break;\n            q = 0;\n            entry = 0;\n        } else if (x == 2) {\t// Up\n            w[r][s - 1] = c;\n            c++;\n            v[r][s - 1] = 1;\n            s--;\n            if (c == h * v2 + 1)\n                break;\n            q = 0;\n            entry = 0;\n        } else if (x == 3) {\t// Right\n            w[r + 1][s] = c;\n            c++;\n            if (v[r][s] == 0)\n                v[r][s] = 2;\n            else\n                v[r][s] = 3;\n            r++;\n            if (c == h * v2 + 1)\n                break;\n            entry = 1;\n        } else if (x == 4) {\t// Down\n            if (q != 1) {\t// Only if not blocked\n                w[r][s + 1] = c;\n                c++;\n                if (v[r][s] == 0)\n                    v[r][s] = 1;\n                else\n                    v[r][s] = 3;\n                s++;\n                if (c == h * v2 + 1)\n                    break;\n                entry = 0;\n            } else {\n                z = 1;\n                if (v[r][s] == 0) {\n                    v[r][s] = 1;\n                    q = 0;\n                    r = 1;\n                    s = 1;\n                    while (w[r][s] == 0) {\n                        if (r < h) {\n                            r++;\n                        } else if (s < v2) {\n                            r = 1;\n                            s++;\n                        } else {\n                            r = 1;\n                            s = 1;\n                        }\n                    }\n                    entry = 0;\n                } else {\n                    v[r][s] = 3;\n                    q = 0;\n                    entry = 2;\n                }\n            }\n        }\n    }\n    for (j = 1; j <= v2; j++) {\n        str = \"I\";\n        for (i = 1; i <= h; i++) {\n            if (v[i][j] < 2)\n                str += \"  I\";\n            else\n                str += \"   \";\n        }\n        print(str + \"\\n\");\n        str = \"\";\n        for (i = 1; i <= h; i++) {\n            if (v[i][j] == 0 || v[i][j] == 2)\n                str += \":--\";\n            else\n                str += \":  \";\n        }\n        print(str + \".\\n\");\n    }\n// If you want to see the order of visited cells\n//    for (j = 1; j <= v2; j++) {\n//        str = \"I\";\n//        for (i = 1; i <= h; i++) {\n//            str += w[i][j] + \" \";\n//        }\n//        print(str + \"\\n\");\n//    }\n}\n\nmain();\n"
  },
  {
    "path": "02_Amazing/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "02_Amazing/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "02_Amazing/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "02_Amazing/perl/amazing.pl",
    "content": "#! /usr/bin/perl\nuse strict;\nuse warnings;\n\n# Translated from BASIC by Alex Kapranoff\n\nuse feature qw/say/;\n\n# width and height of the maze\nmy ($width, $height) = input_dimensions();\n\n# wall masks for all cells\nmy @walls;\n\n# flags of previous visitation for all cells\nmy %is_visited;\n\n# was the path out of the maze found?\nmy $path_found = 0;\n\n# column of entry to the maze in the top line\nmy $entry_col = int(rand($width));\n\n# cell coordinates for traversal\nmy $col = $entry_col;\nmy $row = 0;\n\n$is_visited{$row, $col} = 1;\n\n# looping until we visit every cell\nwhile (keys %is_visited < $width * $height) {\n    if (my @dirs = get_possible_directions()) {\n        my $dir = $dirs[rand @dirs];\n\n        # modify current cell wall if needed\n        $walls[$row]->[$col] |= $dir->[2];\n\n        # move the position\n        $row += $dir->[0];\n        $col += $dir->[1];\n\n        # we found the exit!\n        if ($row == $height) {\n            $path_found = 1;\n            --$row;\n\n            if ($walls[$row]->[$col] == 1) {\n                ($row, $col) = get_next_branch(0, 0);\n            }\n        }\n        else {\n            # modify the new cell wall if needed\n            $walls[$row]->[$col] |= $dir->[3];\n\n            $is_visited{$row, $col} = 1;\n        }\n    }\n    else {\n        ($row, $col) = get_next_branch($row, $col);\n    }\n}\n\nunless ($path_found) {\n    $walls[-1]->[rand $width] |= 1;\n}\n\nprint_maze();\n\nsub input_dimensions {\n    # Print the banner and returns the dimensions as two integers > 1.\n    # The integers are parsed from the first line of standard input.\n    say ' ' x 28, 'AMAZING PROGRAM';\n    say ' ' x 15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY';\n    print \"\\n\" x 4;\n\n    my ($w, $h) = (0, 0);\n\n    while ($w <= 1 || $h <= 1) {\n        print 'WHAT ARE YOUR WIDTH AND LENGTH? ';\n\n        ($w, $h) = <STDIN> =~ / \\d+ /xg;\n\n        if ($w < 1 || $h < 1) {\n            say \"MEANINGLESS DIMENSIONS.  TRY AGAIN.\"\n        }\n    }\n\n    print \"\\n\" x 4;\n\n    return ($w, $h);\n}\n\nsub get_possible_directions {\n    # Returns a list of all directions that are available to go to\n    # from the current coordinates. \"Down\" is available on the last line\n    # until we go there once and mark it as the path through the maze.\n    #\n    # Each returned direction element contains changes to the coordindates and to\n    # the wall masks of the previous and next cell after the move.\n\n    my @rv;\n    # up\n    if ($row > 0 && !$is_visited{$row - 1, $col}) {\n        push @rv, [-1, 0, 0, 1];\n    }\n    # left\n    if ($col > 0 && !$is_visited{$row, $col - 1}) {\n        push @rv, [0, -1, 0, 2];\n    }\n    # right\n    if ($col < $width - 1 && !$is_visited{$row, $col + 1}) {\n        push @rv, [0, 1, 2, 0];\n    }\n    # down\n    if ($row < $height - 1 && !$is_visited{$row + 1, $col}\n        || $row == $height - 1 && !$path_found\n    ) {\n        push @rv, [1, 0, 1, 0];\n    }\n\n    return @rv;\n}\n\nsub get_next_branch {\n    # Returns the cell coordinates to start a new maze branch from.\n    # It looks for a visited cell starting from passed position and\n    # going down in the natural traversal order incrementing column and\n    # rows with a rollover to start at the bottom right corner.\n    my ($y, $x) = @_;\n    do {\n        if ($x < $width - 1) {\n            ++$x;\n        } elsif ($y < $height - 1) {\n            ($y, $x) = ($y + 1, 0);\n        } else {\n            ($y, $x) = (0, 0);\n        }\n    } while (!$is_visited{$y, $x});\n\n    return ($y, $x);\n}\n\nsub print_maze {\n    # Print the full maze based on wall masks.\n    # For each cell, we mark the absense of the wall to the right with\n    # bit 2 and the absense of the wall down with bit 1. Full table:\n    # 0 -> both walls are present\n    # 1 -> wall down is absent\n    # 2 -> wall to the right is absent\n    # 3 -> both walls are absent\n    say join('.', '', map { $_ == $entry_col ? '  ' : '--' } 0 .. $width - 1), '.';\n\n    for my $row (@walls) {\n        say join('  ', map { $_ & 2 ? ' ' : 'I' } 0, @$row);\n        say join(':', '', map { $_ & 1 ? '  ' : '--' } @$row), '.';\n    }\n\n    return;\n}\n"
  },
  {
    "path": "02_Amazing/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "02_Amazing/python/amazing.py",
    "content": "import enum\nimport random\nfrom dataclasses import dataclass\nfrom typing import List, Tuple\n\n# Python translation by Frank Palazzolo - 2/2021\n\n\nclass Maze:\n    def __init__(self, width: int, length: int) -> None:\n        assert width >= 2 and length >= 2\n        used: List[List[int]] = []\n        walls: List[List[int]] = []\n        for _ in range(length):\n            used.append([0] * width)\n            walls.append([0] * width)\n\n        # Pick a random entrance, mark as used\n        enter_col = random.randint(0, width - 1)\n        used[0][enter_col] = 1\n\n        self.used = used\n        self.walls = walls\n        self.enter_col = enter_col\n        self.width = width\n        self.length = length\n\n    def add_exit(self) -> None:\n        \"\"\"Modifies 'walls' to add an exit to the maze.\"\"\"\n        col = random.randint(0, self.width - 1)\n        row = self.length - 1\n        self.walls[row][col] = self.walls[row][col] + 1\n\n    def display(self) -> None:\n        for col in range(self.width):\n            if col == self.enter_col:\n                print(\".  \", end=\"\")\n            else:\n                print(\".--\", end=\"\")\n        print(\".\")\n        for row in range(self.length):\n            print(\"I\", end=\"\")\n            for col in range(self.width):\n                if self.walls[row][col] < 2:\n                    print(\"  I\", end=\"\")\n                else:\n                    print(\"   \", end=\"\")\n            print()\n            for col in range(self.width):\n                if self.walls[row][col] in [0, 2]:\n                    print(\":--\", end=\"\")\n                else:\n                    print(\":  \", end=\"\")\n            print(\".\")\n\n\nclass Direction(enum.Enum):\n    LEFT = 0\n    UP = 1\n    RIGHT = 2\n    DOWN = 3\n\n\n@dataclass\nclass Position:\n    row: int\n    col: int\n\n\n# Give Exit directions nice names\nEXIT_DOWN = 1\nEXIT_RIGHT = 2\n\n\ndef main() -> None:\n    print_intro()\n    width, length = get_maze_dimensions()\n    maze = build_maze(width, length)\n    maze.display()\n\n\ndef print_intro() -> None:\n    print(\" \" * 28 + \"AMAZING PROGRAM\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef build_maze(width: int, length: int) -> Maze:\n    \"\"\"Build two 2D arrays.\"\"\"\n    #\n    # used:\n    #   Initially set to zero, unprocessed cells\n    #   Filled in with consecutive non-zero numbers as cells are processed\n    #\n    # walls:\n    #   Initially set to zero, (all paths blocked)\n    #   Remains 0 if there is no exit down or right\n    #   Set to 1 if there is an exit down\n    #   Set to 2 if there is an exit right\n    #   Set to 3 if there are exits down and right\n    assert width >= 2 and length >= 2\n\n    maze = Maze(width, length)\n    position = Position(row=0, col=maze.enter_col)\n    count = 2\n\n    while count != width * length + 1:\n        possible_dirs = get_possible_directions(maze, position)\n\n        # If we can move in a direction, move and make opening\n        if len(possible_dirs) != 0:\n            position, count = make_opening(maze, possible_dirs, position, count)\n        # otherwise, move to the next used cell, and try again\n        else:\n            while True:\n                if position.col != width - 1:\n                    position.col += 1\n                elif position.row != length - 1:\n                    position.row, position.col = position.row + 1, 0\n                else:\n                    position.row, position.col = 0, 0\n                if maze.used[position.row][position.col] != 0:\n                    break\n\n    maze.add_exit()\n    return maze\n\n\ndef make_opening(\n    maze: Maze,\n    possible_dirs: List[Direction],\n    pos: Position,\n    count: int,\n) -> Tuple[Position, int]:\n    \"\"\"\n    Attention! This modifies 'used' and 'walls'\n    \"\"\"\n    direction = random.choice(possible_dirs)\n    if direction == Direction.LEFT:\n        pos.col = pos.col - 1\n        maze.walls[pos.row][pos.col] = EXIT_RIGHT\n    elif direction == Direction.UP:\n        pos.row = pos.row - 1\n        maze.walls[pos.row][pos.col] = EXIT_DOWN\n    elif direction == Direction.RIGHT:\n        maze.walls[pos.row][pos.col] = maze.walls[pos.row][pos.col] + EXIT_RIGHT\n        pos.col = pos.col + 1\n    elif direction == Direction.DOWN:\n        maze.walls[pos.row][pos.col] = maze.walls[pos.row][pos.col] + EXIT_DOWN\n        pos.row = pos.row + 1\n    maze.used[pos.row][pos.col] = count\n    count += 1\n    return pos, count\n\n\ndef get_possible_directions(maze: Maze, pos: Position) -> List[Direction]:\n    \"\"\"\n    Get a list of all directions that are not blocked.\n\n    Also ignore hit cells that we have already processed\n    \"\"\"\n    possible_dirs = list(Direction)\n    if pos.col == 0 or maze.used[pos.row][pos.col - 1] != 0:\n        possible_dirs.remove(Direction.LEFT)\n    if pos.row == 0 or maze.used[pos.row - 1][pos.col] != 0:\n        possible_dirs.remove(Direction.UP)\n    if pos.col == maze.width - 1 or maze.used[pos.row][pos.col + 1] != 0:\n        possible_dirs.remove(Direction.RIGHT)\n    if pos.row == maze.length - 1 or maze.used[pos.row + 1][pos.col] != 0:\n        possible_dirs.remove(Direction.DOWN)\n    return possible_dirs\n\n\ndef get_maze_dimensions() -> Tuple[int, int]:\n    while True:\n        input_str = input(\"What are your width and length?\")\n        if input_str.count(\",\") == 1:\n            width_str, length_str = input_str.split(\",\")\n            width = int(width_str)\n            length = int(length_str)\n            if width > 1 and length > 1:\n                break\n        print(\"Meaningless dimensions. Try again.\")\n    return width, length\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "02_Amazing/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n\nConverted to Ruby (with tons of inspiration from the Python version) by @marcheiligers\n\nRun `ruby amazing.rb`.\n\nRun `DEBUG=1 ruby amazing.ruby` to see how it works (requires at least Ruby 2.7).\n"
  },
  {
    "path": "02_Amazing/ruby/amazing.rb",
    "content": "# frozen_string_literal: true\n\nDEBUG = !ENV['DEBUG'].nil?\n\nrequire 'io/console' if DEBUG\n\n# BASIC arrays are 1-based, unlike Ruby 0-based arrays,\n# and this class simulates that. BASIC arrays are zero-filled,\n# which is also done here. While we could easily update the\n# algorithm to work with zero-based arrays, this class makes\n# the problem easier to reason about, row or col 1 are the\n# first row or column.\nclass BasicArrayTwoD\n  def initialize(rows, cols)\n    @val = Array.new(rows) { Array.new(cols, 0) }\n  end\n\n  def [](row, col = nil)\n    if col\n      @val[row - 1][col - 1]\n    else\n      @val[row - 1]\n    end\n  end\n\n  def []=(row, col, n)\n    @val[row - 1][col - 1] = n\n  end\n\n  def to_s(width: max_width, row_hilite: nil, col_hilite: nil)\n    @val.map.with_index do |row, row_index|\n      row.map.with_index do |val, col_index|\n        if row_hilite == row_index + 1 && col_hilite == col_index + 1\n          \"[#{val.to_s.center(width)}]\"\n        else\n          val.to_s.center(width + 2)\n        end\n      end.join\n    end.join(\"\\n\")\n  end\n\n  def max_width\n    @val.flat_map { |row| row.map { |val| val.to_s.length } }.sort.last\n  end\nend\n\nclass Maze\n  EXIT_DOWN = 1\n  EXIT_RIGHT = 2\n\n  # Set up a constant hash for directions\n  # The values represent the direction of the move as changes to row, col\n  # and the type of exit when moving in that direction\n  DIRECTIONS = {\n    left: { row: 0, col: -1, exit: EXIT_RIGHT },\n    up: { row: -1, col: 0, exit: EXIT_DOWN },\n    right: { row: 0, col: 1, exit: EXIT_RIGHT },\n    down: { row: 1, col: 0, exit: EXIT_DOWN }\n  }.freeze\n\n  attr_reader :width, :height, :used, :walls, :entry\n\n  def initialize(width, height)\n    @width = width\n    @height = height\n\n    @used = BasicArrayTwoD.new(height, width)\n    @walls = BasicArrayTwoD.new(height, width)\n\n    create\n  end\n\n  def draw\n    # Print the maze\n    draw_top(entry, width)\n    (1..height - 1).each do |row|\n      draw_row(walls[row])\n    end\n    draw_bottom(walls[height])\n  end\n\n  private\n\n  def create\n    # entry represents the location of the opening\n    @entry = (rand * width).round + 1\n\n    # Set up our current row and column, starting at the top and the locations of the opening\n    row = 1\n    col = entry\n    c = 1\n    used[row, col] = c # This marks the opening in the first row\n    c += 1\n\n    while c != width * height + 1 do\n      debug walls, row, col\n      # remove possible directions that are blocked or\n      # hit cells that we have already processed\n      possible_dirs = DIRECTIONS.reject do |dir, change|\n        nrow = row + change[:row]\n        ncol = col + change[:col]\n        nrow < 1 || nrow > height || ncol < 1 || ncol > width || used[nrow, ncol] != 0\n      end.keys\n\n      # If we can move in a direction, move and make opening\n      if possible_dirs.size != 0\n        direction = possible_dirs.sample\n        change = DIRECTIONS[direction] # pick a random direction\n        if %i[left up].include?(direction)\n          row += change[:row]\n          col += change[:col]\n          walls[row, col] = change[:exit]\n        else\n          walls[row, col] += change[:exit]\n          row += change[:row]\n          col += change[:col]\n        end\n        used[row, col] = c\n        c = c + 1\n      # otherwise, move to the next used cell, and try again\n      else\n        loop do\n          if col != width\n            col += 1\n          elsif row != height\n            row += 1\n            col = 1\n          else\n            row = col = 1\n          end\n          break if used[row, col] != 0\n          debug walls, row, col\n        end\n      end\n    end\n\n    # Add a random exit\n    walls[height, (rand * width).round] += 1\n  end\n\n  def draw_top(entry, width)\n    (1..width).each do |i|\n      if i == entry\n        print i == 1 ? '┏  ' : '┳  '\n      else\n        print i == 1 ? '┏━━' : '┳━━'\n      end\n    end\n\n    puts '┓'\n  end\n\n  def draw_row(row)\n    print '┃'\n    row.each.with_index do |val, col|\n      print val < 2 ? '  ┃' : '   '\n    end\n    puts\n    row.each.with_index do |val, col|\n      print val == 0 || val == 2 ? (col == 0 ? '┣━━' : '╋━━') : (col == 0 ? '┃  ' : '┫  ')\n    end\n    puts '┫'\n  end\n\n  def draw_bottom(row)\n    print '┃'\n    row.each.with_index do |val, col|\n      print val < 2 ? '  ┃' : '   '\n    end\n    puts\n    row.each.with_index do |val, col|\n      print val == 0 || val == 2 ? (col == 0 ? '┗━━' : '┻━━') : (col == 0 ? '┗  ' : '┻  ')\n    end\n    puts '┛'\n  end\n\n  def debug(walls, row, col)\n    return unless DEBUG\n\n    STDOUT.clear_screen\n    puts walls.to_s(row_hilite: row, col_hilite: col)\n    sleep 0.1\n  end\nend\n\nclass Amazing\n  def run\n    draw_header\n\n    width, height = ask_dimensions\n    while width <= 1 || height <= 1\n      puts \"MEANINGLESS DIMENSIONS.  TRY AGAIN.\"\n      width, height = ask_dimensions\n    end\n\n    maze = Maze.new(width, height)\n    puts \"\\n\" * 3\n    maze.draw\n  end\n\n  def draw_header\n    puts ' ' * 28 + 'AMAZING PROGRAM'\n    puts ' ' * 15 + 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY'\n    puts \"\\n\" * 3\n  end\n\n  def ask_dimensions\n    print 'WHAT ARE YOUR WIDTH AND HEIGHT? '\n    width = gets.to_i\n    print '?? '\n    height = gets.to_i\n    [width, height]\n  end\nend\n\nAmazing.new.run\n"
  },
  {
    "path": "02_Amazing/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "02_Amazing/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "02_Amazing/rust/src/main.rs",
    "content": "use rand::{Rng, thread_rng, prelude::SliceRandom};\nuse  std::{io, collections::HashSet};\n\nfn main() {\n    //DATA\n    enum Direction {\n        LEFT=0,\n        UP=1,\n        RIGHT=2,\n        DOWN=3,\n    }\n    impl Direction {\n        fn val(&self) -> usize {\n            match self {\n                Direction::LEFT=>0,\n                Direction::UP=>1,\n                Direction::RIGHT=>2,\n                Direction::DOWN=>3,\n            }\n        }\n    }\n    const EXIT_DOWN:usize = 1;\n    const EXIT_RIGHT:usize = 2;\n    let mut rng = thread_rng(); //rng\n    /*\n    vector of:\n        vectors of:\n            integers\n                Initially set to 0, unprocessed cells.\n                Filled in with consecutive non-zero numbers as cells are processed\n    */\n    let mut used; //2d vector\n    /*\n    vector of:\n        vectors of:\n            integers\n                Remains 0 if there is no exit down or right\n                Set to 1 if there is an exit down\n                Set to 2 if there is an exit right\n                Set to 3 if there are exits down and right\n    */\n    let mut walls; //2d vector\n    let width;\n    let height;\n    let entrance_column; //rng, column of entrance\n    let mut row;\n    let mut col;\n    let mut count;\n\n\n\n    //print welcome message\n    println!(\"\n                 AMAZING PROGRAM\n    CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\\n\");\n\n    //prompt for input\n    width = get_user_input(\"What is your width?\");\n    print!(\"\\n\"); //one blank line below\n    height = get_user_input(\"What is your height?\");\n    print!(\"\\n\\n\\n\\n\");//4 blank lines below\n\n    //generate maze\n    //initialize used and wall vectors\n    //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :)\n    used = vec![0; (width * height) as usize];\n    let mut used: Vec<_> = used.as_mut_slice().chunks_mut(width as usize).collect();\n    let used = used.as_mut_slice(); //accessible as used[][]\n    //2d vectors when you don't know the sizes at compile time are wierd, but here's how it's done :)\n    walls = vec![0; (width * height) as usize];\n    let mut walls: Vec<_> = walls.as_mut_slice().chunks_mut(width as usize).collect();\n    let walls = walls.as_mut_slice(); //accessible as walls[][]\n\n    entrance_column=rng.gen_range(0..width-1);\n    row = 0;\n    col = entrance_column;\n    count = 1;\n    used[row][col] = count;\n    count += 1;\n\n    while count != width*height + 1 {\n        //remove possible directions that are blocked or\n        //hit cells already processed\n        let mut possible_directions: HashSet<usize> = vec![Direction::LEFT.val(),Direction::UP.val(),Direction::RIGHT.val(),Direction::DOWN.val()].into_iter().collect(); //create it as a vector bc that's easy, then convert it to a hashset\n        if col==0 || used[row][col-1]!=0 {\n            possible_directions.remove(&Direction::LEFT.val());\n        }\n        if row==0 || used[row-1][col]!=0 {\n            possible_directions.remove(&Direction::UP.val());\n        }\n        if col==width-1 || used[row][col+1]!=0 {\n            possible_directions.remove(&Direction::RIGHT.val());\n        }\n        if row==height-1 || used[row+1][col]!=0 {\n            possible_directions.remove(&Direction::DOWN.val());\n        }\n\n        //If we can move in a direction, move and make opening\n        if possible_directions.len() != 0 { //all values in possible_directions are not NONE\n            let pos_dir_vec: Vec<_> = possible_directions.into_iter().collect(); // convert the set to a vector to get access to the choose method\n            //select a random direction\n            match pos_dir_vec.choose(&mut rng).expect(\"error\") {\n                0=> {\n                    col -= 1;\n                    walls[row][col] = EXIT_RIGHT;\n                },\n                1=> {\n                    row -= 1;\n                    walls[row][col] = EXIT_DOWN;\n                },\n                2=>{\n                    walls[row][col] = walls[row][col] + EXIT_RIGHT;\n                    col += 1;\n                },\n                3=>{\n                    walls[row][col] = walls[row][col] + EXIT_DOWN;\n                    row += 1;\n                },\n                _=>{},\n            }\n            used[row][col]=count;\n            count += 1;\n        }\n        //otherwise, move to the next used cell, and try again\n        else {\n            loop {\n                if col != width-1 {col += 1;}\n                else if row != height-1 {row+=1; col=0;}\n                else {row=0;col=0;}\n\n                if used[row][col] != 0 {break;}\n            }\n        }\n    }\n    // Add a random exit\n    col=rng.gen_range(0..width);\n    row=height-1;\n    walls[row][col]+=1;\n\n    //print maze\n    //first line\n    for c in 0..width {\n        if c == entrance_column {\n            print!(\".  \");\n        }\n        else {\n            print!(\".--\");\n        }\n    }\n    println!(\".\");\n    //rest of maze\n    for r in 0..height {\n        print!(\"I\");\n        for c in 0..width {\n            if walls[r][c]<2 {print!(\"  I\");}\n            else {print!(\"   \");}\n        }\n        println!();\n        for c in 0..width {\n            if walls[r][c] == 0 || walls[r][c]==2 {print!(\":--\");}\n            else {print!(\":  \");}\n        }\n        println!(\".\");\n    }\n\n    //stops the program from ending until you give input, useful when running a compiled .exe\n    println!(\"\\n\\npress ENTER to exit\");\n    io::stdin().read_line(&mut String::new()).expect(\"closing\");\n}\n\nfn get_user_input(prompt: &str) -> usize {\n    //DATA\n    let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n    //input loop\n    return loop {\n\n        //print prompt\n        println!(\"{}\", prompt);\n\n        //read user input from standard input, and store it to raw_input\n        raw_input.clear(); //clear input\n        io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n        //from input, try to read a number\n        match raw_input.trim().parse::<usize>() {\n            Ok(i) => {\n                if i>1 { //min size 1\n                    break i; // this escapes the loop, returning i\n                }\n                else {\n                    println!(\"INPUT OUT OF RANGE.  TRY AGAIN.\");\n                    continue;// run the loop again\n                }\n            }\n            Err(e) => {\n                println!(\"MEANINGLESS DIMENSION.  TRY AGAIN.  {}\", e.to_string().to_uppercase());\n                continue; // run the loop again\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "02_Amazing/vbnet/Amazing.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Amazing\", \"Amazing.vbproj\", \"{FB9DF301-CB34-4C9A-8823-F034303F5DA3}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{FB9DF301-CB34-4C9A-8823-F034303F5DA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FB9DF301-CB34-4C9A-8823-F034303F5DA3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FB9DF301-CB34-4C9A-8823-F034303F5DA3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FB9DF301-CB34-4C9A-8823-F034303F5DA3}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "02_Amazing/vbnet/Amazing.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Amazing</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "02_Amazing/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "02_Amazing/vbnet/program.vb",
    "content": "Imports System\n\nModule Program\n\n    Enum Directions\n        SolveAndReset = 0\n        Left = 1\n        Up = 2\n        Right = 3\n        Down = 4\n    End Enum\n\n    'Program State\n    Dim Width As Integer = 0, Height As Integer = 0, Q As Integer = 0, CellsVisited As Integer = 2, curCol As Integer, curRow As Integer = 1\n    Dim SolutionCompleted As Boolean = False\n    Dim CellVisitHistory(,) As Integer\n    Dim CellState(,) As Integer\n\n    Dim rnd As New Random()\n\n    Public ReadOnly Property BlockedLeft As Boolean\n        Get\n            Return curCol - 1 = 0 OrElse CellVisitHistory(curCol - 1, curRow) <> 0\n        End Get\n    End Property\n    Public ReadOnly Property BlockedAbove As Boolean\n        Get\n            Return curRow - 1 = 0 OrElse CellVisitHistory(curCol, curRow - 1) <> 0\n        End Get\n    End Property\n    Public ReadOnly Property BlockedRight As Boolean\n        Get\n            Return curCol = Width OrElse CellVisitHistory(curCol + 1, curRow) <> 0\n        End Get\n    End Property\n    'Note: \"BlockedBelow\" does NOT include checking if we have a solution!\n    Public ReadOnly Property BlockedBelow As Boolean\n        Get\n            Return curRow = Height OrElse CellVisitHistory(curCol, curRow + 1) <> 0\n        End Get\n    End Property\n    Public ReadOnly Property OnBottomRow As Boolean\n        Get\n            Return curRow.Equals(Height)\n        End Get\n    End Property\n\n    Sub Main(args As String())\n        Const header As String =\n\"             AMAZING PROGRAM\n CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n\"\n        Console.WriteLine(header)\n\n        While Width <= 1 OrElse Height <= 1\n            Console.Write(\"WHAT ARE YOUR WIDTH AND LENGTH? \")\n\n            'We no longer have the old convenient INPUT command, so need to parse out the inputs\n            Dim parts = Console.ReadLine().Split(\",\"c).Select(Function(s) Convert.ToInt32(s.Trim())).ToList()\n            Width = parts(0)\n            Height = parts(1)\n\n            If Width <= 1 OrElse Height <= 1 Then Console.WriteLine($\"MEANINGLESS DIMENSIONS.  TRY AGAIN.{vbCrLf}\")\n        End While\n\n        ReDim CellVisitHistory(Width, Height), CellState(Width, Height)\n\n        Console.WriteLine(\"\n\n\")\n\n        curCol = rnd.Next(1, Width + 1) 'Starting X position\n        CellVisitHistory(curCol, 1) = 1\n        Dim startXPos As Integer = curCol 'we need to know this at the end to print opening line\n\n        Dim keepGoing As Boolean = True\n        While keepGoing\n            If BlockedLeft Then\n                keepGoing = ChoosePath_BlockedToTheLeft()\n            ElseIf BlockedAbove Then\n                keepGoing = ChoosePath_BlockedAbove()\n            ElseIf BlockedRight Then\n                keepGoing = ChoosePath_BlockedToTheRight()\n            Else\n                keepGoing = SelectRandomDirection(Directions.Left, Directions.Up, Directions.Right) 'Go anywhere but down\n            End If\n        End While\n\n        PrintFinalResults(startXPos)\n    End Sub\n\n    Public Sub ResetCurrentPosition()\n        Do\n            If curCol <> Width Then 'not at the right edge\n                curCol += 1\n            ElseIf curRow <> Height Then 'not at the bottom\n                curCol = 1\n                curRow += 1\n            Else\n                curCol = 1\n                curRow = 1\n            End If\n        Loop While CellVisitHistory(curCol, curRow) = 0\n    End Sub\n\n    Dim methods() As Func(Of Boolean) = {AddressOf MarkSolvedAndResetPosition, AddressOf GoLeft, AddressOf GoUp, AddressOf GoRight, AddressOf GoDown}\n    Public Function SelectRandomDirection(ParamArray possibles() As Directions) As Boolean\n        Dim x As Integer = rnd.Next(0, possibles.Length)\n        Return methods(possibles(x))()\n    End Function\n\n    Public Function ChoosePath_BlockedToTheLeft() As Boolean\n        If BlockedAbove Then\n            If BlockedRight Then\n                If curRow <> Height Then\n                    If CellVisitHistory(curCol, curRow + 1) <> 0 Then ' Can't go down, but not at the edge...blocked. Reset and try again\n                        ResetCurrentPosition()\n                        Return True\n                    Else\n                        Return GoDown()\n                    End If\n                ElseIf SolutionCompleted Then 'Can't go Down (there's already another solution)\n                    ResetCurrentPosition()\n                    Return True\n                Else 'Can't go LEFT, UP, RIGHT, or DOWN, but we're on the bottom and there's no solution yet\n                    Return MarkSolvedAndResetPosition()\n                End If\n            ElseIf BlockedBelow Then\n                Return GoRight()\n            ElseIf Not OnBottomRow Then\n                Return SelectRandomDirection(Directions.Right, Directions.Down)\n            ElseIf SolutionCompleted Then 'Can only go right, and we're at the bottom\n                Return GoRight()\n            Else 'Can only go right, we're at the bottom, and there's not a solution yet\n                Return SelectRandomDirection(Directions.Right, Directions.SolveAndReset)\n            End If\n            '== Definitely can go Up ==\n        ElseIf BlockedRight Then\n            If BlockedBelow Then\n                Return GoUp()\n            ElseIf Not OnBottomRow Then\n                Return SelectRandomDirection(Directions.Up, Directions.Down)\n            ElseIf SolutionCompleted Then 'We're on the bottom row, can only go up\n                Return GoUp()\n            Else 'We're on the bottom row, can only go up, but there's no solution\n                Return SelectRandomDirection(Directions.Up, Directions.SolveAndReset)\n            End If\n            '== Definitely can go Up and Right ==\n        ElseIf BlockedBelow Then\n            Return SelectRandomDirection(Directions.Up, Directions.Right)\n        ElseIf Not OnBottomRow Then\n            Return SelectRandomDirection(Directions.Up, Directions.Right, Directions.Down)\n        ElseIf SolutionCompleted Then 'at the bottom, but already have a solution\n            Return SelectRandomDirection(Directions.Up, Directions.Right)\n        Else\n            Return SelectRandomDirection(Directions.Up, Directions.Right, Directions.SolveAndReset)\n        End If\n    End Function\n\n    Public Function ChoosePath_BlockedAbove() As Boolean\n        'No need to check the left side, only called from the \"keepGoing\" loop where LEFT is already cleared\n        If BlockedRight Then\n            If BlockedBelow Then\n                Return GoLeft()\n            ElseIf Not OnBottomRow Then\n                Return SelectRandomDirection(Directions.Left, Directions.Down)\n            ElseIf SolutionCompleted Then 'Can't go down because there's already a solution\n                Return GoLeft()\n            Else 'At the bottom, no solution yet...\n                Return SelectRandomDirection(Directions.Left, Directions.SolveAndReset)\n            End If\n        ElseIf BlockedBelow Then\n            Return SelectRandomDirection(Directions.Left, Directions.Right)\n        ElseIf Not OnBottomRow Then\n            Return SelectRandomDirection(Directions.Left, Directions.Right, Directions.Down)\n        ElseIf SolutionCompleted Then\n            Return SelectRandomDirection(Directions.Left, Directions.Right)\n        Else\n            Return SelectRandomDirection(Directions.Left, Directions.Right, Directions.SolveAndReset)\n        End If\n    End Function\n\n    Public Function ChoosePath_BlockedToTheRight() As Boolean\n        'No need to check Left or Up, only called from the \"keepGoing\" loop where LEFT and UP are already cleared\n        If BlockedRight Then 'Can't go Right -- why? we knew this when calling the function\n            If BlockedBelow Then\n                Return SelectRandomDirection(Directions.Left, Directions.Up)\n            ElseIf Not OnBottomRow Then\n                Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.Down)\n            ElseIf SolutionCompleted Then\n                Return SelectRandomDirection(Directions.Left, Directions.Up)\n            Else\n                Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.SolveAndReset)\n            End If\n        Else 'Should never get here\n            Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.Right) 'Go Left, Up, or Right (but path is blocked?)\n        End If\n    End Function\n\n    Public Sub PrintFinalResults(startPos As Integer)\n        For i As Integer = 0 To Width - 1\n            If i = startPos Then Console.Write(\".  \") Else Console.Write(\".--\")\n        Next\n        Console.WriteLine(\".\")\n\n        If Not SolutionCompleted Then 'Pick a random exit\n            Dim X As Integer = rnd.Next(1, Width + 1)\n            If CellState(X, Height) = 0 Then\n                CellState(X, Height) = 1\n            Else\n                CellState(X, Height) = 3\n            End If\n        End If\n\n        For j As Integer = 1 To Height\n            Console.Write(\"I\")\n            For i As Integer = 1 To Width\n                If CellState(i, j) < 2 Then\n                    Console.Write(\"  I\")\n                Else\n                    Console.Write(\"   \")\n                End If\n            Next\n            Console.WriteLine()\n\n            For i As Integer = 1 To Width\n                If CellState(i, j) = 0 OrElse CellState(i, j) = 2 Then\n                    Console.Write(\":--\")\n                Else\n                    Console.Write(\":  \")\n                End If\n            Next\n            Console.WriteLine(\".\")\n        Next\n    End Sub\n\n    Public Function GoLeft() As Boolean\n        curCol -= 1\n        CellVisitHistory(curCol, curRow) = CellsVisited\n        CellsVisited += 1\n        CellState(curCol, curRow) = 2\n        If CellsVisited > Width * Height Then Return False\n        Q = 0\n        Return True\n    End Function\n\n    Public Function GoUp() As Boolean\n        curRow -= 1\n        CellVisitHistory(curCol, curRow) = CellsVisited\n        CellsVisited += 1\n        CellState(curCol, curRow) = 1\n        If CellsVisited > Width * Height Then Return False\n        Q = 0\n        Return True\n    End Function\n\n    Public Function GoRight() As Boolean\n        CellVisitHistory(curCol + 1, curRow) = CellsVisited\n        CellsVisited += 1\n        If CellState(curCol, curRow) = 0 Then CellState(curCol, curRow) = 2 Else CellState(curCol, curRow) = 3\n        curCol += 1\n        If CellsVisited > Width * Height Then Return False\n        Return ChoosePath_BlockedToTheLeft()\n    End Function\n\n    Public Function GoDown() As Boolean\n        If Q = 1 Then Return MarkSolvedAndResetPosition()\n\n        CellVisitHistory(curCol, curRow + 1) = CellsVisited\n        CellsVisited += 1\n        If CellState(curCol, curRow) = 0 Then CellState(curCol, curRow) = 1 Else CellState(curCol, curRow) = 3\n        curRow += 1\n        If CellsVisited > Width * Height Then Return False\n        Return True\n    End Function\n\n    Public Function MarkSolvedAndResetPosition() As Boolean\n        ' AlWAYS returns true\n        SolutionCompleted = True\n        Q = 1\n        If CellState(curCol, curRow) = 0 Then\n            CellState(curCol, curRow) = 1\n            curCol = 1\n            curRow = 1\n            If CellVisitHistory(curCol, curRow) = 0 Then ResetCurrentPosition()\n        Else\n            CellState(curCol, curRow) = 3\n            ResetCurrentPosition()\n        End If\n        Return True\n    End Function\nEnd Module\n"
  },
  {
    "path": "03_Animal/README.md",
    "content": "### Animal\n\nUnlike other computer games in which the computer picks a number or letter and you must guess what it is, in this game _you_ think of an animal and the _computer_ asks you questions and tries to guess the name of your animal. If the computer guesses incorrectly, it will ask you for a question that differentiates the animal you were thinking of. In this way the computer “learns” new animals. Questions to differentiate new animals should be input without a question mark.\n\nThis version of the game does not have a SAVE feature. If your system allows, you may modify the program to save and reload the array when you want to play the game again. This way you can save what the computer learns over a series of games.\n\nAt any time if you reply “LIST” to the question “ARE YOU THINKING OF AN ANIMAL,” the computer will tell you all the animals it knows so far.\n\nThe program starts originally by knowing only FISH and BIRD. As you build up a file of animals you should use broad, general questions first and then narrow down to more specific ones with later animals. For example, if an elephant was to be your first animal, the computer would ask for a question to distinguish an elephant from a bird. Naturally, there are hundreds of possibilities, however, if you plan to build a large file of animals a good question would be “IS IT A MAMMAL.”\n\nThis program can be easily modified to deal with categories of things other than animals by simply modifying the initial data and the dialogue references to animals. In an educational environment, this would be a valuable program to teach the distinguishing characteristics of many classes of objects — rock formations, geography, marine life, cell structures, etc.\n\nOriginally developed by Arthur Luehrmann at Dartmouth College, Animal was subsequently shortened and modified by Nathan Teichholtz at DEC and Steve North at Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978)\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=4)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=19)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "03_Animal/animal.bas",
    "content": "10 PRINT TAB(32);\"ANIMAL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n40 PRINT \"PLAY 'GUESS THE ANIMAL'\"\n45 PRINT\n50 PRINT \"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\"\n60 PRINT\n70 DIM A$(200)\n80 FOR I=0 TO 3\n90 READ A$(I)\n100 NEXT I\n110 N=VAL(A$(0))\n120 REM          MAIN CONTROL SECTION\n130 INPUT \"ARE YOU THINKING OF AN ANIMAL\";A$\n140 IF A$=\"LIST\" THEN 600\n150 IF LEFT$(A$,1)<>\"Y\" THEN 120\n160 K=1\n170 GOSUB 390\n180 IF LEN(A$(K))=0 THEN 999\n190 IF LEFT$(A$(K),2)=\"\\Q\" THEN 170\n200 PRINT \"IS IT A \";RIGHT$(A$(K),LEN(A$(K))-2);\n210 INPUT A$\n220 A$=LEFT$(A$,1)\n230 IF LEFT$(A$,1)=\"Y\" THEN PRINT \"WHY NOT TRY ANOTHER ANIMAL?\": GOTO 120\n240 INPUT \"THE ANIMAL YOU WERE THINKING OF WAS A \";V$\n250 PRINT \"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\"\n260 PRINT V$;\" FROM A \";RIGHT$(A$(K),LEN(A$(K))-2)\n270 INPUT X$\n280 PRINT \"FOR A \";V$;\" THE ANSWER WOULD BE \";\n290 INPUT A$\n300 A$=LEFT$(A$,1): IF A$<>\"Y\" AND A$<>\"N\" THEN 280\n310 IF A$=\"Y\" THEN B$=\"N\"\n320 IF A$=\"N\" THEN B$=\"Y\"\n330 Z1=VAL(A$(0))\n340 A$(0)=STR$(Z1+2)\n350 A$(Z1)=A$(K)\n360 A$(Z1+1)=\"\\A\"+V$\n370 A$(K)=\"\\Q\"+X$+\"\\\"+A$+STR$(Z1+1)+\"\\\"+B$+STR$(Z1)+\"\\\"\n380 GOTO 120\n390 REM     SUBROUTINE TO PRINT QUESTIONS\n400 Q$=A$(K)\n410 FOR Z=3 TO LEN(Q$)\n415 IF MID$(Q$,Z,1)<>\"\\\" THEN PRINT MID$(Q$,Z,1);: NEXT Z\n420 INPUT C$\n430 C$=LEFT$(C$,1)\n440 IF C$<>\"Y\" AND C$<>\"N\" THEN 410\n450 T$=\"\\\"+C$\n455 FOR X=3 TO LEN(Q$)-1\n460 IF MID$(Q$,X,2)=T$ THEN 480\n470 NEXT X\n475 STOP\n480 FOR Y=X+1 TO LEN(Q$)\n490 IF MID$(Q$,Y,1)=\"\\\" THEN 510\n500 NEXT Y\n505 STOP\n510 K=VAL(MID$(Q$,X+2,Y-X-2))\n520 RETURN\n530 DATA \"4\",\"\\QDOES IT SWIM\\Y2\\N3\\\",\"\\AFISH\",\"\\ABIRD\"\n600 PRINT:PRINT \"ANIMALS I ALREADY KNOW ARE:\"\n605 X=0\n610 FOR I=1 TO 200\n620 IF LEFT$(A$(I),2)<>\"\\A\" THEN 650\n624 PRINT TAB(15*X);\n630 FOR Z=3 TO LEN(A$(I))\n640 IF MID$(A$(I),Z,1)<>\"\\\" THEN PRINT MID$(A$(I),Z,1);: NEXT Z\n645 X=X+1: IF X=4 THEN X=0: PRINT\n650 NEXT I\n660 PRINT\n670 PRINT\n680 GOTO 120\n999 END\n"
  },
  {
    "path": "03_Animal/csharp/Animal.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "03_Animal/csharp/Animal.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30907.101\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Animal\", \"Animal.csproj\", \"{D9A8DAB5-1B29-44A9-B13F-CED17B5A22B9}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D9A8DAB5-1B29-44A9-B13F-CED17B5A22B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D9A8DAB5-1B29-44A9-B13F-CED17B5A22B9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D9A8DAB5-1B29-44A9-B13F-CED17B5A22B9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D9A8DAB5-1B29-44A9-B13F-CED17B5A22B9}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {064879D3-A288-4980-8DC4-59653D5EE2DD}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "03_Animal/csharp/Branch.cs",
    "content": "﻿namespace Animal\n{\n    public class Branch\n    {\n        public string Text { get; set; }\n\n        public bool IsEnd => Yes == null && No == null;\n\n        public Branch Yes { get; set; }\n\n        public Branch No { get; set; }\n\n        public override string ToString()\n        {\n            return $\"{Text} : IsEnd {IsEnd}\";\n        }\n    }\n}\n"
  },
  {
    "path": "03_Animal/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nusing Animal;\n\nConsole.WriteLine(new string(' ', 32) + \"ANIMAL\");\nConsole.WriteLine(new string(' ', 15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\nConsole.WriteLine();\nConsole.WriteLine();\nConsole.WriteLine();\nConsole.WriteLine(\"PLAY 'GUESS THE ANIMAL'\");\nConsole.WriteLine();\nConsole.WriteLine(\"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\");\nConsole.WriteLine();\n\n// Root of the question and answer tree\nBranch rootBranch = new Branch\n{\n    Text = \"DOES IT SWIM\",\n    Yes = new Branch { Text = \"FISH\" },\n    No = new Branch { Text = \"BIRD\" }\n};\n\nstring[] TRUE_INPUTS = { \"Y\", \"YES\", \"T\", \"TRUE\" };\nstring[] FALSE_INPUTS = { \"N\", \"NO\", \"F\", \"FALSE\" };\n\n\nwhile (true)\n{\n    MainGameLoop();\n}\n\nvoid MainGameLoop()\n{\n    // Wait fora YES or LIST command\n    string input = null;\n    while (true)\n    {\n        input = GetInput(\"ARE YOU THINKING OF AN ANIMAL\");\n        if (IsInputListCommand(input))\n        {\n            ListKnownAnimals(rootBranch);\n        }\n        else if (IsInputYes(input))\n        {\n            break;\n        }\n    }\n\n    // Walk through the tree following the YES and NO\n    // branches based on user input.\n    Branch currentBranch = rootBranch;\n    while (!currentBranch.IsEnd)\n    {\n        while (true)\n        {\n            input = GetInput(currentBranch.Text);\n            if (IsInputYes(input))\n            {\n                currentBranch = currentBranch.Yes;\n                break;\n            }\n            else if (IsInputNo(input))\n            {\n                currentBranch = currentBranch.No;\n                break;\n            }\n        }\n    }\n\n    // Was the answer correct?\n    input = GetInput($\"IS IT A {currentBranch.Text}\");\n    if (IsInputYes(input))\n    {\n        Console.WriteLine(\"WHY NOT TRY ANOTHER ANIMAL?\");\n        return;\n    }\n\n    // Interview the user to add a new question and answer\n    // branch to the tree\n    string newAnimal = GetInput(\"THE ANIMAL YOU WERE THINKING OF WAS A\");\n    string newQuestion = GetInput($\"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A {newAnimal} FROM A {currentBranch.Text}\");\n    string newAnswer = null;\n    while (true)\n    {\n        newAnswer = GetInput($\"FOR A {newAnimal} THE ANSWER WOULD BE\");\n        if (IsInputNo(newAnswer))\n        {\n            currentBranch.No = new Branch { Text = newAnimal };\n            currentBranch.Yes = new Branch { Text = currentBranch.Text };\n            currentBranch.Text = newQuestion;\n            break;\n        }\n        else if (IsInputYes(newAnswer))\n        {\n            currentBranch.Yes = new Branch { Text = newAnimal };\n            currentBranch.No = new Branch { Text = currentBranch.Text };\n            currentBranch.Text = newQuestion;\n            break;\n        }\n    }\n}\n\nstring GetInput(string prompt)\n{\n    Console.Write($\"{prompt}? \");\n    string result = Console.ReadLine();\n    if (string.IsNullOrWhiteSpace(result))\n    {\n        return GetInput(prompt);\n    }\n\n    return result.Trim().ToUpper();\n}\n\nbool IsInputYes(string input) => TRUE_INPUTS.Contains(input.ToUpperInvariant().Trim());\n\nbool IsInputNo(string input) => FALSE_INPUTS.Contains(input.ToUpperInvariant().Trim());\n\nbool IsInputListCommand(string input) => input.ToUpperInvariant().Trim() == \"LIST\";\n\nstring[] GetKnownAnimals(Branch branch)\n{\n    List<string> result = new List<string>();\n    if (branch.IsEnd)\n    {\n        return new[] { branch.Text };\n    }\n    else\n    {\n        result.AddRange(GetKnownAnimals(branch.Yes));\n        result.AddRange(GetKnownAnimals(branch.No));\n        return result.ToArray();\n    }\n}\n\nvoid ListKnownAnimals(Branch branch)\n{\n    string[] animals = GetKnownAnimals(branch);\n    for (int x = 0; x < animals.Length; x++)\n    {\n        int column = (x % 4);\n        if (column == 0)\n        {\n            Console.WriteLine();\n        }\n\n        Console.Write(new string(' ', column == 0 ? 0 : 15) + animals[x]);\n    }\n    Console.WriteLine();\n}\n"
  },
  {
    "path": "03_Animal/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "03_Animal/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "03_Animal/java/src/Animal.java",
    "content": "import java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Scanner;\nimport java.util.stream.Collectors;\n\n/**\n * ANIMAL\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n * The original BASIC program uses an array to maintain the questions and answers and to decide which question to\n * ask next. Updated this Java implementation to use a tree instead of the earlier faulty one based on a list (thanks @patimen).\n *\n * Bonus option: TREE --> prints the game decision data as a tree to visualize/debug the state of the game\n */\npublic class Animal {\n\n    public static void main(String[] args) {\n        printIntro();\n        Scanner scan = new Scanner(System.in);\n\n        Node root = new QuestionNode(\"DOES IT SWIM\",\n                new AnimalNode(\"FISH\"), new AnimalNode(\"BIRD\"));\n\n        boolean stopGame = false;\n        while (!stopGame) {\n            String choice = readMainChoice(scan);\n            switch (choice) {\n                case \"TREE\":\n                    printTree(root);\n                    break;\n                case \"LIST\":\n                    printKnownAnimals(root);\n                    break;\n                case \"Q\":\n                case \"QUIT\":\n                    stopGame = true;\n                    break;\n                default:\n                    if (choice.toUpperCase(Locale.ROOT).startsWith(\"Y\")) {\n                        Node current = root; //where we are in the question tree\n                        Node previous; //keep track of parent of current in order to place new questions later on.\n\n                        while (current instanceof QuestionNode) {\n                            var currentQuestion = (QuestionNode) current;\n                            var reply = askQuestionAndGetReply(currentQuestion, scan);\n\n                            previous = current;\n                            current = reply ? currentQuestion.getTrueAnswer() : currentQuestion.getFalseAnswer();\n                            if (current instanceof AnimalNode) {\n                                //We have reached a animal node, so offer it as the guess\n                                var currentAnimal = (AnimalNode) current;\n                                System.out.printf(\"IS IT A %s ? \", currentAnimal.getAnimal());\n                                var animalGuessResponse = readYesOrNo(scan);\n                                if (animalGuessResponse) {\n                                    //we guessed right! end this round\n                                    System.out.println(\"WHY NOT TRY ANOTHER ANIMAL?\");\n                                } else {\n                                    //we guessed wrong :(, ask for feedback\n                                    //cast previous to QuestionNode since we know at this point that it is not a leaf node\n                                    askForInformationAndSave(scan, currentAnimal, (QuestionNode) previous, reply);\n                                }\n                            }\n                        }\n                    }\n            }\n        }\n    }\n\n    /**\n     * Prompt for information about the animal we got wrong\n     * @param current The animal that we guessed wrong\n     * @param previous The root of current\n     * @param previousToCurrentDecisionChoice Whether it was a Y or N answer that got us here. true = Y, false = N\n     */\n    private static void askForInformationAndSave(Scanner scan, AnimalNode current, QuestionNode previous, boolean previousToCurrentDecisionChoice) {\n        //Failed to get it right and ran out of questions\n        //Let's ask the user for the new information\n        System.out.print(\"THE ANIMAL YOU WERE THINKING OF WAS A ? \");\n        String animal = scan.nextLine();\n        System.out.printf(\"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A %s FROM A %s ? \", animal, current.getAnimal());\n        String newQuestion = scan.nextLine();\n        System.out.printf(\"FOR A %s THE ANSWER WOULD BE ? \", animal);\n        boolean newAnswer = readYesOrNo(scan);\n        //Add it to our question store\n        addNewAnimal(current, previous, animal, newQuestion, newAnswer, previousToCurrentDecisionChoice);\n    }\n\n    private static void addNewAnimal(Node current,\n                                     QuestionNode previous,\n                                     String animal,\n                                     String newQuestion,\n                                     boolean newAnswer,\n                                     boolean previousToCurrentDecisionChoice) {\n        var animalNode = new AnimalNode(animal);\n        var questionNode = new QuestionNode(newQuestion,\n                newAnswer ? animalNode : current,\n                !newAnswer ? animalNode : current);\n\n        if (previous != null) {\n            if (previousToCurrentDecisionChoice) {\n                previous.setTrueAnswer(questionNode);\n            } else {\n                previous.setFalseAnswer(questionNode);\n            }\n        }\n    }\n\n    private static boolean askQuestionAndGetReply(QuestionNode questionNode, Scanner scanner) {\n        System.out.printf(\"%s ? \", questionNode.question);\n        return readYesOrNo(scanner);\n    }\n\n    private static boolean readYesOrNo(Scanner scanner) {\n        boolean validAnswer = false;\n        Boolean choseAnswer = null;\n        while (!validAnswer) {\n            String answer = scanner.nextLine();\n            if (answer.toUpperCase(Locale.ROOT).startsWith(\"Y\")) {\n                validAnswer = true;\n                choseAnswer = true;\n            } else if (answer.toUpperCase(Locale.ROOT).startsWith(\"N\")) {\n                validAnswer = true;\n                choseAnswer = false;\n            }\n        }\n        return choseAnswer;\n    }\n\n    private static void printKnownAnimals(Node root) {\n        System.out.println(\"\\nANIMALS I ALREADY KNOW ARE:\");\n\n        List<AnimalNode> leafNodes = collectLeafNodes(root);\n        String allAnimalsString = leafNodes.stream().map(AnimalNode::getAnimal).collect(Collectors.joining(\"\\t\\t\"));\n\n        System.out.println(allAnimalsString);\n    }\n\n    //Traverse the tree and collect all the leaf nodes, which basically have all the animals.\n    private static List<AnimalNode> collectLeafNodes(Node root) {\n        List<AnimalNode> collectedNodes = new ArrayList<>();\n        if (root instanceof AnimalNode) {\n            collectedNodes.add((AnimalNode) root);\n        } else {\n            var q = (QuestionNode) root;\n            collectedNodes.addAll(collectLeafNodes(q.getTrueAnswer()));\n            collectedNodes.addAll(collectLeafNodes(q.getFalseAnswer()));\n        }\n        return collectedNodes;\n    }\n\n    private static String readMainChoice(Scanner scan) {\n        System.out.print(\"ARE YOU THINKING OF AN ANIMAL ? \");\n        return scan.nextLine();\n    }\n\n    private static void printIntro() {\n        System.out.println(\"                                ANIMAL\");\n        System.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println(\"\\n\\n\");\n        System.out.println(\"PLAY 'GUESS THE ANIMAL'\");\n        System.out.println(\"\\n\");\n        System.out.println(\"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\");\n    }\n\n    //Based on https://stackoverflow.com/a/8948691/74057\n    private static void printTree(Node root) {\n        StringBuilder buffer = new StringBuilder(50);\n        print(root, buffer, \"\", \"\");\n        System.out.println(buffer);\n    }\n\n    private static void print(Node root, StringBuilder buffer, String prefix, String childrenPrefix) {\n        buffer.append(prefix);\n        buffer.append(root.toString());\n        buffer.append('\\n');\n\n        if (root instanceof QuestionNode) {\n            var questionNode = (QuestionNode) root;\n            print(questionNode.getTrueAnswer(), buffer, childrenPrefix + \"├─Y─ \", childrenPrefix + \"│   \");\n            print(questionNode.getFalseAnswer(), buffer, childrenPrefix + \"└─N─ \", childrenPrefix + \"    \");\n        }\n    }\n\n\n    /**\n     * Base interface for all nodes in our question tree\n     */\n    private interface Node {\n    }\n\n    private static class QuestionNode implements Node {\n        private final String question;\n        private Node trueAnswer;\n        private Node falseAnswer;\n\n        public QuestionNode(String question, Node trueAnswer, Node falseAnswer) {\n            this.question = question;\n            this.trueAnswer = trueAnswer;\n            this.falseAnswer = falseAnswer;\n        }\n\n        public String getQuestion() {\n            return question;\n        }\n\n        public Node getTrueAnswer() {\n            return trueAnswer;\n        }\n\n        public void setTrueAnswer(Node trueAnswer) {\n            this.trueAnswer = trueAnswer;\n        }\n\n        public Node getFalseAnswer() {\n            return falseAnswer;\n        }\n\n        public void setFalseAnswer(Node falseAnswer) {\n            this.falseAnswer = falseAnswer;\n        }\n\n        @Override\n        public String toString() {\n            return \"Question{'\" + question + \"'}\";\n        }\n    }\n\n    private static class AnimalNode implements Node {\n        private final String animal;\n\n        public AnimalNode(String animal) {\n            this.animal = animal;\n        }\n\n        public String getAnimal() {\n            return animal;\n        }\n\n        @Override\n        public String toString() {\n            return \"Animal{'\" + animal + \"'}\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "03_Animal/java/test/AnimalJavaTest.kt",
    "content": "import com.pcholt.console.testutils.ConsoleTest\nimport org.junit.Test\n\nclass AnimalJavaTest : ConsoleTest() {\n\n    @Test\n    fun `given a standard setup, find the fish`() {\n        assertConversation(\n            \"\"\"\n            $title\n            ARE YOU THINKING OF AN ANIMAL ? {YES}\n            DOES IT SWIM ? {YES}\n            IS IT A FISH ? {YES}\n            WHY NOT TRY ANOTHER ANIMAL?\n            ARE YOU THINKING OF AN ANIMAL ? {QUIT}\n            \"\"\"\n        ) {\n            Animal.main(emptyArray())\n        }\n    }\n\n    @Test\n    fun `given a standard setup, create a cow, and verify`() {\n        assertConversation(\n            \"\"\"\n            $title\n            ARE YOU THINKING OF AN ANIMAL ? {YES}\n            DOES IT SWIM ? {NO}\n            IS IT A BIRD ? {NO}\n            THE ANIMAL YOU WERE THINKING OF WAS A ? {COW}\n            PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\n            COW FROM A BIRD\n            ? {DOES IT EAT GRASS}\n            FOR A COW THE ANSWER WOULD BE ? {YES}\n            ARE YOU THINKING OF AN ANIMAL ? {YES}\n            DOES IT SWIM ? {NO}\n            DOES IT EAT GRASS ? {YES}\n            IS IT A COW ? {YES}\n            WHY NOT TRY ANOTHER ANIMAL?\n            ARE YOU THINKING OF AN ANIMAL ? {QUIT}\n        \"\"\"\n        ) {\n            Animal.main(emptyArray())\n        }\n    }\n\n    private val title = \"\"\"\n                                        ANIMAL\n                      CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n        PLAY 'GUESS THE ANIMAL'\n        THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\n    \"\"\"\n}\n"
  },
  {
    "path": "03_Animal/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "03_Animal/javascript/animal.html",
    "content": "<html>\n<head>\n<title>ANIMAL</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<!--<script src=\"https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js\"></script>-->\n<script src=\"animal.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "03_Animal/javascript/animal.js",
    "content": "// ANIMAL\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                        input_str = input_element.value;\n                                                        document.getElementById(\"output\").removeChild(input_element);\n                                                        print(input_str);\n                                                        print(\"\\n\");\n                                                        resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nprint(tab(32) + \"ANIMAL\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"PLAY 'GUESS THE ANIMAL'\\n\");\nprint(\"\\n\");\nprint(\"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\\n\");\nprint(\"\\n\");\n\nvar k;\nvar n;\nvar str;\nvar q;\nvar z;\nvar c;\nvar t;\n\nvar animals = [\n               \"\\\\QDOES IT SWIM\\\\Y1\\\\N2\\\\\",\n               \"\\\\AFISH\",\n               \"\\\\ABIRD\",\n               ];\n\nn = animals.length;\n\nfunction show_animals() {\n    var x;\n\n    print(\"\\n\");\n    print(\"ANIMALS I ALREADY KNOW ARE:\\n\");\n    str = \"\";\n    x = 0;\n    for (var i = 0; i < n; i++) {\n        if (animals[i].substr(0, 2) == \"\\\\A\") {\n            while (str.length < 15 * x)\n                str += \" \";\n            for (var z = 2; z < animals[i].length; z++) {\n                if (animals[i][z] == \"\\\\\")\n                    break;\n                str += animals[i][z];\n            }\n            x++;\n            if (x == 4) {\n                x = 0;\n                print(str + \"\\n\");\n                str = \"\";\n            }\n        }\n    }\n    if (str != \"\")\n        print(str + \"\\n\");\n}\n\n// Main control section\nasync function main()\n{\n    while (1) {\n        while (1) {\n            print(\"ARE YOU THINKING OF AN ANIMAL\");\n            str = await input();\n            if (str == \"LIST\")\n                show_animals();\n            if (str[0] == \"Y\")\n                break;\n        }\n\n        k = 0;\n        do {\n            // Subroutine to print questions\n            q = animals[k];\n            while (1) {\n                str = \"\";\n                for (z = 2; z < q.length; z++) {\n                    if (q[z] == \"\\\\\")\n                        break;\n                    str += q[z];\n                }\n                print(str);\n                c = await input();\n                if (c[0] == \"Y\" || c[0] == \"N\")\n                    break;\n            }\n            t = \"\\\\\" + c[0];\n            x = q.indexOf(t);\n            k = parseInt(q.substr(x + 2));\n        } while (animals[k].substr(0,2) == \"\\\\Q\") ;\n\n        print(\"IS IT A \" + animals[k].substr(2));\n        a = await input();\n        if (a[0] == \"Y\") {\n            print(\"WHY NOT TRY ANOTHER ANIMAL?\\n\");\n            continue;\n        }\n        print(\"THE ANIMAL YOU WERE THINKING OF WAS A \");\n        v = await input();\n        print(\"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\\n\");\n        print(v + \" FROM A \" + animals[k].substr(2) + \"\\n\");\n        x = await input();\n        while (1) {\n            print(\"FOR A \" + v + \" THE ANSWER WOULD BE \");\n            a = await input();\n            a = a.substr(0, 1);\n            if (a == \"Y\" || a == \"N\")\n                break;\n        }\n        if (a == \"Y\")\n            b = \"N\";\n        if (a == \"N\")\n            b = \"Y\";\n        z1 = animals.length;\n        animals[z1] = animals[k];\n        animals[z1 + 1] = \"\\\\A\" + v;\n        animals[k] = \"\\\\Q\" + x + \"\\\\\" + a + (z1 + 1) + \"\\\\\" + b + z1 + \"\\\\\";\n    }\n}\n\nmain();\n"
  },
  {
    "path": "03_Animal/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "03_Animal/kotlin/src/Animal.kt",
    "content": "/**\n * ANIMAL\n *\n *\n * Converted from BASIC to Kotlin by John Long (@patimen)\n *\n * Animal is basically a perfect example of a binary tree. Implement it\n * as such, with the QuestionNode either having an answer if it is a terminal node\n * or a Question\n */\n\nfun main() {\n    printIntro()\n    val rootQuestionNode =\n        QuestionOrAnswer(question = Question(\"DOES IT SWIM\", QuestionOrAnswer(\"FISH\"), QuestionOrAnswer(\"BIRD\")))\n    while (true) {\n        val choice = ask(\"ARE YOU THINKING OF AN ANIMAL\")\n        when {\n            choice == \"LIST\" -> printKnownAnimals(rootQuestionNode)\n            choice.startsWith(\"Q\") -> return\n            choice.startsWith(\"Y\") -> {\n                // A wrong answer means it's a new animal!\n                val wrongAnswer = rootQuestionNode.getWrongAnswer()\n                if (wrongAnswer == null) {\n                    // The computer got the right answer!\n                    println(\"WHY NOT TRY ANOTHER ANIMAL?\")\n                } else {\n                    // Get a new question to ask next time\n                    wrongAnswer.askForInformationAndSave()\n                }\n            }\n        }\n    }\n}\n\n// Takes care of asking a question (on the same line) and getting\n// an answer or a blank string\nfun ask(question: String): String {\n    print(\"$question? \")\n    return readln().uppercase() ?: \"\"\n}\n\n// Special case for a \"yes or no\" question, returns true of yes\nfun askYesOrNo(question: String): Boolean {\n    return generateSequence {\n        print(\"$question? \")\n        readln()\n    }.firstNotNullOf { yesOrNo(it) }\n}\n\n// If neither Y (true) or N (false), return null, so the above sequence\n// will just keep executing until it gets the answer\nprivate fun yesOrNo(string: String): Boolean? =\n    when (string.uppercase().firstOrNull()) {\n        'Y' -> true\n        'N' -> false\n        else -> null\n    }\n\nprivate fun printKnownAnimals(question: QuestionOrAnswer) {\n    println(\"\\nANIMALS I ALREADY KNOW ARE:\")\n    val animals = question.getAnswers().chunked(4)\n    animals.forEach { line ->\n        // The '*' in front of line.toTypedArray() \"spreads\" the array as a list of parameters instead\n        System.out.printf(\"%-15s\".repeat(line.size), *line.toTypedArray())\n        println()\n    }\n}\n\nprivate fun printIntro() {\n    println(\"                                ANIMAL\")\n    println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    println(\"\\n\\n\")\n    println(\"PLAY 'GUESS THE ANIMAL'\")\n    println(\"\\n\")\n    println(\"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\")\n}\n\nclass QuestionOrAnswer(private var answer: String? = null, var question: Question? = null) {\n    fun getAnswers(): List<String> = answer?.let { listOf(it) } ?: question!!.getAnswers()\n    fun getWrongAnswer(): QuestionOrAnswer? {\n        if (answer != null) {\n            // \"takeUnless\" will return null if the answer is \"yes\". In this case\n            // we will return the \"wrong answer\", aka the terminal answer that was incorrect\n            return this.takeUnless { askYesOrNo(\"IS IT A $answer\") }\n        }\n        return question?.getWrongAnswer()\n    }\n\n    fun askForInformationAndSave() {\n        //Failed to get it right and ran out of questions\n        //Let's ask the user for the new information\n        val newAnimal = ask(\"THE ANIMAL YOU WERE THINKING OF WAS A\")\n        val newQuestion = ask(\"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A \\n$newAnimal FROM A $answer\\n\")\n        val newAnswer = askYesOrNo(\"FOR A $newAnimal THE ANSWER WOULD BE\")\n\n        val trueAnswer = if (newAnswer) newAnimal else answer\n        val falseAnswer = if (newAnswer) answer else newAnimal\n        // Replace our answer with null  and set the question with the data we just got\n        // This makes it a question instead of an answer\n        this.answer = null\n        this.question = Question(newQuestion, QuestionOrAnswer(trueAnswer), QuestionOrAnswer(falseAnswer))\n    }\n}\n\nclass Question(\n    private val question: String,\n    private val trueAnswer: QuestionOrAnswer,\n    private val falseAnswer: QuestionOrAnswer\n) {\n    fun getAnswers(): List<String> = trueAnswer.getAnswers() + falseAnswer.getAnswers()\n\n    fun getWrongAnswer(): QuestionOrAnswer? =\n        if (askYesOrNo(question)) {\n            trueAnswer.getWrongAnswer()\n        } else {\n            falseAnswer.getWrongAnswer()\n        }\n}\n"
  },
  {
    "path": "03_Animal/kotlin/test/AnimalKtTest.kt",
    "content": "import com.pcholt.console.testutils.ConsoleTest\nimport org.junit.Test\n\nclass AnimalKtTest : ConsoleTest() {\n\n    @Test\n    fun `given a standard setup, find the fish`() {\n        assertConversation(\n            \"\"\"\n            $title\n            ARE YOU THINKING OF AN ANIMAL? {YES}\n            DOES IT SWIM? {YES}\n            IS IT A FISH? {YES}\n            WHY NOT TRY ANOTHER ANIMAL?\n            ARE YOU THINKING OF AN ANIMAL? {QUIT}\n            \"\"\"\n        ) {\n            main()\n        }\n    }\n\n    @Test\n    fun `given a standard setup, create a cow, and verify`() {\n        assertConversation(\n            \"\"\"\n            $title\n            ARE YOU THINKING OF AN ANIMAL? {YES}\n            DOES IT SWIM? {NO}\n            IS IT A BIRD? {NO}\n            THE ANIMAL YOU WERE THINKING OF WAS A? {COW}\n            PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\n            COW FROM A BIRD\n            ? {DOES IT EAT GRASS}\n            FOR A COW THE ANSWER WOULD BE? {YES}\n            ARE YOU THINKING OF AN ANIMAL? {YES}\n            DOES IT SWIM? {NO}\n            DOES IT EAT GRASS? {YES}\n            IS IT A COW? {YES}\n            WHY NOT TRY ANOTHER ANIMAL?\n            ARE YOU THINKING OF AN ANIMAL? {QUIT}\n        \"\"\"\n        ) {\n            main()\n        }\n    }\n\n    private val title = \"\"\"\n                                        ANIMAL\n                      CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n        PLAY 'GUESS THE ANIMAL'\n        THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\n    \"\"\"\n}\n"
  },
  {
    "path": "03_Animal/lua/Animal.lua",
    "content": "--\n-- Animal.lua\n--\n\n-- maintain a flat table/list of all the known animals\nlocal animals = {\n    \"FISH\",\n    \"BIRD\"\n}\n\n-- store the questions as a binary tree with each node having a \n-- \"y\" or \"n\" branch\n-- if the node has a member named \"a\" it's an answer, with an index\n-- into the animals list.\n-- Otherwise, it's a question that leads to more nodes.\nlocal questionTree = {\n    q = \"DOES IT SWIM\",\n    y = { a = 1 },\n    n = { a = 2 }\n}\n\n-- print the given prompt string and then wait for input\n-- loops until a non-empty input is given\n-- returns the input as an upper-case string\nfunction askPrompt(promptString)\n    local answered = false \n    local a\n    while (not answered) do \n        print(promptString)\n        a = io.read()\n        a = string.upper(a)\n        if (string.len(a) > 0) then \n            answered = true \n        end\n    end\n    return a\nend\n\n-- print the given prompt string and then wait for the\n-- user to enter a string beginning with \"Y\" or \"N\"\nfunction askYesOrNo(promptString)\n    local a\n    while ((a ~= \"Y\") and (a ~= \"N\")) do \n        a = askPrompt(promptString)\n        a = a:sub(1,1)\n    end\n    return a\nend\n\n-- prints the introductory text from the original BASIC program\nfunction printIntro()\n    print(string.format(\"%32s\", \" \") .. \"ANIMAL\")\n    print(string.format(\"%15s\", \" \") .. \"CREATIVE COMPUTING   MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n    print(\"PLAY 'GUESS THE ANIMAL'\")\n    print(\"THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\")\n    print()\nend\n\n-- prints the animals known in the source list\nfunction listKnownAnimals()\n    print()\n    print(\"ANIMALS I ALREADY KNOW ARE:\")\n\n    local x\n    local item\n    for x = 1,#animals do \n        -- use string.format to space each animal in a 12-character-wide \"cell\"\n        item = string.format(\"%-12s\", animals[x])\n\n        -- io.write() works like print(), but doesn't automatically add a carriage return/newline\n        io.write(item)\n\n        -- every fifth item, start a new line\n        if ((x % 5) == 0) then \n            io.write(\"\\n\")\n        end\n    end\n\n    print()\n    print()\nend\n\n-- Prompts the user for info about the animal they were thinking of, then\n-- uses that to add a new branch to the tree\n--      curNode: the node in the tree where the computer made a wrong guess\n--      branch: the answer the user gave to curNode's question\nfunction addAnimalToTree(curNode, branch)\n    local newAnimal \n    local curResponse = curNode[branch]\n    local guessedIndex = curResponse.a\n    local guessedAnimal = animals[guessedIndex]\n    local newQuestion, newAnswer, newIndex\n    local newNode\n\n    newAnimal = askPrompt(\"THE ANIMAL YOU WERE THINKING OF WAS A ?\")\n    newQuestion = askPrompt(\"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A \"..\n        tostring(newAnimal)..\" FROM A \"..tostring(guessedAnimal))\n    newAnswer = askYesOrNo(\"FOR A \"..tostring(newAnimal)..\" THE ANSWER WOULD BE?\")\n\n    -- add the new animal to the master list at the end, and\n    -- save off its index in the list\n    table.insert(animals, newAnimal)\n    newIndex = #animals\n\n    -- create a new node for the question we just learned\n    newNode = {}\n    newNode.q = newQuestion\n    if (newAnswer == \"Y\") then \n        newNode.y = { a = newIndex }\n        newNode.n = { a = guessedIndex }\n    else \n        newNode.y = { a = guessedIndex }\n        newNode.n = { a = newIndex }\n    end \n\n    -- replace the previous answer with our new node\n    curNode[branch] = newNode\nend\n\n-- Starts at the root of the question tree and asks questions about\n-- the user's animal until the computer hits an \"a\" answer node and tries\n-- to make a guess\nfunction askAboutAnimal()\n    local curNode = questionTree\n    local finished = false\n    local response, responseIndex\n    local nextNode, animalName\n    while (not finished) do \n        response = askYesOrNo(curNode.q .. \"?\")\n        \n        -- convert the response \"Y\" or \"N\" to the lowercase \"y\" or \"n\" that we use to name our branches\n        branch = string.lower(response)\n        nextNode = curNode[branch]\n        \n        -- is the next node an answer node, or another question?\n        if (nextNode.a ~= nil) then \n            -- it's an answer, so make a guess\n            animalName = animals[nextNode.a]\n            response = askYesOrNo(\"IS IT A \"..tostring(animalName)..\"?\")\n            if (response == \"Y\") then\n                -- we got the correct answer, so prompt for a new animal\n                print()\n                print(\"WHY NOT TRY ANOTHER ANIMAL?\")\n            else \n                -- incorrect answer, so add a new entry at this point in the tree\n                addAnimalToTree(curNode, branch)\n            end\n\n            -- whether we were right or wrong, we're finished with this round\n            finished = true\n        else \n            -- it's another question, so advance down the tree\n            curNode = nextNode\n        end\n    end\nend\n\n-- MAIN CONTROL SECTION\n\nprintIntro()\n\n-- loop forever until the player requests an exit by entering a blank line\nlocal exitRequested = false\nlocal answer \n\nwhile (not exitRequested) do\n    print(\"ARE YOU THINKING OF AN ANIMAL?\")\n    answer = io.read()\n    answer = string.upper(answer)\n\n    if (string.len(answer) == 0) then\n        exitRequested = true\n    elseif (answer:sub(1,4) == \"LIST\") then\n        listKnownAnimals()\n    elseif (answer:sub(1,1) == \"Y\") then\n        askAboutAnimal()\n    end\nend\n"
  },
  {
    "path": "03_Animal/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "03_Animal/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "03_Animal/perl/animal.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\n# The Perl ref() built-in returns 'HASH' for a hash reference. But we\n# make it a manifest constant just to avoid typos.\nuse constant REF_HASH   => ref {};\n\nprint <<'EOD';\n                                ANIMAL\n               Creative Computing  Morristown, New Jersey\n\n\n\nPlay 'Guess the Animal'\nThink of an animal and the computer will try to guess it.\n\nEOD\n\n# We keep the accumulated data in a tree structure, initialized here. As\n# we accumulate animals, we replace the 'yes' or 'no' keys with new hash\n# references.\nmy $database = {\n    question    => 'Does it swim',  # Initial question\n    yes         => 'fish',          # Result of answering 'y'\n    no          => 'bird',          # Result of answering 'n'\n};\n\nwhile ( 1 ) {\n\n    my $resp = get_input(\n        'Are you thinking of an an animal? [y/n/list]: '\n    );\n\n    if ( $resp =~ m/ \\A y /smxi ) {\n        # If we got an answer beginning with 'y', walk the database\n        walk_tree( $database );\n    } elsif ( $resp =~ m/ \\A list \\z /smxi ) {\n        # If we got 'list', list the currently-known animals.\n        say '';\n        say 'Animals I already know are:';\n        say \"    $_\" for sort( list_animals( $database ) );\n    }\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'animal' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n# Recurse through the database, returning the names of all animals in\n# it, in an undefined order.\nsub list_animals {\n    my ( $node ) = @ARG;\n    return $node unless REF_HASH eq ref $node;\n    return( map { list_animals( $node->{$_} ) } qw{ yes no } );\n}\n\n# Find or create the desired animal.\n# Ask the question stored in the node given in its argument. If the key\n# selected by the answer ('yes' or 'no') is another node, recurse. If it\n# is an animal name, confirm it, or add a new animal as appropriate.\nsub walk_tree {\n    my ( $node ) = @ARG;\n\n    # Ask the question associated with this node. Turn the true/false\n    # response into 'yes' or 'no', since those are the names of the\n    # respective keys.\n    my $resp = get_yes_no ( $node->{question} ) ? 'yes' : 'no';\n\n    # Chose the datum for the response.\n    my $choice = $node->{ $resp };\n\n    # If the datum is a hash reference\n    if ( REF_HASH eq ref $choice ) {\n\n        # Recurse into it\n        walk_tree( $choice );\n\n    # Otherwise it is an actual animal (i.e. terminal node). Check it.\n    } else {\n\n        # If this is not the animal the player was thinking of\n        unless ( get_yes_no( \"Is it a $choice\" ) ) {\n\n            # Find out what animal the player was thinking of\n            my $animal = lc get_input(\n                'The animal you were thinking of was a ',\n            );\n\n            # Get a yes/no question that distinguishes the animal the\n            # player was thinking of from the animal we found in the\n            # tree.\n            say 'Please type in a question that would distinguish a';\n            my $question = get_input( \"$animal from a $choice: \" );\n\n            # Find out whether the new animal is selected by 'yes' or\n            # 'no'. If 'no', swap the original animal with the new one\n            # for convenience.\n            ( $choice, $animal ) = ( $animal, $choice ) if get_yes_no(\n                \"For a $animal the answer would be\",\n            );\n\n            # Replace the animal we originally found by a new node\n            # giving the original animal, the new animal, and the\n            # question that distinguishes them.\n            $node->{ $resp } = {\n                question    => $question,\n                no          => $animal,\n                yes         => $choice,\n            };\n        }\n\n        # Find out if the player wants to play again. If not, exit. If\n        # so, just return.\n        say '';\n        exit unless get_yes_no( 'Why not try another animal' );\n        return;\n    }\n}\n\n__END__\n\n=head1 TITLE\n\nanimal.pl - Play the game 'animal' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n animal.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of C<animal>, which is the 3ed entry in Basic\nComputer Games.\n\nThe original BASIC was greatly complicated by the need to emulate a\nbinary tree with an array. The implementation using hashes as nodes in\nan actual binary tree is much simpler.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "03_Animal/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "03_Animal/python/animal.py",
    "content": "\"\"\"\nAnimal\n\nFrom: Basic computer Games(1978)\n\n   Unlike other computer games in which the computer\n  picks a number or letter and you must guess what it is,\n  in this game you think of an animal and the computer asks\n  you questions and tries to guess the name of your animal.\n  If the computer guesses incorrectly, it will ask you for a\n  question that differentiates the animal it guessed\n  from the one you were thinking of. In this way the\n  computer \"learns\" new animals. Questions to differentiate\n  new animals should be input without a question mark.\n   This version of the game does not have a SAVE feature.\n  If your sistem allows, you may modify the program to\n  save array A$, then reload the array  when you want\n  to play the game again. This way you can save what the\n  computer learns over a series of games.\n   At any time if you reply 'LIST' to the question \"ARE YOU\n  THINKING OF AN ANIMAL\", the computer will tell you all the\n  animals it knows so far.\n   The program starts originally by knowing only FISH and BIRD.\n  As you build up a file of animals you should use broad,\n  general questions first and then narrow down to more specific\n  ones with later animals. For example, If an elephant was to be\n  your first animal, the computer would ask for a question to distinguish\n  an elephant from a bird. Naturally there are hundreds of possibilities,\n  however, if you plan to build a large file of animals a good question\n  would be \"IS IT A MAMAL\".\n   This program can be easily modified to deal with categories of\n  things other than animals by simply modifying the initial data\n  in Line 530 and the dialogue references to animal in Lines 10,\n  40, 50, 130, 230, 240 and 600. In an educational environment, this\n  would be a valuable program to teach the distinguishing chacteristics\n  of many classes of objects -- rock formations, geography, marine life,\n  cell structures, etc.\n   Originally developed by Arthur Luehrmann at Dartmouth College,\n  Animal was subsequently shortened and modified by Nathan Teichholtz at\n  DEC and Steve North at Creative Computing\n\"\"\"\n\nfrom typing import Optional\n\n\nclass Node:\n    \"\"\"\n    Node of the binary tree of questions.\n    \"\"\"\n\n    def __init__(\n        self, text: str, yes_node: Optional[\"Node\"], no_node: Optional[\"Node\"]\n    ):\n        # the nodes that are leafs have as text the animal's name, otherwise\n        # a yes/no question\n        self.text = text\n        self.yes_node = yes_node\n        self.no_node = no_node\n\n    def update_node(\n        self, new_question: str, answer_new_ques: str, new_animal: str\n    ) -> None:\n        # update the leaf with a question\n        old_animal = self.text\n        # we replace the animal with a new question\n        self.text = new_question\n\n        if answer_new_ques == \"y\":\n            self.yes_node = Node(new_animal, None, None)\n            self.no_node = Node(old_animal, None, None)\n        else:\n            self.yes_node = Node(old_animal, None, None)\n            self.no_node = Node(new_animal, None, None)\n\n    # the leafs have as children None\n    def is_leaf(self) -> bool:\n        return self.yes_node is None and self.no_node is None\n\n\ndef list_known_animals(root_node: Optional[Node]) -> None:\n    \"\"\"Traversing the tree by recursion until we reach the leafs.\"\"\"\n    if root_node is None:\n        return\n\n    if root_node.is_leaf():\n        print(root_node.text, end=\" \" * 11)\n        return\n\n    if root_node.yes_node:\n        list_known_animals(root_node.yes_node)\n\n    if root_node.no_node:\n        list_known_animals(root_node.no_node)\n\n\ndef parse_input(message: str, check_list: bool, root_node: Optional[Node]) -> str:\n    \"\"\"only accepts yes or no inputs and recognizes list operation\"\"\"\n    token = \"\"\n    while token not in [\"y\", \"n\"]:\n        inp = input(message)\n\n        if check_list and inp.lower() == \"list\":\n            print(\"Animals I already know are:\")\n            list_known_animals(root_node)\n            print(\"\\n\")\n\n        token = inp[0].lower() if len(inp) > 0 else \"\"\n    return token\n\n\ndef avoid_void_input(message: str) -> str:\n    answer = \"\"\n    while not answer:\n        answer = input(message)\n    return answer\n\n\ndef print_intro() -> None:\n    print(\" \" * 32 + \"Animal\")\n    print(\" \" * 15 + \"Creative Computing Morristown, New Jersey\\n\")\n    print(\"Play ´Guess the Animal´\")\n    print(\"Think of an animal and the computer will try to guess it.\\n\")\n\n\ndef main() -> None:\n    # Initial tree\n    yes_child = Node(\"Fish\", None, None)\n    no_child = Node(\"Bird\", None, None)\n    root = Node(\"Does it swim?\", yes_child, no_child)\n\n    # Main loop of game\n    print_intro()\n    while (\n        parse_input(\n            \"Are you thinking of an animal? \", True, root\n        )\n        == \"y\"\n    ):\n        keep_asking = True\n        # Start traversing the tree by the root\n        actual_node: Node = root\n\n        while keep_asking:\n\n            if not actual_node.is_leaf():\n\n                # we have to keep asking i.e. traversing nodes\n                answer = parse_input(actual_node.text, False, None)\n\n                # As this is an inner node, both children are not None\n                if answer == \"y\":\n                    assert actual_node.yes_node is not None\n                    actual_node = actual_node.yes_node\n                else:\n                    assert actual_node.no_node is not None\n                    actual_node = actual_node.no_node\n            else:\n                # we have reached a possible answer\n                answer = parse_input(f\"Is it a {actual_node.text}? \", False, None)\n                if answer == \"n\":\n                    # add the new animal to the tree\n                    new_animal = avoid_void_input(\n                        \"The animal you were thinking of was a ? \"\n                    )\n                    new_question = avoid_void_input(\n                        \"Please type in a question that would distinguish a \"\n                        f\"{new_animal} from a {actual_node.text}: \"\n                    )\n                    answer_new_question = parse_input(\n                        f\"for a {new_animal} the answer would be: \", False, None\n                    )\n\n                    actual_node.update_node(f\"{new_question}?\", answer_new_question, new_animal)\n\n                else:\n                    print(\"Why not try another animal?\")\n\n                keep_asking = False\n\n\n########################################################\n# Porting Notes\n#\n#   The data structure used for storing questions and\n#   animals is a binary tree where each non-leaf node\n#   has a question, while the leafs store the animals.\n#\n#   As the original program, this program doesn't store\n#   old questions and animals. A good modification would\n#   be to add a database to store the tree.\n#    Also as the original program, this one can be easily\n#   modified to not only make guesses about animals, by\n#   modyfing the initial data of the tree, the questions\n#   that are asked to the user and the initial message\n#   function  (Lines 120 to 130, 135, 158, 160, 168, 173)\n\n########################################################\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "03_Animal/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "03_Animal/ruby/animal.rb",
    "content": "require 'set'\n\ndef intro\n  puts \"                                ANIMAL\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nPLAY 'GUESS THE ANIMAL'\n\nTHINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\n\n\"\nend\n\ndef ask(question)\n  print \"#{question} \"\n  (gets || '').chomp.upcase\nend\n\nFeature = Struct.new(:question, :yes_guess, :no_guess)\n\ndef add_guess(animals, guess)\n  guess.is_a?(Struct) ? get_all_animals(guess, animals) : animals.add(guess)\nend\n\ndef get_all_animals(feature, animals = Set.new)\n  add_guess(animals, feature.yes_guess)\n  add_guess(animals, feature.no_guess)\n  animals\nend\n\ndef create_feature(current_animal)\n  new_animal = ask('THE ANIMAL YOU WERE THINKING OF WAS A ?')\n  puts \"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A #{new_animal} FROM A #{current_animal}\"\n  question = ask('?')\n  loop do\n    yes_no = ask(\"FOR A #{new_animal} THE ANSWER WOULD BE ?\")\n    next unless ['Y', 'N'].include?(yes_no[0])\n    guesses = yes_no[0] == 'Y' ? [new_animal, current_animal] : [current_animal, new_animal]\n    return Feature.new(question, *guesses)\n  end\nend\n\ndef guess_loop(feature)\n  loop do\n    answer = ask(feature.question)\n    next unless ['Y', 'N'].include?(answer[0])\n    answer_is_yes = answer[0] == 'Y'\n\n    name = answer_is_yes ? feature.yes_guess : feature.no_guess\n    if name.is_a?(Struct)\n      feature = name\n      next\n    end\n\n    guess = ask(\"IS IT A #{name}?\")\n    correct_guess = guess[0] == 'Y'\n\n    if correct_guess\n      puts \"WHY NOT TRY ANOTHER ANIMAL?\"\n      break\n    end\n\n    if answer_is_yes\n      feature.yes_guess = create_feature(name)\n    else\n      feature.no_guess = create_feature(name)\n    end\n    break\n  end\nend\n\ndef main\n  intro\n  feature = Feature.new('DOES IT SWIM?', 'FISH', 'BIRD')\n\n  while true do\n    option = ask(\"ARE YOU THINKING OF AN ANIMAL?\")\n    if option == 'LIST'\n      puts\n      puts \"ANIMALS I ALREADY KNOW ARE:\"\n      puts get_all_animals(feature).to_a.join(\" \" * 15)\n      puts\n    elsif option[0] == 'Y'\n      guess_loop(feature)\n    elsif option == ''\n      puts\n    end\n  end\nend\n\ntrap \"SIGINT\" do puts; exit 130 end\n\nmain\n"
  },
  {
    "path": "03_Animal/rust/Cargo.toml",
    "content": "[package]\nname = \"animal\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "03_Animal/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by [Anton Kaiukov](https://github.com/batk0)\n"
  },
  {
    "path": "03_Animal/rust/src/main.rs",
    "content": "/*******************************************************************************\n * Animal\n * \n * From: Basic computer Games(1978)\n * \n *    Unlike other computer games in which the computer\n *   picks a number or letter and you must guess what it is,\n *   in this game you think of an animal and the computer asks\n *   you questions and tries to guess the name of your animal.\n *   If the computer guesses incorrectly, it will ask you for a\n *   question that differentiates the animal it guessed\n *   from the one you were thinking of. In this way the\n *   computer \"learns\" new animals. Questions to differentiate\n *   new animals should be input without a question mark.\n *    This version of the game does not have a SAVE feature.\n *   If your sistem allows, you may modify the program to\n *   save array A$, then reload the array  when you want\n *   to play the game again. This way you can save what the\n *   computer learns over a series of games.\n *    At any time if you reply 'LIST' to the question \"ARE YOU\n *   THINKING OF AN ANIMAL\", the computer will tell you all the\n *   animals it knows so far.\n *    The program starts originally by knowing only FISH and BIRD.\n *   As you build up a file of animals you should use broad,\n *   general questions first and then narrow down to more specific\n *   ones with later animals. For example, If an elephant was to be\n *   your first animal, the computer would ask for a question to distinguish\n *   an elephant from a bird. Naturally there are hundreds of possibilities,\n *   however, if you plan to build a large file of animals a good question\n *   would be \"IS IT A MAMAL\".\n *    This program can be easily modified to deal with categories of\n *   things other than animals by simply modifying the initial data\n *   in Line 530 and the dialogue references to animal in Lines 10,\n *   40, 50, 130, 230, 240 and 600. In an educational environment, this\n *   would be a valuable program to teach the distinguishing chacteristics\n *   of many classes of objects -- rock formations, geography, marine life,\n *   cell structures, etc.\n *    Originally developed by Arthur Luehrmann at Dartmouth College,\n *   Animal was subsequently shortened and modified by Nathan Teichholtz at\n *   DEC and Steve North at Creative Computing\n ******************************************************************************/\n/*******************************************************************************\n * Porting notes:\n * \n * The data structure used for the game is B-Tree where each leaf is an animal\n * and non-leaf node is a question.\n * \n * B-Tree is implemented in non-traditional way. It uses HashMap for string\n * nodes data and use determenistic method to calculate keys for left (yes) and \n * right (no) nodes. (See comments in the code.)\n * \n * The logic of the game mostly kept in `main` function with the use of some\n * helper functions.\n ******************************************************************************/\nuse std::collections::HashMap;\nuse std::io;\n\n/// Main function that contains all the logic.\nfn main() {\n    println!(\"{: ^80}\", \"Animal\");\n    println!(\"{: ^80}\\n\", \"Creative Computing Morristown, New Jersey\");\n    println!(\"Play ´Guess the Animal´\");\n    println!(\"Think of an animal and the computer will try to guess it.\\n\");\n\n    // Initial game data\n    let mut animal = BTree::new(\n        \"Does it swim\".to_string(),\n        \"Fish\".to_string(),\n        \"Bird\".to_string(),\n    );\n    \n    // Main game loop\n    while keep_playing() {\n        animal.restart();\n        // Ask questions until player reaches an animal.\n        while ! animal.is_leaf() {\n            println!(\"{}? \", animal.get());\n            if yes_no() {\n                animal.yes();\n            } else {\n                animal.no();\n            }\n        }\n        // Ask if this is the animal player is thinking of.\n        println!(\"Is it a {}? \", animal.get());\n        if ! yes_no() {\n            // Add a new animal if it's not, and distiguish it from the existing\n            // one with a question.\n            println!(\"The animal you were thinking of was a ? \");\n            let new_animal = read_input();\n            let old_animal = animal.get();\n            println!(\"Please type in a question that would distinguish a {} from a {}: \",\n                new_animal, old_animal );\n            let new_question = read_input();\n                println!(\"for a {} the answer would be: \", new_animal);\n            if yes_no() {\n                animal.set(new_question, new_animal, old_animal)\n            } else {\n                animal.set(new_question, old_animal, new_animal)\n            }\n        }\n        println!(\"Why not try another animal?\");\n    }\n}\n\n/// Reads the input line from [`io::stdin`] and returns it as a [`String`].\nfn read_input() -> String {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input).unwrap();\n    input.trim().parse::<String>().unwrap()\n}\n\n/// Asks the player whether the player wants to continue playing. Returns \n/// [`true`] if the answer is yes.\nfn keep_playing() -> bool {\n    println!(\"Are you thinking of an animal? \");\n    yes_no()\n}\n\n/// Checks whether given answer is `yes` or `no`, returns [`true`] if yes.\nfn yes_no() -> bool {\n    loop {\n        let answer = read_input().to_lowercase();\n        if answer != \"y\" && answer != \"yes\" && answer != \"n\" && answer != \"no\" {\n            println!(\"Please type `yes` or `no`\");\n            continue;\n        }\n        return answer == \"y\" || answer == \"yes\";\n    }\n}\n\n/// Binary Tree data structure. Implemented the similar way to Max/Min Heap.\nstruct BTree {\n    /// contains all nodes data (questions and animals).\n    nodes: HashMap<usize,String>,\n    /// contains the key to current node in the game.\n    cursor: usize,\n}\n\nimpl BTree {\n    /// Creates new [`BTree`] with one root node (question) and two childs \n    /// (animals).\n    fn new(value: String, yes: String, no: String) -> BTree {\n        let nodes: HashMap<usize,String> = HashMap::from([\n            (0, value),\n            (1, yes),\n            (2, no),\n        ]);\n        BTree { nodes: nodes, cursor: 0 }\n    }\n    \n    /// Returns the key for left node (yes) based on the postition of the \n    /// [`BTree::cursor`].\n    fn get_yes_key(&self) -> usize {\n        &self.cursor * 2 + 1\n    }\n\n    /// Returns the key for right node (no) based on the postition of the \n    /// [`BTree::cursor`].\n    fn get_no_key(&self) -> usize {\n        &self.cursor * 2 + 2\n    }\n    \n    /// Check if current node is a leaf (has no children).\n    fn is_leaf(&self) -> bool {\n        ! ( self.nodes.contains_key(&self.get_yes_key()) || \n            self.nodes.contains_key(&self.get_no_key()) )\n    }\n\n    /// Moves cursor to `yes` (left node) if the node exists.\n    fn yes(&mut self) {\n        if self.nodes.contains_key(&self.get_yes_key()) {\n            self.cursor = self.get_yes_key();   \n        }\n    }\n\n    /// Moves cursor to `no` (right node) if the node exists.\n    fn no(&mut self) {\n        if self.nodes.contains_key(&self.get_no_key()) {\n            self.cursor = self.get_no_key();   \n        }\n    }\n    \n    /// Sets new value (question) and two children (animals) at current position\n    /// of the [`BTree::cursor`].\n    fn set(&mut self, value: String, yes: String, no: String) {\n        if let Some(v) = self.nodes.get_mut(&self.cursor) {\n            *v = value;\n        }\n        self.nodes.insert(self.get_yes_key(), yes);\n        self.nodes.insert(self.get_no_key(), no);\n    }\n    \n    /// Returns the value (question or animal) of the current node.\n    fn get(&self) -> String {\n        if let Some(t) = self.nodes.get(&self.cursor) {\n            return t.to_string();\n        }\n        \"\".to_string()\n    }\n\n    /// Reset cursor to 0 (root node).\n    fn restart(&mut self) {\n        self.cursor = 0;\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    \n    #[test]\n    fn test_new() {\n        let got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        let want = BTree{nodes: HashMap::from([\n            (0, \"root\".to_string()),\n            (1, \"yes\".to_string()),\n            (2, \"no\".to_string()),\n        ]), cursor: 0};\n        assert_eq!(got.nodes, want.nodes);\n        assert_eq!(got.cursor, want.cursor);\n    }\n\n    #[test]\n    fn test_get() {\n        let got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        let want = \"root\".to_string();\n        assert_eq!(got.get(), want);\n    }\n\n    #[test]\n    fn test_set() {\n        let mut got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        got.set(\"Root\".to_string(), \"Yes\".to_string(), \"No\".to_string());\n        let want = BTree{nodes: HashMap::from([\n                (0, \"Root\".to_string()),\n                (1, \"Yes\".to_string()),\n                (2, \"No\".to_string()),\n            ]), cursor: 0};\n        assert_eq!(got.nodes, want.nodes);\n        assert_eq!(got.cursor, want.cursor);\n    }\n\n    #[test]\n    fn test_yes() {\n        let mut got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        let want = \"yes\".to_string();\n        let want_cursor = 1;\n        got.yes();\n        assert_eq!(got.get(), want);\n        assert_eq!(got.cursor, want_cursor);\n    }\n\n    #[test]\n    fn test_no() {\n        let mut got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        let want = \"no\".to_string();\n        let want_cursor = 2;\n        got.no();\n        assert_eq!(got.get(), want);\n        assert_eq!(got.cursor, want_cursor);\n    }\n\n    #[test]\n    fn test_is_leaf() {\n        let mut got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        assert!(!got.is_leaf(), \"should not be leaf\");\n        got.yes();\n        assert!(got.is_leaf(), \"should be leaf\");\n    }\n\n    #[test]\n    fn test_get_key() {\n        let mut got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        assert_eq!(got.get_yes_key(), 1);\n        assert_eq!(got.get_no_key(), 2);\n        got.yes();\n        assert_eq!(got.get_yes_key(), 3);\n        assert_eq!(got.get_no_key(), 4);\n    }\n\n    #[test]\n    fn test_restart() {\n        let mut got = BTree::new(\"root\".to_string(), \"yes\".to_string(), \"no\".to_string());\n        assert_eq!(got.cursor, 0);\n        got.yes();\n        assert_eq!(got.cursor, 1);\n        got.restart();\n        assert_eq!(got.cursor, 0);\n    }\n}\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Animal.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Animal</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n    <OptionStrict>On</OptionStrict>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Branch.vb",
    "content": "﻿Public Class Branch\n    Public Property Text As String\n\n    Public ReadOnly Property IsEnd As Boolean\n        Get\n            Return Yes Is Nothing AndAlso No Is Nothing\n        End Get\n    End Property\n\n    Public Property Yes As Branch\n    Public Property No As Branch\n\n    ' Allows walking all the descendants recursively\n    Public Iterator Function DescendantTexts() As IEnumerable(Of String)\n        If Yes IsNot Nothing Then\n            Yield Yes.Text\n            For Each childText In Yes.DescendantTexts\n                Yield childText\n            Next\n        End If\n\n        If No IsNot Nothing Then\n            Yield No.Text\n            For Each childText In No.DescendantTexts\n                Yield childText\n            Next\n        End If\n    End Function\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Game.vb",
    "content": "﻿Option Compare Text\n\nPublic Class Game\n    ' This Dictionary holds the corresponding value for each of the variants of \"YES\" and \"NO\" we accept\n    ' Note that the Dictionary is case-insensitive, meaning it maps \"YES\", \"yes\" and even \"yEs\" to True\n    Private Shared ReadOnly YesNoResponses As New Dictionary(Of String, Boolean)(StringComparer.InvariantCultureIgnoreCase) From {\n        {\"yes\", True},\n        {\"y\", True},\n        {\"true\", True},\n        {\"t\", True},\n        {\"1\", True},\n        {\"no\", False},\n        {\"n\", False},\n        {\"false\", False},\n        {\"f\", False},\n        {\"0\", False}\n    }\n\n    ReadOnly console As ConsoleAdapterBase\n\n    ' The pre-initialized root branch\n    ReadOnly root As New Branch With {\n        .Text = \"DOES IT SWIM?\",\n        .Yes = New Branch With {.Text = \"FISH\"},\n        .No = New Branch With {.Text = \"BIRD\"}\n    }\n\n    ''' <summary>Reduces a string or console input to True, False or Nothing. Case-insensitive.</summary>\n    ''' <param name=\"s\">Optional String to reduce via the same logic. If not passed in, will use console.ReadLine</param>\n    ''' <returns>\n    ''' Returns True for a \"yes\" response (yes, y, true, t, 1) and False for a \"no\" response (no, n, false, f, 0).<br/>\n    ''' Returns Nothing if the response doesn't match any of these.\n    ''' </returns>\n    Private Function GetYesNo(Optional s As String = Nothing) As Boolean?\n        s = If(s, console.ReadLine)\n        Dim ret As Boolean\n        If YesNoResponses.TryGetValue(s, ret) Then Return ret\n        Return Nothing\n    End Function\n\n    Sub New(console As ConsoleAdapterBase)\n        If console Is Nothing Then Throw New ArgumentNullException(NameOf(console))\n        Me.console = console\n    End Sub\n\n\n    Sub BeginLoop()\n        ' Print the program heading\n        console.WriteCenteredLines(\n\"ANIMAL\nCREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n\n        ' Print the program description\n        console.Write(\n\"\n\n\nPLAY 'GUESS THE ANIMAL'\n\nTHINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.\n\n\")\n\n        Do\n            console.Write(\"ARE YOU THINKING OF AN ANIMAL? \")\n\n            Dim response = console.ReadLine\n            If response = \"list\" Then\n                ' List all the stored animals\n                console.Write(\n\"\nANIMALS I ALREADY KNOW ARE:\n\")\n\n                ' We're using a ForEach extension method instead of the regular For Each loop to provide the index alongside the text\n                root.DescendantTexts.ForEach(Sub(text, index)\n                                                 ' We want to move to the next line after every four animals\n                                                 ' But for the first animal, where the index is 0, 0 Mod 4 will also return 0\n                                                 ' So we have to explicitly exclude the first animal\n                                                 If index > 0 AndAlso index Mod 4 = 0 Then console.WriteLine()\n                                                 console.Write($\"{text.MaxLength(15),-15}\")\n                                             End Sub)\n                console.Write(\n\"\n\n\")\n                Continue Do\n            End If\n\n            Dim ynResponse = GetYesNo(response)\n            If ynResponse Is Nothing OrElse Not ynResponse Then Continue Do\n\n            Dim currentBranch = root\n            Do While Not currentBranch.IsEnd\n                ' Branches can either be questions, or end branches\n                ' We have to walk the questions, prompting each time for \"yes\" or \"no\"\n                console.Write($\"{currentBranch.Text} \")\n                Do\n                    ynResponse = GetYesNo()\n                Loop While ynResponse Is Nothing\n\n                ' Depending on the answer, we'll follow either the branch at \"Yes\" or \"No\"\n                currentBranch = If(\n                    ynResponse,\n                    currentBranch.Yes,\n                    currentBranch.No\n                )\n            Loop\n\n            ' Now we're at an end branch\n            console.Write($\"IS IT A {currentBranch.Text}? \")\n            ynResponse = GetYesNo()\n            If ynResponse Then ' Only if ynResponse = True will we go into this If Then block\n                ' The computer guessed the animal; we can go back to the beginning of the game\n                console.WriteLine(\"WHY NOT TRY ANOTHER ANIMAL?\")\n                Continue Do\n            End If\n\n            ' Get the new animal from the user\n            console.Write(\"THE ANIMAL YOU WERE THINKING OF WAS A ? \")\n            Dim newAnimal = console.ReadLine.ToUpperInvariant\n\n            ' Get the question used to distinguish the new animal from the current end branch\n            console.Write(\n$\"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\n{newAnimal} FROM A {currentBranch.Text}\n\")\n            Dim newQuestion = console.ReadLine.ToUpperInvariant\n\n            ' Get the answer to that question, for the new animal\n            ' for the old animal, the answer will be the opposite\n            console.Write($\"FOR A {newAnimal} THE ANSWER WOULD BE? \")\n            Do\n                ynResponse = GetYesNo()\n            Loop While ynResponse Is Nothing\n\n            ' Create the new end branch for the new animal\n            Dim newBranch = New Branch With {.Text = newAnimal}\n\n            ' Copy over the current animal to another new end branch\n            Dim currentBranchCopy = New Branch With {.Text = currentBranch.Text}\n\n            ' Make the current branch into the distinguishing question\n            currentBranch.Text = newQuestion\n\n            ' Set the Yes and No branches of the current branch according to the answer\n            If ynResponse Then\n                currentBranch.Yes = newBranch\n                currentBranch.No = currentBranchCopy\n            Else\n                currentBranch.No = newBranch\n                currentBranch.Yes = currentBranchCopy\n            End If\n\n            ' TODO how do we exit?\n        Loop\n    End Sub\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Program.vb",
    "content": "﻿Module Program\n    Sub Main()\n        Dim game As New Game(New ConsoleAdapter)\n        game.BeginLoop()\n    End Sub\nEnd Module\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Shared/ConsoleAdapter.vb",
    "content": "﻿Public Class ConsoleAdapter\n    Inherits ConsoleAdapterBase\n\n    Public Overrides Sub Write(value As Object)\n        Console.Write(value)\n    End Sub\n\n    Public Overrides Sub WriteLine()\n        Console.WriteLine()\n    End Sub\n\n    Public Overrides Sub WriteCenteredLines(value As Object)\n        If Console.CursorLeft <> 0 Then WriteLine()\n        Dim toWrite = If(value?.ToString, \"\")\n        For Each line In toWrite.Split(Environment.NewLine)\n            Write($\"{Space((Console.WindowWidth - line.Length) \\ 2)}{line}\")\n            WriteLine()\n        Next\n    End Sub\n\n    Public Overrides Function ReadLine() As String\n        Dim response As String\n        Do\n            response = Console.ReadLine\n        Loop While response Is Nothing\n        Return response.Trim\n    End Function\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Shared/ConsoleAdapterBase.vb",
    "content": "﻿Public MustInherit Class ConsoleAdapterBase\n    Public MustOverride Sub Write(value As Object)\n    Public MustOverride Sub WriteLine()\n    Public MustOverride Sub WriteCenteredLines(value As Object)\n\n    ''' <summary>Implementations should always return a String without leading or trailing whitespace, never Nothng</summary>\n    Public MustOverride Function ReadLine() As String\n\n    Public Sub WriteLine(value As Object)\n        Write(value)\n        WriteLine()\n    End Sub\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal/Shared/Extensions.vb",
    "content": "﻿Imports System.Runtime.CompilerServices\n\nPublic Module Extensions\n    <Extension> Public Sub ForEach(Of T)(src As IEnumerable(Of T), action As Action(Of T))\n        For Each x In src\n            action(x)\n        Next\n    End Sub\n    <Extension> Public Sub ForEach(Of T)(src As IEnumerable(Of T), action As Action(Of T, Integer))\n        Dim index As Integer\n        For Each x In src\n            action(x, index)\n            index += 1\n        Next\n    End Sub\n\n    <Extension> Public Function MaxLength(s As String, value As Integer) As String\n        If s Is Nothing Then Return Nothing\n        Return s.Substring(0, Math.Min(s.Length, value))\n    End Function\n\n    <Extension> Public Function ForceEndsWith(s As String, toAppend As String) As String\n        If Not s.EndsWith(toAppend, StringComparison.OrdinalIgnoreCase) Then s += toAppend\n        Return s\n    End Function\n\n    <Extension> Public Function ToTitleCase(s As String) As String\n        If s Is Nothing Then Return Nothing\n        Return Char.ToUpperInvariant(s(0)) + s.Substring(1).ToUpperInvariant\n    End Function\n\n    ' https://stackoverflow.com/a/3681580/111794\n    <Extension> Public Function ToReverseCase(s As String) As String\n        If s Is Nothing Then Return Nothing\n        Return New String(s.Select(Function(c) If(\n            Not Char.IsLetter(c),\n            c,\n            If(\n                Char.IsUpper(c), Char.ToLowerInvariant(c), Char.ToUpperInvariant(c)\n            )\n            )).ToArray)\n    End Function\n\n    ' https://stackoverflow.com/a/58132204/111794\n    <Extension> Public Function Slice(Of T)(lst As IList(Of T), start As Integer, [end] As Integer) As T()\n        start = If(start >= 0, start, lst.Count + start)\n        [end] = If([end] > 0, [end], lst.Count + [end])\n        Return lst.Skip(start).Take([end] - start).ToArray\n    End Function\nEnd Module\n"
  },
  {
    "path": "03_Animal/vbnet/Animal.Tests/Animal.Tests.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <RootNamespace>Animal.Tests</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <IsPackable>false</IsPackable>\n    <OptionStrict>On</OptionStrict>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.0.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.3\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"3.1.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Animal\\Animal.vbproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "03_Animal/vbnet/Animal.Tests/EndOfInputsException.vb",
    "content": "﻿''' <summary>\n''' <para>Indicates that there are no more inputs in the MockConsole.</para>\n''' We need this while testing, because otherwise the game loop will continue forever, waiting for a nonexistent input.\n''' </summary>\nPublic Class EndOfInputsException\n    Inherits Exception\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal.Tests/MockConsole.vb",
    "content": "﻿Imports System.IO\n\nPublic Class MockConsole\n    Inherits ConsoleAdapterBase\n\n    Private inputs As Queue(Of String)\n    Public ReadOnly Lines As New List(Of (line As String, centered As Boolean)) From {\n        (\"\", False)\n    }\n\n    ' TODO it's possible to clear all the lines, and we'd have to check once again in WriteString and WriteCenteredLine if there are any lines\n\n    Sub New(Inputs As IEnumerable(Of String))\n        Me.inputs = New Queue(Of String)(Inputs)\n    End Sub\n\n    Private Sub CheckLinesInitialized()\n        If Lines.Count = 0 Then Lines.Add((\"\", False))\n    End Sub\n\n    Private Sub WriteString(s As String, Optional centered As Boolean = False)\n        If s Is Nothing Then Return\n        CheckLinesInitialized()\n        s.Split(Environment.NewLine).ForEach(Sub(line, index)\n                                                 If index = 0 Then\n                                                     Dim currentLast = Lines(Lines.Count - 1)\n                                                     ' centered should never come from the current last line\n                                                     ' if WriteCenteredLine is called, it immediately creates a new line\n                                                     Lines(Lines.Count - 1) = (currentLast.line + line, centered)\n                                                 Else\n                                                     Lines.Add((line, centered))\n                                                 End If\n                                             End Sub)\n    End Sub\n\n    Public Overrides Sub Write(value As Object)\n        WriteString(value?.ToString)\n    End Sub\n\n    Public Overrides Sub WriteLine()\n        Lines.Add((\"\", False))\n    End Sub\n\n    Public Overrides Sub WriteCenteredLines(value As Object)\n        If Lines.Count = 0 Then Lines.Add((\"\", False))\n        Dim currentLast = Lines(Lines.Count - 1).line\n        If currentLast.Length > 0 Then Lines.Add((\"\", False))\n        WriteString(value?.ToString, True)\n        WriteLine()\n    End Sub\n\n    Public Overrides Function ReadLine() As String\n        ' Indicates the end of a test run, for programs which loop endlessly\n        If inputs.Count = 0 Then Throw New EndOfInputsException\n\n        Dim nextInput = inputs.Dequeue.Trim\n        WriteLine(nextInput)\n        Return nextInput\n    End Function\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal.Tests/TestContainer.vb",
    "content": "Imports Xunit\nImports Animal\nImports System.IO\n\nPublic Class TestContainer\n    Private Shared Function ResponseVariantExpander(src As IEnumerable(Of String)) As TheoryData(Of String)\n        Dim theoryData = New TheoryData(Of String)\n        src.\n            SelectMany(Function(x) {x, x.Substring(0, 1)}).\n            SelectMany(Function(x) {\n                x,\n                x.ToUpperInvariant,\n                x.ToLowerInvariant,\n                x.ToTitleCase,\n                x.ToReverseCase\n            }).\n            Distinct.\n            ForEach(Sub(x) theoryData.Add(x))\n        Return theoryData\n    End Function\n    Private Shared YesVariantsThepryData As TheoryData(Of String) = ResponseVariantExpander({\"yes\", \"true\", \"1\"})\n    Private Shared Function YesVariants() As TheoryData(Of String)\n        Return YesVariantsThepryData\n    End Function\n    Private Shared NoVariantsThepryData As TheoryData(Of String) = ResponseVariantExpander({\"no\", \"false\", \"0\"})\n    Private Shared Function NoVariants() As TheoryData(Of String)\n        Return NoVariantsThepryData\n    End Function\n\n    ''' <summary>Test LIST variants</summary>\n    <Theory>\n    <InlineData(\"LIST\")>\n    <InlineData(\"list\")>\n    <InlineData(\"List\")>\n    <InlineData(\"lIST\")>\n    Sub List(listResponse As String)\n        Dim console As New MockConsole({listResponse})\n        Dim game As New Game(console)\n        Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())\n        Assert.Equal(\n            {\n                \"ANIMALS I ALREADY KNOW ARE:\",\n                \"FISH           BIRD           \"\n            },\n            console.Lines.Slice(-4, -2).Select(Function(x) x.line)\n        )\n    End Sub\n\n    '' <summary>Test YES variants</summary>\n    <Theory>\n    <MemberData(NameOf(YesVariants))>\n    Sub YesVariant(yesVariant As String)\n        Dim console As New MockConsole({yesVariant})\n        Dim game As New Game(console)\n        Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())\n        Assert.Equal(\n            {\n                $\"ARE YOU THINKING OF AN ANIMAL? {yesVariant}\",\n                \"DOES IT SWIM? \"\n            },\n            console.Lines.Slice(-2, 0).Select(Function(x) x.line)\n        )\n    End Sub\n\n    '' <summary>Test NO variants</summary>\n    <Theory>\n    <MemberData(NameOf(NoVariants))>\n    Sub NoVariant(noVariant As String)\n        Dim console As New MockConsole({\"y\", noVariant})\n        Dim game As New Game(console)\n        Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())\n        Assert.Equal(\n            {\n                $\"DOES IT SWIM? {noVariant}\",\n                \"IS IT A BIRD? \"\n            },\n            console.Lines.Slice(-2, 0).Select(Function(x) x.line)\n        )\n    End Sub\n\n    ''' <summary>Test adding a new animal and using the new animal in the game</summary>\n    <Fact>\n    Sub TestAddedAnimal()\n        Dim console As New MockConsole({\n            \"y\",\n            \"y\",\n            \"n\",\n            \"whale\",\n            \"is it a mammal?\",\n            \"y\",\n            \"y\",\n            \"y\",\n            \"y\",\n            \"y\"\n        })\n        Dim game As New Game(console)\n        Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())\n        Assert.Equal(\n            {\n                \"ARE YOU THINKING OF AN ANIMAL? y\",\n                \"DOES IT SWIM? y\",\n                \"IS IT A FISH? n\",\n                \"THE ANIMAL YOU WERE THINKING OF WAS A ? whale\",\n                \"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A\",\n                \"WHALE FROM A FISH\",\n                \"is it a mammal?\",\n                \"FOR A WHALE THE ANSWER WOULD BE? y\",\n                \"ARE YOU THINKING OF AN ANIMAL? y\",\n                \"DOES IT SWIM? y\",\n                \"IS IT A MAMMAL? y\",\n                \"IS IT A WHALE? y\",\n                \"WHY NOT TRY ANOTHER ANIMAL?\",\n                \"ARE YOU THINKING OF AN ANIMAL? \"\n            },\n            console.Lines.Slice(9, 100).Select(Function(x) x.line)\n        )\n    End Sub\nEnd Class\n"
  },
  {
    "path": "03_Animal/vbnet/Animal.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32112.339\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{778DAE3C-4631-46EA-AA77-85C1314464D9}\") = \"Animal\", \"Animal\\Animal.vbproj\", \"{5517E4CE-BCF9-4D1F-9A17-B620C1B96B0D}\"\nEndProject\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Animal.Tests\", \"Animal.Tests\\Animal.Tests.vbproj\", \"{3986C6A2-77D4-4F00-B3CF-F5736C623B1E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{5517E4CE-BCF9-4D1F-9A17-B620C1B96B0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5517E4CE-BCF9-4D1F-9A17-B620C1B96B0D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5517E4CE-BCF9-4D1F-9A17-B620C1B96B0D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5517E4CE-BCF9-4D1F-9A17-B620C1B96B0D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{3986C6A2-77D4-4F00-B3CF-F5736C623B1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3986C6A2-77D4-4F00-B3CF-F5736C623B1E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3986C6A2-77D4-4F00-B3CF-F5736C623B1E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3986C6A2-77D4-4F00-B3CF-F5736C623B1E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {88469A47-E30C-4763-A325-074101D16608}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "03_Animal/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n\nThis takes some inspiration from the [C# port of Animal](https://github.com/zspitz/basic-computer-games/tree/main/03_Animal/csharp).\n\nThe `Game` class takes a console abstraction (`ConsoleAdapterBase`), which could also be used for different UIs, such as WinForms or a web page.\nThis solution also has an xUnit tests project.\nResponses can be entered in any capitalization, but animals and the distinguishing question will be converted to uppercase.\n"
  },
  {
    "path": "04_Awari/README.md",
    "content": "### Awari\n\nAwari is an ancient African game played with seven sticks and thirty-six stones or beans laid out as shown above. The board is divided into six compartments or pits on each side. In addition, there are two special home pits at the ends.\n\nA move is made by taking all the beans from any (non-empty) pit on your own side. Starting from the pit to the right of this one, these beans are ‘sown’ one in each pit working around the board anticlockwise.\n\nA turn consists of one or two moves. If the last bean of your move is sown in your own home you may take a second move.\n\nIf the last bean sown in a move lands in an empty pit, provided that the opposite pit is not empty, all the beans in the opposite pit, together with the last bean sown are ‘captured’ and moved to the player’s home.\n\nWhen either side is empty, the game is finished. The player with the most beans in his home has won.\n\nIn the computer version, the board is printed as 14 numbers representing the 14 pits.\n\n```\n    3   3   3   3   3   3\n0                           0\n    3   3   3   3   3   3\n```\n\nThe pits on your (lower) side are numbered 1-6 from left to right. The pits on my (the computer’s) side are numbered from my left (your right).\n\nTo make a move you type in the number of a pit. If the last bean lands in your home, the computer types ‘AGAIN?’ and then you type in your second move.\n\nThe computer’s move is typed, followed by a diagram of the board in its new state. The computer always offers you the first move. This is considered to be a slight advantage.\n\nThere is a learning mechanism in the program that causes the play of the computer to improve as it playes more games.\n\nThe original version of Awari is adopted from one originally written by Geoff Wyvill of Bradford, Yorkshire, England.\n\n---\n\nAs published in Basic Computer Games (1978)\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=6)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=21)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n"
  },
  {
    "path": "04_Awari/awari.bas",
    "content": "5 PRINT TAB(34);\"AWARI\"\n7 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n10 DATA 0\n15 DIM B(13),G(13),F(50):READ N\n20 PRINT:PRINT:E=0\n25 FOR I=0 TO 12:B(I)=3:NEXT I\n30 C=0:F(N)=0:B(13)=0:B(6)=0\n35 GOSUB 500\n40 PRINT \"YOUR MOVE\";:GOSUB 110\n45 IF E=0 THEN 80\n50 IF M=H THEN GOSUB 100\n55 IF E=0 THEN 80\n60 PRINT \"MY MOVE IS \";:GOSUB 800\n65 IF E=0 THEN 80\n70 IF M=H THEN PRINT \",\";:GOSUB 800\n75 IF E>0 THEN 35\n80 PRINT:PRINT\"GAME OVER\"\n85 D=B(6)-B(13):IF D<0 THEN PRINT \"I WIN BY\";-D;\"POINTS\":GOTO 20\n90 N=N+1:IF D=0 THEN PRINT \"DRAWN GAME\":GOTO 20\n95 PRINT \"YOU WIN BY\";D;\"POINTS\":GOTO 20\n100 PRINT \"AGAIN\";\n110 INPUT M:IF M<7 THEN IF M>0 THEN M=M-1:GOTO 130\n120 PRINT \"ILLEGAL MOVE\":GOTO 100\n130 IF B(M)=0 THEN 120\n140 H=6:GOSUB 200\n150 GOTO 500\n200 K=M:GOSUB 600\n205 E=0:IF K>6 THEN K=K-7\n210 C=C+1:IF C<9 THEN F(N)=F(N)*6+K\n215 FOR I=0 TO 5:IF B(I)<>0 THEN 230\n220 NEXT I\n225 RETURN\n230 FOR I=7 TO 12:IF B(I)<>0 THEN E=1:RETURN\n235 GOTO 220\n500 PRINT:PRINT\"   \";\n505 FOR I=12 TO 7 STEP -1:GOSUB 580\n510 NEXT I\n515 PRINT:I=13:GOSUB 580\n520 PRINT \"                       \";:PRINT B(6):PRINT \"   \";\n525 FOR I=0 TO 5:GOSUB 580\n530 NEXT I\n535 PRINT:PRINT:RETURN\n580 IF B(I)<10 THEN PRINT \" \";\n585 PRINT B(I);:RETURN\n600 P=B(M):B(M)=0\n605 FOR P=P TO 1 STEP -1:M=M+1:IF M>13 THEN M=M-14\n610 B(M)=B(M)+1:NEXT P\n615 IF B(M)=1 THEN IF M<>6 THEN IF M<>13 THEN IF B(12-M)<>0 THEN 625\n620 RETURN\n625 B(H)=B(H)+B(12-M)+1:B(M)=0:B(12-M)=0:RETURN\n800 D=-99:H=13\n805 FOR I=0 TO 13:G(I)=B(I):NEXT I\n810 FOR J=7 TO 12:IF B(J)=0 THEN 885\n815 Q=0:M=J:GOSUB 600\n820 FOR I=0 TO 5:IF B(I)=0 THEN 845\n825 L=B(I)+I:R=0\n830 IF L>13 THEN L=L-14:R=1:GOTO 830\n835 IF B(L)=0 THEN IF L<>6 THEN IF L<>13 THEN R=B(12-L)+R\n840 IF R>Q THEN Q=R\n845 NEXT I\n850 Q=B(13)-B(6)-Q:IF C>8 THEN 875\n855 K=J:IF K>6 THEN K=K-7\n860 FOR I=0 TO N-1:IF F(N)*6+K=INT(F(I)/6^(7-C)+.1) THEN Q=Q-2\n870 NEXT I\n875 FOR I=0 TO 13:B(I)=G(I):NEXT I\n880 IF Q>=D THEN A=J:D=Q\n885 NEXT J\n890 M=A:PRINT CHR$(42+M);:GOTO 200\n900 FOR I=0 TO N-1:PRINT B(I):NEXT I\n999 END\n"
  },
  {
    "path": "04_Awari/csharp/Awari.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <RootNamespace>Awari</RootNamespace>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "04_Awari/csharp/Awari.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Awari\", \"Awari.csproj\", \"{DD161F58-D90F-481A-8275-96E01D229A70}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DD161F58-D90F-481A-8275-96E01D229A70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DD161F58-D90F-481A-8275-96E01D229A70}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DD161F58-D90F-481A-8275-96E01D229A70}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DD161F58-D90F-481A-8275-96E01D229A70}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {7F5C288A-A6C6-4AC0-96E3-6A3B482A0947}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "04_Awari/csharp/Game.cs",
    "content": "namespace Awari;\n\npublic class Game\n{\n    public int[] PlayerPits => _beans[0..6];\n    public int[] ComputerPits => _beans[7..13];\n    public int PlayerHome => _beans[_playerHome];\n    public int ComputerHome => _beans[_computerHome];\n\n    private bool IsDone =>\n        PlayerPits.All(b => b == 0) // if all the player's pits are empty\n     || ComputerPits.All(b => b == 0); // or if all the computer's pits are empty\n\n    public GameState State { get; private set; }\n\n    public void Reset()\n    {\n        State = GameState.PlayerMove;\n\n        Array.Fill(_beans, _initialPitValue);\n        _beans[_playerHome] = 0;\n        _beans[_computerHome] = 0;\n\n        _moveCount = 0;\n        _notWonGameMoves[^1] = 0;\n    }\n\n    public bool IsLegalPlayerMove(int move) =>\n        move is > 0 and < 7\n     && _beans[move - 1] > 0; // arrays are zero-based, but moves are one-based\n\n    public void PlayerMove(int move) => MoveAndRegister(move - 1, _playerHome);\n\n    public List<int> ComputerTurn()\n    {\n        // keep a list of moves made by the computer in a single turn (1 or 2)\n        List<int> moves = new();\n\n        moves.Add(ComputerMove()); // ComputerMove() returns the move made\n\n        // only if a second move is possible, do it\n        if (State == GameState.ComputerSecondMove)\n            moves.Add(ComputerMove());\n\n        return moves;\n    }\n\n    public GameOutcome GetOutcome()\n    {\n        if (State != GameState.Done)\n            throw new InvalidOperationException(\"Game is not yet done.\");\n\n        int difference = _beans[_playerHome] - _beans[_computerHome];\n        var winner = difference switch\n        {\n            < 0 => GameWinner.Computer,\n            0 => GameWinner.Draw,\n            > 0 => GameWinner.Player,\n        };\n\n        return new GameOutcome(winner, Math.Abs(difference));\n    }\n\n    private void MoveAndRegister(int pit, int homePosition)\n    {\n        int lastMovedBean = Move(_beans, pit, homePosition);\n\n        // encode moves by player and computer into a 'base 6' number\n        // e.g. if the player moves 5, the computer moves 2, and the player moves 4,\n        // that would be encoded as ((5 * 6) * 6) + (2 * 6) + 4 = 196\n        if (pit > 6) pit -= 7;\n        _moveCount++;\n        if (_moveCount < 9)\n            _notWonGameMoves[^1] = _notWonGameMoves[^1] * 6 + pit;\n\n        // determine next state based on current state, whether the game's done, and whether the last moved bean moved\n        // into the player's home position\n        State = (State, IsDone, lastMovedBean == homePosition) switch\n        {\n            (_, true, _) => GameState.Done,\n            (GameState.PlayerMove, _, true) => GameState.PlayerSecondMove,\n            (GameState.PlayerMove, _, false) => GameState.ComputerMove,\n            (GameState.PlayerSecondMove, _, _) => GameState.ComputerMove,\n            (GameState.ComputerMove, _, true) => GameState.ComputerSecondMove,\n            (GameState.ComputerMove, _, false) => GameState.PlayerMove,\n            (GameState.ComputerSecondMove, _, _) => GameState.PlayerMove,\n            _ => throw new InvalidOperationException(\"Unexpected game state\"),\n        };\n\n        // do some bookkeeping if the game is done, but not won by the computer\n        if (State == GameState.Done\n         && _beans[_playerHome] >= _beans[_computerHome])\n            // add an entry for the next game\n            _notWonGameMoves.Add(0);\n    }\n\n    private static int Move(int[] beans, int pit, int homePosition)\n    {\n        int beansToMove = beans[pit];\n        beans[pit] = 0;\n\n        // add the beans that were in the pit to other pits, moving clockwise around the board\n        for (; beansToMove >= 1; beansToMove--)\n        {\n            // wrap around if pit exceeds 13\n            pit = (pit + 1) % 14;\n\n            beans[pit]++;\n        }\n\n        if (beans[pit] == 1 // if the last bean was sown in an empty pit\n         && pit is not _playerHome and not _computerHome // which is not either player's home\n         && beans[12 - pit] != 0) // and the pit opposite is not empty\n        {\n            // move the last pit sown and the _beans in the pit opposite to the player's home\n            beans[homePosition] = beans[homePosition] + beans[12 - pit] + 1;\n            beans[pit] = 0;\n            beans[12 - pit] = 0;\n        }\n\n        return pit;\n    }\n\n    private int ComputerMove()\n    {\n        int move = DetermineComputerMove();\n        MoveAndRegister(move, homePosition: _computerHome);\n\n        // the result is only used to return it to the application, so translate it from an array index (between 7 and\n        // 12) to a pit number (between 1 and 6)\n        return move - 6;\n    }\n\n    private int DetermineComputerMove()\n    {\n        int bestScore = -99;\n        int move = 0;\n\n        // for each of the computer's possible moves, simulate them to calculate a score and pick the best one\n        for (int j = 7; j < 13; j++)\n        {\n            if (_beans[j] <= 0)\n                continue;\n\n            int score = SimulateMove(j);\n\n            if (score >= bestScore)\n            {\n                move = j;\n                bestScore = score;\n            }\n        }\n\n        return move;\n    }\n\n    private int SimulateMove(int move)\n    {\n        // make a copy of the current state, so we can safely mess with it\n        var hypotheticalBeans = new int[14];\n        _beans.CopyTo(hypotheticalBeans, 0);\n\n        // simulate the move in our copy\n        Move(hypotheticalBeans, move, homePosition: _computerHome);\n\n        // determine the 'best' move the player could make after this (best for them, not for the computer)\n        int score = ScoreBestNextPlayerMove(hypotheticalBeans);\n\n        // score this move by calculating how far ahead we would be after the move, and subtracting the player's next\n        // move score\n        score = hypotheticalBeans[_computerHome] - hypotheticalBeans[_playerHome] - score;\n\n        // have we seen the current set of moves before in a drawn/lost game? after 8 moves it's unlikely we'll find any\n        // matches, since games will have diverged. also we don't have space to store that many moves.\n        if (_moveCount < 8)\n        {\n            int translatedMove = move - 7;  // translate from 7 through 12 to 0 through 5\n\n            // if the first two moves in this game were 1 and 2, and this hypothetical third move would be a 3,\n            // movesSoFar would be (1 * 36) + (2 * 6) + 3 = 51\n            int movesSoFar = _notWonGameMoves[^1] * 6 + translatedMove;\n\n            // since we store moves as a 'base 6' number, we need to divide stored moves by a power of 6\n            // let's say we've a stored lost game where the moves were, in succession, 1 through 8, the value stored\n            // would be:\n            // 8 + (7 * 6) + (6 * 36) + (5 * 216) + (4 * 1296) + (3 * 7776) + (2 * 46656) + (1 * 279936) = 403106\n            // to figure out the first three moves, we'd need to divide by 7776, resulting in 51.839...\n            double divisor = Math.Pow(6.0, 7 - _moveCount);\n\n            foreach (int previousGameMoves in _notWonGameMoves)\n                // if this combination of moves so far ultimately resulted in a draw/loss, give it a lower score\n                // note that this can happen multiple times\n                if (movesSoFar == (int) (previousGameMoves / divisor + 0.1))\n                    score -= 2;\n        }\n\n        return score;\n    }\n\n    private static int ScoreBestNextPlayerMove(int[] hypotheticalBeans)\n    {\n        int bestScore = 0;\n\n        for (int i = 0; i < 6; i++)\n        {\n            if (hypotheticalBeans[i] <= 0)\n                continue;\n\n            int score = ScoreNextPlayerMove(hypotheticalBeans, i);\n\n            if (score > bestScore)\n                bestScore = score;\n        }\n\n        return bestScore;\n    }\n\n    private static int ScoreNextPlayerMove(int[] hypotheticalBeans, int move)\n    {\n        // figure out where the last bean will land\n        int target = hypotheticalBeans[move] + move;\n        int score = 0;\n\n        // if it wraps around, that means the player is adding to his own pits, which is good\n        if (target > 13)\n        {\n            // prevent overrunning the number of pits we have\n            target %= 14;\n            score = 1;\n        }\n\n        // if the player's move ends up in an empty pit, add the value of the pit on the opposite side to the score\n        if (hypotheticalBeans[target] == 0 && target is not _playerHome and not _computerHome)\n            score += hypotheticalBeans[12 - target];\n\n        return score;\n    }\n\n    private const int _playerHome = 6;\n    private const int _computerHome = 13;\n    private const int _initialPitValue = 3;\n\n    private readonly int[] _beans = new int[14];\n    private readonly List<int> _notWonGameMoves = new() { 0 };    // not won means draw or lose\n    private int _moveCount;\n}\n\npublic enum GameState\n{\n    PlayerMove,\n    PlayerSecondMove,\n    ComputerMove,\n    ComputerSecondMove,\n    Done,\n}\n\npublic enum GameWinner\n{\n    Player,\n    Computer,\n    Draw,\n}\n\npublic record struct GameOutcome(GameWinner Winner, int Difference);\n"
  },
  {
    "path": "04_Awari/csharp/Program.cs",
    "content": "﻿using Awari;\n\nConsole.WriteLine(Tab(34) + \"AWARI\");\nConsole.WriteLine(Tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\nGame game = new();\n\nwhile (true)\n{\n    game.Reset();\n    DisplayGame();\n\n    while (game.State != GameState.Done)\n    {\n        switch (game.State)\n        {\n            case GameState.PlayerMove:\n                PlayerMove(second: false);\n                break;\n            case GameState.PlayerSecondMove:\n                PlayerMove(second: true);\n                break;\n            case GameState.ComputerMove:\n                ComputerTurn();\n                break;\n        }\n\n        DisplayGame();\n    }\n\n    var outcome = game.GetOutcome();\n\n    string outcomeLabel =\n        outcome.Winner switch\n        {\n            GameWinner.Computer => $\"I WIN BY {outcome.Difference} POINTS\",\n            GameWinner.Draw => \"DRAWN GAME\",\n            GameWinner.Player => $\"YOU WIN BY {outcome.Difference} POINTS\",\n            _ => throw new InvalidOperationException($\"Unexpected winner {outcome.Winner}.\"),\n        };\n    Console.WriteLine(outcomeLabel);\n    Console.WriteLine();\n}\n\nvoid DisplayGame()\n{\n    // display the computer's pits\n    Console.Write(\"   \");\n    foreach (var pit in game.ComputerPits.Reverse())\n        Console.Write($\"{pit,2} \");\n    Console.WriteLine();\n\n    // display both homes\n    Console.WriteLine($\"{game.ComputerHome,2}{Tab(19)}{game.PlayerHome,2}\");\n\n    // display the player's pits\n    Console.Write(\"   \");\n    foreach (var pit in game.PlayerPits)\n        Console.Write($\"{pit,2} \");\n    Console.WriteLine();\n\n    Console.WriteLine();\n}\n\nvoid PlayerMove(bool second = false)\n{\n    int move = GetMove(second);\n    game.PlayerMove(move);\n}\n\nint GetMove(bool second)\n{\n    string prompt = second ? \"AGAIN? \" : \"YOUR MOVE? \";\n\n    while (true)\n    {\n        Console.Write(prompt);\n\n        string input = Console.ReadLine() ?? \"\";\n\n        // input must be a number between 1 and 6, and the pit must have > 0 beans\n        if (int.TryParse(input, out int move)\n         && game.IsLegalPlayerMove(move))\n            return move;\n\n        Console.WriteLine(\"ILLEGAL MOVE\");\n    }\n}\n\nvoid ComputerTurn()\n{\n    var moves = game.ComputerTurn();\n    string movesString = string.Join(\",\", moves);\n\n    Console.WriteLine($\"MY MOVE IS {movesString}\");\n}\n\nstring Tab(int n) => new(' ', n);\n"
  },
  {
    "path": "04_Awari/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "04_Awari/java/Awari.java",
    "content": "import java.util.Scanner;\nimport java.util.Random;\n\npublic class Awari{\n\tint []board;\n\tprivate final int playerPits;\n\tprivate final int computerPits;\n\tprivate final int playerHome;\n\tprivate final int computerHome;\n\tScanner input;\n\tint sumPlayer;\n\tint sumComputer;\n\tAwari(){\n\t\tinput = new Scanner(System.in);\n\t\tplayerPits = 0;\n\t\tcomputerPits = 7;\n\t\tplayerHome = 6;\n\t\tcomputerHome = 13;\n\t\tsumPlayer = 18;\n\t\tsumComputer = 18;\n\t\tboard = new int [14];\n\t\tfor (int i=0;i<6;i++){\n\t\t\tboard[playerPits+i]=3;\n\t\t\tboard[computerPits+i]=3;\n\t\t}\n\t\tSystem.out.println(\"\t\t AWARI\");\n\t\tSystem.out.println(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\");\n\t\tprintBoard();\n\t\tplayerMove(true);\n\t}\n\n\tprivate void printBoard(){\n\t\tSystem.out.print(\"\\n    \");\n\t\tfor (int i=0;i<6;i++){\n\t\t\tSystem.out.print(String.format(\"%2d\",board[12-i]));\n\t\t\tSystem.out.print(\"  \");\n\t\t}\n\t\tSystem.out.println(\"\");\n\t\tSystem.out.print(String.format(\"%2d\",board[computerHome]));\n\t\tSystem.out.print(\"                          \");\n\t\tSystem.out.println(String.format(\"%2d\",board[playerHome]));\n\t\tSystem.out.print(\"    \");\n\t\tfor(int i=0;i<6;i++){\n\t\t\tSystem.out.print(String.format(\"%2d\",board[playerPits+i]));\n                        System.out.print(\"  \");\n\t\t}\n\t\tSystem.out.println(\"\");\n\t}\n\n\tprivate void playerMove(boolean val){\n\t\tSystem.out.println(\"\\nComputerSum PlayerSum\"+sumComputer+\" \"+sumPlayer);\n\t\tif(val == true)\n\t\t\tSystem.out.print(\"YOUR MOVE? \");\n\t\telse\n\t\t\tSystem.out.print(\"AGAIN? \");\n\t\tint move =  input.nextInt();\n\t\twhile(move<1||move>6||board[move-1]==0){\n\t\t\tSystem.out.print(\"INVALID MOVE!!! TRY AGAIN  \");\n\t\t\tmove = input.nextInt();\n\t\t}\n\t\tint seeds = board[move-1];\n\t\tboard[move-1] = 0;\n\t\tsumPlayer -= seeds;\n\t\tint last_pos = distribute(seeds,move);\n\t\tif(last_pos == playerHome){\n\t\t\tprintBoard();\n\t\t\tif(isGameOver(true)){\n\t\t\t\tSystem.exit(0);\n\t\t\t}\n\t\t\tplayerMove(false);\n\t\t}\n\t\telse if(board[last_pos] == 1&&last_pos != computerHome){\n\t\t\tint opp = calculateOpposite(last_pos);\n\t\t\tif(last_pos<6){\n\t\t\t\tsumPlayer+=board[opp];\n\t\t\t\tsumComputer-=board[opp];\n\t\t\t}\n\t\t\telse{\n\t\t\t\tsumComputer+=board[opp];\n\t\t\t\tsumPlayer-=board[opp];\n\t\t\t}\n\t\t\tboard[last_pos]+=board[opp];\n\t\t\tboard[opp] = 0;\n\t\t\tprintBoard();\n\t\t\tif(isGameOver(false)){\n\t\t\t\tSystem.exit(0);\n\t\t\t}\n\t\t\tcomputerMove(true);\n\t\t}\n\t\telse{\n\t\t\tprintBoard();\n\t\t\tif(isGameOver(false)){\n\t\t\t\tSystem.exit(0);\n\t\t\t}\n\t\t\tcomputerMove(true);\n\t\t}\n\t}\n\n\tprivate void computerMove(boolean value){\n\t\tint val=-1;\n\t\tSystem.out.println(\"\\nComputerSum PlayerSum\"+sumComputer+\" \"+sumPlayer);\n\t\tfor(int i=0;i<6;i++){\n\t\t\tif(6-i == board[computerPits+i])\n\t\t\t\tval = i;\n\t\t}\n\t\tint move ;\n\t\tif(val == -1)\n\t\t{\n\t\t\tRandom random = new Random();\n\t\t\tmove = random.nextInt(6)+computerPits;\n\t\t\twhile(board[move] == 0){\n\t\t\t\tmove = random.nextInt(6)+computerPits;\n\t\t\t}\n\t\t\tif(value == true)\n\t\t\t\tSystem.out.println(String.format(\"MY MOVE IS %d \",move-computerPits+1));\n\t\t\telse\n\t\t\t\tSystem.out.println(String.format(\",%d\",move-computerPits+1));\n\t\t\tint seeds = board[move];\n\t\t\tboard[move] = 0;\n\t\t\tsumComputer-=seeds;\n\t\t\tint last_pos = distribute(seeds,move+1);\n\t\t\tif(board[last_pos] == 1&&last_pos != playerHome){\n                \t        int opp = calculateOpposite(last_pos);\n\t\t\t\t if(last_pos<6){\n\t                                sumPlayer+=board[opp];\n        \t                        sumComputer-=board[opp];\n                \t        }\n                        \telse{\n\t                                sumComputer+=board[opp];\n        \t                        sumPlayer-=board[opp];\n                \t        }\n        \t                board[last_pos]+=board[opp];\n\t                        board[opp] = 0;\n                        \tprintBoard();\n                \t        if(isGameOver(false)){\n        \t                        System.exit(0);\n\t                        }\n                \t}\n\t\t\telse{\n\t\t\t\tprintBoard();\n\t                        if(isGameOver(false)){\n        \t                        System.exit(0);\n                \t        }\n\t\t\t}\n\t\t\tplayerMove(true);\n\t\t}\n\t\telse {\n\t\t\tmove = val+computerPits;\n\t\t\tif(value == true)\n\t\t\t\tSystem.out.print(String.format(\"MY MOVE IS %d\",move-computerPits+1));\n\t\t\telse\n\t\t\t\tSystem.out.print(String.format(\",%d\",move-computerPits+1));\n\t\t\tint seeds = board[move];\n                        board[move] = 0;\n                        sumComputer-=seeds;\n                        int last_pos = distribute(seeds,move+1);\n\t\t\tif(last_pos == computerHome){\n\t\t\t\tif(isGameOver(true) ){\n\t\t\t\t\tSystem.exit(0);\n\t\t\t\t}\n\t\t\t\tcomputerMove(false);\n\t\t\t}\n\t\t}\n\t}\n\n\n\tprivate int distribute(int seeds, int pos){\n\t\twhile(seeds!=0){\n\t\t\tif(pos==14)\n\t\t\t\tpos=0;\n\t\t\tif(pos<6)\n\t\t\t\tsumPlayer++;\n\t\t\telse if(pos>6&&pos<13)\n\t\t\t\tsumComputer++;\n\t\t\tboard[pos]++;\n\t\t\tpos++;\n\t\t\tseeds--;\n\t\t}\n\t\treturn pos-1;\n\t}\n\n\tprivate int calculateOpposite(int pos){\n\t\treturn 12-pos;\n\t}\n\n\tprivate boolean isGameOver(boolean show){\n\t\tif(sumPlayer == 0 || sumComputer == 0){\n\t\t\tif(show)\n\t\t\t\tprintBoard();\n\t\t\tSystem.out.println(\"GAME OVER\");\n\t\t\tif(board[playerHome]>board[computerHome]){\n\t\t\t\tSystem.out.println(String.format(\"YOU WIN BY %d POINTS\",board[playerHome]-board[computerHome]));\n\t\t\t}\n\t\t\telse if(board[playerHome]<board[computerHome]){\n\t\t\t\tSystem.out.println(String.format(\"YOU LOSE BY %d POINTS\",board[computerHome]-board[playerHome]));\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.println(\"DRAW\");\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\n}\n"
  },
  {
    "path": "04_Awari/java/AwariGame.java",
    "content": "public class AwariGame {\n    public static void main(String[] args) {\n        Awari awari = new Awari();\n    }\n}\n"
  },
  {
    "path": "04_Awari/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "04_Awari/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "04_Awari/javascript/awari.html",
    "content": "<html>\n<head>\n<title>AWARI</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"awari.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "04_Awari/javascript/awari.js",
    "content": "// AWARI\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nprint(tab(34) + \"AWARI\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n\nn = 0;\n\nb = [0,0,0,0,0,0,0,0,0,0,0,0,0,0];\ng = [0,0,0,0,0,0,0,0,0,0,0,0,0,0];\nf = [];\nfor (i = 0; i <= 50; i++) {\n    f[i] = 0;\n}\n\nfunction show_number(number)\n{\n    if (number < 10)\n        print(\"  \" + number + \" \");\n    else\n        print(\" \" + number + \" \");\n}\n\nfunction show_board()\n{\n    var i;\n\n    print(\"\\n\");\n    print(\"   \");\n    for (i = 12; i >= 7; i--)\n        show_number(b[i]);\n    print(\"\\n\");\n    i = 13;\n    show_number(b[i]);\n    print(\"                       \" + b[6] + \"\\n\");\n    print(\"   \");\n    for (i = 0; i <= 5; i++)\n        show_number(b[i]);\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nfunction do_move()\n{\n    k = m;\n    adjust_board();\n    e = 0;\n    if (k > 6)\n        k -= 7;\n    c++;\n    if (c < 9)\n        f[n] = f[n] * 6 + k\n        for (i = 0; i <= 5; i++) {\n            if (b[i] != 0) {\n                for (i = 7; i <= 12; i++) {\n                    if (b[i] != 0) {\n                        e = 1;\n                        return;\n                    }\n                }\n            }\n        }\n}\n\nfunction adjust_board()\n{\n    p = b[m];\n    b[m] = 0;\n    while (p >= 1) {\n        m++;\n        if (m > 13)\n            m -= 14;\n        b[m]++;\n        p--;\n    }\n    if (b[m] == 1) {\n        if (m != 6 && m != 13) {\n            if (b[12 - m] != 0) {\n                b[h] += b[12 - m] + 1;\n                b[m] = 0;\n                b[12 - m] = 0;\n            }\n        }\n    }\n}\n\nfunction computer_move()\n{\n    d = -99;\n    h = 13;\n    for (i = 0; i<= 13; i++)\t// Backup board\n        g[i] = b[i];\n    for (j = 7; j <= 12; j++) {\n        if (b[j] == 0)\n            continue;\n        q = 0;\n        m = j;\n        adjust_board();\n        for (i = 0; i <= 5; i++) {\n            if (b[i] == 0)\n                continue;\n            l = b[i] + i;\n            r = 0;\n            while (l > 13) {\n                l -= 14;\n                r = 1;\n            }\n            if (b[l] == 0) {\n                if (l != 6 && l != 13)\n                    r = b[12 - l] + r;\n            }\n            if (r > q)\n                q = r;\n        }\n        q = b[13] - b[6] - q;\n        if (c < 8) {\n            k = j;\n            if (k > 6)\n                k -= 7;\n            for (i = 0; i <= n - 1; i++) {\n                if (f[n] * 6 + k == Math.floor(f[i] / Math.pow(7 - c, 6) + 0.1))\n                    q -= 2;\n            }\n        }\n        for (i = 0; i <= 13; i++)\t// Restore board\n            b[i] = g[i];\n        if (q >= d) {\n            a = j;\n            d = q;\n        }\n    }\n    m = a;\n    print(m - 6);\n    do_move();\n}\n\n// Main program\nasync function main()\n{\n    while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        e = 0;\n        for (i = 0; i <= 12; i++)\n            b[i] = 3;\n\n        c = 0;\n        f[n] = 0;\n        b[13] = 0;\n        b[6] = 0;\n\n        while (1) {\n            show_board();\n            print(\"YOUR MOVE\");\n            while (1) {\n                m = parseInt(await input());\n                if (m < 7) {\n                    if (m > 0) {\n                        m--;\n                        if (b[m] != 0)\n                            break;\n                    }\n                }\n                print(\"ILLEGAL MOVE\\n\");\n                print(\"AGAIN\");\n            }\n            h = 6;\n            do_move();\n            show_board();\n            if (e == 0)\n                break;\n            if (m == h) {\n                print(\"AGAIN\");\n                while (1) {\n                    m = parseInt(await input());\n                    if (m < 7) {\n                        if (m > 0) {\n                            m--;\n                            if (b[m] != 0)\n                                break;\n                        }\n                    }\n                    print(\"ILLEGAL MOVE\\n\");\n                    print(\"AGAIN\");\n                }\n                h = 6;\n                do_move();\n                show_board();\n            }\n            if (e == 0)\n                break;\n            print(\"MY MOVE IS \");\n            computer_move();\n            if (e == 0)\n                break;\n            if (m == h) {\n                print(\",\");\n                computer_move();\n            }\n            if (e == 0)\n                break;\n        }\n        print(\"\\n\");\n        print(\"GAME OVER\\n\");\n        d = b[6] - b[13];\n        if (d < 0)\n            print(\"I WIN BY \" + -d + \" POINTS\\n\");\n        else if (d == 0) {\n            n++;\n            print(\"DRAWN GAME\\n\");\n        } else {\n            n++;\n            print(\"YOU WIN BY \" + d + \" POINTS\\n\");\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "04_Awari/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "04_Awari/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "04_Awari/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "04_Awari/perl/awari.pl",
    "content": "#!/usr/bin/env perl\nuse v5.24;\nuse warnings;\nuse experimental 'signatures';\nno warnings 'experimental::signatures';\nuse List::Util 'none';\n\n# our board will be represented with an array of 14 slots, from 0 to 13.\n# Positions 6 and 13 represent the \"home pit\" for the human and the\n# computer, respectively.\nuse constant PLAYER_HOME => 6;\nuse constant COMPUTER_HOME => 13;\n\nuse constant FIRST => 0;\nuse constant AGAIN => 1;\n\nexit main(@ARGV);\n\nsub main {\n   $|++; # disable buffering on standard output, every print will be\n         # done immediately\n\n   welcome(); # startup message\n\n   # this array will keep track of computer-side failures, defined as\n   # \"the computer did not win\". Whenever the computer loses or draws, the\n   # specific sequence of moves will be saved and then used to drive\n   # the search for a (hopefully) optimal move.\n   my $failures = [];\n   while ('enjoying') {\n\n      # a new game starts, let's reset the board to the initial condition\n      my $board = [ (3) x 6, 0, (3) x 6, 0 ];\n\n      # this string will keep track of all moves performed\n      my $moves = '/';\n\n      # the human player starts\n      my $turn = 'player';\n\n      say \"\\n\";\n      print_board($board);\n\n      while (not is_game_over($board)) {\n\n         my $move; # this will collect the move in this turn\n\n         if ($turn eq 'player') { # \"first\" move for player\n\n            # player_move(...) does the move selected by the player,\n            # returning both the selected move as well as the pit id\n            # where the last seed landed\n            ($move, my $landing) = player_move($board);\n\n            # if we landed on the Player's Home Pit we get another move\n            $turn = $landing == PLAYER_HOME ? 'player-again' : 'computer';\n         }\n         elsif ($turn eq 'player-again') { # \"second\" move for player\n\n            # here we call player_move making it clear that it's the\n            # second move, to get the right prompt eventually. We only\n            # care for the $move as the result, so we ignore the other.\n            ($move) = player_move($board, AGAIN);\n            $turn = 'computer';\n         }\n         else {\n\n            # the computer_move(...) function analyzes the $board as well\n            # as adapting the strategy based on past \"failures\" (i.e.\n            # matches where the computer did not win). For this it's\n            # important to pass the log of these failures, as well as the\n            # full record of moves in this specific match.\n            ($move, my $landing) = computer_move($board, $failures, $moves);\n            print \"\\nMY MOVE IS \", $move - 6;\n\n            # do the second move in the turn if conditions apply\n            if ($landing == COMPUTER_HOME && ! is_game_over($board)) {\n\n               # save the first move before doing the second one!\n               $moves .= \"$move/\";\n\n               my ($move) = computer_move($board, $failures, $moves);\n               print ',', $move - 6;\n            }\n            $turn = 'player';\n         }\n\n         # append the last selected move by either party, to track this\n         # specific match (useful for computer's AI and ML)\n         $moves .= \"$move/\";\n         print_board($board);\n      }\n\n      # assess_victory() returns the difference between player's and\n      # computer's seeds, so a negative value is a win for the computer.\n      my $computer_won = assess_victory($board) < 0;\n\n      # if this last match was a \"failure\" (read: not a win for the\n      # computer), then record it for future memory.\n      push $failures->@*, $moves unless $computer_won;\n   }\n\n   return 0;\n}\n\n# calculate the difference between the two home pits. Negative values mean\n# that the computer won, 0 is a draw, positive values is a player's win.\n# The difference is also returned back, in case of need.\nsub assess_victory ($board) {\n   say \"\\nGAME OVER\";\n   my $difference = $board->[PLAYER_HOME] - $board->[COMPUTER_HOME];\n   if ($difference < 0) {\n      say 'I WIN BY ', -$difference, ' POINTS';\n   }\n   else {\n      say $difference ? \"YOU WIN BY $difference POINTS\" : 'DRAWN GAME';\n   }\n   return $difference;\n}\n\n# move the seeds from $pit and take into account possible bonuses\nsub move_seeds ($board, $pit) {\n\n   # get the seeds from the selected pit $pit\n   my $seeds = $board->[$pit];\n   $board->[$pit] = 0;\n\n   # $landing will be our \"moving cursor\" to place seeds around\n   my $landing = $pit;\n   while ($seeds > 0) {\n      $landing = ($landing + 1) % 14; # 12 --> 13 -[wrap]-> 0 --> 1\n      --$seeds;\n      ++$board->[$landing];\n   }\n\n   # check for \"stealing seeds\" condition. This cannot happen in home pits\n   if ($landing != PLAYER_HOME && $landing != COMPUTER_HOME\n       && $board->[$landing] == 1 && $board->[12 - $landing] > 0) {\n      my $home = $pit < 7 ? PLAYER_HOME : COMPUTER_HOME;\n      $board->[$home] += 1 + $board->[12 - $landing];\n      $board->@[$landing, 12 - $landing] = (0, 0);\n   }\n\n   return ($pit, $landing);\n}\n\nsub get_player_move ($board, $prompt) {\n   print \"\\n$prompt? \";\n   while (defined(my $move = <STDIN>)) {\n      chomp($move); # remove newline\n      return $move - 1 if $move =~ m{\\A[1-6]\\z}mxs && $board->[$move - 1];\n      print 'ILLEGAL MOVE\\nAGAIN? ';\n   }\n   die \"goodbye\\n\";\n}\n\nsub player_move ($board, $stage = FIRST) {\n   my $prompt = $stage == FIRST ? 'YOUR MOVE' : 'AGAIN';\n   my $selected_move = get_player_move($board, $prompt);\n   return move_seeds($board, $selected_move);\n}\n\nsub computer_move ($board, $failures, $moves) {\n\n   # we will go through all possible moves for the computer and all\n   # possible responses by the player, collecting the \"best\" move in terms\n   # of reasonable outcome (assuming that each side wants to maximize their\n   # outcome. $best_move will eventually contain the best move for the\n   # computer, and $best_difference the best difference in scoring (as\n   # seen from the computer).\n   my ($best_move, $best_difference);\n   for my $c_move (7 .. 12) {\n      next unless $board->[$c_move]; # only consider pits with seeds inside\n\n      # we work on a copy of the board to do all our trial-and-errors\n      my $copy = [ $board->@* ];\n      move_seeds($copy, $c_move);\n\n      # it's time to \"think like a player\" and see what's the \"best\" move\n      # for the player in this situation. This heuristic is \"not perfect\"\n      # but it seems OK anyway.\n      my $best_player_score = 0;\n      for my $p_move (0 .. 5) {\n         next unless $copy->[$p_move]; # only pits with seeds inside\n         my $landing = $copy->[$p_move] + $p_move;\n\n         # the player's score for this move, calculated as additional seeds\n         # placed in the player's pit. The original algorithm sets this to\n         # 1 only if the $landing position is greater than 13, which can\n         # be obtained by setting the ORIGINAL environment variable to a\n         # \"true\" value (in Perl terms). Otherwise it is calculated\n         # according to the real rules for the game.\n         my $p_score = $ENV{ORIGINAL} ? $landing > 13\n            : ($landing + 1) % 14 > 6;\n\n         # whatever, the landing position must be within the bounds\n         $landing %= 14;\n\n         # if the conditions apply, the player's move might win additional\n         # seeds, which we have to to take into account.\n         $p_score += $copy->[12 - $landing]\n            if $copy->[$landing] == 0\n            && $landing != PLAYER_HOME && $landing != COMPUTER_HOME;\n\n         # let's compare this move's score against the best collected\n         # so far (as a response to a specific computer's move).\n         $best_player_score = $p_score if $p_score > $best_player_score;\n      }\n\n      # the overall score for the player is the additional seeds we just\n      # calculated into $best_player_score plus the seeds that were already\n      # in the player's pit\n      $best_player_score += $copy->[PLAYER_HOME];\n\n      # the best difference we can aim for with this computer's move must\n      # assume that the player will try its best\n      my $difference = $copy->[COMPUTER_HOME] - $best_player_score;\n\n      # now it's time to check this computer's move against the history\n      # of failed matches. $candidate_moves will be the \"candidate\" list\n      # of moves if we accept this one.\n      my $candidate_moves = $moves . $c_move . '/';\n      for my $failure ($failures->@*) {\n\n         # index(.) returns 0 if and only if $candidate_moves appears at\n         # the very beginning of $failure, i.e. it matches a previous\n         # behaviour.\n         next if index($failure, $candidate_moves) != 0;\n\n         # same sequence of moves as before... assign a penalty\n         $difference -= 2;\n      }\n\n      # update $best_move and $best_difference if they need to\n      ($best_move, $best_difference) = ($c_move, $difference)\n         if (! defined $best_move) || ($best_difference < $difference);\n   }\n\n   # apply the selected move and return\n   return move_seeds($board, $best_move);\n}\n\nsub welcome {\n   say ' ' x 34, 'AWARI';\n   say ' ' x 15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY';\n}\n\nsub print_board ($board) {\n   my $template = '\n    %2d  %2d  %2d  %2d  %2d  %2d\n %2d                         %d\n    %2d  %2d  %2d  %2d  %2d  %2d\n';\n   printf $template, $board->@[12, 11, 10, 9, 8 , 7, 13, 6, 0 .. 5];\n   return;\n}\n\nsub is_game_over ($board) {\n\n   # game over if the player's side is empty\n   return 1 if none { $_ } $board->@[0 ..  5];\n\n   # game over if the computers' side is empty\n   return 1 if none { $_ } $board->@[7 .. 12];\n\n   # not game over\n   return 0;\n}\n"
  },
  {
    "path": "04_Awari/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "04_Awari/python/awari.py",
    "content": "\"\"\"\nAWARI\n\nAn ancient African game (see also Kalah, Mancala).\n\nPorted by Dave LeCompte\n\"\"\"\n\n# PORTING NOTES\n#\n# This game started out as 70 lines of BASIC, and I have ported it\n# before. I find it somewhat amazing how efficient (densely packed) the\n# original code is. Of course, the original code has fairly cryptic\n# variable names (as was forced by BASIC's limitation on long (2+\n# character) variable names). I have done my best here to interpret what\n# each variable is doing in context, and rename them appropriately.\n#\n# I have endeavored to leave the logic of the code in place, as it's\n# interesting to see a 2-ply game tree evaluation written in BASIC,\n# along with what a reader in 2021 would call \"machine learning\".\n#\n# As each game is played, the move history is stored as base-6\n# digits stored losing_book[game_number]. If the human player wins or\n# draws, the computer increments game_number, effectively \"recording\"\n# that loss to be referred to later. As the computer evaluates moves, it\n# checks the potential game state against these losing game records, and\n# if the potential move matches with the losing game (up to the current\n# number of moves), that move is evaluated at a two point penalty.\n#\n# Compare this, for example with MENACE, a mechanical device for\n# \"learning\" tic-tac-toe:\n# https://en.wikipedia.org/wiki/Matchbox_Educable_Noughts_and_Crosses_Engine\n#\n# The base-6 representation allows game history to be VERY efficiently\n# represented. I considered whether to rewrite this representation to be\n# easier to read, but I elected to TRY to document it, instead.\n#\n# Another place where I have made a difficult decision between accuracy\n# and correctness is inside the \"wrapping\" code where it considers\n# \"while human_move_end > 13\". The original BASIC code reads:\n#\n# 830 IF L>13 THEN L=L-14:R=1:GOTO 830\n#\n# I suspect that the intention is not to assign 1 to R, but to increment\n# R. I discuss this more in a porting note comment next to the\n# translated code. If you wish to play a more accurate version of the\n# game as written in the book, you can convert the increment back to an\n# assignment.\n#\n# I continue to be impressed with this jewel of a game; as soon as I had\n# the AI playing against me, it was beating me. I've been able to score\n# a few wins against the computer, but even at its 2-ply lookahead, it\n# beats me nearly always. I would like to become better at this game to\n# explore the effectiveness of the \"losing book\" machine learning.\n#\n#\n# EXERCISES FOR THE READER\n# One could go many directions with this game:\n# - change the initial number of stones in each pit\n# - change the number of pits\n# - only allow capturing if you end on your side of the board\n# - don't allow capturing at all\n# - don't drop a stone into the enemy \"home\"\n# - go clockwise, instead\n# - allow the player to choose to go clockwise or counterclockwise\n# - instead of a maximum of two moves, allow each move that ends on the\n#   \"home\" to be followed by a free move.\n# - increase the AI lookahead\n# - make the scoring heuristic a little more nuanced\n# - store history to a file on disk (or in the cloud!) to allow the AI\n#   to learn over more than a single session\n\nfrom typing import Dict, List, Tuple\n\ngame_number: int = 0\nmove_count: int = 0\nlosing_book: List[int] = []\nn = 0\n\nMAX_HISTORY = 9\nLOSING_BOOK_SIZE = 50\n\n\ndef draw_pit(line: str, board, pit_index) -> str:\n    val = board[pit_index]\n    line += \" \"\n    if val < 10:\n        line += \" \"\n    return line + str(val) + \" \"\n\n\ndef draw_board(board) -> None:\n    print()\n\n    # Draw the top (computer) pits\n    line = \"   \"\n    for i in range(12, 6, -1):\n        line = draw_pit(line, board, i)\n    print(line)\n\n    # Draw the side (home) pits\n    line = draw_pit(\"\", board, 13)\n    line += \" \" * 24\n    line = draw_pit(line, board, 6)\n    print(line)\n\n    # Draw the bottom (player) pits\n    line = \"   \"\n    for i in range(0, 6):\n        line = draw_pit(line, board, i)\n    print(line)\n    print()\n    print()\n\n\ndef play_game(board: List[int]) -> None:\n    # Place the beginning stones\n    for i in range(0, 13):\n        board[i] = 3\n\n    # Empty the home pits\n    board[6] = 0\n    board[13] = 0\n\n    global move_count\n    move_count = 0\n\n    # clear the history record for this game\n    losing_book[game_number] = 0\n\n    while True:\n        draw_board(board)\n\n        print(\"YOUR MOVE\")\n        landing_spot, is_still_going, home = player_move(board)\n        if not is_still_going:\n            break\n        if landing_spot == home:\n            landing_spot, is_still_going, home = player_move_again(board)\n        if not is_still_going:\n            break\n\n        print(\"MY MOVE\")\n        landing_spot, is_still_going, home, msg = computer_move(\"\", board)\n\n        if not is_still_going:\n            print(msg)\n            break\n        if landing_spot == home:\n            landing_spot, is_still_going, home, msg = computer_move(f\"{msg} , \", board)\n        if not is_still_going:\n            print(msg)\n            break\n        print(msg)\n\n    game_over(board)\n\n\ndef computer_move(msg: str, board) -> Tuple[int, bool, int, str]:\n    # This function does a two-ply lookahead evaluation; one computer\n    # move plus one human move.\n    #\n    # To do this, it makes a copy (temp_board) of the board, plays\n    # each possible computer move and then uses math to work out what\n    # the scoring heuristic is for each possible human move.\n    #\n    # Additionally, if it detects that a potential move puts it on a\n    # series of moves that it has recorded in its \"losing book\", it\n    # penalizes that move by two stones.\n\n    best_quality = -99\n\n    # Make a copy of the board, so that we can experiment. We'll put\n    # everything back, later.\n    temp_board = board[:]\n\n    # For each legal computer move 7-12\n    for computer_move in range(7, 13):\n        if board[computer_move] == 0:\n            continue\n        do_move(computer_move, 13, board)  # try the move (1 move lookahead)\n\n        best_player_move_quality = 0\n        # for all legal human moves 0-5 (responses to computer move computer_move)\n        for human_move_start in range(0, 6):\n            if board[human_move_start] == 0:\n                continue\n\n            human_move_end = board[human_move_start] + human_move_start\n            this_player_move_quality = 0\n\n            # If this move goes around the board, wrap backwards.\n            #\n            # PORTING NOTE: The careful reader will note that I am\n            # incrementing this_player_move_quality for each wrap,\n            # while the original code only set it equal to 1.\n            #\n            # I expect this was a typo or oversight, but I also\n            # recognize that you'd have to go around the board more\n            # than once for this to be a difference, and even so, it\n            # would be a very small difference; there are only 36\n            # stones in the game, and going around the board twice\n            # requires 24 stones.\n\n            while human_move_end > 13:\n                human_move_end = human_move_end - 14\n                this_player_move_quality += 1\n\n            if (\n                (board[human_move_end] == 0)\n                and (human_move_end != 6)\n                and (human_move_end != 13)\n            ):\n                # score the capture\n                this_player_move_quality += board[12 - human_move_end]\n\n            if this_player_move_quality > best_player_move_quality:\n                best_player_move_quality = this_player_move_quality\n\n        # This is a zero sum game, so the better the human player's\n        # move is, the worse it is for the computer player.\n        computer_move_quality = board[13] - board[6] - best_player_move_quality\n\n        if move_count < MAX_HISTORY:\n            move_digit = computer_move\n            if move_digit > 6:\n                move_digit = move_digit - 7\n\n            # Calculate the base-6 history representation of the game\n            # with this move. If that history is in our \"losing book\",\n            # penalize that move.\n            for prev_game_number in range(game_number):\n                if losing_book[game_number] * 6 + move_digit == int(\n                    losing_book[prev_game_number] / 6 ^ (7 - move_count) + 0.1  # type: ignore\n                ):\n                    computer_move_quality -= 2\n\n        # Copy back from temporary board\n        for i in range(14):\n            board[i] = temp_board[i]\n\n        if computer_move_quality >= best_quality:\n            best_move = computer_move\n            best_quality = computer_move_quality\n\n    selected_move = best_move\n\n    move_str = chr(42 + selected_move)\n    if msg:\n        msg += f\", {move_str}\"\n    else:\n        msg = move_str\n\n    move_number, is_still_going, home = execute_move(selected_move, 13, board)\n\n    return move_number, is_still_going, home, msg\n\n\ndef game_over(board) -> None:\n    print()\n    print(\"GAME OVER\")\n\n    pit_difference = board[6] - board[13]\n    if pit_difference < 0:\n        print(f\"I WIN BY {-pit_difference} POINTS\")\n\n    else:\n        global n\n        n = n + 1\n\n        if pit_difference == 0:\n            print(\"DRAWN GAME\")\n        else:\n            print(f\"YOU WIN BY {pit_difference} POINTS\")\n\n\ndef do_capture(m, home, board) -> None:\n    board[home] += board[12 - m] + 1\n    board[m] = 0\n    board[12 - m] = 0\n\n\ndef do_move(m, home, board) -> int:\n    move_stones = board[m]\n    board[m] = 0\n\n    for _stones in range(move_stones, 0, -1):\n        m = m + 1\n        if m > 13:\n            m = m - 14\n        board[m] += 1\n    if board[m] == 1 and (m != 6) and (m != 13) and (board[12 - m] != 0):\n        do_capture(m, home, board)\n    return m\n\n\ndef player_has_stones(board) -> bool:\n    return any(board[i] > 0 for i in range(6))\n\n\ndef computer_has_stones(board: Dict[int, int]) -> bool:\n    return any(board[i] > 0 for i in range(7, 13))\n\n\ndef execute_move(move, home: int, board) -> Tuple[int, bool, int]:\n    move_digit = move\n    last_location = do_move(move, home, board)\n\n    if move_digit > 6:\n        move_digit = move_digit - 7\n\n    global move_count\n    move_count += 1\n    if move_count < MAX_HISTORY:\n        # The computer keeps a chain of moves in losing_book by\n        # storing a sequence of moves as digits in a base-6 number.\n        #\n        # game_number represents the current game,\n        # losing_book[game_number] records the history of the ongoing\n        # game.  When the computer evaluates moves, it tries to avoid\n        # moves that will lead it into paths that have led to previous\n        # losses.\n        losing_book[game_number] = losing_book[game_number] * 6 + move_digit\n\n    is_still_going = bool(player_has_stones(board) and computer_has_stones(board))\n    return last_location, is_still_going, home\n\n\ndef player_move_again(board) -> Tuple[int, bool, int]:\n    print(\"AGAIN\")\n    return player_move(board)\n\n\ndef player_move(board) -> Tuple[int, bool, int]:\n    while True:\n        print(\"SELECT MOVE 1-6\")\n        m = int(input()) - 1\n\n        if m > 5 or m < 0 or board[m] == 0:\n            print(\"ILLEGAL MOVE\")\n            continue\n\n        break\n\n    ending_spot, is_still_going, home = execute_move(m, 6, board)\n\n    draw_board(board)\n\n    return ending_spot, is_still_going, home\n\n\ndef main() -> None:\n    print(\" \" * 34 + \"AWARI\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\")\n\n    board = [0] * 14  # clear the board representation\n    global losing_book\n    losing_book = [0] * LOSING_BOOK_SIZE  # clear the \"machine learning\" state\n\n    while True:\n        play_game(board)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "04_Awari/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/) by [Alex Scown](https://github.com/TheScown)\n"
  },
  {
    "path": "04_Awari/ruby/awari.rb",
    "content": "require 'strscan'\n\n# Prints a number according to Vintage Basic's PRINT statement\n# @param n The number to print\ndef print_number(n)\n  # PRINT adds padding after a number and before a positive number\n  print ' ' if n >= 0\n  print n.to_s\n  print ' '\nend\n\n# Mimic the INPUT statement using Vintage Basic as a reference\n# @param prompt The prompt to show to the user\n# @return An array of strings representing the inputted values\ndef input(prompt)\n  prompt_suffix = '? '\n  print \"#{prompt}#{prompt_suffix}\"\n\n  input = gets.chomp.strip\n  scanner = StringScanner.new(input)\n  input_values = []\n\n  until scanner.eos?\n    scanner.scan(/\\s+/)\n\n    if scanner.check(/\"/)\n      scanner.scan(/\"/)\n      next_string = scanner.scan_until(/\"/)\n\n      if next_string\n        # Remove the trailing close quote\n        next_string.chomp!('\"')\n      else\n        # No close quote – Vintage Basic crashes in this case\n        raise 'Unmatched quotes in input'\n      end\n    elsif scanner.exist?(/,/)\n      next_string = scanner.scan_until(/,/).chomp(',')\n    else\n      next_string = scanner.scan_until(/\\s+|$/).rstrip\n    end\n\n    input_values << next_string\n  end\n\n  input_values << '' if input_values.empty?\n\n  input_values\nend\n\nclass Game\n  def initialize(history, non_win_count)\n    @beans = Array.new(13, 3)\n    @beans[6] = 0\n    @beans[13] = 0\n\n    @turn_counter = 0\n\n    @history = history\n    @non_win_count = non_win_count\n  end\n\n  # @return [Boolean] True if the computer did not win the game\n  def play\n    while true\n      print_beans\n\n      move = get_move(\"YOUR MOVE\")\n      home_pit = 6\n      computer_home_pit = 13\n\n      last_pit = perform_move(move, home_pit)\n\n      print_beans\n\n      break if game_over\n\n      if home_pit == last_pit\n        second_move = get_move(\"AGAIN\")\n\n        perform_move(second_move, home_pit)\n\n        print_beans\n\n        break if game_over\n      end\n\n      computer_move, computer_last_pit = get_computer_move\n      print \"MY MOVE IS #{computer_move - 6}\"\n\n      break if game_over\n\n      if computer_last_pit == computer_home_pit\n        second_computer_move, _ = get_computer_move\n        print \",#{second_computer_move - 6}\"\n\n        break if game_over\n      end\n    end\n\n    end_game\n  end\n\n  private\n\n  def game_over\n    @beans[0...6].all? { |b| b == 0 } || @beans[7...13].all? { |b| b == 0 }\n  end\n\n  # @return [Boolean] True if the computer did not win\n  def end_game\n    puts\n    puts \"GAME OVER\"\n\n    difference = @beans[6] - @beans[13]\n\n    if difference < 0\n      puts \"I WIN BY #{-difference} POINTS\"\n\n      return\n    end\n\n    puts \"YOU WIN BY #{difference} POINTS\" if difference > 0\n    puts \"DRAWN GAME\" if difference == 0\n\n    difference >= 0\n  end\n\n  # @param [Integer] move\n  # @param [Integer] home_pit\n  def perform_move(move, home_pit)\n    last_pit = distribute_beans(move, home_pit)\n\n    update_history(move)\n\n    last_pit\n  end\n\n  def update_history(current_move)\n    k = current_move % 7\n    @turn_counter += 1\n\n    # Add the move to the history\n    @history[@non_win_count] = @history[@non_win_count] * 6 + k if @turn_counter < 9\n  end\n\n  def print_beans\n    puts\n\n    # Print computer beans\n    print ' ' * 3\n    @beans[7...13].reverse.each { |bean_count| print_bean(bean_count) }\n    puts\n\n    # Print home beans\n    print_bean(@beans[13])\n    print ' ' * 23\n    print_number(@beans[6]) # This is not print_bean in line with the original version\n    puts\n\n    # Print player beans\n    print ' ' * 3\n    @beans[0...6].each { |bean_count| print_bean(bean_count) }\n    puts\n\n    puts\n  end\n\n  def get_move(prompt)\n    move = get_integer_input(prompt)\n\n    while move < 1 || move > 6 || @beans[move - 1] == 0\n      puts \"ILLEGAL MOVE\"\n      move = get_integer_input(\"AGAIN\")\n    end\n\n    move - 1\n  end\n\n  def distribute_beans(start_pit, home_pit, beans = @beans)\n    beans_to_distribute = beans[start_pit]\n    beans[start_pit] = 0\n\n    current_pit = start_pit\n\n    (0...beans_to_distribute).each do\n      current_pit = (current_pit + 1) % beans.size\n      beans[current_pit] += 1\n    end\n\n    # If the last pit was empty before we put a bean in it (and it's not a scoring pit), add beans to score\n    if beans[current_pit] == 1 && current_pit != 6 && current_pit != 13 && beans[12 - current_pit] != 0\n      beans[home_pit] = beans[home_pit] + beans[12 - current_pit] + 1\n      beans[current_pit] = 0\n      beans[12 - current_pit] = 0\n    end\n\n    current_pit\n  end\n\n  def print_bean(bean_count)\n    print ' ' if bean_count < 10\n    print_number(bean_count)\n  end\n\n  def get_integer_input(prompt)\n    integer_value = nil\n\n    input_values = input(prompt)\n\n    while integer_value.nil?\n      print '!EXTRA INPUT IGNORED' if (input_values.size > 1)\n\n      value = input_values.first\n\n      begin\n        integer_value = Integer(value)\n      rescue\n        puts '!NUMBER EXPECTED - RETRY INPUT LINE'\n        input_values = input('')\n      end\n    end\n\n    integer_value\n  end\n\n  def get_computer_move\n    d = -99\n    home_pit = 13\n\n    chosen_move = 7\n\n    # Test all possible moves\n    (7...13).each do |move_under_test|\n      # Create a copy of the beans to test against\n      beans_copy = @beans.dup\n\n      # If the move is not legal, skip it\n      next if beans_copy[move_under_test] == 0\n\n      # Determine the best response the player may make to this move\n      player_max_score = 0\n\n      # Make the move under test against the copy\n      distribute_beans(move_under_test, home_pit, beans_copy)\n\n      # Test every player response\n      (0...6).each do |i|\n        # Skip the move if it would be illegal\n        next if beans_copy[i] == 0\n\n        # Determine the last\n        landing_with_overflow = beans_copy[i] + i\n        # If landing > 13 the player has put a bean in both home pits\n        player_move_score = (landing_with_overflow > 14) ? 1 : 0\n        # Find the actual pit\n        landing = landing_with_overflow % 14\n\n        # If the landing pit is empty, the player will steal beans\n        if beans_copy[landing] == 0 && landing != 6 && landing != 13\n          player_move_score = beans_copy[12 - landing] + player_move_score\n        end\n\n        # Update the max score if this move is the best player move\n        player_max_score = player_move_score if player_move_score > player_max_score\n      end\n\n      # Final score for move is computer score, minus the player's score and any player gains from their best move\n      final_score = beans_copy[13] - beans_copy[6] - player_max_score\n\n      if @turn_counter < 9\n        k = move_under_test % 7\n\n        (0...@non_win_count).each do |i|\n          # Penalise move if it was used in a losing game\n          final_score = final_score - 2 if @history[@non_win_count] * 6 + k == ((Float(@history[i]) / 6 ** (7 - @turn_counter)) + 0.1).floor\n        end\n      end\n\n      # Choose the move if it is the best move found so far\n      if final_score >= d\n        chosen_move = move_under_test\n        d = final_score\n      end\n    end\n\n    last_pit = perform_move(chosen_move, home_pit)\n\n    [chosen_move, last_pit]\n  end\nend\n\nputs 'AWARI'.center(80)\nputs 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY'.center(80)\n\n# Initialise stable variables\nhistory = Array.new(50)\nnon_win_count = 0\n\n# APPLICATION LOOP\nwhile true\n  puts\n  puts\n\n  history[non_win_count] = 0\n\n  game = Game.new(history, non_win_count)\n\n  computer_didnt_win = game.play\n  non_win_count += 1 if computer_didnt_win\nend\n"
  },
  {
    "path": "04_Awari/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\""
  },
  {
    "path": "04_Awari/rust/src/main.rs",
    "content": "use std::{thread, time::Duration};\n\nuse rand::Rng;\n\n// AI \"learning\" is not implemented. Don't have the time. - Ugur\n\nfn main() {\n    loop {\n        let mut game = Game::default();\n\n        loop {\n            game.draw();\n            if game.play_turn(false) {\n                break;\n            }\n        }\n    }\n}\n\nenum DistributeResult {\n    Normal,\n    // Leftover beans\n    EndOnHomePit(bool),\n    // \"true\" if ended on Player Home Pit\n    EndOnEmptyPit(usize),\n    // \"index\" of the empty pit within the Row\n    ChosenEmpty,\n}\n\nstruct Game {\n    pits: [u8; 14],\n    player_turn: bool,\n}\n\nimpl Default for Game {\n    fn default() -> Self {\n        println!(\"\\n\\n\\t\\t AWARI\");\n        println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\");\n\n        Self {\n            pits: [3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0],\n            player_turn: true,\n        }\n    }\n}\n\nimpl Game {\n    fn step_through(&mut self, mut index: usize) -> usize {\n        let mut bean_amount = self.pits[index];\n        self.pits[index] = 0;\n\n        loop {\n            index += 1;\n\n            if index > self.pits.len() - 1 {\n                index = 0;\n            }\n\n            self.pits[index] += 1;\n\n            bean_amount -= 1;\n            if bean_amount == 0 {\n                return index;\n            }\n        }\n    }\n\n    fn play_turn(&mut self, is_repeat: bool) -> bool {\n        use DistributeResult::*;\n\n        if self.is_game_over() {\n            println!(\"\\nGame Over!\");\n            let (player_beans, ai_beans) = (self.pits[6], self.pits[13]);\n            if player_beans == ai_beans {\n                println!(\"It's a draw\")\n            } else if player_beans > ai_beans {\n                println!(\"You win by {}\", player_beans - ai_beans);\n            } else {\n                println!(\"I win by {}\", ai_beans - player_beans);\n            }\n            return true;\n        }\n\n        let chosen_index = if self.player_turn {\n            player_prompt(if is_repeat { \"Again?\" } else { \"Your move?\" }) - 1\n        } else {\n            println!(\"========================\");\n\n            thread::sleep(Duration::from_secs(1));\n\n            let non_empty_pits: Vec<usize> = self\n                .pits\n                .iter()\n                .enumerate()\n                .filter(|&(i, p)| (7..13).contains(&i) && *p > 0)\n                .map(|(i, _)| i)\n                .collect();\n            let random_index = rand::thread_rng().gen_range(0..non_empty_pits.len());\n            let ai_move = non_empty_pits[random_index];\n\n            println!(\"My move is {}\", ai_move - 6);\n\n            println!(\"========================\");\n            ai_move\n        };\n\n        match self.process_choice(chosen_index) {\n            Normal => (),\n            EndOnHomePit(player) => {\n                self.draw();\n\n                if player == self.player_turn && !is_repeat {\n                    self.play_turn(true);\n                }\n            }\n            EndOnEmptyPit(last_index) => {\n                let opposite_index = 12 - last_index;\n                let home_index = if self.player_turn { 6 } else { 13 };\n                let won_beans = 1 + self.pits[opposite_index];\n\n                self.pits[last_index] = 0;\n                self.pits[opposite_index] = 0;\n                self.pits[home_index] += won_beans;\n            }\n            ChosenEmpty => {\n                println!(\"Chosen pit is empty\");\n                return self.play_turn(is_repeat);\n            }\n        }\n\n        if !is_repeat {\n            self.player_turn = !self.player_turn;\n        }\n\n        false\n    }\n\n    pub fn process_choice(&mut self, index: usize) -> DistributeResult {\n        use DistributeResult::*;\n\n        if self.pits[index] == 0 {\n            return ChosenEmpty;\n        }\n\n        let last_index = self.step_through(index);\n\n        if last_index == 6 && self.player_turn {\n            return EndOnHomePit(true);\n        } else if last_index == 13 && !self.player_turn {\n            return EndOnHomePit(false);\n        } else if self.pits[last_index] == 1 {\n            return EndOnEmptyPit(last_index);\n        }\n\n        Normal\n    }\n\n    fn is_game_over(&self) -> bool {\n        let player_empty = !(0..6).any(|i| self.pits[i] > 0);\n        let ai_empty = !(7..13).any(|i| self.pits[i] > 0);\n        player_empty || ai_empty\n    }\n\n    fn draw(&self) {\n        let row_as_string = |player: bool| -> String {\n            let mut row_as_string = String::new();\n\n            let range = if player { 0..6 } else { 7..13 };\n\n            range.for_each(|i| {\n                let mut bean_amount_as_string = self.pits[i].to_string();\n                bean_amount_as_string.push_str(\"  \");\n\n                if player {\n                    row_as_string.push_str(&bean_amount_as_string);\n                } else {\n                    row_as_string.insert_str(0, &bean_amount_as_string);\n                }\n            });\n\n            row_as_string\n        };\n\n        println!(\n            \"\\n  {}\\n{}                  {}\\n  {}\\n\",\n            row_as_string(false),\n            self.pits[13].to_string(),\n            self.pits[6].to_string(),\n            row_as_string(true)\n        );\n    }\n}\n\npub fn player_prompt(message: &str) -> usize {\n    loop {\n        let mut input = String::new();\n        println!(\"{}\", message);\n\n        if let Ok(_) = std::io::stdin().read_line(&mut input) {\n            match input.trim().parse::<usize>() {\n                Ok(n) => {\n                    if (1..=6).contains(&n) {\n                        return n;\n                    } else {\n                        println!(\"Enter a number between 1 and 6\")\n                    }\n                }\n                Err(e) => {\n                    println!(\"{}\", e);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "04_Awari/vbnet/Awari.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Awari\", \"Awari.vbproj\", \"{718AECEB-CC24-49C8-B620-B2F93E021C51}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{718AECEB-CC24-49C8-B620-B2F93E021C51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{718AECEB-CC24-49C8-B620-B2F93E021C51}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{718AECEB-CC24-49C8-B620-B2F93E021C51}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{718AECEB-CC24-49C8-B620-B2F93E021C51}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "04_Awari/vbnet/Awari.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Awari</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "04_Awari/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "05_Bagels/README.md",
    "content": "### Bagels\n\nIn this game, the computer picks a 3-digit secret number using the digits 0 to 9 and you attempt to guess what it is. You are allowed up to twenty guesses. No digit is repeated. After each guess the computer will give you clues about your guess as follows:\n\n- PICO    One digit is correct, but in the wrong place\n- FERMI    One digit is in the correct place\n- BAGELS   No digit is correct\n\nYou will learn to draw inferences from the clues and, with practice, you’ll learn to improve your score. There are several good strategies for playing Bagels. After you have found a good strategy, see if you can improve it. Or try a different strategy altogether to see if it is any better. While the program allows up to twenty guesses, if you use a good strategy it should not take more than eight guesses to get any number.\n\nThe original authors of this program are D. Resek and P. Rowe of the Lawrence Hall of Science, Berkeley, California.\n\n---\n\nAs published in Basic Computer Games (1978)\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=9)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=21)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "05_Bagels/bagels.bas",
    "content": "5 PRINT TAB(33);\"BAGELS\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\":PRINT:PRINT\n15 REM *** BAGLES NUMBER GUESSING GAME\n20 REM *** ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE\n25 REM *** LAWRENCE HALL OF SCIENCE, U.C. BERKELY\n30 DIM A1(3),A(3),B(3)\n40 Y=0:T=255\n50 PRINT:PRINT:PRINT\n70 INPUT \"WOULD YOU LIKE THE RULES (YES OR NO)\";A$\n90 IF LEFT$(A$,1)=\"N\" THEN 150\n100 PRINT:PRINT \"I AM THINKING OF A THREE-DIGIT NUMBER.  TRY TO GUESS\"\n110 PRINT \"MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:\"\n120 PRINT \"   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION\"\n130 PRINT \"   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION\"\n140 PRINT \"   BAGELS - NO DIGITS CORRECT\"\n150 FOR I=1 TO 3\n160 A(I)=INT(10*RND(1))\n165 IF I-1=0 THEN 200\n170 FOR J=1 TO I-1\n180 IF A(I)=A(J) THEN 160\n190 NEXT J\n200 NEXT I\n210 PRINT:PRINT \"O.K.  I HAVE A NUMBER IN MIND.\"\n220 FOR I=1 TO 20\n230 PRINT \"GUESS #\";I,\n240 INPUT A$\n245 IF LEN(A$)<>3 THEN 630\n250 FOR Z=1 TO 3:A1(Z)=ASC(MID$(A$,Z,1)):NEXT Z\n260 FOR J=1 TO 3\n270 IF A1(J)<48 THEN 300\n280 IF A1(J)>57 THEN 300\n285 B(J)=A1(J)-48\n290 NEXT J\n295 GOTO 320\n300 PRINT \"WHAT?\"\n310 GOTO 230\n320 IF B(1)=B(2) THEN 650\n330 IF B(2)=B(3) THEN 650\n340 IF B(3)=B(1) THEN 650\n350 C=0:D=0\n360 FOR J=1 TO 2\n370 IF A(J)<>B(J+1) THEN 390\n380 C=C+1\n390 IF A(J+1)<>B(J) THEN 410\n400 C=C+1\n410 NEXT J\n420 IF A(1)<>B(3) THEN 440\n430 C=C+1\n440 IF A(3)<>B(1) THEN 460\n450 C=C+1\n460 FOR J=1 TO 3\n470 IF A(J)<>B(J) THEN 490\n480 D=D+1\n490 NEXT J\n500 IF D=3 THEN 680\n505 IF C=0 THEN 545\n520 FOR J=1 TO C\n530 PRINT \"PICO \";\n540 NEXT J\n545 IF D=0 THEN 580\n550 FOR J=1 TO D\n560 PRINT \"FERMI \";\n570 NEXT J\n580 IF C+D<>0 THEN 600\n590 PRINT \"BAGELS\";\n600 PRINT\n605 NEXT I\n610 PRINT \"OH WELL.\"\n615 PRINT \"THAT'S TWENTY GUESSES.  MY NUMBER WAS\";100*A(1)+10*A(2)+A(3)\n620 GOTO 700\n630 PRINT \"TRY GUESSING A THREE-DIGIT NUMBER.\":GOTO 230\n650 PRINT \"OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND\"\n660 PRINT \"HAS NO TWO DIGITS THE SAME.\":GOTO 230\n680 PRINT \"YOU GOT IT!!!\":PRINT\n690 Y=Y+1\n700 INPUT \"PLAY AGAIN (YES OR NO)\";A$\n720 IF LEFT$(A$,1)=\"Y\" THEN 150\n730 IF Y=0 THEN 750\n740 PRINT:PRINT \"A\";Y;\"POINT BAGELS BUFF!!\"\n750 PRINT \"HOPE YOU HAD FUN.  BYE.\"\n999 END\n"
  },
  {
    "path": "05_Bagels/csharp/BagelNumber.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace BasicComputerGames.Bagels\n{\n\tpublic enum BagelValidation\n\t{\n\t\tValid,\n\t\tWrongLength,\n\t\tNotUnique,\n\t\tNonDigit\n\t};\n\tpublic class BagelNumber\n\t{\n\t\tprivate static readonly Random Rnd = new Random();\n\n\t\tprivate readonly int[] _digits;\n\t\tpublic override string ToString()\n\t\t{\n\t\t\treturn String.Join('-', _digits);\n\t\t}\n\n\t\tpublic static BagelNumber CreateSecretNumber(int numDigits)\n\t\t{\n\t\t\tif (numDigits < 3 || numDigits > 9)\n\t\t\t\tthrow new ArgumentOutOfRangeException(nameof(numDigits),\n\t\t\t\t\t\"Number of digits must be between 3 and 9, inclusive\");\n\n\t\t\tvar digits = GetDigits(numDigits);\n\t\t\treturn new BagelNumber(digits);\n\t\t}\n\n\n\n\t\tpublic static BagelValidation IsValid(string number, int length)\n\t\t{\n\t\t\tif (number.Length != length)\n\t\t\t\treturn BagelValidation.WrongLength;\n\n\t\t\tif (!number.All(Char.IsDigit))\n\t\t\t\treturn BagelValidation.NonDigit;\n\n\t\t\tif (new HashSet<char>(number).Count != length)\n\t\t\t\treturn BagelValidation.NotUnique;\n\n\t\t\treturn BagelValidation.Valid;\n\t\t}\n\n\t\tpublic BagelNumber(string number)\n\t\t{\n\t\t\tif (number.Any(d => !Char.IsDigit(d)))\n\t\t\t\tthrow new ArgumentException(\"Number must be all unique digits\", nameof(number));\n\n\t\t\t_digits = number.Select(d => d - '0').ToArray();\n\t\t}\n\n\t\t//public BagelNumber(long number)\n\t\t//{\n\t\t//\tvar digits = new List<int>();\n\t\t//\tif (number >= 1E10)\n\t\t//\t\tthrow new ArgumentOutOfRangeException(nameof(number), \"Number can be no more than 9 digits\");\n\n\t\t//\twhile (number > 0)\n\t\t//\t{\n\t\t//\t\tlong num = number / 10;\n\t\t//\t\tint digit = (int)(number - (num * 10));\n\t\t//\t\tnumber = num;\n\t\t//\t\tdigits.Add(digit);\n\t\t//\t}\n\n\t\t//\t_digits = digits.ToArray();\n\t\t//}\n\n\t\tpublic BagelNumber(int[] digits)\n\t\t{\n\t\t\t_digits = digits;\n\t\t}\n\n\t\tprivate static  int[] GetDigits(int numDigits)\n\t\t{\n\t\t\tint[] digits = {1, 2, 3, 4, 5, 6, 7, 8, 9};\n\t\t\tShuffle(digits);\n\t\t\treturn digits.Take(numDigits).ToArray();\n\n\t\t}\n\n\t\tprivate static void Shuffle(int[] digits)\n\t\t{\n\t\t\tfor (int i = digits.Length - 1; i > 0; --i)\n\t\t\t{\n\t\t\t\tint pos = Rnd.Next(i);\n\t\t\t\tvar t = digits[i];\n\t\t\t\tdigits[i] = digits[pos];\n\t\t\t\tdigits[pos] = t;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic (int pico, int fermi) CompareTo(BagelNumber other)\n\t\t{\n\t\t\tint pico = 0;\n\t\t\tint fermi = 0;\n\t\t\tfor (int i = 0; i < _digits.Length; i++)\n\t\t\t{\n\t\t\t\tfor (int j = 0; j < other._digits.Length; j++)\n\t\t\t\t{\n\t\t\t\t\tif (_digits[i] == other._digits[j])\n\t\t\t\t\t{\n\t\t\t\t\t\tif (i == j)\n\t\t\t\t\t\t\t++fermi;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t++pico;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn (pico, fermi);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "05_Bagels/csharp/Bagels.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"TextUtil.cs\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "05_Bagels/csharp/Bagels.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bagels\", \"Bagels.csproj\", \"{2FC5F33F-2C4B-4707-94E5-3C9B2B633EFE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{2FC5F33F-2C4B-4707-94E5-3C9B2B633EFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2FC5F33F-2C4B-4707-94E5-3C9B2B633EFE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2FC5F33F-2C4B-4707-94E5-3C9B2B633EFE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2FC5F33F-2C4B-4707-94E5-3C9B2B633EFE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "05_Bagels/csharp/Game.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\nnamespace BasicComputerGames.Bagels\n{\n\tpublic class Game : GameBase\n\t{\n\t\tpublic void GameLoop()\n\t\t{\n\t\t\tDisplayIntroText();\n\t\t\tint points = 0;\n\t\t\tdo\n\t\t\t{\n\t\t\t\tvar result =PlayRound();\n\t\t\t\tif (result)\n\t\t\t\t\t++points;\n\t\t\t} while (TryAgain());\n\n\t\t\tConsole.WriteLine();\n\t\t\tConsole.WriteLine($\"A {points} point Bagels buff!!\");\n\t\t\tConsole.WriteLine(\"Hope you had fun. Bye.\");\n\t\t}\n\n\t\tprivate const int Length = 3;\n\t\tprivate const int MaxGuesses = 20;\n\n\t\tprivate bool  PlayRound()\n\t\t{\n\t\t\tvar secret = BagelNumber.CreateSecretNumber(Length);\n\t\t\tConsole.WriteLine(\"O.K. I have a number in mind.\");\n\t\t\tfor (int guessNo = 1; guessNo <= MaxGuesses; ++guessNo)\n\t\t\t{\n\t\t\t\tstring strGuess;\n\t\t\t\tBagelValidation isValid;\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tConsole.WriteLine($\"Guess #{guessNo}\");\n\t\t\t\t\tstrGuess = Console.ReadLine();\n\t\t\t\t\tisValid = BagelNumber.IsValid(strGuess, Length);\n\t\t\t\t\tPrintError(isValid);\n\t\t\t\t} while (isValid != BagelValidation.Valid);\n\n\t\t\t\tvar guess = new BagelNumber(strGuess);\n\t\t\t\tvar fermi = 0;\n\t\t\t\tvar pico = 0;\n\t\t\t\t(pico, fermi) = secret.CompareTo(guess);\n\t\t\t\tif(pico + fermi == 0)\n\t\t\t\t\tConsole.Write(\"BAGELS!\");\n\t\t\t\telse if (fermi == Length)\n\t\t\t\t{\n\t\t\t\t\tConsole.WriteLine(\"You got it!\");\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tPrintList(\"Pico \", pico);\n\t\t\t\t\tPrintList(\"Fermi \", fermi);\n\t\t\t\t}\n\t\t\t\tConsole.WriteLine();\n\t\t\t}\n\n\t\t\tConsole.WriteLine(\"Oh, well.\");\n\t\t\tConsole.WriteLine($\"That's {MaxGuesses} guesses.  My Number was {secret}\");\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tprivate void PrintError(BagelValidation isValid)\n\t\t{\n\t\t\tswitch (isValid)\n\t\t\t{\n\t\t\t\tcase BagelValidation.NonDigit:\n\t\t\t\t\tConsole.WriteLine(\"What?\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase BagelValidation.NotUnique:\n\t\t\t\t\tConsole.WriteLine(\"Oh, I forgot to tell you that the number I have in mind has no two digits the same.\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase BagelValidation.WrongLength:\n\t\t\t\t\tConsole.WriteLine($\"Try guessing a {Length}-digit number.\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase BagelValidation.Valid:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tprivate void PrintList(string msg, int repeat)\n\t\t{\n\t\t\tfor(int i=0; i<repeat; ++i)\n\t\t\t\tConsole.Write(msg);\n\t\t}\n\n\t\tprivate void DisplayIntroText()\n\t\t{\n\t\t\tConsole.ForegroundColor = ConsoleColor.Yellow;\n\t\t\tConsole.WriteLine(\"Bagels\");\n\t\t\tConsole.WriteLine(\"Creating Computing, Morristown, New Jersey.\");\n\t\t\tConsole.WriteLine();\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.DarkGreen;\n\t\t\tConsole.WriteLine(\n\t\t\t\t\"Original code author unknow but suspected to be from Lawrence Hall of Science, U.C. Berkley\");\n\t\t\tConsole.WriteLine(\"Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.\");\n\t\t\tConsole.WriteLine(\"Modernized and converted to C# in 2021 by James Curran (noveltheory.com).\");\n\t\t\tConsole.WriteLine();\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.Gray;\n\t\t\tConsole.WriteLine(\"I am thinking of a three-digit number.  Try to guess\");\n\t\t\tConsole.WriteLine(\"my number and I will give you clues as follows:\");\n\t\t\tConsole.WriteLine(\"   pico   - One digit correct but in the wrong position\");\n\t\t\tConsole.WriteLine(\"   fermi  - One digit correct and in the right position\");\n\t\t\tConsole.WriteLine(\"   bagels - No digits correct\");\n\t\t\tConsole.WriteLine();\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.Yellow;\n\t\t\tConsole.WriteLine(\"Press any key start the game.\");\n\t\t\tConsole.ReadKey(true);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "05_Bagels/csharp/GameBase.cs",
    "content": "﻿using System;\n\nnamespace BasicComputerGames.Bagels\n{\n\tpublic class GameBase\n\t{\n\t\tprotected Random Rnd { get; } = new Random();\n\n\t\t/// <summary>\n\t\t/// Prompt the player to try again, and wait for them to press Y or N.\n\t\t/// </summary>\n\t\t/// <returns>Returns true if the player wants to try again, false if they have finished playing.</returns>\n\t\tprotected bool TryAgain()\n\t\t{\n\t\t\tConsole.ForegroundColor = ConsoleColor.White;\n\t\t\tConsole.WriteLine(\"Would you like to try again? (Press 'Y' for yes or 'N' for no)\");\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.Yellow;\n\t\t\tConsole.Write(\"> \");\n\n\t\t\tchar pressedKey;\n\t\t\t// Keep looping until we get a recognised input\n\t\t\tdo\n\t\t\t{\n\t\t\t\t// Read a key, don't display it on screen\n\t\t\t\tConsoleKeyInfo key = Console.ReadKey(true);\n\t\t\t\t// Convert to upper-case so we don't need to care about capitalisation\n\t\t\t\tpressedKey = Char.ToUpper(key.KeyChar);\n\t\t\t\t// Is this a key we recognise? If not, keep looping\n\t\t\t} while (pressedKey != 'Y' && pressedKey != 'N');\n\t\t\t// Display the result on the screen\n\t\t\tConsole.WriteLine(pressedKey);\n\n\t\t\t// Return true if the player pressed 'Y', false for anything else.\n\t\t\treturn (pressedKey == 'Y');\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "05_Bagels/csharp/Program.cs",
    "content": "﻿namespace BasicComputerGames.Bagels\n{\n\tpublic class Program\n\t{\n\t\tpublic static void Main(string[] args)\n\t\t{\n\t\t\t// Create an instance of our main Game class\n\t\t\tvar game = new Game();\n\n\t\t\t// Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.\n\t\t\tgame.GameLoop();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "05_Bagels/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "05_Bagels/java/BagelGame.java",
    "content": "/******************************************************************************\n*\n* Encapsulates all the state and game logic for one single game of Bagels\n*\n* Used by Bagels.java\n*\n* Jeff Jetton, 2020\n*\n******************************************************************************/\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Set;\n\npublic class BagelGame {\n\n  public static final String CORRECT = \"FERMI FERMI FERMI\";\n  public static final int MAX_GUESSES = 20;\n\n  enum GameState {\n      RUNNING,\n      WON,\n      LOST\n    }\n\n  private GameState      state = GameState.RUNNING;\n  private List<Integer>  secretNum;\n  private int            guessNum = 1;\n\n  public BagelGame() {\n    // No-arg constructor for when you don't need to set the seed\n    this(new Random());\n  }\n\n  public BagelGame(long seed) {\n    // Setting the seed as a long value\n    this(new Random(seed));\n  }\n\n  public BagelGame(Random rand) {\n    // This is the \"real\" constructor, which expects an instance of\n    // Random to use for shuffling the digits of the secret number.\n\n    // Since the digits cannot repeat in our \"number\", we can't just\n    // pick three random 0-9 integers. Instead, we'll treat it like\n    // a deck of ten cards, numbered 0-9.\n    List<Integer> digits = new ArrayList<Integer>(10);\n    // The 10 specified initial allocation, not actual size,\n    // which is why we add rather than set each element...\n    for (int i = 0; i < 10; i++) {\n      digits.add(i);\n    }\n    // Collections offers a handy-dandy shuffle method. Normally it\n    // uses a fresh Random class PRNG, but we're supplying our own\n    // to give us controll over whether or not we set the seed\n    Collections.shuffle(digits, rand);\n\n    // Just take the first three digits\n    secretNum = digits.subList(0, 3);\n  }\n\n  public boolean isOver() {\n    return state != GameState.RUNNING;\n  }\n\n  public boolean isWon() {\n    return state == GameState.WON;\n  }\n\n  public int getGuessNum() {\n    return guessNum;\n  }\n\n  public String getSecretAsString() {\n    // Convert the secret number to a three-character string\n    String secretString = \"\";\n    for (int n : secretNum) {\n      secretString += n;\n    }\n    return secretString;\n  }\n\n  @Override\n  public String toString() {\n    // Quick report of game state for debugging purposes\n    String s = \"Game is \" + state + \"\\n\";\n    s += \"Current Guess Number: \" + guessNum + \"\\n\";\n    s += \"Secret Number: \" + secretNum;\n    return s;\n  }\n\n  public String validateGuess(String guess) {\n    // Checks the passed string and returns null if it's a valid guess\n    // (i.e., exactly three numeric characters)\n    // If not valid, returns an \"error\" string to display to user.\n    String error = \"\";\n\n    if (guess.length() == 3) {\n      // Correct length. Are all the characters numbers?\n      try {\n        Integer.parseInt(guess);\n      } catch (NumberFormatException ex) {\n        error = \"What?\";\n      }\n      if (error == \"\") {\n        // Check for unique digits by placing each character in a set\n        Set<Character> uniqueDigits = new HashSet<Character>();\n        for (int i = 0; i < guess.length(); i++){\n          uniqueDigits.add(guess.charAt(i));\n        }\n        if (uniqueDigits.size() != guess.length()) {\n          error = \"Oh, I forgot to tell you that the number I have in mind\\n\";\n          error += \"has no two digits the same.\";\n        }\n      }\n    } else {\n      error = \"Try guessing a three-digit number.\";\n    }\n\n    return error;\n  }\n\n  public String makeGuess(String s) throws IllegalArgumentException {\n    // Processes the passed guess string (which, ideally, should be\n    // validated by previously calling validateGuess)\n    // Return a response string (PICO, FERMI, etc.) if valid\n    // Also sets game state accordingly (sets win state or increments\n    // number of guesses)\n\n    // Convert string to integer list, just to keep things civil\n    List<Integer> guess = new ArrayList<Integer>(3);\n    for (int i = 0; i < 3; i++) {\n      guess.add((int)s.charAt(i) - 48);\n    }\n\n    // Build response string...\n    String response = \"\";\n    // Correct digit, but in wrong place?\n    for (int i = 0; i < 2; i++) {\n      if (secretNum.get(i) == guess.get(i+1)) {\n        response += \"PICO \";\n      }\n      if (secretNum.get(i+1) == guess.get(i)) {\n        response += \"PICO \";\n      }\n    }\n    if (secretNum.get(0) == guess.get(2)) {\n      response += \"PICO \";\n    }\n    if (secretNum.get(2) == guess.get(0)) {\n      response += \"PICO \";\n    }\n    // Correct digits in right place?\n    for (int i = 0; i < 3; i++) {\n      if (secretNum.get(i) == guess.get(i)) {\n        response += \"FERMI \";\n      }\n    }\n    // Nothin' right?\n    if (response == \"\") {\n      response = \"BAGELS\";\n    }\n    // Get rid of any space that might now be at the end\n    response = response.trim();\n    // If correct, change state\n    if (response.equals(CORRECT)) {\n      state = GameState.WON;\n    } else {\n      // If not, increment guess counter and check for game over\n      guessNum++;\n      if (guessNum > MAX_GUESSES) {\n        state = GameState.LOST;\n      }\n    }\n    return response;\n  }\n\n}\n"
  },
  {
    "path": "05_Bagels/java/Bagels.java",
    "content": "/******************************************************************************\n*\n* Bagels\n*\n* From: BASIC Computer Games (1978)\n*       Edited by David H. Ahl\n*\n* \"In this game, the computer picks a 3-digit secret number using\n*  the digits 0 to 9 and you attempt to guess what it is.  You are\n*  allowed up to twenty guesses.  No digit is repeated.  After\n*  each guess the computer will give you clues about your guess\n*  as follows:\n*\n*  PICO     One digit is correct, but in the wrong place\n*  FERMI    One digit is in the correct place\n*  BAGELS   No digit is correct\n*\n* \"You will learn to draw inferences from the clues and, with\n*  practice, you'll learn to improve your score.  There are several\n*  good strategies for playing Bagels.  After you have found a good\n*  strategy, see if you can improve it.  Or try a different strategy\n*  altogether and see if it is any better.  While the program allows\n*  up to twenty guesses, if you use a good strategy it should not\n*  take more than eight guesses to get any number.\n*\n* \"The original authors of this program are D. Resek and P. Rowe of\n*  the Lawrence Hall of Science, Berkeley, California.\"\n*\n* Java port by Jeff Jetton, 2020, based on an earlier Python port\n*\n******************************************************************************/\n\nimport java.util.Scanner;\n\npublic class Bagels {\n\n  public static void main(String[] args) {\n\n    int gamesWon = 0;\n\n    // Intro text\n    System.out.println(\"\\n\\n                Bagels\");\n    System.out.println(\"Creative Computing  Morristown, New Jersey\");\n    System.out.println(\"\\n\\n\");\n    System.out.print(\"Would you like the rules (Yes or No)? \");\n\n    // Need instructions?\n    Scanner scan = new Scanner(System.in);\n    String s = scan.nextLine();\n    if (s.length() == 0 || s.toUpperCase().charAt(0) != 'N') {\n      System.out.println();\n      System.out.println(\"I am thinking of a three-digit number.  Try to guess\");\n      System.out.println(\"my number and I will give you clues as follows:\");\n      System.out.println(\"   PICO   - One digit correct but in the wrong position\");\n      System.out.println(\"   FERMI  - One digit correct and in the right position\");\n      System.out.println(\"   BAGELS - No digits correct\");\n    }\n\n    // Loop for playing multiple games\n    boolean stillPlaying = true;\n    while(stillPlaying) {\n\n      // Set up a new game\n      BagelGame game = new BagelGame();\n      System.out.println(\"\\nO.K.  I have a number in mind.\");\n\n      // Loop guess and responsses until game is over\n      while (!game.isOver()) {\n        String guess = getValidGuess(game);\n        String response = game.makeGuess(guess);\n        // Don't print a response if the game is won\n        if (!game.isWon()) {\n          System.out.println(response);\n        }\n      }\n\n      // Game is over. But did we win or lose?\n      if (game.isWon()) {\n        System.out.println(\"You got it!!!\\n\");\n        gamesWon++;\n      } else {\n        System.out.println(\"Oh well\");\n        System.out.print(\"That's \" + BagelGame.MAX_GUESSES + \" guesses.  \");\n        System.out.println(\"My number was \" + game.getSecretAsString());\n      }\n\n      stillPlaying = getReplayResponse();\n    }\n\n    // Print goodbye message\n    if (gamesWon > 0) {\n      System.out.println(\"\\nA \" + gamesWon + \" point Bagels buff!!\");\n    }\n    System.out.println(\"Hope you had fun.  Bye.\\n\");\n  }\n\n  private static String getValidGuess(BagelGame game) {\n    // Keep asking for a guess until valid\n    Scanner scan = new Scanner(System.in);\n    boolean valid = false;\n    String guess = \"\";\n    String error;\n\n    while (!valid) {\n      System.out.print(\"Guess # \" + game.getGuessNum() + \"     ? \");\n      guess = scan.nextLine().trim();\n      error = game.validateGuess(guess);\n      if (error == \"\") {\n        valid = true;\n      } else {\n        System.out.println(error);\n      }\n    }\n    return guess;\n  }\n\n  private static boolean getReplayResponse() {\n    // keep asking for response until valid\n    Scanner scan = new Scanner(System.in);\n    // Keep looping until a non-zero-length string is entered\n    while (true) {\n      System.out.print(\"Play again (Yes or No)? \");\n      String response = scan.nextLine().trim();\n      if (response.length() > 0) {\n        return response.toUpperCase().charAt(0) == 'Y';\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "05_Bagels/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "05_Bagels/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "05_Bagels/javascript/bagels.html",
    "content": "<html>\n<head>\n<title>BAGELS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bagels.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "05_Bagels/javascript/bagels.js",
    "content": "// BAGELS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nprint(tab(33) + \"BAGELS\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n\n// *** Bagles number guessing game\n// *** Original source unknown but suspected to be\n// *** Lawrence Hall of Science, U.C. Berkeley\n\na1 = [0,0,0,0];\na = [0,0,0,0];\nb = [0,0,0,0];\n\ny = 0;\nt = 255;\n\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\n\n// Main program\nasync function main()\n{\n    while (1) {\n        print(\"WOULD YOU LIKE THE RULES (YES OR NO)\");\n        str = await input();\n        if (str.substr(0, 1) != \"N\") {\n            print(\"\\n\");\n            print(\"I AM THINKING OF A THREE-DIGIT NUMBER.  TRY TO GUESS\\n\");\n            print(\"MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:\\n\");\n            print(\"   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION\\n\");\n            print(\"   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION\\n\");\n            print(\"   BAGELS - NO DIGITS CORRECT\\n\");\n        }\n        for (i = 1; i <= 3; i++) {\n            do {\n                a[i] = Math.floor(Math.random() * 10);\n                for (j = i - 1; j >= 1; j--) {\n                    if (a[i] == a[j])\n                        break;\n                }\n            } while (j >= 1) ;\n        }\n        print(\"\\n\");\n        print(\"OK.  I HAVE A NUMBER IN MIND.\\n\");\n        for (i = 1; i <= 20; i++) {\n            while (1) {\n                print(\"GUESS #\" + i);\n                str = await input();\n                if (str.length != 3) {\n                    print(\"TRY GUESSING A THREE-DIGIT NUMBER.\\n\");\n                    continue;\n                }\n                for (z = 1; z <= 3; z++)\n                    a1[z] = str.charCodeAt(z - 1);\n                for (j = 1; j <= 3; j++) {\n                    if (a1[j] < 48 || a1[j] > 57)\n                        break;\n                    b[j] = a1[j] - 48;\n                }\n                if (j <= 3) {\n                    print(\"WHAT?\");\n                    continue;\n                }\n                if (b[1] == b[2] || b[2] == b[3] || b[3] == b[1]) {\n                    print(\"OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND\\n\");\n                    print(\"HAS NO TWO DIGITS THE SAME.\\n\");\n                    continue;\n                }\n                break;\n            }\n            c = 0;\n            d = 0;\n            for (j = 1; j <= 2; j++) {\n                if (a[j] == b[j + 1])\n                    c++;\n                if (a[j + 1] == b[j])\n                    c++;\n            }\n            if (a[1] == b[3])\n                c++;\n            if (a[3] == b[1])\n                c++;\n            for (j = 1; j <= 3; j++) {\n                if (a[j] == b[j])\n                    d++;\n            }\n            if (d == 3)\n                break;\n            for (j = 0; j < c; j++)\n                print(\"PICO \");\n            for (j = 0; j < d; j++)\n                print(\"FERMI \");\n            if (c + d == 0)\n                print(\"BAGELS\");\n            print(\"\\n\");\n        }\n        if (i <= 20) {\n            print(\"YOU GOT IT!!!\\n\");\n            print(\"\\n\");\n        } else {\n            print(\"OH WELL.\\n\");\n            print(\"THAT'S YOUR TWENTIETH GUESS.  MY NUMBER WAS \" + a[1] + a[2] + a[3]);\n        }\n        y++;\n        print(\"PLAY AGAIN (YES OR NO)\");\n        str = await input();\n        if (str.substr(0, 1) != \"Y\")\n            break;\n    }\n    if (y == 0)\n        print(\"HOPE YOU HAD FUN.  BYE.\\n\");\n    else\n        print(\"\\nA \" + y + \" POINT BAGELS BUFF!!\\n\");\n\n}\n\nmain();\n"
  },
  {
    "path": "05_Bagels/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "05_Bagels/kotlin/bagels.kt",
    "content": "import java.util.Random\n\nfun main() {\n    println(\"BAGELS\")\n    println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    var a = mutableListOf(0, 0, 0)\n    var y = 0\n    var t = 255\n    println()\n    println()\n    println()\n    println(\"WOULD YOU LIKE THE RULES (YES OR NO)? \")\n    var astring = readLine()\n    if (astring?.substring(0, 1) != \"N\") {\n        println()\n        println()\n        println(\"I AM THINKING OF A THREE-DIGIT NUMBER.  TRY TO GUESS\")\n        println(\"MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:\")\n        println(\"   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION\")\n        println(\"   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION\")\n        println(\"   BAGELS - NO DIGITS CORRECT\")\n    }\n    var i = 0\n    var random = Random()\n    while (i < 3) {\n        a[i] = random.nextInt(9) + 1\n        if (i > 0) {\n            for (j in 0 until i) {\n                if (a[i] == a[j])\n                {\n                    a[i] = random.nextInt(9) + 1\n                    i--\n                }\n            }\n        }\n        i++\n    }\n    println()\n    println(\"O.K.  I HAVE A NUMBER IN MIND.\")\n    do {\n        var i = 1\n        while (i <= 20) {\n            do {\n                var repeatGuess = false\n                println(\"GUESS #\" + i)\n                astring = readLine()\n                if (astring?.length != 3) {\n                    println(\"TRY GUESSING A THREE-DIGIT NUMBER.\")\n                    repeatGuess = true\n                } else {\n                    for (j in 0..2) {\n                        if (astring[j].toInt() < 48 || astring[j].toInt() > 57) {\n                            println(\"WHAT?\")\n                            repeatGuess = true\n                        }\n                    }\n\n                    if (astring[0] == astring[1] ||\n                        astring[1] == astring[2] ||\n                        astring[2] == astring[0]\n                    ) {\n                        println(\"OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND\")\n                        println(\"HAS NO TWO DIGITS THE SAME.\")\n                        repeatGuess = true\n                    }\n                }\n            } while (repeatGuess);\n\n            var c = 0\n            var d = 0\n            for (j in 0..2) {\n                if (astring!![j]?.toInt() - 48 == a[j]) {\n                    c++\n                    d++\n                }\n                if (j < 2 && astring!![j]?.toInt() - 48 == a[j + 1]) c++\n            }\n            if (astring!![2]?.toInt() - 48 == a[0]) c++\n            if (astring!![0]?.toInt() - 48 == a[2]) c++\n\n            if (d == 3) {\n                break;\n            }\n            if (c != 0) {\n                for (j in 1..c) {\n                    print(\"PICO \")\n                }\n            }\n            if (d != 0) {\n                for (j in 1..d) {\n                    print(\"FERMI \")\n                }\n            }\n            if (c + d == 0) {\n                print(\"BAGELS \")\n            }\n            println()\n            i++\n        }\n\n        if (i == 21) {\n            println(\"OH WELL.\")\n            println(\"THAT'S TWENTY GUESSES.  MY NUMBER WAS \" + a[0] + a[1] + a[2])\n        }\n        else {\n            println(\"YOU GOT IT!!!\")\n            println()\n            y++\n        }\n        println(\"PLAY AGAIN (YES OR NO)?\")\n        astring = readLine()\n    } while (astring?.substring(0, 1) == \"Y\");\n    if (y != 0) {\n        println()\n        println(\"A $y POINT BAGELS BUFF!!\")\n    }\n    println (\"HOPE YOU HAD FUN.  BYE.\")\n}\n"
  },
  {
    "path": "05_Bagels/lua/Bagels.lua",
    "content": "---\n--- Bagels\n--- Ported by Joe Nellis.\n--- Text displayed is altered slightly from the original program to allow for\n--- more (or less) than three digits to be guessed. Change the difficulty to\n--- the number of digits you wish in the secret code.\n---\n\n--- difficult is number of digits to use\nlocal difficulty = 3\n\nprint [[\n                                BAGELS\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n]]\n\nfunction getInput(prompt)\n    io.write(prompt)\n    io.flush()\n    local input = io.read(\"l\") \n    if not input then  --- test for EOF\n        print(\"GOODBYE\")\n        os.exit(0)\n    end\n    return input\nend\n\nlocal needsRules = getInput(\"WOULD YOU LIKE THE RULES? (YES OR NO) \")\nprint()\nif needsRules:match(\"[yY].*\") then\n    print(string.format( [[\nI AM THINKING OF A %u DIGIT NUMBER.  TRY TO GUESS\nMY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:\n   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION\n   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION\n   BAGELS - NO DIGITS\n   ]], difficulty))\nend\n\nfunction play(numDigits, score)\n    local digits = { \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\" }\n    --- secret number must not have duplicate digits\n    --- randomly swap numDigits at the head of this list to create secret number\n    for i = 1, numDigits do\n        local j = math.random(1, 10)\n        digits[i], digits[j] = digits[j], digits[i]\n    end\n\n    print \"O.K.  I HAVE A NUMBER IN MIND.\"\n    for guessNum = 1, 20 do\n        :: GUESS_AGAIN :: ---<!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n        local guess = getInput(string.format(\"GUESS #%u\\t?\",guessNum))\n        if #guess ~= numDigits then\n            print(\"TRY GUESSING A\", numDigits, \"DIGIT NUMBER.\")\n            goto GUESS_AGAIN\n        elseif not guess:match(\"^(%d+)$\") then\n            print(\"WHAT?\")\n            goto GUESS_AGAIN\n        else\n            --- check if user has duplicate digits\n            for i = 1, numDigits - 1 do\n                for j = i + 1, numDigits do\n                    if (guess:sub(i, i) == guess:sub(j, j)) then\n                        print(\"OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE\")\n                        print(\"IN MIND HAS NO TWO DIGITS THE SAME.\")\n                        goto GUESS_AGAIN\n                    end\n                end\n            end\n        end\n\n        local report = \"\"\n        --- check for picos, right digit, wrong place\n        for i = 1, numDigits do\n            for j = i + 1, numDigits - 1 + i do\n                if (guess:sub(i, i) == digits[(j - 1) % numDigits + 1]) then\n                    report = report .. \"PICO \"\n                end\n            end\n        end\n        --- check for fermis, right digit, right place\n        for i = 1, numDigits do\n            if (guess:sub(i, i) == digits[i]) then\n                report = report .. \"FERMI \"\n            end\n        end\n\n        if (report == string.rep(\"FERMI \", numDigits)) then\n            print \"YOU GOT IT!!!\"\n            print \"\"\n            score = score + 1\n            goto PLAY_AGAIN\n        end\n        if (report == \"\") then\n            print(\"BAGELS\")\n        else\n            print(report)\n        end\n    end\n    print \"OH WELL.\"\n    print(\"THAT'S TWENTY GUESSES. MY NUMBER WAS \"\n            .. table.concat(digits, \"\", 1, numDigits))\n\n    :: PLAY_AGAIN :: ---<!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n    local playAgain = getInput(\"PLAY AGAIN (YES OR NO)?\")\n    print()\n    if (playAgain:match(\"[yY].*\")) then\n        return play(numDigits, score)\n    else\n        if (score > 0) then\n            print(\"A\", score, \"POINT BAGELS BUFF!!\")\n        end\n        print \"HOPE YOU HAD FUN. BYE.\"\n    end\nend\n\nplay(difficulty, 0) --- default is numDigits=3, score=0\n\n"
  },
  {
    "path": "05_Bagels/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "05_Bagels/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "05_Bagels/perl/bagels.pl",
    "content": "#!/usr/bin/perl\r\n\r\nuse strict;\r\nuse warnings;\r\n\r\n# global variable declaration (just the user's score)\r\nmy($Y) = 0;\r\n\r\n\r\n# yes_input is a subroutine that returns a true value\r\n# if the first character of the user's input from STDIN\r\n# is a 'Y' (checking case-insensitively via regex)\r\nsub yes_input {\r\n    chomp(my $A = <STDIN>);\r\n    return $A =~ m/^Y/i;\r\n}\r\n\r\n# Main code starts here.\r\n\r\nprint ' 'x32; print \"Bagels\\n\";\r\nprint ' 'x14; print \"Creative Computing  Morristown, New Jersey\\n\\n\";\r\n\r\n# Provide instructions if requested\r\nprint \"Would you like the rules (yes or no)? \";\r\nif (yes_input()) {\r\n\r\n    # Print out the instructions using a here doc\r\n    # (useful for large blocks of text)\r\n    print <<HERE;\r\n\r\nI am thinking of a three-digit number.  Try to guess\r\nmy number and I will give you clues as follows:\r\n  PICO   - one digit correct but in the wrong position\r\n  FERMI  - one digit correct and in the right place\r\n  BAGELS - no digits correct\r\nHERE\r\n}\r\n\r\n# There are three code loops here. The outermost one, labeled 'PLAY',\r\n# performs one game start to finish every time it runs.\r\n# The next loop is a for loop that implements the required 20 guesses.\r\n# And the innermost loop, labeled 'CHECK', does the game logic of\r\n# checking the user's guess to make sure it's valid, figuring out\r\n# the response, and rewarding the user if they won.\r\n\r\nPLAY: while (1) {\r\n\r\n    # The computer's number is three randomly selected unique digits.\r\n    # To generate the number, 3 digits are randomly splice()d out\r\n    # of the @DIGITS array, which is initialized with the digits 0 to 9.\r\n    my @DIGITS = (0..9);\r\n    my @A = ();\r\n    push @A, splice(@DIGITS, int(rand(scalar @DIGITS)), 1) for 1..3;\r\n\r\n    print \"\\n\";\r\n    print \"O.K.  I have a number in mind.\\n\";\r\n\r\n    for my $i (1..20) {\r\n\r\n        # Note that the CHECK loop will automatically loop to ask\r\n        # for the user's input, and it's only with the 'next' and\r\n        # 'last' statements that this loop is exited. So if the\r\n        # user's input is somehow invalid, we just print out an\r\n        # appropriate message. Execution will by default return\r\n        # to the start of the loop, and only leaves the loop if\r\n        # the user's input is successfully parsed and accepted\r\n        # (look for the 'next' and 'last' statements below).\r\n\r\n        CHECK: while (1) {\r\n            printf(\"Guess # %2d ? \", $i);\r\n            chomp(my $A = <STDIN>);\r\n\r\n            # Use a regex to check if the user entered three digits,\r\n            # and complain if they did not.\r\n            if ($A !~ m{^(\\d)(\\d)(\\d)$}) {\r\n                print \"What?\\n\";\r\n                # Program execution will now pass through the rest\r\n                # of the logic below and loop back to the start\r\n                # of the CHECK loop.\r\n            } else {\r\n\r\n                # As a side effect of the regex match above, the\r\n                # $1, $2, and $3 variables are each of the digits\r\n                # of the user's guess. Perl treats numbers and\r\n                # strings interchangably, so we will not have to\r\n                # use the ASC() conversion functions required\r\n                # by the BASIC program.\r\n                my @B = ($1,$2,$3);\r\n\r\n                # Check for duplicate digits in the user's guess\r\n                if ($B[0] == $B[1] || $B[0] == $B[2] || $B[1] == $B[2]) {\r\n                    print \"Oh, I forgot to tell you that the number I have in mind\\n\";\r\n                    print \"has no two digits the same.\\n\";\r\n                    # Again, no further action is required here\r\n                    # because we want to loop back to the start\r\n                    # of the CHECK loop.\r\n                } else {\r\n\r\n                    # This code block is the actual game logic, so\r\n                    # it's executed only if the user's input has\r\n                    # passed all the above checks.\r\n                    my($C,$D);\r\n                    $C = 0; $D = 0;\r\n\r\n                    # As a replacement for the original BASIC logic,\r\n                    # this for loop works over an anonymous array of\r\n                    # pairs of digits to compare the computer's and\r\n                    # the user's digits to see how many similar ones\r\n                    # there are. Keep in mind that Perl arrays are\r\n                    # zero-indexed, so we're comparing items numbered\r\n                    # 0, 1, and 2, instead of 1, 2, and 3 in BASIC.\r\n\r\n                    for my $PAIR ( [0,1], [1,0], [1,2], [2,1], [0,2], [2,0] ) {\r\n                        if ($A[$PAIR->[0]] == $B[$PAIR->[1]]) {\r\n                            ++$C;\r\n                        }\r\n                    }\r\n\r\n                    # Check for digits that are correctly guessed\r\n                    for my $i (0..2) {\r\n                        if ($A[$i] == $B[$i]) {\r\n                            ++$D;\r\n                        }\r\n                    }\r\n\r\n                    # If the user guessed all 3 digits they get\r\n                    # a point, and the 'PLAY' loop is restarted\r\n                    # (see the 'continue' loop below)\r\n                    if ($D == 3) {\r\n                        print \"You got it!!!\\n\\n\";\r\n                        ++$Y;\r\n                        next PLAY;\r\n                    }\r\n\r\n                    # Print out the clues. The 'x' operator\r\n                    # prints out the string the indicated number\r\n                    # of times. The \"BAGELS\" line uses Perl's\r\n                    # ternary operator to print the word if\r\n                    # the expression ($C + $D) is equal to 0.\r\n\r\n                    printf(\"%s%s%s\\n\",\r\n                        \"PICO \" x$C,\r\n                        \"FERMI \"x$D,\r\n                        ($C+$D==0 ? \"BAGELS\" : '')\r\n                    );\r\n\r\n                    # Program execution leaves the CHECK loop and\r\n                    # goes to the next iteration of the $i loop.\r\n                    last CHECK;\r\n\r\n                } # end of game logic else block\r\n            } # end of regex match else block\r\n\r\n            # If program execution reaches this particular point,\r\n            # then the user's input has not been accepted (the\r\n            # only ways out of this loop are the \"next PLAY\" statement\r\n            # when the user wins, and the \"last CHECK\" statement\r\n            # when the user's input is successfully parsed).\r\n            # So the program execution goes back to the top of the\r\n            # CHECK loop, printing the request for user input\r\n            # again.\r\n\r\n        } # end of CHECK loop\r\n\r\n        # This location is reached by the \"last CHECK\" statement,\r\n        # and it's another execution of the $i loop.\r\n\r\n    } # end of $i loop\r\n\r\n    # If program execution reaches here, the user has guessed 20\r\n    # times and not won.\r\n\r\n    print \"Oh well.\\n\";\r\n    printf(\"That's twenty guesses. My number was %s\\n\", join('',@A));\r\n\r\n} # end of the PLAY loop\r\n\r\n# This 'continue' block is executed before the conditional part of the\r\n# PLAY loop is evaluated, so we can ask if the user wants another game\r\n# (i.e., if we should restart the PLAY loop).\r\n\r\ncontinue {\r\n\r\n    # This 'continue' loop is reached either when the PLAY loop has completed\r\n    # or via the 'next PLAY' statement when the user wins a game. In either\r\n    # case we ask if the player wants to go again, and use the 'last'\r\n    # statement to exit the loop if the response is not yes.\r\n    print \"Play again (yes or no) ? \";\r\n    last unless yes_input();\r\n}\r\n\r\n# And as in the original BASIC program, print out\r\n# the user's score only if it is > 0.\r\nprintf(\"A %d point bagels buff!\\n\", $Y) if $Y > 0;\r\nprint \"Hope you had fun.  Bye.\\n\";\r\n"
  },
  {
    "path": "05_Bagels/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "05_Bagels/python/bagels.py",
    "content": "\"\"\"\r\nBagels\r\n\r\nFrom: BASIC Computer Games (1978)\r\n      Edited by David H. Ahl\r\n\r\n\"In this game, the computer picks a 3-digit secret number using\r\n the digits 0 to 9 and you attempt to guess what it is.  You are\r\n allowed up to twenty guesses.  No digit is repeated.  After\r\n each guess the computer will give you clues about your guess\r\n as follows:\r\n\r\n PICO     One digit is correct, but in the wrong place\r\n FERMI    One digit is in the correct place\r\n BAGELS   No digit is correct\r\n\r\n\"You will learn to draw inferences from the clues and, with\r\n practice, you'll learn to improve your score.  There are several\r\n good strategies for playing Bagels.  After you have found a good\r\n strategy, see if you can improve it.  Or try a different strategy\r\n altogether and see if it is any better.  While the program allows\r\n up to twenty guesses, if you use a good strategy it should not\r\n take more than eight guesses to get any number.\r\n\r\n\"The original authors of this program are D. Resek and P. Rowe of\r\n the Lawrence Hall of Science, Berkeley, California.\"\r\n\r\n\r\nPython port by Jeff Jetton, 2019\r\n\"\"\"\r\n\r\n\r\nimport random\r\nfrom typing import List\r\n\r\nMAX_GUESSES = 20\r\n\r\n\r\ndef print_rules() -> None:\r\n    print(\"\\nI am thinking of a three-digit number.  Try to guess\")\r\n    print(\"my number and I will give you clues as follows:\")\r\n    print(\"   PICO   - One digit correct but in the wrong position\")\r\n    print(\"   FERMI  - One digit correct and in the right position\")\r\n    print(\"   BAGELS - No digits correct\")\r\n\r\n\r\ndef pick_number() -> List[str]:\r\n    # Note that this returns a list of individual digits\r\n    # as separate strings, not a single integer or string\r\n    numbers = list(range(10))\r\n    random.shuffle(numbers)\r\n    num = numbers[:3]\r\n    return [str(i) for i in num]\r\n\r\n\r\ndef get_valid_guess(guesses: int) -> str:\r\n    valid = False\r\n    while not valid:\r\n        guess = input(f\"Guess # {guesses}     ? \")\r\n        guess = guess.strip()\r\n        # Guess must be three characters\r\n        if len(guess) == 3:\r\n            # And they should be numbers\r\n            if guess.isnumeric():\r\n                # And the numbers must be unique\r\n                if len(set(guess)) == 3:\r\n                    valid = True\r\n                else:\r\n                    print(\"Oh, I forgot to tell you that the number I have in mind\")\r\n                    print(\"has no two digits the same.\")\r\n            else:\r\n                print(\"What?\")\r\n        else:\r\n            print(\"Try guessing a three-digit number.\")\r\n\r\n    return guess\r\n\r\n\r\ndef build_result_string(num: List[str], guess: str) -> str:\r\n    result = \"\"\r\n\r\n    # Correct digits in wrong place\r\n    for i in range(2):\r\n        if num[i] == guess[i + 1]:\r\n            result += \"PICO \"\r\n        if num[i + 1] == guess[i]:\r\n            result += \"PICO \"\r\n    if num[0] == guess[2]:\r\n        result += \"PICO \"\r\n    if num[2] == guess[0]:\r\n        result += \"PICO \"\r\n\r\n    # Correct digits in right place\r\n    for i in range(3):\r\n        if num[i] == guess[i]:\r\n            result += \"FERMI \"\r\n\r\n    # Nothing right?\r\n    if result == \"\":\r\n        result = \"BAGELS\"\r\n\r\n    return result\r\n\r\n\r\ndef main() -> None:\r\n    # Intro text\r\n    print(\"\\n                Bagels\")\r\n    print(\"Creative Computing  Morristown, New Jersey\\n\\n\")\r\n\r\n    # Anything other than N* will show the rules\r\n    response = input(\"Would you like the rules (Yes or No)? \")\r\n    if len(response) > 0:\r\n        if response.upper()[0] != \"N\":\r\n            print_rules()\r\n    else:\r\n        print_rules()\r\n\r\n    games_won = 0\r\n    still_running = True\r\n    while still_running:\r\n\r\n        # New round\r\n        num = pick_number()\r\n        num_str = \"\".join(num)\r\n        guesses = 1\r\n\r\n        print(\"\\nO.K.  I have a number in mind.\")\r\n        guessing = True\r\n        while guessing:\r\n\r\n            guess = get_valid_guess(guesses)\r\n\r\n            if guess == num_str:\r\n                print(\"You got it!!!\\n\")\r\n                games_won += 1\r\n                guessing = False\r\n            else:\r\n                print(build_result_string(num, guess))\r\n                guesses += 1\r\n                if guesses > MAX_GUESSES:\r\n                    print(\"Oh well\")\r\n                    print(f\"That's {MAX_GUESSES} guesses.  My number was {num_str}\")\r\n                    guessing = False\r\n\r\n        valid_response = False\r\n        while not valid_response:\r\n            response = input(\"Play again (Yes or No)? \")\r\n            if len(response) > 0:\r\n                valid_response = True\r\n                if response.upper()[0] != \"Y\":\r\n                    still_running = False\r\n\r\n    if games_won > 0:\r\n        print(f\"\\nA {games_won} point Bagels buff!!\")\r\n\r\n    print(\"Hope you had fun.  Bye.\\n\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n\r\n######################################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   The original program did an unusually good job of validating the\r\n#   player's input (compared to many of the other programs in the\r\n#   book). Those checks and responses have been exactly reproduced.\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   It should probably mention that there's a maximum of MAX_NUM\r\n#   guesses in the instructions somewhere, shouldn't it?\r\n#\r\n#   Could this program be written to use anywhere from, say 2 to 6\r\n#   digits in the number to guess? How would this change the routine\r\n#   that creates the \"result\" string?\r\n#\r\n######################################################################\r\n"
  },
  {
    "path": "05_Bagels/ruby/README.md",
    "content": "## BAGELS\n\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/) by [Tom Armitage](https://github.com/infovore)\n\n## Translator's notes:\n\nThis is a highly imperative port. As such, it's very much, in the spirit of David Ahl's original version, and also highly un-Rubyish.\n\nA few decisions I made:\n\n* the main loop is a 'while' loop. Most games are a main loop that runs until it doesn't, and I felt that \"while the player wished to keep playing, the game should run\" was an appropriate structure.\n* lots of puts and gets; that feels appropriate to the Ahl implementation. No clever cli or curses libraries here.\n* the number in question, and the player's answer, are stored as numbers. They're only converted into arrays for the purpose of `puts_clue_for` - ie, when comparison is need. The original game stored them as arrays, which made sense, but given the computer says \"I have a number in mind\", I decided to store what was in its 'mind' as a number.\n* the `String#center` method from Ruby 2.5~ sure is handy.\n"
  },
  {
    "path": "05_Bagels/ruby/bagels.rb",
    "content": "# Bagels\n# Number guessing game.\n# Original source unknown but suspected to be\n# Lawrence Hall of Science, U.C. Berkeley\n\ndef print_instructions\n  puts\n  puts 'I am thinking of a three-digit number. Try to guess'\n  puts 'my number and i will give you clues as follows:'\n  puts '   PICO   - one digit correct but in the wrong position'\n  puts '   FERMI  - one digit correct and in the right position'\n  puts '   BAGELS - no digits correct'\nend\n\ndef generate_target\n  # pick a three digit number with no repeating numbers.\n  # gien that, 102-987 is a reasonable starting point!\n  target = rand(102..987) while target.to_s.split('').uniq.size < 3\n  target\nend\n\ndef puts_clue_for(guess_number, target_number)\n  guess_array = guess_number.to_s.split('')\n  target_array = target_number.to_s.split('')\n\n  clues = [].tap do |clue|\n    guess_array.each_with_index do |n, i|\n      if target_array[i] == n\n        clue << 'FERMI'\n      elsif target_array.include?(n)\n        clue << 'PICO'\n      end\n    end\n  end\n\n  # sort clues so that FERMIs come before PICOs, but\n  # you don't know which response responds to which number\n  if clues.length > 0\n    puts clues.sort.join\n  else\n    puts 'BAGELS'\n  end\nend\n\nplayer_points = 0\ndesire_to_play = true\n\nputs 'Bagels'.center(72)\nputs 'Creative Computing  Morristown, New Jersey'.center(72)\n5.times { puts }\n\nputs 'Would you like to the rules? [Y]es or [N]o.'\ninstructions_request = gets.chomp.downcase\n\nprint_instructions if %w[yes y].include?(instructions_request)\n\nwhile desire_to_play\n  target = generate_target\n\n  2.times { puts }\n  puts 'OK. I have a number in mind.'\n\n  guess_count = 0\n  guess = 0\n\n  while (guess != target) && guess_count < 20\n    guess_count += 1\n\n    puts \"Guess ##{guess_count}:\"\n\n    raw_guess = gets.chomp\n\n    ## if the guess isn't numerical, sound confused\n    if raw_guess =~ /[^0-9]/\n      puts 'What?'\n      next\n    end\n\n    ## if the guess is more ore less than three digits, prompt player\n    if raw_guess.length != 3\n      puts 'Try guessing a three digit number'\n      next\n    end\n\n    ## if the guess contains duplicate numbers, give player a clue\n    if raw_guess.split('').uniq.size < 3\n      puts 'Oh, I forgot to tell you: the number I have in mind has no two digits the same.'\n      next\n    end\n\n    guess = raw_guess.to_i\n\n    if guess != target\n      puts_clue_for(guess, target)\n      puts\n    end\n  end\n\n  if guess == target\n    player_points += 1\n\n    puts 'You got it!!!'\n    puts\n  else\n    puts 'Oh well.'\n    puts \"That's twenty guesses. My number was #{target_number_array.join('')}.\"\n  end\n\n  puts\n  puts 'Would you like to play again? [Y]es or [N]o'\n\n  play_again_request = gets.chomp\n  desire_to_play = %w[yes y].include?(play_again_request)\nend\n\nputs \"A #{player_points} point bagels buff!!\"\nputs 'Hope you had fun. Bye.'\n"
  },
  {
    "path": "05_Bagels/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "05_Bagels/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Till Klister [tikste@github](https://github.com/tikste).\n"
  },
  {
    "path": "05_Bagels/rust/src/main.rs",
    "content": "use std::io;\nuse std::io::{stdin, stdout, Write};\n\nuse rand::prelude::SliceRandom;\n\ntype Digits = [u8; 3];\n\nfn main() -> io::Result<()> {\n    print_header();\n    if !read_lowercase_input()?.starts_with('n') {\n        print_rules();\n    }\n    let mut win_count = 0;\n    loop {\n        let solution = generate_random_digits();\n        println!(\"\\nO.K. I have a number in mind.\");\n        if guess(solution)? {\n            win_count += 1;\n            println!(\"You got it!!!\");\n        } else {\n            println!(\n                \"\\nOh well\\nThat's twenty guesses: My number was {}{}{}\",\n                solution[0], solution[1], solution[2]\n            );\n        }\n        println!(\"\\nPlay again (yes or no)?\");\n        if read_lowercase_input()? != \"yes\" {\n            println!();\n            if win_count > 0 {\n                println!(\"A {win_count} point bagels buff!!\");\n            }\n            println!(\"Hope you had fun. Bye.\");\n            return Ok(());\n        }\n    }\n}\n\nfn print_header() {\n    println!(\"                  Bagels\");\n    println!(\"Creative-Computing  Morristown, New Jersey\");\n    println!();\n    println!(\"Would you like the rules (yes or no)?\");\n}\n\nfn print_rules() {\n    println!();\n    println!(\"I am thinking of a three-digit number. Try to guess\");\n    println!(\"my number and I will give you clues as follows:\");\n    println!(\"   Pico   - one digit correct but in the wrong position\");\n    println!(\"   Fermi  - one digit correct and in the right position\");\n    println!(\"   Bagles - no digits correct\");\n}\n\nfn read_lowercase_input() -> io::Result<String> {\n    let mut input = String::new();\n    stdin().read_line(&mut input)?;\n    Ok(input.trim().to_lowercase())\n}\n\nfn generate_random_digits() -> Digits {\n    let range = 0..10;\n    let mut numbers = range.into_iter().collect::<Vec<u8>>();\n    numbers.shuffle(&mut rand::thread_rng());\n    let mut digits = Digits::default();\n    let len = digits.len();\n    digits.copy_from_slice(&numbers[..len]);\n    digits\n}\n\nfn guess(solution: Digits) -> io::Result<bool> {\n    for round in 1..21 {\n        let guess = read_valid_guess(round)?;\n        if guess == solution {\n            return Ok(true);\n        } else {\n            let mut pico = 0;\n            let mut fermi = 0;\n            for i in 0..guess.len() {\n                if guess[i] == solution[i] {\n                    fermi += 1;\n                } else if solution.contains(&guess[i]) {\n                    pico += 1;\n                }\n            }\n            let mut status = String::new();\n            if pico == 0 && fermi == 0 {\n                status += \"Bagels\";\n            } else {\n                for _ in 0..pico {\n                    status += \"Pico \";\n                }\n                for _ in 0..fermi {\n                    status += \"Fermi \";\n                }\n            };\n            println!(\"{}\", status.trim_end());\n        }\n    }\n    Ok(false)\n}\n\nfn read_valid_guess(round: u8) -> io::Result<Digits> {\n    let mut guess = Digits::default();\n    loop {\n        let space = \" \".repeat(if round < 10 { 5 } else { 4 });\n        print!(\"Guess #{round}{space}? \");\n        stdout().flush()?;\n        let input = read_lowercase_input()?;\n        if input.len() == guess.len() {\n            let mut i = 0;\n            for c in input.chars() {\n                if let Ok(digit) = c.to_string().parse::<u8>() {\n                    if guess[..i].contains(&digit) {\n                        println!(\"\\nOh, I forgot to tell you that the number I have in mind\\nhas no two digits the same.\");\n                        break;\n                    }\n                    guess[i] = digit;\n                    i += 1;\n                    if i == guess.len() {\n                        return Ok(guess);\n                    }\n                } else {\n                    println!(\"What?\");\n                    break;\n                }\n            }\n        } else {\n            println!(\"Try guessing a three-digit number.\");\n        }\n    }\n}\n"
  },
  {
    "path": "05_Bagels/vbnet/Bagels.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bagels\", \"Bagels.vbproj\", \"{913FE7A8-B481-4EB3-8938-566BEAD5B0F2}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{913FE7A8-B481-4EB3-8938-566BEAD5B0F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{913FE7A8-B481-4EB3-8938-566BEAD5B0F2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{913FE7A8-B481-4EB3-8938-566BEAD5B0F2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{913FE7A8-B481-4EB3-8938-566BEAD5B0F2}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "05_Bagels/vbnet/Bagels.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bagels</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "05_Bagels/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "06_Banner/README.md",
    "content": "### Banner\n\nThis program creates a large banner on a terminal of any message you input. The letters may be any dimension of you wish although the letter height plus distance from left-hand side should not exceed 6 inches. Experiment with the height and width until you get a pleasing effect on whatever terminal you are using.\n\nThis program was written by Leonard Rosendust of Brooklyn, New York.\n\n---\n\nAs published in Basic Computer Games (1978)\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=10)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=25)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- The \"SET PAGE\" input, stored in `O$`, has no effect.  It was probably meant as an opportunity for the user to set their pin-feed printer to the top of the page before proceeding.\n\n- The data values for each character are the bit representation of each horizontal row of the printout (vertical column of a character), plus one.  Perhaps because of this +1, the original code (and some of the ports here) are much more complicated than they need to be.\n\n(please note any difficulties or challenges in porting here)\n\n"
  },
  {
    "path": "06_Banner/banner.bas",
    "content": "10 INPUT \"HORIZONTAL\";X\n20 INPUT \"VERTICAL\";Y\n21 INPUT \"CENTERED\";L$\n22 G1=0:IF L$>\"P\" THEN G1=1\n23 INPUT \"CHARACTER (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED)\";M$\n29 PRINT \"STATEMENT\";\n30 INPUT A$\n35 INPUT \"SET PAGE\";O$\n40 A=ASC(LEFT$(A$,1))\n50 REM\n60 REM\n70 FOR T=1 TO LEN(A$)\n80 P$=MID$(A$,T,1)\n90 FOR O=1 TO 50\n95 READ S$,S(1),S(2),S(3),S(4),S(5),S(6),S(7)\n96 IF P$=\" \" THEN 812\n100 IF P$=S$ THEN 200\n120 NEXT O\n200 RESTORE\n201 X$=M$\n202 IF M$=\"ALL\" THEN X$=S$\n205 FOR U=1 TO 7\n210 FOR K=8 TO 0 STEP -1\n230 IF 2^K<S(U) THEN 270\n240 J(9-K)=0\n250 GOTO 280\n270 J(9-K)=1: S(U)=S(U)-2^K\n272 IF S(U)=1 THEN 815\n280 NEXT K\n445 FOR T1=1 TO X\n447 PRINT TAB((63-4.5*Y)*G1/(LEN(X$))+1);\n450 FOR B=1 TO F(U)\n460 IF J(B)=0 THEN 500\n465 FOR I=1 TO Y: PRINT X$;: NEXT I\n470 GOTO 600\n500 FOR I=1 TO Y\n510 FOR I1=1 TO LEN(X$)\n520 PRINT \" \";: NEXT I1\n530 NEXT I\n600 NEXT B\n620 PRINT\n630 NEXT T1\n700 NEXT U\n750 FOR H=1 TO 2*X: PRINT: NEXT H\n800 NEXT T\n806 FOR H=1 TO 75: PRINT: NEXT H\n810 END\n812 FOR H=1 TO 7*X: PRINT: NEXT H\n813 GOTO 800\n815 F(U)=9-K: GOTO 445\n899 DATA \" \",0,0,0,0,0,0,0\n900 DATA \"A\",505,37,35,34,35,37,505\n901 DATA \"G\",125,131,258,258,290,163,101\n902 DATA \"E\",512,274,274,274,274,258,258\n903 DATA \"T\",2,2,2,512,2,2,2\n904 DATA \"W\",256,257,129,65,129,257,256\n905 DATA \"L\",512,257,257,257,257,257,257\n906 DATA \"S\",69,139,274,274,274,163,69\n907 DATA \"O\",125,131,258,258,258,131,125\n908 DATA \"N\",512,7,9,17,33,193,512\n909 DATA \"F\",512,18,18,18,18,2,2\n910 DATA \"K\",512,17,17,41,69,131,258\n911 DATA \"B\",512,274,274,274,274,274,239\n912 DATA \"D\",512,258,258,258,258,131,125\n913 DATA \"H\",512,17,17,17,17,17,512\n914 DATA \"M\",512,7,13,25,13,7,512\n915 DATA \"?\",5,3,2,354,18,11,5\n916 DATA \"U\",128,129,257,257,257,129,128\n917 DATA \"R\",512,18,18,50,82,146,271\n918 DATA \"P\",512,18,18,18,18,18,15\n919 DATA \"Q\",125,131,258,258,322,131,381\n920 DATA \"Y\",8,9,17,481,17,9,8\n921 DATA \"V\",64,65,129,257,129,65,64\n922 DATA \"X\",388,69,41,17,41,69,388\n923 DATA \"Z\",386,322,290,274,266,262,260\n924 DATA \"I\",258,258,258,512,258,258,258\n925 DATA \"C\",125,131,258,258,258,131,69\n926 DATA \"J\",65,129,257,257,257,129,128\n927 DATA \"1\",0,0,261,259,512,257,257\n928 DATA \"2\",261,387,322,290,274,267,261\n929 DATA \"*\",69,41,17,512,17,41,69\n930 DATA \"3\",66,130,258,274,266,150,100\n931 DATA \"4\",33,49,41,37,35,512,33\n932 DATA \"5\",160,274,274,274,274,274,226\n933 DATA \"6\",194,291,293,297,305,289,193\n934 DATA \"7\",258,130,66,34,18,10,8\n935 DATA \"8\",69,171,274,274,274,171,69\n936 DATA \"9\",263,138,74,42,26,10,7\n937 DATA \"=\",41,41,41,41,41,41,41\n938 DATA \"!\",1,1,1,384,1,1,1\n939 DATA \"0\",57,69,131,258,131,69,57\n940 DATA \".\",1,1,129,449,129,1,1\n1000 STOP\n1002 END\n"
  },
  {
    "path": "06_Banner/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "06_Banner/csharp/banner.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace banner\n{\n    class Banner\n    {\n        private int Horizontal { get; set; }\n        private int Vertical { get; set; }\n        private bool Centered { get; set; }\n        private string Character { get; set; }\n        private string Statement { get; set; }\n\n        // This provides a bit-ended representation of each symbol\n        // that can be output.  Each symbol is defined by 7 parts -\n        // where each part is an integer value that, when converted to\n        // the binary representation, shows which section is filled in\n        // with values and which are spaces.  i.e., the 'filled in'\n        // parts represent the actual symbol on the paper.\n        Dictionary<char, int[]> letters = new Dictionary<char, int[]>()\n        {\n            {' ', new int[] { 0, 0, 0, 0, 0, 0, 0 } },\n            {'A', new int[] {505, 37, 35, 34, 35, 37, 505} },\n            {'B', new int[] {512, 274, 274, 274, 274, 274, 239} },\n            {'C', new int[] {125, 131, 258, 258, 258, 131, 69} },\n            {'D', new int[] {512, 258, 258, 258, 258, 131, 125} },\n            {'E', new int[] {512, 274, 274, 274, 274, 258, 258} },\n            {'F', new int[] {512, 18, 18, 18, 18, 2, 2} },\n            {'G', new int[] {125, 131, 258, 258, 290, 163, 101} },\n            {'H', new int[] {512, 17, 17, 17, 17, 17, 512} },\n            {'I', new int[] {258, 258, 258, 512, 258, 258, 258} },\n            {'J', new int[] {65, 129, 257, 257, 257, 129, 128} },\n            {'K', new int[] {512, 17, 17, 41, 69, 131, 258} },\n            {'L', new int[] {512, 257, 257, 257, 257, 257, 257} },\n            {'M', new int[] {512, 7, 13, 25, 13, 7, 512} },\n            {'N', new int[] {512, 7, 9, 17, 33, 193, 512} },\n            {'O', new int[] {125, 131, 258, 258, 258, 131, 125} },\n            {'P', new int[] {512, 18, 18, 18, 18, 18, 15} },\n            {'Q', new int[] {125, 131, 258, 258, 322, 131, 381} },\n            {'R', new int[] {512, 18, 18, 50, 82, 146, 271} },\n            {'S', new int[] {69, 139, 274, 274, 274, 163, 69} },\n            {'T', new int[] {2, 2, 2, 512, 2, 2, 2} },\n            {'U', new int[] {128, 129, 257, 257, 257, 129, 128} },\n            {'V', new int[] {64, 65, 129, 257, 129, 65, 64} },\n            {'W', new int[] {256, 257, 129, 65, 129, 257, 256} },\n            {'X', new int[] {388, 69, 41, 17, 41, 69, 388} },\n            {'Y', new int[] {8, 9, 17, 481, 17, 9, 8} },\n            {'Z', new int[] {386, 322, 290, 274, 266, 262, 260} },\n            {'0', new int[] {57, 69, 131, 258, 131, 69, 57} },\n            {'1', new int[] {0, 0, 261, 259, 512, 257, 257} },\n            {'2', new int[] {261, 387, 322, 290, 274, 267, 261} },\n            {'3', new int[] {66, 130, 258, 274, 266, 150, 100} },\n            {'4', new int[] {33, 49, 41, 37, 35, 512, 33} },\n            {'5', new int[] {160, 274, 274, 274, 274, 274, 226} },\n            {'6', new int[] {194, 291, 293, 297, 305, 289, 193} },\n            {'7', new int[] {258, 130, 66, 34, 18, 10, 8} },\n            {'8', new int[] {69, 171, 274, 274, 274, 171, 69} },\n            {'9', new int[] {263, 138, 74, 42, 26, 10, 7} },\n            {'?', new int[] {5, 3, 2, 354, 18, 11, 5} },\n            {'*', new int[] {69, 41, 17, 512, 17, 41, 69} },\n            {'=', new int[] {41, 41, 41, 41, 41, 41, 41} },\n            {'!', new int[] {1, 1, 1, 384, 1, 1, 1} },\n            {'.', new int[] {1, 1, 129, 449, 129, 1, 1} }\n        };\n\n\n        /// <summary>\n        /// This displays the provided text on the screen and then waits for the user\n        /// to enter a integer value greater than 0.\n        /// </summary>\n        /// <param name=\"DisplayText\">Text to display on the screen asking for the input</param>\n        /// <returns>The integer value entered by the user</returns>\n        private int GetNumber(string DisplayText)\n        {\n            Console.Write(DisplayText);\n            string TempStr = Console.ReadLine();\n\n            Int32.TryParse(TempStr, out int TempInt);\n\n            if (TempInt <= 0)\n            {\n                throw new ArgumentException($\"{DisplayText} must be greater than zero\");\n            }\n\n            return TempInt;\n        }\n\n        /// <summary>\n        /// This displays the provided text on the screen and then waits for the user\n        /// to enter a Y or N.  It cheats by just looking for a 'y' and returning that\n        /// as true.  Anything else that the user enters is returned as false.\n        /// </summary>\n        /// <param name=\"DisplayText\">Text to display on the screen asking for the input</param>\n        /// <returns>Returns true or false</returns>\n        private bool GetBool(string DisplayText)\n        {\n            Console.Write(DisplayText);\n            return (Console.ReadLine().StartsWith(\"y\", StringComparison.InvariantCultureIgnoreCase));\n        }\n\n        /// <summary>\n        /// This displays the provided text on the screen and then waits for the user\n        /// to enter an arbitrary string.  That string is then returned 'as-is'.\n        /// </summary>\n        /// <param name=\"DisplayText\">Text to display on the screen asking for the input</param>\n        /// <returns>The string entered by the user.</returns>\n        private string GetString(string DisplayText)\n        {\n            Console.Write(DisplayText);\n            return (Console.ReadLine().ToUpper());\n        }\n\n        /// <summary>\n        /// This queries the user for the various inputs needed by the program.\n        /// </summary>\n        private void GetInput()\n        {\n            Horizontal = GetNumber(\"Horizontal \");\n            Vertical = GetNumber(\"Vertical \");\n            Centered = GetBool(\"Centered \");\n            Character = GetString(\"Character (type 'ALL' if you want character being printed) \");\n            Statement = GetString(\"Statement \");\n            // We don't care about what the user enters here.  This is just telling them\n            // to set the page in the printer.\n            _ = GetString(\"Set page \");\n        }\n\n        /// <summary>\n        /// This prints out a single character of the banner - adding\n        /// a few blanks lines as a spacer between characters.\n        /// </summary>\n        private void PrintChar(char ch)\n        {\n            // In the trivial case (a space character), just print out the spaces\n            if (ch.Equals(' '))\n            {\n                Console.WriteLine(new string('\\n', 7 * Horizontal));\n                return;\n            }\n\n            // If a specific character to be printed was provided by the user,\n            // then user that as our ouput character - otherwise take the\n            // current character\n            char outCh = Character == \"ALL\" ? ch : Character[0];\n            int[] letter = new int[7];\n            try\n            {\n                letters[outCh].CopyTo(letter, 0);\n            }\n            catch (KeyNotFoundException)\n            {\n                throw new KeyNotFoundException($\"The provided letter {outCh} was not found in the letters list\");\n            }\n\n            // This iterates through each of the parts that make up\n            // each letter.  Each part represents 1 * Horizontal lines\n            // of actual output.\n            for (int idx = 0; idx < 7; idx++)\n            {\n                // New int array declarations default to zeros\n                // numSections decides how many 'sections' need to be printed\n                // for a given line of each character\n                int[] numSections = new int[7];\n                // fillInSection decides whether each 'section' of the\n                // character gets filled in with the character or with blanks\n                int[] fillInSection = new int[9];\n\n                // This uses the value in each part to decide which\n                // sections are empty spaces in the letter or filled in\n                // spaces.  For each section marked with 1 in fillInSection,\n                // that will correspond to 1 * Vertical characters actually\n                // being output.\n                for (int exp = 8; exp >= 0; exp--)\n                {\n                    if (Math.Pow(2, exp) < letter[idx])\n                    {\n                        fillInSection[8 - exp] = 1;\n                        letter[idx] -= (int)Math.Pow(2, exp);\n                        if (letter[idx] == 1)\n                        {\n                            // Once we've exhausted all of the sections\n                            // defined in this part of the letter, then\n                            // we marked that number and break out of this\n                            // for loop.\n                            numSections[idx] = 8 - exp;\n                            break;\n                        }\n                    }\n                }\n\n                // Now that we know which sections of this part of the letter\n                // are filled in or spaces, we can actually create the string\n                // to print out.\n                string lineStr = \"\";\n\n                if (Centered)\n                    lineStr += new string(' ', (int)(63 - 4.5 * Vertical) * 1 / 1 + 1);\n\n                for (int idx2 = 0; idx2 <= numSections[idx]; idx2++)\n                {\n                    lineStr = lineStr + new string(fillInSection[idx2] == 0 ? ' ' : outCh, Vertical);\n                }\n\n                // Then we print that string out 1 * Horizontal number of times\n                for (int lineidx = 1; lineidx <= Horizontal; lineidx++)\n                {\n                    Console.WriteLine(lineStr);\n                }\n            }\n\n            // Finally, add a little spacer after each character for readability.\n            Console.WriteLine(new string('\\n', 2 * Horizontal - 1));\n        }\n\n        /// <summary>\n        /// This prints the entire banner based in the parameters\n        /// the user provided.\n        /// </summary>\n        private void PrintBanner()\n        {\n            // Iterate through each character in the statement\n            foreach (char ch in Statement)\n            {\n                PrintChar(ch);\n            }\n\n            // In the original version, it would print an additional 75 blank\n            // lines in order to feed the printer paper...don't really need this\n            // since we're not actually printing.\n            // Console.WriteLine(new string('\\n', 75));\n        }\n\n        /// <summary>\n        /// Main entry point into the banner class and handles the main loop.\n        /// </summary>\n        public void Play()\n        {\n            GetInput();\n            PrintBanner();\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            new Banner().Play();\n        }\n    }\n}\n"
  },
  {
    "path": "06_Banner/csharp/banner.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "06_Banner/csharp/banner.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31321.278\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Banner\", \"Banner.csproj\", \"{7E8612AB-AFFD-4F72-855F-8172786F28FD}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7E8612AB-AFFD-4F72-855F-8172786F28FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7E8612AB-AFFD-4F72-855F-8172786F28FD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7E8612AB-AFFD-4F72-855F-8172786F28FD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7E8612AB-AFFD-4F72-855F-8172786F28FD}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {FF2A268C-9C4A-457F-8733-2E8931E07A1D}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "06_Banner/java/Banner.java",
    "content": "import java.util.Scanner;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.lang.Math;\n\n/**\n * Game of Banner\n * <p>\n * Based on the BASIC game of Banner here\n * https://github.com/coding-horror/basic-computer-games/blob/main/06%20Banner/banner.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Banner {\n\n  private final Scanner scan;  // For user input\n\n  public Banner() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Banner\n\n  public void play() {\n\n    int bitIndex = 0;\n    int centerFlag = 0;\n    int dataIndex = 0;\n    int hIndex = 0;\n    int horizontal = 0;\n    int index = 0;\n    int letterIndex = 0;\n    int tempVal = 0;\n    int vertical = 0;\n    int vIndex = 0;\n    int writeIndex = 0;\n\n    int[] writerMap = new int[10];\n    int[] writeLimit = new int[10];\n\n    String centerResponse = \"\";\n    String characters = \"\";\n    String letter = \"\";\n    String lineContent = \"\";\n    String setPage = \"\";\n    String statement = \"\";\n    String token = \"\";  // Print token\n\n    Map<String, int[]> symbolData = new HashMap<String, int[]>();\n    symbolData.put(\" \", new int[]{0,0,0,0,0,0,0,0              });\n    symbolData.put(\"A\", new int[]{0,505,37,35,34,35,37,505     });\n    symbolData.put(\"G\", new int[]{0,125,131,258,258,290,163,101});\n    symbolData.put(\"E\", new int[]{0,512,274,274,274,274,258,258});\n    symbolData.put(\"T\", new int[]{0,2,2,2,512,2,2,2            });\n    symbolData.put(\"W\", new int[]{0,256,257,129,65,129,257,256 });\n    symbolData.put(\"L\", new int[]{0,512,257,257,257,257,257,257});\n    symbolData.put(\"S\", new int[]{0,69,139,274,274,274,163,69  });\n    symbolData.put(\"O\", new int[]{0,125,131,258,258,258,131,125});\n    symbolData.put(\"N\", new int[]{0,512,7,9,17,33,193,512      });\n    symbolData.put(\"F\", new int[]{0,512,18,18,18,18,2,2        });\n    symbolData.put(\"K\", new int[]{0,512,17,17,41,69,131,258    });\n    symbolData.put(\"B\", new int[]{0,512,274,274,274,274,274,239});\n    symbolData.put(\"D\", new int[]{0,512,258,258,258,258,131,125});\n    symbolData.put(\"H\", new int[]{0,512,17,17,17,17,17,512     });\n    symbolData.put(\"M\", new int[]{0,512,7,13,25,13,7,512       });\n    symbolData.put(\"?\", new int[]{0,5,3,2,354,18,11,5          });\n    symbolData.put(\"U\", new int[]{0,128,129,257,257,257,129,128});\n    symbolData.put(\"R\", new int[]{0,512,18,18,50,82,146,271    });\n    symbolData.put(\"P\", new int[]{0,512,18,18,18,18,18,15      });\n    symbolData.put(\"Q\", new int[]{0,125,131,258,258,322,131,381});\n    symbolData.put(\"Y\", new int[]{0,8,9,17,481,17,9,8          });\n    symbolData.put(\"V\", new int[]{0,64,65,129,257,129,65,64    });\n    symbolData.put(\"X\", new int[]{0,388,69,41,17,41,69,388     });\n    symbolData.put(\"Z\", new int[]{0,386,322,290,274,266,262,260});\n    symbolData.put(\"I\", new int[]{0,258,258,258,512,258,258,258});\n    symbolData.put(\"C\", new int[]{0,125,131,258,258,258,131,69 });\n    symbolData.put(\"J\", new int[]{0,65,129,257,257,257,129,128 });\n    symbolData.put(\"1\", new int[]{0,0,0,261,259,512,257,257    });\n    symbolData.put(\"2\", new int[]{0,261,387,322,290,274,267,261});\n    symbolData.put(\"*\", new int[]{0,69,41,17,512,17,41,69      });\n    symbolData.put(\"3\", new int[]{0,66,130,258,274,266,150,100 });\n    symbolData.put(\"4\", new int[]{0,33,49,41,37,35,512,33      });\n    symbolData.put(\"5\", new int[]{0,160,274,274,274,274,274,226});\n    symbolData.put(\"6\", new int[]{0,194,291,293,297,305,289,193});\n    symbolData.put(\"7\", new int[]{0,258,130,66,34,18,10,8      });\n    symbolData.put(\"8\", new int[]{0,69,171,274,274,274,171,69  });\n    symbolData.put(\"9\", new int[]{0,263,138,74,42,26,10,7      });\n    symbolData.put(\"=\", new int[]{0,41,41,41,41,41,41,41       });\n    symbolData.put(\"!\", new int[]{0,1,1,1,384,1,1,1            });\n    symbolData.put(\"0\", new int[]{0,57,69,131,258,131,69,57    });\n    symbolData.put(\".\", new int[]{0,1,1,129,449,129,1,1        });\n\n    System.out.print(\"HORIZONTAL? \");\n    horizontal = Integer.parseInt(scan.nextLine());\n\n    System.out.print(\"VERTICAL? \");\n    vertical = Integer.parseInt(scan.nextLine());\n\n    System.out.print(\"CENTERED? \");\n    centerResponse = scan.nextLine().toUpperCase();\n\n    centerFlag = 0;\n\n    // Lexicographical comparison\n    if (centerResponse.compareTo(\"P\") > 0) {\n      centerFlag = 1;\n    }\n\n    System.out.print(\"CHARACTER (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED)? \");\n    characters = scan.nextLine().toUpperCase();\n\n    System.out.print(\"STATEMENT? \");\n    statement = scan.nextLine().toUpperCase();\n\n    // Initiates the print\n    System.out.print(\"SET PAGE? \");\n    setPage = scan.nextLine();\n\n    // Begin loop through statement letters\n    for (letterIndex = 1; letterIndex <= statement.length(); letterIndex++) {\n\n      // Extract a letter\n      letter = String.valueOf(statement.charAt(letterIndex - 1));\n\n      // Begin loop through all symbol data\n      for (String symbolString: symbolData.keySet()) {\n\n        // Begin letter handling\n        if (letter.equals(\" \")) {\n          for (index = 1; index <= (7 * horizontal); index++) {\n            System.out.println(\"\");\n          }\n          break;\n\n        } else if (letter.equals(symbolString)) {\n          token = characters;\n\n          if (characters.equals(\"ALL\")) {\n            token = symbolString;\n          }\n\n          for (dataIndex = 1; dataIndex <= 7; dataIndex++) {\n\n            // Avoid overwriting symbol data\n            tempVal = symbolData.get(symbolString)[dataIndex];\n\n            for (bitIndex = 8; bitIndex >= 0; bitIndex--) {\n\n              if (Math.pow(2, bitIndex) < tempVal) {\n                writerMap[9 - bitIndex] = 1;\n                tempVal -= Math.pow(2, bitIndex);\n\n                if (tempVal == 1) {\n                  writeLimit[dataIndex] = 9 - bitIndex;\n                  break;\n                }\n\n              } else {\n\n                writerMap[9 - bitIndex] = 0;\n              }\n            }  // End of bitIndex loop\n\n            for (hIndex = 1; hIndex <= horizontal; hIndex++) {\n\n              // Add whitespace for centering\n              lineContent = \" \".repeat((int)((63 - 4.5 * vertical) * centerFlag / token.length()));\n\n              for (writeIndex = 1; writeIndex <= writeLimit[dataIndex]; writeIndex++) {\n\n                if (writerMap[writeIndex] == 0) {\n\n                  for (vIndex = 1; vIndex <= vertical; vIndex++) {\n\n                    for (index = 1; index <= token.length(); index++) {\n                      lineContent += \" \";\n                    }\n                  }\n\n                } else {\n\n                  for (vIndex = 1; vIndex <= vertical; vIndex++) {\n                    lineContent += token;\n                  }\n                }\n\n              }  // End of writeIndex loop\n\n              System.out.println(lineContent);\n\n            }  // End of hIndex loop\n\n          }  // End of dataIndex loop\n\n          // Add padding between letters\n          for (index = 1; index <= 2 * horizontal; index++) {\n            System.out.println(\"\");\n          }\n\n        }  // End letter handling\n\n      }  // End loop through all symbol data\n\n    }  // End loop through statement letters\n\n    // Add extra length to the banner\n    for (index = 1; index <= 75; index++) {\n      System.out.println(\"\");\n    }\n\n  }  // End of method play\n\n  public static void main(String[] args) {\n\n    Banner game = new Banner();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class Banner\n"
  },
  {
    "path": "06_Banner/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "06_Banner/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "06_Banner/javascript/banner.html",
    "content": "<html>\n<head>\n<title>BANNER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"banner.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "06_Banner/javascript/banner.js",
    "content": "// BANNER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar letters = [\" \",0,0,0,0,0,0,0,\n               \"A\",505,37,35,34,35,37,505,\n               \"G\",125,131,258,258,290,163,101,\n               \"E\",512,274,274,274,274,258,258,\n               \"T\",2,2,2,512,2,2,2,\n               \"W\",256,257,129,65,129,257,256,\n               \"L\",512,257,257,257,257,257,257,\n               \"S\",69,139,274,274,274,163,69,\n               \"O\",125,131,258,258,258,131,125,\n               \"N\",512,7,9,17,33,193,512,\n               \"F\",512,18,18,18,18,2,2,\n               \"K\",512,17,17,41,69,131,258,\n               \"B\",512,274,274,274,274,274,239,\n               \"D\",512,258,258,258,258,131,125,\n               \"H\",512,17,17,17,17,17,512,\n               \"M\",512,7,13,25,13,7,512,\n               \"?\",5,3,2,354,18,11,5,\n               \"U\",128,129,257,257,257,129,128,\n               \"R\",512,18,18,50,82,146,271,\n               \"P\",512,18,18,18,18,18,15,\n               \"Q\",125,131,258,258,322,131,381,\n               \"Y\",8,9,17,481,17,9,8,\n               \"V\",64,65,129,257,129,65,64,\n               \"X\",388,69,41,17,41,69,388,\n               \"Z\",386,322,290,274,266,262,260,\n               \"I\",258,258,258,512,258,258,258,\n               \"C\",125,131,258,258,258,131,69,\n               \"J\",65,129,257,257,257,129,128,\n               \"1\",0,0,261,259,512,257,257,\n               \"2\",261,387,322,290,274,267,261,\n               \"*\",69,41,17,512,17,41,69,\n               \"3\",66,130,258,274,266,150,100,\n               \"4\",33,49,41,37,35,512,33,\n               \"5\",160,274,274,274,274,274,226,\n               \"6\",194,291,293,297,305,289,193,\n               \"7\",258,130,66,34,18,10,8,\n               \"8\",69,171,274,274,274,171,69,\n               \"9\",263,138,74,42,26,10,7,\n               \"=\",41,41,41,41,41,41,41,\n               \"!\",1,1,1,384,1,1,1,\n               \"0\",57,69,131,258,131,69,57,\n               \".\",1,1,129,449,129,1,1];\n\nf = [];\nj = [];\ns = [];\n\n// Main program\nasync function main()\n{\n    print(\"HORIZONTAL\");\n    x = parseInt(await input());\n    print(\"VERTICAL\");\n    y = parseInt(await input());\n    print(\"CENTERED\");\n    ls = await input();\n    g1 = 0;\n    if (ls > \"P\")\n        g1 = 1;\n    print(\"CHARACTER (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED)\");\n    ms = await input();\n    print(\"STATEMENT\");\n    as = await input();\n    print(\"SET PAGE\");\t// This means to prepare printer, just press Enter\n    os = await input();\n\n    for (t = 0; t < as.length; t++) {\n        ps = as.substr(t, 1);\n        for (o = 0; o < 50 * 8; o += 8) {\n            if (letters[o] == ps) {\n                for (u = 1; u <= 7; u++)\n                    s[u] = letters[o + u];\n                break;\n            }\n        }\n        if (o == 50 * 8) {\n            ps = \" \";\n            o = 0;\n        }\n//      print(\"Doing \" + o + \"\\n\");\n        if (o == 0) {\n            for (h = 1; h <= 7 * x; h++)\n                print(\"\\n\");\n        } else {\n            xs = ms;\n            if (ms == \"ALL\")\n                xs = ps;\n            for (u = 1; u <= 7; u++) {\n                // An inefficient way of extracting bits\n                // but good enough in BASIC because there\n                // aren't bit shifting operators.\n                for (k = 8; k >= 0; k--) {\n                    if (Math.pow(2, k) >= s[u]) {\n                        j[9 - k] = 0;\n                    } else {\n                        j[9 - k] = 1;\n                        s[u] -= Math.pow(2, k);\n                        if (s[u] == 1) {\n                            f[u] = 9 - k;\n                            break;\n                        }\n                    }\n                }\n                for (t1 = 1; t1 <= x; t1++) {\n                    str = tab((63 - 4.5 * y) * g1 / xs.length + 1);\n                    for (b = 1; b <= f[u]; b++) {\n                        if (j[b] == 0) {\n                            for (i = 1; i <= y; i++)\n                                str += tab(xs.length);\n                        } else {\n                            for (i = 1; i <= y; i++)\n                                str += xs;\n                        }\n                    }\n                    print(str + \"\\n\");\n                }\n            }\n            for (h = 1; h <= 2 * x; h++)\n                print(\"\\n\");\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "06_Banner/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "06_Banner/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "06_Banner/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "06_Banner/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "06_Banner/perl/banner.pl",
    "content": "#!/usr/bin/perl\n\n# Banner program in Perl\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\nsub print_lines\n{\n    my $lines = shift;\n    print \"\\n\" x $lines;\n}\n\n# each letter is made of 7 slices (or rows);\n# the initial & unused 0 is to allow for Perl arrays being 0-based\n#   but allow the algorithm to be 1-based (like Basic arrays);\n# the numbers are essentially the dots/columns per slice in powers of 2.\nmy %data = (\n    \" \" => [ 0,  0, 0, 0, 0, 0, 0, 0 ], \n    \".\" => [ 0,  1, 1, 129, 449, 129, 1, 1 ], \n    \"!\" => [ 0,  1, 1, 1, 384, 1, 1, 1 ], \n    \"=\" => [ 0,  41, 41, 41, 41, 41, 41, 41 ], \n    \"?\" => [ 0,  5, 3, 2, 354, 18, 11, 5 ], \n    \"*\" => [ 0,  69, 41, 17, 512, 17, 41, 69 ], \n    \"0\" => [ 0,  57, 69, 131, 258, 131, 69, 57 ], \n    \"1\" => [ 0,  0, 0, 261, 259, 512, 257, 257 ], \n    \"2\" => [ 0,  261, 387, 322, 290, 274, 267, 261 ], \n    \"3\" => [ 0,  66, 130, 258, 274, 266, 150, 100 ], \n    \"4\" => [ 0,  33, 49, 41, 37, 35, 512, 33 ], \n    \"5\" => [ 0,  160, 274, 274, 274, 274, 274, 226 ], \n    \"6\" => [ 0,  194, 291, 293, 297, 305, 289, 193 ], \n    \"7\" => [ 0,  258, 130, 66, 34, 18, 10, 8 ], \n    \"8\" => [ 0,  69, 171, 274, 274, 274, 171, 69 ], \n    \"9\" => [ 0,  263, 138, 74, 42, 26, 10, 7 ], \n    \"A\" => [ 0,  505, 37, 35, 34, 35, 37, 505 ], \n    \"B\" => [ 0,  512, 274, 274, 274, 274, 274, 239 ], \n    \"C\" => [ 0,  125, 131, 258, 258, 258, 131, 69 ], \n    \"D\" => [ 0,  512, 258, 258, 258, 258, 131, 125 ], \n    \"E\" => [ 0,  512, 274, 274, 274, 274, 258, 258 ], \n    \"F\" => [ 0,  512, 18, 18, 18, 18, 2, 2 ], \n    \"G\" => [ 0,  125, 131, 258, 258, 290, 163, 101 ], \n    \"H\" => [ 0,  512, 17, 17, 17, 17, 17, 512 ], \n    \"I\" => [ 0,  258, 258, 258, 512, 258, 258, 258 ], \n    \"J\" => [ 0,  65, 129, 257, 257, 257, 129, 128 ], \n    \"K\" => [ 0,  512, 17, 17, 41, 69, 131, 258 ], \n    \"L\" => [ 0,  512, 257, 257, 257, 257, 257, 257 ], \n    \"M\" => [ 0,  512, 7, 13, 25, 13, 7, 512 ], \n    \"N\" => [ 0,  512, 7, 9, 17, 33, 193, 512 ], \n    \"O\" => [ 0,  125, 131, 258, 258, 258, 131, 125 ], \n    \"P\" => [ 0,  512, 18, 18, 18, 18, 18, 15 ], \n    \"Q\" => [ 0,  125, 131, 258, 258, 322, 131, 381 ], \n    \"R\" => [ 0,  512, 18, 18, 50, 82, 146, 271 ], \n    \"S\" => [ 0,  69, 139, 274, 274, 274, 163, 69 ], \n    \"T\" => [ 0,  2, 2, 2, 512, 2, 2, 2 ], \n    \"U\" => [ 0,  128, 129, 257, 257, 257, 129, 128 ], \n    \"V\" => [ 0,  64, 65, 129, 257, 129, 65, 64 ], \n    \"W\" => [ 0,  256, 257, 129, 65, 129, 257, 256 ], \n    \"X\" => [ 0,  388, 69, 41, 17, 41, 69, 388 ], \n    \"Y\" => [ 0,  8, 9, 17, 481, 17, 9, 8 ], \n    \"Z\" => [ 0,  386, 322, 290, 274, 266, 262, 260 ], \n);\n\nmy ($horz, $vert, $center, $char, $msg) = (0, 0, '', '', '');\n\n# get args to run with\nwhile ($horz < 1)\n{\n    print \"HORIZONTAL (1 or more): \";\n    chomp($horz = <>);\n    $horz = int($horz);\n}\n\nwhile ($vert < 1)\n{\n    print \"VERTICAL (1 or more): \";\n    chomp($vert = <>);\n    $vert = int($vert);\n}\n\nprint \"CENTERED (Y/N): \";\nchomp($center = <>);\n$center = ($center =~ m/^Y/i) ? 1 : 0;\n\n# note you can enter multiple chars and the program will do the right thing\n# thanks to the length() calls below, which was in the original Basic\nprint \"CHARACTER TO PRINT (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED): \";\nchomp($char = uc(<>));\n\nwhile (!$msg)\n{\n    print \"STATEMENT: \";\n    chomp($msg = uc(<>));\n}\n\nprint \"SET PAGE TO PRINT, HIT RETURN WHEN READY\";\n$_ = <>;\nprint_lines(2 * $horz);\n\n# print the message\nfor my $letter ( split(//, $msg) )\n{\n    if (!exists($data{$letter}))\n    {\n        die \"Cannot use letter '$letter'!\";\n    }\n    my @s = @{$data{$letter}};\n    #if ($letter eq \" \") { print_lines(7 * $horz); next; }\n\n    my $print_letter = ($char eq \"ALL\") ? $letter : $char;\n    for my $slice (1 .. 7)\n    {\n        my (@j, @f);\n        for (my $k = 8; $k >= 0; $k--)\n        {\n            if (2**$k < $s[$slice])\n            {\n                $j[9 - $k] = 1;\n                $s[$slice] = $s[$slice] - 2**$k;\n                if ($s[$slice] == 1)\n                {\n                    $f[$slice] = 9 - $k;\n                }\n            }\n            else\n            {\n                $j[9 - $k] = 0;\n            }\n        }\n\n        for my $t1 (1 .. $horz)\n        {\n            print \" \" x int((63 - 4.5 * $vert) * $center / (length($print_letter)) + 1);\n            for my $b (1 .. (defined($f[$slice]) ? $f[$slice] : 0))\n            {\n                my $str = $j[$b] ? $print_letter : (\" \" x length($print_letter));\n                print $str for (1 .. $vert);\n            }\n            print \"\\n\";\n        }\n    }\n\n    # space between letters\n    print_lines(2 * $horz);\n}\n\n# while in the original code, this seems pretty excessive\n#print_lines(75);\n\nexit(0);\n"
  },
  {
    "path": "06_Banner/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "06_Banner/python/banner.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nBANNER\n\nConverted from BASIC to Python by Trevor Hobson\n\"\"\"\n\nletters = {\n    \" \": [0, 0, 0, 0, 0, 0, 0],\n    \"A\": [505, 37, 35, 34, 35, 37, 505],\n    \"G\": [125, 131, 258, 258, 290, 163, 101],\n    \"E\": [512, 274, 274, 274, 274, 258, 258],\n    \"T\": [2, 2, 2, 512, 2, 2, 2],\n    \"W\": [256, 257, 129, 65, 129, 257, 256],\n    \"L\": [512, 257, 257, 257, 257, 257, 257],\n    \"S\": [69, 139, 274, 274, 274, 163, 69],\n    \"O\": [125, 131, 258, 258, 258, 131, 125],\n    \"N\": [512, 7, 9, 17, 33, 193, 512],\n    \"F\": [512, 18, 18, 18, 18, 2, 2],\n    \"K\": [512, 17, 17, 41, 69, 131, 258],\n    \"B\": [512, 274, 274, 274, 274, 274, 239],\n    \"D\": [512, 258, 258, 258, 258, 131, 125],\n    \"H\": [512, 17, 17, 17, 17, 17, 512],\n    \"M\": [512, 7, 13, 25, 13, 7, 512],\n    \"?\": [5, 3, 2, 354, 18, 11, 5],\n    \"U\": [128, 129, 257, 257, 257, 129, 128],\n    \"R\": [512, 18, 18, 50, 82, 146, 271],\n    \"P\": [512, 18, 18, 18, 18, 18, 15],\n    \"Q\": [125, 131, 258, 258, 322, 131, 381],\n    \"Y\": [8, 9, 17, 481, 17, 9, 8],\n    \"V\": [64, 65, 129, 257, 129, 65, 64],\n    \"X\": [388, 69, 41, 17, 41, 69, 388],\n    \"Z\": [386, 322, 290, 274, 266, 262, 260],\n    \"I\": [258, 258, 258, 512, 258, 258, 258],\n    \"C\": [125, 131, 258, 258, 258, 131, 69],\n    \"J\": [65, 129, 257, 257, 257, 129, 128],\n    \"1\": [0, 0, 261, 259, 512, 257, 257],\n    \"2\": [261, 387, 322, 290, 274, 267, 261],\n    \"*\": [69, 41, 17, 512, 17, 41, 69],\n    \"3\": [66, 130, 258, 274, 266, 150, 100],\n    \"4\": [33, 49, 41, 37, 35, 512, 33],\n    \"5\": [160, 274, 274, 274, 274, 274, 226],\n    \"6\": [194, 291, 293, 297, 305, 289, 193],\n    \"7\": [258, 130, 66, 34, 18, 10, 8],\n    \"8\": [69, 171, 274, 274, 274, 171, 69],\n    \"9\": [263, 138, 74, 42, 26, 10, 7],\n    \"=\": [41, 41, 41, 41, 41, 41, 41],\n    \"!\": [1, 1, 1, 384, 1, 1, 1],\n    \"0\": [57, 69, 131, 258, 131, 69, 57],\n    \".\": [1, 1, 129, 449, 129, 1, 1],\n}\n\n\ndef print_banner() -> None:\n    f = [0] * 7\n    j = [0] * 9\n\n    while True:\n        try:\n            horizontal = int(input(\"Horizontal \"))\n            if horizontal < 1:\n                raise ValueError(\"Horizontal must be greater than zero\")\n            break\n\n        except ValueError:\n            print(\"Please enter a number greater than zero\")\n    while True:\n        try:\n            vertical = int(input(\"Vertical \"))\n            if vertical < 1:\n                raise ValueError(\"Vertical must be greater than zero\")\n            break\n\n        except ValueError:\n            print(\"Please enter a number greater than zero\")\n    g1 = 1 if input(\"Centered \").lower().startswith(\"y\") else 0\n    character = input(\n        \"Character (type 'ALL' if you want character being printed) \"\n    ).upper()\n    statement = input(\"Statement \")\n\n    input(\"Set page \")  # This means to prepare printer, just press Enter\n\n    for statement_char in statement:\n        s = letters[statement_char].copy()\n        x_str = character\n        if x_str == \"ALL\":\n            x_str = statement_char\n        if x_str == \" \":\n            print(\"\\n\" * (7 * horizontal))\n        else:\n            for u in range(0, 7):\n                for k in range(8, -1, -1):\n                    if 2**k >= s[u]:\n                        j[8 - k] = 0\n                    else:\n                        j[8 - k] = 1\n                        s[u] = s[u] - 2**k\n                        if s[u] == 1:\n                            f[u] = 8 - k\n                            break\n                for _t1 in range(1, horizontal + 1):\n                    line_str = \" \" * int((63 - 4.5 * vertical) * g1 / len(x_str) + 1)\n                    for b in range(0, f[u] + 1):\n                        if j[b] == 0:\n                            for _ in range(1, vertical + 1):\n                                line_str = line_str + \" \" * len(x_str)\n                        else:\n                            line_str = line_str + x_str * vertical\n                    print(line_str)\n            print(\"\\n\" * (2 * horizontal - 1))\n    # print(\"\\n\" * 75)  # Feed some more paper from the printer\n\n\nif __name__ == \"__main__\":\n    print_banner()\n"
  },
  {
    "path": "06_Banner/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "06_Banner/ruby/banner.rb",
    "content": "#!/usr/bin/env ruby\n\n# Banner\n# reinterpreted from BASIC by stephan.com\n\n# this implementation diverges from the original in some notable\n# ways, but maintains the same font definition as before as well\n# as the same somewhat bizarre way of interpreting it.  It would\n# be more efficient to redesign the font to allow `\"%09b\" % row`\n# and then some substitutions.\n\nFONT = {\n  ' ' => [0, 0, 0, 0, 0, 0, 0].freeze,\n  '!' => [1, 1, 1, 384, 1, 1, 1].freeze,\n  '*' => [69, 41, 17, 512, 17, 41, 69].freeze,\n  '.' => [1, 1, 129, 449, 129, 1, 1].freeze,\n  '0' => [57, 69, 131, 258, 131, 69, 57].freeze,\n  '1' => [0, 0, 261, 259, 512, 257, 257].freeze,\n  '2' => [261, 387, 322, 290, 274, 267, 261].freeze,\n  '3' => [66, 130, 258, 274, 266, 150, 100].freeze,\n  '4' => [33, 49, 41, 37, 35, 512, 33].freeze,\n  '5' => [160, 274, 274, 274, 274, 274, 226].freeze,\n  '6' => [194, 291, 293, 297, 305, 289, 193].freeze,\n  '7' => [258, 130, 66, 34, 18, 10, 8].freeze,\n  '8' => [69, 171, 274, 274, 274, 171, 69].freeze,\n  '9' => [263, 138, 74, 42, 26, 10, 7].freeze,\n  '=' => [41, 41, 41, 41, 41, 41, 41].freeze,\n  '?' => [5, 3, 2, 354, 18, 11, 5].freeze,\n  'a' => [505, 37, 35, 34, 35, 37, 505].freeze,\n  'b' => [512, 274, 274, 274, 274, 274, 239].freeze,\n  'c' => [125, 131, 258, 258, 258, 131, 69].freeze,\n  'd' => [512, 258, 258, 258, 258, 131, 125].freeze,\n  'e' => [512, 274, 274, 274, 274, 258, 258].freeze,\n  'f' => [512, 18, 18, 18, 18, 2, 2].freeze,\n  'g' => [125, 131, 258, 258, 290, 163, 101].freeze,\n  'h' => [512, 17, 17, 17, 17, 17, 512].freeze,\n  'i' => [258, 258, 258, 512, 258, 258, 258].freeze,\n  'j' => [65, 129, 257, 257, 257, 129, 128].freeze,\n  'k' => [512, 17, 17, 41, 69, 131, 258].freeze,\n  'l' => [512, 257, 257, 257, 257, 257, 257].freeze,\n  'm' => [512, 7, 13, 25, 13, 7, 512].freeze,\n  'n' => [512, 7, 9, 17, 33, 193, 512].freeze,\n  'o' => [125, 131, 258, 258, 258, 131, 125].freeze,\n  'p' => [512, 18, 18, 18, 18, 18, 15].freeze,\n  'q' => [125, 131, 258, 258, 322, 131, 381].freeze,\n  'r' => [512, 18, 18, 50, 82, 146, 271].freeze,\n  's' => [69, 139, 274, 274, 274, 163, 69].freeze,\n  't' => [2, 2, 2, 512, 2, 2, 2].freeze,\n  'u' => [128, 129, 257, 257, 257, 129, 128].freeze,\n  'v' => [64, 65, 129, 257, 129, 65, 64].freeze,\n  'w' => [256, 257, 129, 65, 129, 257, 256].freeze,\n  'x' => [388, 69, 41, 17, 41, 69, 388].freeze,\n  'y' => [8, 9, 17, 481, 17, 9, 8].freeze,\n  'z' => [386, 322, 290, 274, 266, 262, 260].freeze\n}.freeze\n\nputs 'horizontal'\nx = gets.strip.to_i\nputs 'vertical'\ny = gets.strip.to_i\nputs 'centered'\ncentered = gets.strip.downcase.chars.first == 'y'\nputs 'character (\"all\" for character being printed)'\nfill = gets.strip.downcase\nputs 'statement'\nstatement = gets.strip.downcase\n\nall = (fill.downcase == 'all')\nlenxs = all ? 1 : fill.length\nstart = 1\nstart += (63 - 4.5 * y) / lenxs if centered\n\nstatement.each_char do |char|\n  next puts \"\\n\" * 7 * x if char == ' '\n\n  xs = all ? char : fill\n  FONT[char].each do |su|\n    print ' ' * start\n    8.downto(0) do |k|\n      if (1 << k) < su\n        print xs * y\n        su -= (1 << k)\n      else\n        print ' ' * (y * lenxs)\n      end\n    end\n    puts\n  end\n\n  (2 * x).times { puts }\nend\n75.times { puts }\n"
  },
  {
    "path": "06_Banner/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "06_Banner/vbnet/banner.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31321.278\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{778DAE3C-4631-46EA-AA77-85C1314464D9}\") = \"Banner\", \"Banner.vbproj\", \"{091ABE13-3E70-4848-B836-592F725915A3}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{091ABE13-3E70-4848-B836-592F725915A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{091ABE13-3E70-4848-B836-592F725915A3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{091ABE13-3E70-4848-B836-592F725915A3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{091ABE13-3E70-4848-B836-592F725915A3}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {04E18CE1-1C55-432F-A15A-DC2FA9DDC0F1}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "06_Banner/vbnet/banner.vb",
    "content": "Imports System\n\nModule Banner\n    Private Horizontal As Integer\n    Private Vertical As Integer\n    Private Centered As Boolean\n    Private Character As String\n    Private Statement As String\n\n    ' This provides a bit-ended representation of each symbol\n    ' that can be output.  Each symbol Is defined by 7 parts -\n    ' where each part Is an integer value that, when converted to\n    ' the binary representation, shows which section Is filled in\n    ' with values And which are spaces.  i.e., the 'filled in'\n    ' parts represent the actual symbol on the paper.\n    Private letters As Dictionary(Of Char, Integer()) = New Dictionary(Of Char, Integer()) From\n        {\n            {\" \", {0, 0, 0, 0, 0, 0, 0}},\n            {\"A\", {505, 37, 35, 34, 35, 37, 505}},\n            {\"B\", {512, 274, 274, 274, 274, 274, 239}},\n            {\"C\", {125, 131, 258, 258, 258, 131, 69}},\n            {\"D\", {512, 258, 258, 258, 258, 131, 125}},\n            {\"E\", {512, 274, 274, 274, 274, 258, 258}},\n            {\"F\", {512, 18, 18, 18, 18, 2, 2}},\n            {\"G\", {125, 131, 258, 258, 290, 163, 101}},\n            {\"H\", {512, 17, 17, 17, 17, 17, 512}},\n            {\"I\", {258, 258, 258, 512, 258, 258, 258}},\n            {\"J\", {65, 129, 257, 257, 257, 129, 128}},\n            {\"K\", {512, 17, 17, 41, 69, 131, 258}},\n            {\"L\", {512, 257, 257, 257, 257, 257, 257}},\n            {\"M\", {512, 7, 13, 25, 13, 7, 512}},\n            {\"N\", {512, 7, 9, 17, 33, 193, 512}},\n            {\"O\", {125, 131, 258, 258, 258, 131, 125}},\n            {\"P\", {512, 18, 18, 18, 18, 18, 15}},\n            {\"Q\", {125, 131, 258, 258, 322, 131, 381}},\n            {\"R\", {512, 18, 18, 50, 82, 146, 271}},\n            {\"S\", {69, 139, 274, 274, 274, 163, 69}},\n            {\"T\", {2, 2, 2, 512, 2, 2, 2}},\n            {\"U\", {128, 129, 257, 257, 257, 129, 128}},\n            {\"V\", {64, 65, 129, 257, 129, 65, 64}},\n            {\"W\", {256, 257, 129, 65, 129, 257, 256}},\n            {\"X\", {388, 69, 41, 17, 41, 69, 388}},\n            {\"Y\", {8, 9, 17, 481, 17, 9, 8}},\n            {\"Z\", {386, 322, 290, 274, 266, 262, 260}},\n            {\"0\", {57, 69, 131, 258, 131, 69, 57}},\n            {\"1\", {0, 0, 261, 259, 512, 257, 257}},\n            {\"2\", {261, 387, 322, 290, 274, 267, 261}},\n            {\"3\", {66, 130, 258, 274, 266, 150, 100}},\n            {\"4\", {33, 49, 41, 37, 35, 512, 33}},\n            {\"5\", {160, 274, 274, 274, 274, 274, 226}},\n            {\"6\", {194, 291, 293, 297, 305, 289, 193}},\n            {\"7\", {258, 130, 66, 34, 18, 10, 8}},\n            {\"8\", {69, 171, 274, 274, 274, 171, 69}},\n            {\"9\", {263, 138, 74, 42, 26, 10, 7}},\n            {\"?\", {5, 3, 2, 354, 18, 11, 5}},\n            {\"*\", {69, 41, 17, 512, 17, 41, 69}},\n            {\"=\", {41, 41, 41, 41, 41, 41, 41}},\n            {\"!\", {1, 1, 1, 384, 1, 1, 1}},\n            {\".\", {1, 1, 129, 449, 129, 1, 1}}\n        }\n\n    ' <summary>\n    ' This displays the provided text on the screen And then waits for the user\n    ' to enter a integer value greater than 0.\n    ' </summary>\n    ' <param name=\"DisplayText\">Text to display on the screen asking for the input</param>\n    ' <returns>The integer value entered by the user</returns>\n    Private Function GetNumber(DisplayText As String) As Integer\n        Console.Write(DisplayText)\n        Dim TempStr As String = Console.ReadLine()\n        Dim TempInt As Integer\n\n        Int32.TryParse(TempStr, TempInt)\n\n        If (TempInt <= 0) Then\n            Throw New ArgumentException($\"{DisplayText} must be greater than zero\")\n        End If\n\n        Return TempInt\n    End Function\n\n    ' <summary>\n    ' This displays the provided text on the screen And then waits for the user\n    ' to enter a Y Or N.  It cheats by just looking for a 'y' and returning that\n    ' as true.  Anything else that the user enters Is returned as false.\n    ' </summary>\n    ' <param name=\"DisplayText\">Text to display on the screen asking for the input</param>\n    ' <returns>Returns true Or false</returns>\n    Private Function GetBool(DisplayText As String) As Boolean\n        Console.Write(DisplayText)\n        Return Console.ReadLine().StartsWith(\"y\", StringComparison.InvariantCultureIgnoreCase)\n    End Function\n\n    ' <summary>\n    ' This displays the provided text on the screen And then waits for the user\n    ' to enter an arbitrary string.  That string Is then returned 'as-is'.\n    ' </summary>\n    ' <param name=\"DisplayText\">Text to display on the screen asking for the input</param>\n    ' <returns>The string entered by the user.</returns>\n    Private Function GetString(DisplayText As String) As String\n        Console.Write(DisplayText)\n        Return (Console.ReadLine().ToUpper())\n    End Function\n\n    ' <summary>\n    ' This queries the user for the various inputs needed by the program.\n    ' </summary>\n    Private Sub GetInput()\n        Horizontal = GetNumber(\"Horizontal \")\n        Vertical = GetNumber(\"Vertical \")\n        Centered = GetBool(\"Centered \")\n        Character = GetString(\"Character (type 'ALL' if you want character being printed) \")\n        Statement = GetString(\"Statement \")\n        ' We don't care about what the user enters here.  This is just telling them\n        ' to set the page in the printer.\n        GetString(\"Set page \")\n    End Sub\n\n    ' <summary>\n    ' This prints out a single character of the banner - adding\n    ' a few blanks lines as a spacer between characters.\n    ' </summary>\n    Private Sub PrintChar(ch As Char)\n        ' In the trivial case (a space character), just print out the spaces\n        If ch.Equals(\" \") Then\n            Console.WriteLine(New String(\"\\n\", 7 * Horizontal))\n            Return\n        End If\n\n        ' If a specific character to be printed was provided by the user,\n        ' then user that as our ouput character - otherwise take the\n        ' current character\n        Dim outCh As Char = IIf(Character.Equals(\"ALL\"), ch, Character.Substring(0, 1))\n        Dim letter(7) As Integer\n        Try\n            letters(outCh).CopyTo(letter, 0)\n        Catch ex As KeyNotFoundException\n            Throw New KeyNotFoundException($\"The provided letter {outCh} was not found in the letters list\")\n        End Try\n\n        ' This iterates through each of the parts that make up\n        ' each letter.  Each part represents 1 * Horizontal lines\n        ' of actual output.\n        For idx As Integer = 0 To 7\n            ' New int array declarations default to zeros\n            ' numSections decides how many 'sections' need to be printed\n            ' for a given line of each character\n            Dim numSections(7) As Integer\n            ' fillInSection decides whether each 'section' of the\n            ' character gets filled in with the character Or with blanks\n            Dim fillInSection(9) As Integer\n\n            ' This uses the value in each part to decide which\n            ' sections are empty spaces in the letter Or filled in\n            ' spaces.  For each section marked with 1 in fillInSection,\n            ' that will correspond to 1 * Vertical characters actually\n            ' being output.\n            For exp As Integer = 8 To 0 Step -1\n                If (Math.Pow(2, exp) < letter(idx)) Then\n                    fillInSection(8 - exp) = 1\n                    letter(idx) -= Math.Pow(2, exp)\n                    If (letter(idx) = 1) Then\n                        ' Once we've exhausted all of the sections\n                        ' defined in this part of the letter, then\n                        ' we marked that number And break out of this\n                        ' for loop.\n                        numSections(idx) = 8 - exp\n                        Exit For\n                    End If\n                End If\n            Next exp\n\n            ' Now that we know which sections of this part of the letter\n            ' are filled in Or spaces, we can actually create the string\n            ' to print out.\n            Dim lineStr As String = \"\"\n\n            If (Centered) Then\n                lineStr += New String(\" \", (63 - 4.5 * Vertical) * 1 / 1 + 1)\n            End If\n\n            For idx2 As Integer = 0 To numSections(idx)\n                lineStr = lineStr + New String(IIf(fillInSection(idx2) = 0, \" \", outCh), Vertical)\n            Next idx2\n\n            ' Then we print that string out 1 * Horizontal number of times\n            For lineIdx As Integer = 1 To Horizontal\n                Console.WriteLine(lineStr)\n            Next lineIdx\n        Next idx\n\n\n        ' Finally, add a little spacer after each character for readability.\n        Console.WriteLine(New String(Environment.NewLine, 2 * Horizontal - 1))\n    End Sub\n\n    ' <summary>\n    ' This prints the entire banner based in the parameters\n    ' the user provided.\n    ' </summary>\n    Private Sub PrintBanner()\n        ' Iterate through each character in the statement\n        For Each ch As Char In Statement\n            PrintChar(ch)\n        Next ch\n\n        ' In the original version, it would print an additional 75 blank\n        ' lines in order to feed the printer paper...don't really need this\n        ' since we're not actually printing.\n        Console.WriteLine(New String(Environment.NewLine, 75))\n    End Sub\n\n    ' <summary>\n    ' Main entry point into the banner class And handles the main loop.\n    ' </summary>\n    Public Sub Play()\n        GetInput()\n        PrintBanner()\n    End Sub\nEnd Module\n\nModule Program\n    Sub Main(args As String())\n        Banner.Play()\n    End Sub\nEnd Module\n"
  },
  {
    "path": "06_Banner/vbnet/banner.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Banner</RootNamespace>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "07_Basketball/README.md",
    "content": "### Basketball\n\nThis program simulates a game of basketball between Dartmouth College and an opponent of your choice. You are the Dartmouth captain and control the type of shot and defense during the course of the game.\n\nThere are four types of shots:\n1. Long Jump Shot (30ft)\n2. Short Jump Shot (15ft)\n3. Lay Up\n4. Set Shot\n\nBoth teams use the same defense, but you may call it:\n- Enter (6): Press\n- Enter (6.5): Man-to-man\n- Enter (7): Zone\n- Enter (7.5): None\n\nTo change defense, type \"0\" as your next shot.\n\nNote: The game is biased slightly in favor of Dartmouth. The average probability of a Dartmouth shot being good is 62.95% compared to a probability of 61.85% for their opponent. (This makes the sample run slightly remarkable in that Cornell won by a score of 45 to 42 Hooray for the Big Red!)\n\nCharles Bacheller of Dartmouth College was the original author of this game.\n\n---\n\nAs published in Basic Computer Games (1978)\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=12)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=27)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n##### Original bugs\n\n###### Initial defense selection\n\nIf a number <6 is entered for the starting defense then the original code prompts again until a value >=6 is entered,\nbut then skips the opponent selection center jump.\n\nThe C# port does not reproduce this behavior. It does prompt for a correct value, but will then go to opponent selection\nfollowed by the center jump.\n\n###### Unvalidated defense selection\n\nThe original code does not validate the value entered for the defense beyond checking that it is >=6. A large enough\ndefense value will guarantee that all shots are good, and the game gets rather predictable.\n\nThis bug is preserved in the C# port.\n"
  },
  {
    "path": "07_Basketball/basketball.bas",
    "content": "5 PRINT TAB(31);\"BASKETBALL\"\n7 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n8 PRINT:PRINT:PRINT\n10 PRINT \"THIS IS DARTMOUTH COLLEGE BASKETBALL.  YOU WILL BE DARTMOUTH\"\n20 PRINT \" CAPTAIN AND PLAYMAKER.  CALL SHOTS AS FOLLOWS:  1. LONG\"\n30 PRINT \" (30 FT.) JUMP SHOT; 2. SHORT (15 FT.) JUMP SHOT; 3. LAY\"\n40 PRINT \" UP; 4. SET SHOT.\"\n60 PRINT \"BOTH TEAMS WILL USE THE SAME DEFENSE.  CALL DEFENSE AS\"\n70 PRINT \"FOLLOWS:  6. PRESS; 6.5 MAN-TO MAN; 7. ZONE; 7.5 NONE.\"\n72 PRINT \"TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\"\n76 INPUT \"YOUR STARTING DEFENSE WILL BE\";D:IF D<6 THEN 2010\n79 PRINT\n80 INPUT \"CHOOSE YOUR OPPONENT\";O$\n370 PRINT \"CENTER JUMP\"\n390 IF RND(1)> 3/5 THEN 420\n400 PRINT O$;\" CONTROLS THE TAP.\"\n410 GOTO 3000\n420 PRINT \"DARTMOUTH CONTROLS THE TAP.\"\n425 PRINT\n430 INPUT \"YOUR SHOT\";Z\n440 P=0\n445 IF Z<>INT(Z) THEN 455\n446 IF Z<0 OR Z>4 THEN 455\n447 GOTO 460\n455 PRINT \"INCORRECT ANSWER.  RETYPE IT. \";:GOTO 430\n460 IF RND(1)<.5 THEN 1000\n480 IF T<100 THEN 1000\n490 PRINT\n491 IF S(1)<>S(0) THEN 510\n492 PRINT:PRINT \"   ***** END OF SECOND HALF *****\":PRINT\n493 PRINT \"SCORE AT END OF REGULATION TIME:\"\n494 PRINT \"        DARTMOUTH:\";S(1);\"  \";O$;\":\";S(0)\n495 PRINT\n496 PRINT \"BEGIN TWO MINUTE OVERTIME PERIOD\"\n499 T=93\n500 GOTO 370\n510 PRINT \"   ***** END OF GAME *****\"\n515 PRINT \"FINAL SCORE: DARTMOUTH:\";S(1);\"  \";O$;\":\";S(0)\n520 STOP\n600 PRINT\n610 PRINT \"   *** TWO MINUTES LEFT IN THE GAME ***\"\n620 PRINT\n630 RETURN\n1000 ON Z GOTO 1040,1040\n1030 GOTO 1300\n1040 T=T+1\n1041 IF T=50 THEN 8000\n1042 IF T=92 THEN 1046\n1043 GOTO 1050\n1046 GOSUB 600\n1050 PRINT \"JUMP SHOT\"\n1060 IF RND(1)>.341*D/8 THEN 1090\n1070 PRINT \"SHOT IS GOOD.\"\n1075 GOSUB 7000\n1085 GOTO 3000\n1090 IF RND(1)>.682*D/8 THEN 1200\n1100 PRINT \"SHOT IS OFF TARGET.\"\n1105 IF D/6*RND(1)>.45 THEN 1130\n1110 PRINT \"DARTMOUTH CONTROLS THE REBOUND.\"\n1120 GOTO 1145\n1130 PRINT \"REBOUND TO \";O$\n1140 GOTO 3000\n1145 IF RND(1)>.4 THEN 1158\n1150 GOTO 1300\n1158 IF D=6 THEN 5100\n1160 PRINT \"BALL PASSED BACK TO YOU. \";\n1170 GOTO 430\n1180 IF RND(1)>.9 THEN 1190\n1185 PRINT \"PLAYER FOULED, TWO SHOTS.\"\n1187 GOSUB 4000\n1188 GOTO 3000\n1190 PRINT \"BALL STOLEN. \";O$;\"'S BALL.\"\n1195 GOTO 3000\n1200 IF RND(1)>.782*D/8 THEN 1250\n1210 PRINT \"SHOT IS BLOCKED.  BALL CONTROLLED BY \";\n1230 IF RND(1)>.5 THEN 1242\n1235 PRINT \"DARTMOUTH.\"\n1240 GOTO 430\n1242 PRINT O$;\".\"\n1245 GOTO 3000\n1250 IF RND(1)>.843*D/8 THEN 1270\n1255 PRINT \"SHOOTER IS FOULED.  TWO SHOTS.\"\n1260 GOSUB 4000\n1265 GOTO 3000\n1270 PRINT \"CHARGING FOUL.  DARTMOUTH LOSES BALL.\"\n1280 GOTO 3000\n1300 T=T+1\n1301 IF T=50 THEN 8000\n1302 IF T=92 THEN 1304\n1303 GOTO 1305\n1304 GOSUB 600\n1305 IF Z=0 THEN 2010\n1310 IF Z>3 THEN 1700\n1320 PRINT \"LAY UP.\"\n1330 IF 7/D*RND(1)>.4 THEN 1360\n1340 PRINT \"SHOT IS GOOD.  TWO POINTS.\"\n1345 GOSUB 7000\n1355 GOTO 3000\n1360 IF 7/D*RND(1)>.7 THEN 1500\n1370 PRINT \"SHOT IS OFF THE RIM.\"\n1380 IF RND(1)>2/3 THEN 1415\n1390 PRINT O$;\" CONTROLS THE REBOUND.\"\n1400 GOTO 3000\n1415 PRINT \"DARTMOUTH CONTROLS THE REBOUND.\"\n1420 IF RND(1)>.4 THEN 1440\n1430 GOTO 1300\n1440 PRINT \"BALL PASSED BACK TO YOU.\";\n1450 GOTO 430\n1500 IF 7/D*RND(1)>.875 THEN 1600\n1510 PRINT \"SHOOTER FOULED.  TWO SHOTS.\"\n1520 GOSUB 4000\n1530 GOTO 3000\n1600 IF 7/D*RND(1)>.925 THEN 1630\n1610 PRINT \"SHOT BLOCKED. \";O$;\"'S BALL.\"\n1620 GOTO 3000\n1630 PRINT \"CHARGING FOUL.  DARTMOUTH LOSES THE BALL.\"\n1640 GOTO 3000\n1700 PRINT \"SET SHOT.\"\n1710 GOTO 1330\n2010 INPUT \"YOUR NEW DEFENSIVE ALLIGNMENT IS\";D\n2030 IF D<6 THEN 2010\n2040 GOTO 425\n3000 P=1\n3005 T=T+1\n3008 IF T=50 THEN 8000\n3012 GOTO 3018\n3015 GOSUB 600\n3018 PRINT\n3020 Z1=10/4*RND(1)+1\n3030 IF Z1>2 THEN 3500\n3040 PRINT \"JUMP SHOT.\"\n3050 IF 8/D*RND(1)>.35 THEN 3100\n3060 PRINT \"SHOT IS GOOD.\"\n3080 GOSUB 6000\n3090 GOTO 425\n3100 IF 8/D*RND(1)>.75 THEN 3200\n3105 PRINT \"SHOT IS OFF RIM.\"\n3110 IF D/6*RND(1)>.5 THEN 3150\n3120 PRINT \"DARTMOUTH CONTROLS THE REBOUND.\"\n3130 GOTO 425\n3150 PRINT O$;\" CONTROLS THE REBOUND.\"\n3160 IF D=6 THEN 5000\n3165 IF RND(1)>.5 THEN 3175\n3168 PRINT \"PASS BACK TO \";O$;\" GUARD.\"\n3170 GOTO 3000\n3175 GOTO 3500\n3200 IF 8/D*RND(1)>.9 THEN 3310\n3210 PRINT \"PLAYER FOULED.  TWO SHOTS.\"\n3220 GOSUB 4000\n3230 GOTO 425\n3310 PRINT \"OFFENSIVE FOUL.  DARTMOUTH'S BALL.\"\n3320 GOTO 425\n3500 IF Z1>3 THEN 3800\n3510 PRINT \"LAY UP.\"\n3520 IF 7/D*RND(1)>.413 THEN 3600\n3530 PRINT \"SHOT IS GOOD.\"\n3540 GOSUB 6000\n3550 GOTO 425\n3600 PRINT \"SHOT IS MISSED.\"\n3610 GOTO 3110\n3800 PRINT \"SET SHOT.\"\n3810 GOTO 3520\n4000 REM FOUL SHOOTING\n4010 IF RND(1)>.49 THEN 4050\n4020 PRINT \"SHOOTER MAKES BOTH SHOTS.\"\n4030 S(1-P)=S(1-P)+2\n4040 GOSUB 6010\n4041 RETURN\n4050 IF RND(1)>.75 THEN 4100\n4060 PRINT \"SHOOTER MAKES ONE SHOT AND MISSES ONE.\"\n4070 S(1-P)=S(1-P)+1\n4080 GOTO 4040\n4100 PRINT \"BOTH SHOTS MISSED.\"\n4110 GOTO 4040\n5000 IF RND(1)>.75 THEN 5010\n5005 GOTO 3165\n5010 PRINT \"BALL STOLEN.  EASY LAY UP FOR DARTMOUTH.\"\n5015 GOSUB 7000\n5030 GOTO 3000\n5100 IF RND(1)>.6 THEN 5120\n5110 GOTO 1160\n5120 PRINT \"PASS STOLEN BY \";O$;\" EASY LAYUP.\"\n5130 GOSUB 6000\n5140 GOTO 425\n6000 S(0)=S(0)+2\n6010 PRINT \"SCORE: \";S(1);\"TO\";S(0)\n6020 RETURN\n7000 S(1)=S(1)+2\n7010 GOSUB 6010\n7020 RETURN\n8000 PRINT:PRINT \"   ***** END OF FIRST HALF *****\":PRINT\n8010 PRINT \"SCORE: DARTMOUTH:\";S(1);\"  \";O$;\":\";S(0)\n8015 PRINT\n8016 PRINT\n8020 GOTO 370\n9999 END\n"
  },
  {
    "path": "07_Basketball/csharp/Basketball.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "07_Basketball/csharp/Basketball.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Basketball\", \"Basketball.csproj\", \"{00D03FB3-B485-480F-B14D-746371BDE08B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{00D03FB3-B485-480F-B14D-746371BDE08B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00D03FB3-B485-480F-B14D-746371BDE08B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{00D03FB3-B485-480F-B14D-746371BDE08B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{00D03FB3-B485-480F-B14D-746371BDE08B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "07_Basketball/csharp/Clock.cs",
    "content": "using Basketball.Resources;\nusing Games.Common.IO;\n\nnamespace Basketball;\n\ninternal class Clock\n{\n    private readonly IReadWrite _io;\n    private int time;\n\n    public Clock(IReadWrite io) => _io = io;\n\n    public bool IsHalfTime => time == 50;\n    public bool IsFullTime => time >= 100;\n    public bool TwoMinutesLeft => time == 92;\n\n    public void Increment(Scoreboard scoreboard)\n    {\n        time += 1;\n        if (IsHalfTime) { scoreboard.Display(Resource.Formats.EndOfFirstHalf); }\n        if (TwoMinutesLeft) { _io.Write(Resource.Streams.TwoMinutesLeft); }\n    }\n\n    public void StartOvertime() => time = 93;\n}"
  },
  {
    "path": "07_Basketball/csharp/Defense.cs",
    "content": "namespace Basketball;\n\ninternal class Defense\n{\n    private float _value;\n\n    public Defense(float value) => Set(value);\n\n    public void Set(float value) => _value = value;\n\n    public static implicit operator float(Defense defense) => defense._value;\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Game.cs",
    "content": "using Basketball.Plays;\nusing Basketball.Resources;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\n\nnamespace Basketball;\n\ninternal class Game\n{\n    private readonly Clock _clock;\n    private readonly Scoreboard _scoreboard;\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n\n    private Game(Clock clock, Scoreboard scoreboard, TextIO io, IRandom random)\n    {\n        _clock = clock;\n        _scoreboard = scoreboard;\n        _io = io;\n        _random = random;\n    }\n\n    public static Game Create(TextIO io, IRandom random)\n    {\n        io.Write(Resource.Streams.Introduction);\n\n        var defense = new Defense(io.ReadDefense(\"Your starting defense will be\"));\n        var clock = new Clock(io);\n\n        io.WriteLine();\n\n        var scoreboard = new Scoreboard(\n            new Team(\"Dartmouth\", new HomeTeamPlay(io, random, clock, defense)),\n            new Team(io.ReadString(\"Choose your opponent\"), new VisitingTeamPlay(io, random, clock, defense)),\n            io);\n\n        return new Game(clock, scoreboard, io, random);\n    }\n\n    public void Play()\n    {\n        var ballContest = new BallContest(0.4f, \"{0} controls the tap\", _io, _random);\n\n        while (true)\n        {\n            _io.WriteLine(\"Center jump\");\n            ballContest.Resolve(_scoreboard);\n\n            _io.WriteLine();\n\n            while (true)\n            {\n                var isFullTime = _scoreboard.Offense.ResolvePlay(_scoreboard);\n                if (isFullTime && IsGameOver()) { return; }\n                if (_clock.IsHalfTime) { break; }\n            }\n        }\n    }\n\n    private bool IsGameOver()\n    {\n        _io.WriteLine();\n        if (_scoreboard.ScoresAreEqual)\n        {\n            _scoreboard.Display(Resource.Formats.EndOfSecondHalf);\n            _clock.StartOvertime();\n            return false;\n        }\n\n        _scoreboard.Display(Resource.Formats.EndOfGame);\n        return true;\n    }\n}\n"
  },
  {
    "path": "07_Basketball/csharp/IRandomExtensions.cs",
    "content": "using Games.Common.Randomness;\n\nnamespace Basketball;\n\ninternal static class IRandomExtensions\n{\n    internal static Shot NextShot(this IRandom random) => Shot.Get(random.NextFloat(1, 3.5f));\n}\n"
  },
  {
    "path": "07_Basketball/csharp/IReadWriteExtensions.cs",
    "content": "using Games.Common.IO;\n\nnamespace Basketball;\n\ninternal static class IReadWriteExtensions\n{\n    public static float ReadDefense(this IReadWrite io, string prompt)\n    {\n        while (true)\n        {\n            var defense = io.ReadNumber(prompt);\n            if (defense >= 6) { return defense; }\n        }\n    }\n\n    private static bool TryReadInteger(this IReadWrite io, string prompt, out int intValue)\n    {\n        var floatValue = io.ReadNumber(prompt);\n        intValue = (int)floatValue;\n        return intValue == floatValue;\n    }\n\n    public static Shot? ReadShot(this IReadWrite io, string prompt)\n    {\n        while (true)\n        {\n            if (io.TryReadInteger(prompt, out var value) && Shot.TryGet(value, out var shot))\n            {\n                return shot;\n            }\n            io.Write(\"Incorrect answer.  Retype it. \");\n        }\n    }\n}\n"
  },
  {
    "path": "07_Basketball/csharp/JumpShot.cs",
    "content": "namespace Basketball;\n\npublic class JumpShot : Shot\n{\n    public JumpShot()\n        : base(\"Jump shot\")\n    {\n    }\n}"
  },
  {
    "path": "07_Basketball/csharp/Plays/BallContest.cs",
    "content": "using Games.Common.IO;\nusing Games.Common.Randomness;\n\nnamespace Basketball.Plays;\n\ninternal class BallContest\n{\n    private readonly float _probability;\n    private readonly string _messageFormat;\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    internal BallContest(float probability, string messageFormat, IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _probability = probability;\n        _messageFormat = messageFormat;\n        _random = random;\n    }\n\n    internal bool Resolve(Scoreboard scoreboard)\n    {\n        var winner = _random.NextFloat() <= _probability ? scoreboard.Home : scoreboard.Visitors;\n        scoreboard.Offense = winner;\n        _io.WriteLine(_messageFormat, winner);\n        return false;\n    }\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Plays/HomeTeamPlay.cs",
    "content": "using Games.Common.IO;\nusing Games.Common.Randomness;\n\nnamespace Basketball.Plays;\n\ninternal class HomeTeamPlay : Play\n{\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n    private readonly Clock _clock;\n    private readonly Defense _defense;\n    private readonly BallContest _ballContest;\n\n    public HomeTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense)\n        : base(io, random, clock)\n    {\n        _io = io;\n        _random = random;\n        _clock = clock;\n        _defense = defense;\n        _ballContest = new BallContest(0.5f, \"Shot is blocked.  Ball controlled by {0}.\", _io, _random);\n    }\n\n    internal override bool Resolve(Scoreboard scoreboard)\n    {\n        var shot = _io.ReadShot(\"Your shot\");\n\n        if (_random.NextFloat() >= 0.5f && _clock.IsFullTime) { return true; }\n\n        if (shot is null)\n        {\n            _defense.Set(_io.ReadDefense(\"Your new defensive alignment is\"));\n            _io.WriteLine();\n            return false;\n        }\n\n        if (shot is JumpShot jumpShot)\n        {\n            if (ClockIncrementsToHalfTime(scoreboard)) { return false; }\n            if (!Resolve(jumpShot, scoreboard)) { return false; }\n        }\n\n        do\n        {\n            if (ClockIncrementsToHalfTime(scoreboard)) { return false; }\n        } while (Resolve(shot, scoreboard));\n\n        return false;\n    }\n\n    // The Resolve* methods resolve the probabilistic outcome of the current game state.\n    // They return true if the Home team should continue the play and attempt a layup, false otherwise.\n    private bool Resolve(JumpShot shot, Scoreboard scoreboard) =>\n        Resolve(shot.ToString(), _defense / 8)\n            .Do(0.341f, () => scoreboard.AddBasket(\"Shot is good\"))\n            .Or(0.682f, () => ResolveShotOffTarget(scoreboard))\n            .Or(0.782f, () => _ballContest.Resolve(scoreboard))\n            .Or(0.843f, () => ResolveFreeThrows(scoreboard, \"Shooter is fouled.  Two shots.\"))\n            .Or(() => scoreboard.Turnover($\"Charging foul.  {scoreboard.Home} loses ball.\"));\n\n    private bool Resolve(Shot shot, Scoreboard scoreboard) =>\n        Resolve(shot.ToString(), _defense / 7)\n            .Do(0.4f, () => scoreboard.AddBasket(\"Shot is good.  Two points.\"))\n            .Or(0.7f, () => ResolveShotOffTheRim(scoreboard))\n            .Or(0.875f, () => ResolveFreeThrows(scoreboard, \"Shooter fouled.  Two shots.\"))\n            .Or(0.925f, () => scoreboard.Turnover($\"Shot blocked. {scoreboard.Visitors}'s ball.\"))\n            .Or(() => scoreboard.Turnover($\"Charging foul.  {scoreboard.Home} loses ball.\"));\n\n    private bool ResolveShotOffTarget(Scoreboard scoreboard) =>\n        Resolve(\"Shot is off target\", 6 / _defense)\n            .Do(0.45f, () => ResolveHomeRebound(scoreboard, ResolvePossibleSteal))\n            .Or(() => scoreboard.Turnover($\"Rebound to {scoreboard.Visitors}\"));\n\n    private bool ResolveHomeRebound(Scoreboard scoreboard, Action<Scoreboard> endOfPlayAction) =>\n        Resolve($\"{scoreboard.Home} controls the rebound.\")\n            .Do(0.4f, () => true)\n            .Or(() => endOfPlayAction.Invoke(scoreboard));\n    private void ResolvePossibleSteal(Scoreboard scoreboard)\n    {\n        if (_defense == 6 && _random.NextFloat() > 0.6f)\n        {\n            scoreboard.Turnover();\n            scoreboard.AddBasket($\"Pass stolen by {scoreboard.Visitors} easy layup.\");\n            _io.WriteLine();\n        }\n        _io.Write(\"Ball passed back to you. \");\n    }\n\n    private void ResolveShotOffTheRim(Scoreboard scoreboard) =>\n        Resolve(\"Shot is off the rim.\")\n            .Do(2 / 3f, () => scoreboard.Turnover($\"{scoreboard.Visitors} controls the rebound.\"))\n            .Or(() => ResolveHomeRebound(scoreboard, _ => _io.WriteLine(\"Ball passed back to you.\")));\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Plays/Play.cs",
    "content": "using Games.Common.IO;\nusing Games.Common.Randomness;\n\nnamespace Basketball.Plays;\n\ninternal abstract class Play\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    private readonly Clock _clock;\n\n    public Play(IReadWrite io, IRandom random, Clock clock)\n    {\n        _io = io;\n        _random = random;\n        _clock = clock;\n    }\n\n    protected bool ClockIncrementsToHalfTime(Scoreboard scoreboard)\n    {\n        _clock.Increment(scoreboard);\n        return _clock.IsHalfTime;\n    }\n\n    internal abstract bool Resolve(Scoreboard scoreboard);\n\n    protected void ResolveFreeThrows(Scoreboard scoreboard, string message) =>\n        Resolve(message)\n            .Do(0.49f, () => scoreboard.AddFreeThrows(2, \"Shooter makes both shots.\"))\n            .Or(0.75f, () => scoreboard.AddFreeThrows(1, \"Shooter makes one shot and misses one.\"))\n            .Or(() => scoreboard.AddFreeThrows(0, \"Both shots missed.\"));\n\n    protected Probably Resolve(string message) => Resolve(message, 1f);\n\n    protected Probably Resolve(string message, float defenseFactor)\n    {\n        _io.WriteLine(message);\n        return new Probably(defenseFactor, _random);\n    }\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Plays/VisitingTeamPlay.cs",
    "content": "using Games.Common.IO;\nusing Games.Common.Randomness;\n\nnamespace Basketball.Plays;\n\ninternal class VisitingTeamPlay : Play\n{\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n    private readonly Defense _defense;\n\n    public VisitingTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense)\n        : base(io, random, clock)\n    {\n        _io = io;\n        _random = random;\n        _defense = defense;\n    }\n\n    internal override bool Resolve(Scoreboard scoreboard)\n    {\n        if (ClockIncrementsToHalfTime(scoreboard)) { return false; }\n\n        _io.WriteLine();\n        var shot = _random.NextShot();\n\n        if (shot is JumpShot jumpShot)\n        {\n            var continuePlay = Resolve(jumpShot, scoreboard);\n            _io.WriteLine();\n            if (!continuePlay) { return false; }\n        }\n\n        while (true)\n        {\n            var continuePlay = Resolve(shot, scoreboard);\n            _io.WriteLine();\n            if (!continuePlay) { return false; }\n        }\n    }\n\n    // The Resolve* methods resolve the probabilistic outcome of the current game state.\n    // They return true if the Visiting team should continue the play and attempt a layup, false otherwise.\n    private bool Resolve(JumpShot shot, Scoreboard scoreboard) =>\n        Resolve(shot.ToString(), _defense / 8)\n            .Do(0.35f, () => scoreboard.AddBasket(\"Shot is good.\"))\n            .Or(0.75f, () => ResolveBadShot(scoreboard, \"Shot is off the rim.\", _defense * 6))\n            .Or(0.9f, () => ResolveFreeThrows(scoreboard, \"Player fouled.  Two shots.\"))\n            .Or(() => _io.WriteLine($\"Offensive foul.  {scoreboard.Home}'s ball.\"));\n\n    private bool Resolve(Shot shot, Scoreboard scoreboard) =>\n        Resolve(shot.ToString(), _defense / 7)\n            .Do(0.413f, () => scoreboard.AddBasket(\"Shot is good.\"))\n            .Or(() => ResolveBadShot(scoreboard, \"Shot is missed.\", 6 / _defense));\n\n    private bool ResolveBadShot(Scoreboard scoreboard, string message, float defenseFactor) =>\n        Resolve(message, defenseFactor)\n            .Do(0.5f, () => scoreboard.Turnover($\"{scoreboard.Home} controls the rebound.\"))\n            .Or(() => ResolveVisitorsRebound(scoreboard));\n\n    private bool ResolveVisitorsRebound(Scoreboard scoreboard)\n    {\n        _io.Write($\"{scoreboard.Visitors} controls the rebound.\");\n        if (_defense == 6 && _random.NextFloat() <= 0.25f)\n        {\n            _io.WriteLine();\n            scoreboard.Turnover();\n            scoreboard.AddBasket($\"Ball stolen.  Easy lay up for {scoreboard.Home}.\");\n            return false;\n        }\n\n        if (_random.NextFloat() <= 0.5f)\n        {\n            _io.WriteLine();\n            _io.Write($\"Pass back to {scoreboard.Visitors} guard.\");\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Probably.cs",
    "content": "using Games.Common.Randomness;\n\nnamespace Basketball;\n\n/// <summary>\n/// Supports a chain of actions to be performed based on various probabilities. The original game code gets a new\n/// random number for each probability check. Evaluating a set of probabilities against a single random number is\n/// much simpler, but yield a very different outcome distribution. The purpose of this class is to simplify the code\n/// to for the original probabilistic branch decisions.\n/// </summary>\ninternal struct Probably\n{\n    private readonly float _defenseFactor;\n    private readonly IRandom _random;\n    private readonly bool? _result;\n\n    internal Probably(float defenseFactor, IRandom random, bool? result = null)\n    {\n        _defenseFactor = defenseFactor;\n        _random = random;\n        _result = result;\n    }\n\n    public Probably Do(float probability, Action action) =>\n        ShouldResolveAction(probability)\n            ? new Probably(_defenseFactor, _random, Resolve(action) ?? false)\n            : this;\n\n    public Probably Do(float probability, Func<bool> action) =>\n        ShouldResolveAction(probability)\n            ? new Probably(_defenseFactor, _random, Resolve(action) ?? false)\n            : this;\n\n    public Probably Or(float probability, Action action) => Do(probability, action);\n\n    public Probably Or(float probability, Func<bool> action) => Do(probability, action);\n\n    public bool Or(Action action) => _result ?? Resolve(action) ?? false;\n\n    private bool? Resolve(Action action)\n    {\n        action.Invoke();\n        return _result;\n    }\n\n    private bool? Resolve(Func<bool> action) => action.Invoke();\n\n    private readonly bool ShouldResolveAction(float probability) =>\n        _result is null && _random.NextFloat() <= probability * _defenseFactor;\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Program.cs",
    "content": "using Basketball;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\n\nvar game = Game.Create(new ConsoleIO(), new RandomNumberGenerator());\n\ngame.Play();"
  },
  {
    "path": "07_Basketball/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "07_Basketball/csharp/Resources/EndOfFirstHalf.txt",
    "content": "\n   ***** End of first half *****\n\nScore: {0}: {1}    {2}: {3}\n\n"
  },
  {
    "path": "07_Basketball/csharp/Resources/EndOfGame.txt",
    "content": "   ***** End of game *****\nFinal score: {0}: {1}    {2}: {3}"
  },
  {
    "path": "07_Basketball/csharp/Resources/EndOfSecondHalf.txt",
    "content": "\n   ***** End of second half *****\n\nScore at end of regulation time:\n         {0}: {1}    {2}: {3}\n\nBegin two minute overtime period"
  },
  {
    "path": "07_Basketball/csharp/Resources/Introduction.txt",
    "content": "                               Basketball\n               Creative Computing  Morristown, New Jersey\n\n\n\nThis is Dartmouth College basketball.  You will be Dartmouth\n captain and playmaker.  Call shots as follows:  1. Long\n (30 ft.) jump shot; 2. Short (15 ft.) jump shot; 3. Lay\n up; 4. Set shot.\nBoth teams will use the same defense.  Call defense as\nfollows:  6. Press; 6.5 Man-to-man; 7. Zone; 7.5 None.\nTo change defense, just type 0 as your next shot."
  },
  {
    "path": "07_Basketball/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Basketball.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n        public static Stream TwoMinutesLeft => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string EndOfFirstHalf => GetString();\n        public static string EndOfGame => GetString();\n        public static string EndOfSecondHalf => GetString();\n        public static string Score => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Basketball.Resources.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "07_Basketball/csharp/Resources/Score.txt",
    "content": "Score:  {1} to {3}"
  },
  {
    "path": "07_Basketball/csharp/Resources/TwoMinutesLeft.txt",
    "content": "\n   *** Two minutes left in the game ***\n\n"
  },
  {
    "path": "07_Basketball/csharp/Scoreboard.cs",
    "content": "using Basketball.Resources;\nusing Games.Common.IO;\n\nnamespace Basketball;\n\ninternal class Scoreboard\n{\n    private readonly Dictionary<Team, uint> _scores;\n    private readonly IReadWrite _io;\n\n    public Scoreboard(Team home, Team visitors, IReadWrite io)\n    {\n        _scores = new() { [home] = 0, [visitors] = 0 };\n        Home = home;\n        Visitors = visitors;\n        Offense = home;  // temporary value till first center jump\n        _io = io;\n    }\n\n    public bool ScoresAreEqual => _scores[Home] == _scores[Visitors];\n    public Team Offense { get; set; }\n    public Team Home { get; }\n    public Team Visitors { get; }\n\n    public void AddBasket(string message) => AddScore(2, message);\n\n    public void AddFreeThrows(uint count, string message) => AddScore(count, message);\n\n    private void AddScore(uint score, string message)\n    {\n        if (Offense is null) { throw new InvalidOperationException(\"Offense must be set before adding to score.\"); }\n\n        _io.WriteLine(message);\n        _scores[Offense] += score;\n        Turnover();\n        Display();\n    }\n\n    public void Turnover(string? message = null)\n    {\n        if (message is not null) { _io.WriteLine(message); }\n\n        Offense = Offense == Home ? Visitors : Home;\n    }\n\n    public void Display(string? format = null) =>\n        _io.WriteLine(format ?? Resource.Formats.Score, Home, _scores[Home], Visitors, _scores[Visitors]);\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Shot.cs",
    "content": "namespace Basketball;\n\npublic class Shot\n{\n    private readonly string _name;\n\n    public Shot(string name)\n    {\n        _name = name;\n    }\n\n    public static bool TryGet(int shotNumber, out Shot? shot)\n    {\n        shot = shotNumber switch\n        {\n            // Although the game instructions reference two different jump shots,\n            // the original game code treats them both the same and just prints \"Jump shot\"\n            0 => null,\n            <= 2 => new JumpShot(),\n            3 => new Shot(\"Lay up\"),\n            4 => new Shot(\"Set shot\"),\n            _ => null\n        };\n        return shotNumber == 0 || shot is not null;\n    }\n\n    public static Shot Get(float shotNumber) =>\n        shotNumber switch\n        {\n            <= 2 => new JumpShot(),\n            > 3 => new Shot(\"Set shot\"),\n            > 2 => new Shot(\"Lay up\"),\n            _ => throw new Exception(\"Unexpected value\")\n        };\n\n    public override string ToString() => _name;\n}\n"
  },
  {
    "path": "07_Basketball/csharp/Team.cs",
    "content": "using Basketball.Plays;\n\nnamespace Basketball;\n\ninternal record Team(string Name, Play PlayResolver)\n{\n    public override string ToString() => Name;\n\n    public bool ResolvePlay(Scoreboard scoreboard) => PlayResolver.Resolve(scoreboard);\n}\n"
  },
  {
    "path": "07_Basketball/java/Basketball.java",
    "content": "import java.lang.Math;\nimport java.util.*;\nimport java.util.Scanner;\n\n/* The basketball class is a computer game that allows you to play as\n  Dartmouth College's captain and playmaker\n  The game uses set probabilites to simulate outcomes of each posession\n  You are able to choose your shot types as well as defensive formations */\n\npublic class Basketball {\n    int time = 0;\n    int[] score = {0, 0};\n    double defense = -1;\n    List<Double> defense_choices = Arrays.asList(6.0, 6.5, 7.0, 7.5);\n    int shot = -1;\n    List<Integer> shot_choices = Arrays.asList(0, 1, 2, 3, 4);\n    double opponent_chance = 0;\n    String opponent = null;\n\n    public Basketball() {\n\n        // Explains the keyboard inputs\n        System.out.println(\"\\t\\t\\t Basketball\");\n        System.out.println(\"\\t Creative Computing  Morristown, New Jersey\\n\\n\\n\");\n        System.out.println(\"This is Dartmouth College basketball. \");\n        System.out.println(\"Υou will be Dartmouth captain and playmaker.\");\n        System.out.println(\"Call shots as follows:\");\n        System.out.println(\"1. Long (30ft.) Jump Shot; 2. Short (15 ft.) Jump Shot; \"\n              + \"3. Lay up; 4. Set Shot\");\n        System.out.println(\"Both teams will use the same defense. Call Defense as follows:\");\n        System.out.println(\"6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None.\");\n        System.out.println(\"To change defense, just type 0 as your next shot.\");\n        System.out.print(\"Your starting defense will be? \");\n\n        Scanner scanner = new Scanner(System.in); // creates a scanner\n\n        // takes input for a defense\n        if (scanner.hasNextDouble()) {\n            defense = scanner.nextDouble();\n        }\n        else {\n            scanner.next();\n        }\n\n        // makes sure that input is legal\n        while (!defense_choices.contains(defense)) {\n            System.out.print(\"Your new defensive allignment is? \");\n            if (scanner.hasNextDouble()) {\n                defense = scanner.nextDouble();\n            }\n            else {\n                scanner.next();\n                continue;\n            }\n        }\n\n        // takes input for opponent's name\n        System.out.print(\"\\nChoose your opponent? \");\n\n        opponent = scanner.next();\n        start_of_period();\n    }\n\n    // adds points to the score\n    // team can take 0 or 1, for opponent or Dartmouth, respectively\n    private void add_points(int team, int points) {\n        score[team] += points;\n        print_score();\n    }\n\n\n    private void ball_passed_back() {\n        System.out.print(\"Ball passed back to you. \");\n        dartmouth_ball();\n    }\n\n    // change defense, called when the user enters 0 for their shot\n    private void change_defense() {\n        defense = -1;\n        Scanner scanner = new Scanner(System.in); // creates a scanner\n\n        while (!defense_choices.contains(defense)) {\n            System.out.println(\"Your new defensive allignment is? \");\n            if (scanner.hasNextDouble()) {\n                defense = (double)(scanner.nextDouble());\n            }\n            else {\n                continue;\n            }\n        }\n\n        dartmouth_ball();\n    }\n\n    // simulates two foul shots for a player and adds the points\n    private void foul_shots(int team) {\n        System.out.println(\"Shooter fouled.  Two shots.\");\n\n        if (Math.random() > .49) {\n            if (Math.random() > .75) {\n                System.out.println(\"Both shots missed.\");\n            }\n            else {\n                System.out.println(\"Shooter makes one shot and misses one.\");\n                score[team] += 1;\n            }\n        }\n        else {\n            System.out.println(\"Shooter makes both shots.\");\n            score[team] += 2;\n        }\n\n        print_score();\n    }\n\n    // called when time = 50, starts a new period\n    private void halftime() {\n        System.out.println(\"\\n   ***** End of first half *****\\n\");\n        print_score();\n        start_of_period();\n    }\n\n    // prints the current score\n    private void print_score() {\n        System.out.println(\"Score:  \" + score[1] + \" to \" + score[0] + \"\\n\");\n    }\n\n    // simulates a center jump for posession at the beginning of a period\n    private void start_of_period() {\n        System.out.println(\"Center jump\");\n        if (Math.random() > .6) {\n            System.out.println(\"Dartmouth controls the tap.\\n\");\n            dartmouth_ball();\n        }\n        else {\n            System.out.println(opponent + \" controls the tap.\\n\");\n            opponent_ball();\n        }\n    }\n\n    // called when t = 92\n    private void two_minute_warning() {\n        System.out.println(\"   *** Two minutes left in the game ***\");\n    }\n\n    // called when the user enters 1 or 2 for their shot\n    private void dartmouth_jump_shot() {\n        time ++;\n        if (time == 50) {\n            halftime();\n        }\n        else if (time == 92) {\n            two_minute_warning();\n        }\n\n        System.out.println(\"Jump Shot.\");\n        // simulates chances of different possible outcomes\n        if (Math.random() > .341 * defense / 8) {\n            if (Math.random() > .682 * defense / 8) {\n                if (Math.random() > .782 * defense / 8) {\n                    if (Math.random() > .843 * defense / 8) {\n                        System.out.println(\"Charging foul. Dartmouth loses ball.\\n\");\n                        opponent_ball();\n                    }\n                    else {\n                        // player is fouled\n                        foul_shots(1);\n                        opponent_ball();\n                    }\n                }\n                else {\n                    if (Math.random() > .5) {\n                        System.out.println(\"Shot is blocked. Ball controlled by \" +\n                              opponent + \".\\n\");\n                        opponent_ball();\n                    }\n                    else {\n                        System.out.println(\"Shot is blocked. Ball controlled by Dartmouth.\");\n                        dartmouth_ball();\n                    }\n                }\n            }\n            else {\n                System.out.println(\"Shot is off target.\");\n                if (defense / 6 * Math.random() > .45) {\n                    System.out.println(\"Rebound to \" + opponent + \"\\n\");\n                    opponent_ball();\n                }\n                else {\n                    System.out.println(\"Dartmouth controls the rebound.\");\n                    if (Math.random() > .4) {\n                        if (defense == 6 && Math.random() > .6) {\n                            System.out.println(\"Pass stolen by \" + opponent\n                                  + \", easy lay up\");\n                            add_points(0, 2);\n                            dartmouth_ball();\n                        }\n                        else {\n                            // ball is passed back to you\n                            ball_passed_back();\n                        }\n                    }\n                    else {\n                        System.out.println(\"\");\n                        dartmouth_non_jump_shot();\n                    }\n                }\n            }\n        }\n        else {\n            System.out.println(\"Shot is good.\");\n            add_points(1, 2);\n            opponent_ball();\n        }\n    }\n\n    // called when the user enters 0, 3, or 4\n    // lay up, set shot, or defense change\n    private void dartmouth_non_jump_shot() {\n        time ++;\n        if (time == 50) {\n            halftime();\n        }\n        else if (time == 92) {\n            two_minute_warning();\n        }\n\n        if (shot == 4) {\n            System.out.println(\"Set shot.\");\n        }\n        else if (shot == 3) {\n            System.out.println(\"Lay up.\");\n        }\n        else if (shot == 0) {\n            change_defense();\n        }\n\n        // simulates different outcomes after a lay up or set shot\n        if (7/defense*Math.random() > .4) {\n            if (7/defense*Math.random() > .7) {\n                if (7/defense*Math.random() > .875) {\n                    if (7/defense*Math.random() > .925) {\n                        System.out.println(\"Charging foul. Dartmouth loses the ball.\\n\");\n                        opponent_ball();\n                    }\n                    else {\n                        System.out.println(\"Shot blocked. \" + opponent + \"'s ball.\\n\");\n                        opponent_ball();\n                    }\n                }\n                else {\n                    foul_shots(1);\n                    opponent_ball();\n                }\n            }\n            else {\n                System.out.println(\"Shot is off the rim.\");\n                if (Math.random() > 2/3) {\n                    System.out.println(\"Dartmouth controls the rebound.\");\n                    if (Math.random() > .4) {\n                        System.out.println(\"Ball passed back to you.\\n\");\n                        dartmouth_ball();\n                    }\n                    else {\n                        dartmouth_non_jump_shot();\n                    }\n                }\n                else {\n                    System.out.println(opponent + \" controls the rebound.\\n\");\n                    opponent_ball();\n                }\n            }\n        }\n        else {\n            System.out.println(\"Shot is good. Two points.\");\n            add_points(1, 2);\n            opponent_ball();\n        }\n    }\n\n\n    // plays out a Dartmouth posession, starting with your choice of shot\n    private void dartmouth_ball() {\n        Scanner scanner = new Scanner(System.in); // creates a scanner\n        System.out.print(\"Your shot? \");\n        shot = -1;\n        if (scanner.hasNextInt()) {\n            shot = scanner.nextInt();\n        }\n        else {\n            System.out.println(\"\");\n            scanner.next();\n        }\n\n        while (!shot_choices.contains(shot)) {\n            System.out.print(\"Incorrect answer. Retype it. Your shot?\");\n            if (scanner.hasNextInt()) {\n                shot = scanner.nextInt();\n            }\n            else {\n                System.out.println(\"\");\n                scanner.next();\n            }\n        }\n\n        if (time < 100 || Math.random() < .5) {\n            if (shot == 1 || shot == 2) {\n                dartmouth_jump_shot();\n            }\n            else {\n                dartmouth_non_jump_shot();\n            }\n        }\n        else {\n            if (score[0] != score[1]) {\n                System.out.println(\"\\n   ***** End Of Game *****\");\n                System.out.println(\"Final Score: Dartmouth: \" + score[1] + \"  \"\n                      + opponent + \": \" + score[0]);\n                System.exit(0);\n            }\n            else {\n                System.out.println(\"\\n   ***** End Of Second Half *****\");\n                System.out.println(\"Score at end of regulation time:\");\n                System.out.println(\"     Dartmouth: \" + score[1] + \" \" +\n                      opponent + \": \" + score[0]);\n                System.out.println(\"Begin two minute overtime period\");\n                time = 93;\n                start_of_period();\n            }\n        }\n    }\n\n    // simulates the opponents jumpshot\n    private void opponent_jumpshot() {\n        System.out.println(\"Jump Shot.\");\n        if (8/defense*Math.random() > .35) {\n            if (8/defense*Math.random() > .75) {\n                if (8/defense*Math.random() > .9) {\n                    System.out.println(\"Offensive foul. Dartmouth's ball.\\n\");\n                    dartmouth_ball();\n                }\n                else {\n                    foul_shots(0);\n                    dartmouth_ball();\n                }\n            }\n            else {\n                System.out.println(\"Shot is off the rim.\");\n                if (defense/6*Math.random() > .5) {\n                    System.out.println(opponent + \" controls the rebound.\");\n                    if (defense == 6) {\n                        if (Math.random() > .75) {\n                            System.out.println(\"Ball stolen. Easy lay up for Dartmouth.\");\n                            add_points(1, 2);\n                            opponent_ball();\n                        }\n                        else {\n                            if (Math.random() > .5) {\n                                System.out.println(\"\");\n                                opponent_non_jumpshot();\n                            }\n                            else {\n                                System.out.println(\"Pass back to \" + opponent +\n                                      \" guard.\\n\");\n                                opponent_ball();\n                            }\n                        }\n                    }\n                    else {\n                        if (Math.random() > .5) {\n                            opponent_non_jumpshot();\n                        }\n                        else {\n                            System.out.println(\"Pass back to \" + opponent +\n                                  \" guard.\\n\");\n                            opponent_ball();\n                        }\n                    }\n                }\n                else {\n                    System.out.println(\"Dartmouth controls the rebound.\\n\");\n                    dartmouth_ball();\n                }\n            }\n        }\n        else {\n            System.out.println(\"Shot is good.\");\n            add_points(0, 2);\n            dartmouth_ball();\n        }\n    }\n\n    // simulates opponents lay up or set shot\n    private void opponent_non_jumpshot() {\n        if (opponent_chance > 3) {\n            System.out.println(\"Set shot.\");\n        }\n        else {\n            System.out.println(\"Lay up\");\n        }\n        if (7/defense*Math.random() > .413) {\n            System.out.println(\"Shot is missed.\");\n            if (defense/6*Math.random() > .5) {\n                System.out.println(opponent + \" controls the rebound.\");\n                if (defense == 6) {\n                    if (Math.random() > .75) {\n                        System.out.println(\"Ball stolen. Easy lay up for Dartmouth.\");\n                        add_points(1, 2);\n                        opponent_ball();\n                    }\n                    else {\n                        if (Math.random() > .5) {\n                            System.out.println(\"\");\n                            opponent_non_jumpshot();\n                        }\n                        else {\n                            System.out.println(\"Pass back to \" + opponent +\n                                  \" guard.\\n\");\n                            opponent_ball();\n                        }\n                    }\n                }\n                else {\n                    if (Math.random() > .5) {\n                        System.out.println(\"\");\n                        opponent_non_jumpshot();\n                    }\n                    else {\n                        System.out.println(\"Pass back to \" + opponent + \" guard\\n\");\n                        opponent_ball();\n                    }\n                }\n            }\n            else {\n                System.out.println(\"Dartmouth controls the rebound.\\n\");\n                dartmouth_ball();\n            }\n        }\n        else {\n            System.out.println(\"Shot is good.\");\n            add_points(0, 2);\n            dartmouth_ball();\n        }\n    }\n\n    // simulates an opponents possesion\n    // #randomly picks jump shot or lay up / set shot.\n    private void opponent_ball() {\n        time ++;\n        if (time == 50) {\n            halftime();\n        }\n        opponent_chance = 10/4*Math.random()+1;\n        if (opponent_chance > 2) {\n            opponent_non_jumpshot();\n        }\n        else {\n            opponent_jumpshot();\n        }\n    }\n\n    public static void main(String[] args) {\n        Basketball new_game = new Basketball();\n    }\n}\n"
  },
  {
    "path": "07_Basketball/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "07_Basketball/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "07_Basketball/javascript/basketball.html",
    "content": "<html>\n<head>\n<title>BASKETBALL</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"basketball.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "07_Basketball/javascript/basketball.js",
    "content": "// BASKETBALL\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar s = [0, 0];\nvar z;\nvar d;\nvar p;\nvar your_turn;\nvar game_restart;\n\nfunction two_minutes()\n{\n    print(\"\\n\");\n    print(\"   *** TWO MINUTES LEFT IN THE GAME ***\\n\");\n    print(\"\\n\");\n}\n\nfunction show_scores()\n{\n    print(\"SCORE: \" + s[1] + \" TO \" + s[0] + \"\\n\");\n}\n\nfunction score_computer()\n{\n    s[0] = s[0] + 2;\n    show_scores();\n}\n\nfunction score_player()\n{\n    s[1] = s[1] + 2;\n    show_scores();\n}\n\nfunction half_time()\n{\n    print(\"\\n\");\n    print(\"   ***** END OF FIRST HALF *****\\n\");\n    print(\"SCORE: DARMOUTH: \" + s[1] + \"  \" + os + \": \" + s[0] + \"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nfunction foul()\n{\n    if (Math.random() <= 0.49) {\n        print(\"SHOOTER MAKES BOTH SHOTS.\\n\");\n        s[1 - p] = s[1 - p] + 2;\n        show_scores();\n    } else if (Math.random() <= 0.75) {\n        print(\"SHOOTER MAKES ONE SHOT AND MISSES ONE.\\n\");\n        s[1 - p] = s[1 - p] + 1;\n        show_scores();\n    } else {\n        print(\"BOTH SHOTS MISSED.\\n\");\n        show_scores();\n    }\n}\n\nfunction player_play()\n{\n    if (z == 1 || z == 2) {\n        t++;\n        if (t == 50) {\n            half_time();\n            game_restart = 1;\n            return;\n        }\n        if (t == 92)\n            two_minutes();\n        print(\"JUMP SHOT\\n\");\n        if (Math.random() <= 0.341 * d / 8) {\n            print(\"SHOT IS GOOD.\\n\");\n            score_player();\n            return;\n        }\n        if (Math.random() <= 0.682 * d / 8) {\n            print(\"SHOT IS OFF TARGET.\\n\");\n            if (d / 6 * Math.random() >= 0.45) {\n                print(\"REBOUND TO \" + os + \"\\n\");\n                return;\n            }\n            print(\"DARTMOUTH CONTROLS THE REBOUND.\\n\");\n            if (Math.random() > 0.4) {\n                if (d == 6) {\n                    if (Math.random() > 0.6) {\n                        print(\"PASS STOLEN BY \" + os + \" EASY LAYUP.\\n\");\n                        score_computer();\n                        return;\n                    }\n                }\n                print(\"BALL PASSED BACK TO YOU. \");\n                your_turn = 1;\n                return;\n            }\n        } else if (Math.random() <= 0.782 * d / 8) {\n            print(\"SHOT IS BLOCKED.  BALL CONTROLLED BY \");\n            if (Math.random() <= 0.5) {\n                print(\"DARTMOUTH.\\n\");\n                your_turn = 1;\n                return;\n            }\n            print(os + \".\\n\");\n            return;\n        } else if (Math.random() <= 0.843 * d / 8) {\n            print(\"SHOOTER IS FOULED.  TWO SHOTS.\\n\");\n            foul();\n            return;\n            // In original code but lines 1180-1195 aren't used (maybe replicate from computer's play)\n            //        } else if (Math.random() <= 0.9 * d / 8) {\n            //            print(\"PLAYER FOULED, TWO SHOTS.\\n\");\n            //            foul();\n            //            return;\n        } else {\n            print(\"CHARGING FOUL.  DARTMOUTH LOSES BALL.\\n\");\n            return;\n        }\n    }\n    while (1) {\n        if (++t == 50) {\n            half_time();\n            game_restart = 1;\n            return;\n        }\n        if (t == 92)\n            two_minutes();\n        if (z == 0) {\n            your_turn = 2;\n            return;\n        }\n        if (z <= 3)\n            print(\"LAY UP.\\n\");\n        else\n            print(\"SET SHOT.\\n\");\n        if (7 / d * Math.random() <= 0.4) {\n            print(\"SHOT IS GOOD.  TWO POINTS.\\n\");\n            score_player();\n            return;\n        }\n        if (7 / d * Math.random() <= 0.7) {\n            print(\"SHOT IS OFF THE RIM.\\n\");\n            if (Math.random() <= 2.0 / 3.0) {\n                print(os + \" CONTROLS THE REBOUND.\\n\");\n                return;\n            }\n            print(\"DARMOUTH CONTROLS THE REBOUND.\\n\");\n            if (Math.random() <= 0.4)\n                continue;\n            print(\"BALL PASSED BACK TO YOU.\\n\");\n            your_turn = 1;\n            return;\n        }\n        if (7 /d * Math.random() <= 0.875) {\n            print(\"SHOOTER FOULED.  TWO SHOTS.\\n\");\n            foul();\n            return;\n        }\n        if (7 /d * Math.random() <= 0.925) {\n            print(\"SHOT BLOCKED. \" + os + \"'S BALL.\\n\");\n            return;\n        }\n        print(\"CHARGING FOUL.  DARTHMOUTH LOSES THE BALL.\\n\");\n        return;\n    }\n}\n\nfunction computer_play()\n{\n    rebound = 0;\n    while (1) {\n        p = 1;\n        if (++t == 50) {\n            half_time();\n            game_restart = 1;\n            return;\n        }\n        print(\"\\n\");\n        z1 = 10 / 4 * Math.random() + 1;\n        if (z1 <= 2) {\n            print(\"JUMP SHOT.\\n\");\n            if (8 / d * Math.random() <= 0.35) {\n                print(\"SHOT IS GOOD.\\n\");\n                score_computer();\n                return;\n            }\n            if (8 / d * Math.random() <= 0.75) {\n                print(\"SHOT IS OFF RIM.\\n\");\n                if (d / 6 * Math.random() <= 0.5) {\n                    print(\"DARMOUTH CONTROLS THE REBOUND.\\n\");\n                    return;\n                }\n                print(os + \" CONTROLS THE REBOUND.\\n\");\n                if (d == 6) {\n                    if (Math.random() <= 0.75) {\n                        print(\"BALL STOLEN.  EASY LAP UP FOR DARTMOUTH.\\n\");\n                        score_player();\n                        continue;\n                    }\n                    if (Math.random() > 0.6) {\n                        print(\"PASS STOLEN BY \" + os + \" EASY LAYUP.\\n\");\n                        score_computer();\n                        return;\n                    }\n                    print(\"BALL PASSED BACK TO YOU. \");\n                    return;\n                }\n                if (Math.random() <= 0.5) {\n                    print(\"PASS BACK TO \" + os + \" GUARD.\\n\");\n                    continue;\n                }\n            } else if (8 / d * Math.random() <= 0.90) {\n                print(\"PLAYER FOULED.  TWO SHOTS.\\n\");\n                foul();\n                return;\n            } else {\n                print(\"OFFENSIVE FOUL.  DARTMOUTH'S BALL.\\n\");\n                return;\n            }\n        }\n        while (1) {\n            if (z1 > 3) {\n                print(\"SET SHOT.\\n\");\n            } else {\n                print(\"LAY UP.\\n\");\n            }\n            if (7 / d * Math.random() <= 0.413) {\n                print(\"SHOT IS GOOD.\\n\");\n                score_computer();\n                return;\n            }\n            print(\"SHOT IS MISSED.\\n\");\n            // Spaguetti jump, better to replicate code\n            if (d / 6 * Math.random() <= 0.5) {\n                print(\"DARMOUTH CONTROLS THE REBOUND.\\n\");\n                return;\n            }\n            print(os + \" CONTROLS THE REBOUND.\\n\");\n            if (d == 6) {\n                if (Math.random() <= 0.75) {\n                    print(\"BALL STOLEN.  EASY LAP UP FOR DARTMOUTH.\\n\");\n                    score_player();\n                    break;\n                }\n                if (Math.random() > 0.6) {\n                    print(\"PASS STOLEN BY \" + os + \" EASY LAYUP.\\n\");\n                    score_computer();\n                    return;\n                }\n                print(\"BALL PASSED BACK TO YOU. \");\n                return;\n            }\n            if (Math.random() <= 0.5) {\n                print(\"PASS BACK TO \" + os + \" GUARD.\\n\");\n                break;\n            }\n        }\n    }\n}\n\n// Main program\nasync function main()\n{\n    print(tab(31) + \"BASKETBALL\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS DARTMOUTH COLLEGE BASKETBALL.  YOU WILL BE DARTMOUTH\\n\");\n    print(\" CAPTAIN AND PLAYMAKER.  CALL SHOTS AS FOLLOWS:  1. LONG\\n\");\n    print(\" (30 FT.) JUMP SHOT; 2. SHORT (15 FT.) JUMP SHOT; 3. LAY\\n\");\n    print(\" UP; 4. SET SHOT.\\n\");\n    print(\"BOTH TEAMS WILL USE THE SAME DEFENSE.  CALL DEFENSE AS\\n\");\n    print(\"FOLLOWS:  6. PRESS; 6.5 MAN-TO MAN; 7. ZONE; 7.5 NONE.\\n\");\n    print(\"TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\\n\");\n    print(\"YOUR STARTING DEFENSE WILL BE\");\n    t = 0;\n    p = 0;\n    d = parseFloat(await input());\n    if (d < 6) {\n        your_turn = 2;\n    } else {\n        print(\"\\n\");\n        print(\"CHOOSE YOUR OPPONENT\");\n        os = await input();\n        game_restart = 1;\n    }\n    while (1) {\n        if (game_restart) {\n            game_restart = 0;\n            print(\"CENTER JUMP\\n\");\n            if (Math.random() > 3.0 / 5.0) {\n                print(\"DARMOUTH CONTROLS THE TAP.\\n\");\n            } else {\n                print(os + \" CONTROLS THE TAP.\\n\");\n                computer_play();\n            }\n        }\n        if (your_turn == 2) {\n            print(\"YOUR NEW DEFENSIVE ALLIGNMENT IS\");\n            d = parseFloat(await input());\n        }\n        print(\"\\n\");\n        while (1) {\n            print(\"YOUR SHOT\");\n            z = parseInt(await input());\n            p = 0;\n            if (z != Math.floor(z) || z < 0 || z > 4)\n                print(\"INCORRECT ANSWER.  RETYPE IT. \");\n            else\n                break;\n        }\n        if (Math.random() < 0.5 || t < 100) {\n            game_restart = 0;\n            your_turn = 0;\n            player_play();\n            if (game_restart == 0 && your_turn == 0)\n                computer_play();\n        } else {\n            print(\"\\n\");\n            if (s[1] == s[0]) {\n                print(\"\\n\");\n                print(\"   ***** END OF SECOND HALF *****\\n\");\n                print(\"\\n\");\n                print(\"SCORE AT END OF REGULATION TIME:\\n\");\n                print(\"        DARTMOUTH: \" + s[1] + \"  \" + os + \": \" + s[0] + \"\\n\");\n                print(\"\\n\");\n                print(\"BEGIN TWO MINUTE OVERTIME PERIOD\\n\");\n                t = 93;\n                print(\"CENTER JUMP\\n\");\n                if (Math.random() > 3.0 / 5.0)\n                    print(\"DARMOUTH CONTROLS THE TAP.\\n\");\n                else\n                    print(os + \" CONTROLS THE TAP.\\n\");\n            } else {\n                print(\"   ***** END OF GAME *****\\n\");\n                print(\"FINAL SCORE: DARMOUTH: \" + s[1] + \"  \" + os + \": \" + s[0] + \"\\n\");\n                break;\n            }\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "07_Basketball/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "07_Basketball/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "07_Basketball/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "07_Basketball/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nThere are two version of the code here, a \"faithful\" translation (basketball-orig.pl) and\na \"modern\" translation (basketball.pl). The main difference between the 2 are is that the\nfaithful translation has 3 GOTOs in it while the modern version has no GOTO. I have added\na \"TIME\" print when the score is shown so the Clock is visible. Halftime is at \"50\" and\nend of game is at 100 (per the Basic code).\n\nThe 3 GOTOs in the faitful version are because of the way the original code jumped into\nthe \"middle of logic\" that has no obivious way to avoid ... that I can see, at least while\nstill maintaining something of the look and structure of the original Basic.\n\nThe modern version avoided the GOTOs by restructuring the program in the 2 \"play()\" subs.\nDespite the change, this should play the same way as the faithful version.\n\nAll of the percentages remain the same. If writing this from scratch, we really should\nhave only a single play() sub which uses the same code for both teams, which would also\nmake the game more fair ... but that wasn't done so the percent edge to Darmouth has been\nmaintained here.\n"
  },
  {
    "path": "07_Basketball/perl/basketball-orig.pl",
    "content": "#!/usr/bin/perl\n\n# Basketball program in Perl\n#   This is fairly faithful translation from the original Basic.\n#   This becomes apparent because there are actually 3 GOTOs still present\n#   because of the way the original code jumped into the \"middle of logic\"\n#   that has no obivious way to avoid ... that I can see.\n#   For better structure and no GOTOs, see the other version of this program.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $Defense=0;      # dartmouth defense value\nmy $Opponent;       # name of opponent\nmy @Score = (0, 0); # scores, dart is [0], opponent is [1]\nmy $Player = 0;     # player, 0 = dart, 1 = opp\nmy $Timer = 0;      # time tick, 100 ticks per game, 50 is end of first half, if tie at end then back to T=93\nmy $DoPlay = 1;     # true if game is still being played\nmy $ConTeam;        # controlling team, \"dart\" or \"opp\"\nmy $ShotType = 0;   # current shot type\n\n\nprint \"\\n\";\nprint \" \" x 31, \"BASKETBALL\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\";\nprint \"\\n\\n\\n\";\n\nprint \"THIS IS DARTMOUTH COLLEGE BASKETBALL.  YOU WILL BE DARTMOUTH\\n\";\nprint \"CAPTAIN AND PLAYMAKER.  CALL SHOTS AS FOLLOWS:\\n\";\nprint \"   1. LONG (30 FT.) JUMP SHOT;\\n\";\nprint \"   2. SHORT (15 FT.) JUMP SHOT;\\n\";\nprint \"   3. LAY UP;\\n\";\nprint \"   4. SET SHOT.\\n\";\nprint \"BOTH TEAMS WILL USE THE SAME DEFENSE.  CALL DEFENSE AS FOLLOWS:\\n\";\nprint \"   6. PRESS;\\n\";\nprint \"   6.5 MAN-TO MAN;\\n\";\nprint \"   7. ZONE;\\n\";\nprint \"   7.5 NONE.\\n\";\nprint \"TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\\n\\n\";\nget_defense();\nprint \"\\n\";\nprint \"CHOOSE YOUR OPPONENT: \";\nchomp($Opponent = <>);\n\n$ConTeam = center_jump();\nwhile ($DoPlay)\n{\n    print \"\\n\";\n    if ($ConTeam eq \"dart\")\n    {\n        $Player = 0;\n        get_your_shot();\n        dartmouth_play();\n    }\n    else\n    {\n        opponent_play();\n    }\n    if ($Timer >= 100)\n    {\n        check_end_game();\n        last if (!$DoPlay);\n        $Timer = 93;\n        $ConTeam = center_jump();\n    }\n}\nexit(0);\n\n###############################################################\n\nsub dartmouth_play\n{\n    if ($ShotType == 1 || $ShotType == 2)\n    {\n        $Timer++;\n        if ($Timer == 50)\n        {\n            end_first_half();\n            return;\n        }\n        if ($Timer == 92)\n        {\n            two_min_left();\n        }\n\n        print \"JUMP SHOT\\n\";\n        if (rand(1) <= 0.341 * $Defense / 8)\n        {\n            print \"SHOT IS GOOD.\\n\";\n            dartmouth_score();\n            $ConTeam = \"opp\";\n            return;\n        }\n\n        if (rand(1) <= 0.682*$Defense/8)\n        {\n            print \"SHOT IS OFF TARGET.\\n\";\n            if ($Defense/6*rand(1) > 0.45)\n            {\n                print \"REBOUND TO \", $Opponent, \"\\n\";\n                $ConTeam = \"opp\";\n                return;\n            }\n\n            print \"DARTMOUTH CONTROLS THE REBOUND.\\n\";\n            if (rand(1) <= 0.4) { goto L1300; }\n            if ($Defense == 6)\n            {\n                if (rand(1) <= 0.6)\n                {\n                    print \"PASS STOLEN BY $Opponent, EASY LAYUP.\\n\";\n                    opp_score();\n                    $ConTeam = \"dart\"; return;\n                    return;\n                }\n            }\n            print \"BALL PASSED BACK TO YOU.\\n\";\n            $ConTeam = \"dart\";\n            return;\n        }\n\n        if (rand(1) <= 0.782*$Defense/8)\n        {\n            print \"SHOT IS BLOCKED.  BALL CONTROLLED BY \"; # no NL\n            if (rand(1) > 0.5)\n            {\n                print \"$Opponent.\\n\";\n                $ConTeam = \"opp\";\n                return;\n            }\n            else\n            {\n                print \"DARTMOUTH.\\n\";\n                $ConTeam = \"dart\";\n                return;\n            }\n        }\n\n        if (rand(1) > 0.843*$Defense/8)\n        {\n            print \"CHARGING FOUL.  DARTMOUTH LOSES BALL.\\n\";\n            $ConTeam = \"opp\";\n            return;\n        }\n        else\n        {\n            print \"SHOOTER IS FOULED.  TWO SHOTS.\\n\";\n            foul_shooting();\n            $ConTeam = \"opp\";\n            return;\n        }\n    }\n\n    L1300:\n    while (1)\n    {\n        $Timer++;\n        if ($Timer == 50)\n        {\n            end_first_half();\n            return;\n        }\n        if ($Timer == 92) { two_min_left(); }\n        if ($ShotType == 0) \n        {\n            get_defense();\n            return;\n        }\n        print '', ($ShotType > 3 ? \"SET SHOT.\" : \"LAY UP.\"), \"\\n\";\n        if (7 / $Defense * rand(1) <= 0.4)\n        {\n            print \"SHOT IS GOOD.  TWO POINTS.\\n\";\n            dartmouth_score();\n            $ConTeam = \"opp\";\n            return;\n        }\n\n        if (7 / $Defense * rand(1) <= 0.7)\n        {\n            print \"SHOT IS OFF THE RIM.\\n\";\n            if (rand(1) <= 0.667)\n            {\n                print \"$Opponent CONTROLS THE REBOUND.\\n\";\n                $ConTeam = \"opp\";\n                return;\n            }\n\n            print \"DARTMOUTH CONTROLS THE REBOUND.\\n\";\n            next if (rand(1) <= 0.4);\n\n            print \"BALL PASSED BACK TO YOU.\\n\";\n            $ConTeam = \"dart\";\n            return;\n        }\n\n        if (7 / $Defense * rand(1) <= 0.875)\n        {\n            print \"SHOOTER FOULED.  TWO SHOTS.\\n\";\n            foul_shooting();\n            $ConTeam = \"opp\";\n            return;\n        }\n\n        if (7 / $Defense * rand(1) <= 0.925)\n        {\n            print \"SHOT BLOCKED. $Opponent\\'S BALL.\\n\";\n            $ConTeam = \"opp\";\n            return;\n        }\n\n        print \"CHARGING FOUL.  DARTMOUTH LOSES THE BALL.\\n\";\n        $ConTeam = \"opp\";\n        return;\n    }\n}\n\nsub get_defense\n{\n    $Defense = 0;\n    while ($Defense < 6 || $Defense > 7.5)\n    {\n        print \"YOUR NEW DEFENSIVE ALLIGNMENT IS (6, 6.5, 7. 7.5): \";\n        chomp($Defense = <>);\n        ($Defense) =~ m/(\\d(\\.\\d)?)/;\n    }\n}\n\nsub opponent_play\n{\n    $Player = 1;\n    $Timer++;\n    if ($Timer == 50)\n    {\n        end_first_half();\n        $ConTeam = center_jump();\n        return;\n    }\n\n    print \"\\n\";\n    while (1)\n    {\n        my $shot = 10.0 / 4 * rand(1) + 1;\n        if ($shot <= 2.0)\n        {\n            print \"JUMP SHOT.\\n\";\n            if (8.0 / $Defense * rand(1) <= 0.35)\n            {\n                print \"SHOT IS GOOD.\\n\";\n                opp_score();\n                $ConTeam = \"dart\";\n                return;\n            }\n\n            if (8.0 / $Defense * rand(1) <=  0.75)\n            {\n                print \"SHOT IS OFF RIM.\\n\";\n\n                L3110:\n                if ($Defense / 6.0 * rand(1) <= 0.5)\n                {\n                    print \"DARTMOUTH CONTROLS THE REBOUND.\\n\";\n                    $ConTeam = \"dart\";\n                    return;\n                }\n                print \"$Opponent CONTROLS THE REBOUND.\\n\";\n                if ($Defense == 6)\n                {\n                    if (rand(1) <= 0.75)\n                    {\n                        print \"BALL STOLEN.  EASY LAY UP FOR DARTMOUTH.\\n\";\n                        dartmouth_score();\n                        $ConTeam = \"opp\";\n                        return;\n                    }\n                }\n                if (rand(1) <= 0.5)\n                {\n                    print \"PASS BACK TO $Opponent GUARD.\\n\";\n                    $ConTeam = \"opp\";\n                    return;\n                }\n                goto L3500;\n            }\n\n            if (8.0 / $Defense * rand(1) <= 0.9)\n            {\n                print \"PLAYER FOULED.  TWO SHOTS.\\n\";\n                foul_shooting();\n                $ConTeam = \"dart\";\n                return;\n            }\n            print \"OFFENSIVE FOUL.  DARTMOUTH'S BALL.\\n\";\n            $ConTeam = \"dart\";\n            return;\n        }\n\n        L3500:\n        print ($shot > 3 ? \"SET SHOT.\\n\" : \"LAY UP.\\n\");\n        if (7.0 / $Defense * rand(1) > 0.413)\n        {\n            print \"SHOT IS MISSED.\\n\";\n            {\n            no warnings;\n            goto L3110;\n            }\n        }\n        else\n        {\n            print \"SHOT IS GOOD.\\n\";\n            opp_score();\n            $ConTeam = \"dart\";\n            return;\n        }\n    }\n}\n\nsub opp_score\n{\n    $Score[0] += 2;\n    print_score();\n}\n\nsub dartmouth_score\n{\n    $Score[1] += 2;\n    print_score();\n}\n\nsub print_score\n{\n    print \"SCORE: $Score[1] TO $Score[0]\\n\";\n    print \"TIME: $Timer\\n\";\n}\n\nsub end_first_half\n{\n    print \"\\n   ***** END OF FIRST HALF *****\\n\\n\";\n    print \"SCORE: DARTMOUTH: $Score[1]   $Opponent: $Score[0]\\n\\n\\n\";\n    center_jump();\n}\n\nsub get_your_shot\n{\n    $ShotType = -1;\n    while ($ShotType < 0 || $ShotType > 4)\n    {\n        print \"YOUR SHOT (0-4): \";\n        chomp($ShotType = <>);\n        $ShotType = int($ShotType);\n        if ($ShotType < 0 || $ShotType > 4)\n        {\n            print \"INCORRECT ANSWER.  RETYPE IT. \";\n        }\n    }\n}\n\nsub center_jump\n{\n    print \"CENTER JUMP\\n\";\n    if (rand(1) <= 0.6)\n    {\n        print \"$Opponent CONTROLS THE TAP.\\n\";\n        return \"opp\";\n    }\n    print \"DARTMOUTH CONTROLS THE TAP.\\n\";\n    return \"dart\";\n}\n\nsub check_end_game\n{\n    print \"\\n\";\n    if ($Score[1] != $Score[0])\n    {\n        print \"   ***** END OF GAME *****\\n\";\n        print \"FINAL SCORE: DARTMOUTH: $Score[1]    $Opponent: $Score[0]\\n\\n\";\n        $DoPlay = 0;\n    }\n    else\n    {\n        print \"\\n   ***** END OF SECOND HALF *****\\n\";\n        print \"SCORE AT END OF REGULATION TIME:\\n\";\n        print \"        DARTMOUTH: $Score[1]    $Opponent: $Score[0]\\n\\n\";\n        print \"BEGIN TWO MINUTE OVERTIME PERIOD\\n\";\n    }\n}\n\nsub two_min_left\n{\n    print \"\\n   *** TWO MINUTES LEFT IN THE GAME ***\\n\\n\";\n}\n\nsub foul_shooting\n{\n    if (rand(1) > 0.49)\n    {\n        if (rand(1) > 0.75)\n        {\n            print \"BOTH SHOTS MISSED.\\n\";\n        }\n        else\n        {\n            print \"SHOOTER MAKES ONE SHOT AND MISSES ONE.\\n\";\n            $Score[1 - $Player]++;\n        }\n    }\n    else\n    {\n        print \"SHOOTER MAKES BOTH SHOTS.\\n\";\n        $Score[1 - $Player] += 2;\n    }\n\n    print_score();\n}\n"
  },
  {
    "path": "07_Basketball/perl/basketball.pl",
    "content": "#!/usr/bin/perl\n\n# Basketball program in Perl\n#   While this should play the same way as the fairly faithful translation version,\n#   there are no GOTOs in this code. That was achieved by restructuring the program\n#   in the 2 *_play() subs. All of the percentages remain the same. If writing this\n#   from scratch, we really should have only a play() sub which uses the same code\n#   for both teams, but the percent edge to Darmouth has been maintained here.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $Defense=0;      # dartmouth defense value\nmy $Opponent;       # name of opponent\nmy @Score = (0, 0); # scores, dart is [0], opponent is [1]\nmy $Player = 0;     # player, 0 = dart, 1 = opp\nmy $Timer = 0;      # time tick, 100 ticks per game, 50 is end of first half, if tie at end then back to T=93\nmy $DoPlay = 1;     # true if game is still being played\nmy $ConTeam;        # controlling team, \"dart\" or \"opp\"\nmy $ShotType = 0;   # current shot type\n\n\nprint \"\\n\";\nprint \" \" x 31, \"BASKETBALL\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\";\nprint \"\\n\\n\\n\";\n\nprint \"THIS IS DARTMOUTH COLLEGE BASKETBALL.  YOU WILL BE DARTMOUTH\\n\";\nprint \"CAPTAIN AND PLAYMAKER.  CALL SHOTS AS FOLLOWS:\\n\";\nprint \"   1. LONG (30 FT.) JUMP SHOT;\\n\";\nprint \"   2. SHORT (15 FT.) JUMP SHOT;\\n\";\nprint \"   3. LAY UP;\\n\";\nprint \"   4. SET SHOT.\\n\";\nprint \"BOTH TEAMS WILL USE THE SAME DEFENSE.  CALL DEFENSE AS FOLLOWS:\\n\";\nprint \"   6. PRESS;\\n\";\nprint \"   6.5 MAN-TO MAN;\\n\";\nprint \"   7. ZONE;\\n\";\nprint \"   7.5 NONE.\\n\";\nprint \"TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\\n\\n\";\nget_defense();\nprint \"\\n\";\nprint \"CHOOSE YOUR OPPONENT: \";\nchomp($Opponent = <>);\n\n$ConTeam = center_jump();\nwhile ($DoPlay)\n{\n    print \"\\n\";\n    if ($ConTeam eq \"dart\")\n    {\n        get_your_shot();\n        dartmouth_play();\n    }\n    else\n    {\n        $ShotType = 10.0 / 4 * rand(1) + 1;\n        opponent_play();\n    }\n    if ($Timer >= 100)\n    {\n        check_end_game();\n        last if (!$DoPlay);\n        $Timer = 93;\n        $ConTeam = center_jump();\n    }\n}\nexit(0);\n\n###############################################################\n\nsub dartmouth_play\n{\n    $Player = 0;\n    print \"\\n\";\n    while (1)\n    {\n        $Timer++;\n        if ($Timer == 50) { end_first_half(); return; }\n        if ($Timer == 92) { two_min_left(); }\n\n        if ($ShotType == 0) \n        {\n            get_defense();\n            return; # for new ShotType\n        }\n        elsif ($ShotType == 1 || $ShotType == 2)\n        {\n            print \"JUMP SHOT\\n\";\n            if (rand(1) <= 0.341 * $Defense / 8)\n            {\n                print \"SHOT IS GOOD.\\n\";\n                dartmouth_score();\n                last;\n            }\n\n            if (rand(1) <= 0.682*$Defense/8)\n            {\n                print \"SHOT IS OFF TARGET.\\n\";\n                if ($Defense/6*rand(1) > 0.45)\n                {\n                    print \"REBOUND TO $Opponent\\n\";\n                    last;\n                }\n\n                print \"DARTMOUTH CONTROLS THE REBOUND.\\n\";\n                if (rand(1) <= 0.4)\n                {\n                    $ShotType = (rand(1) <= 0.5) ? 3 : 4;\n                    next;\n                }\n                if ($Defense == 6)\n                {\n                    if (rand(1) <= 0.6)\n                    {\n                        print \"PASS STOLEN BY $Opponent, EASY LAYUP.\\n\";\n                        opp_score();\n                        next;\n                    }\n                }\n                print \"BALL PASSED BACK TO YOU.\\n\";\n                next;\n            }\n\n            if (rand(1) <= 0.782*$Defense/8)\n            {\n                print \"SHOT IS BLOCKED.  BALL CONTROLLED BY \"; # no NL\n                if (rand(1) > 0.5)\n                {\n                    print \"$Opponent.\\n\";\n                    last;\n                }\n                else\n                {\n                    print \"DARTMOUTH.\\n\";\n                    next;\n                }\n            }\n\n            if (rand(1) > 0.843*$Defense/8)\n            {\n                print \"CHARGING FOUL.  DARTMOUTH LOSES BALL.\\n\";\n                last;\n            }\n            else\n            {\n                print \"SHOOTER IS FOULED.  TWO SHOTS.\\n\";\n                foul_shooting();\n                last;\n            }\n        }\n        else # elsif ($ShotType >= 3)\n        {\n            print '', ($ShotType > 3 ? \"SET SHOT.\" : \"LAY UP.\"), \"\\n\";\n            if (7 / $Defense * rand(1) <= 0.4)\n            {\n                print \"SHOT IS GOOD.  TWO POINTS.\\n\";\n                dartmouth_score();\n                last;\n            }\n\n            if (7 / $Defense * rand(1) <= 0.7)\n            {\n                print \"SHOT IS OFF THE RIM.\\n\";\n                if (rand(1) <= 0.667)\n                {\n                    print \"$Opponent CONTROLS THE REBOUND.\\n\";\n                    last;\n                }\n\n                print \"DARTMOUTH CONTROLS THE REBOUND.\\n\";\n                next if (rand(1) <= 0.4);\n\n                print \"BALL PASSED BACK TO YOU.\\n\";\n                next;\n            }\n\n            if (7 / $Defense * rand(1) <= 0.875)\n            {\n                print \"SHOOTER FOULED.  TWO SHOTS.\\n\";\n                foul_shooting();\n                last;\n            }\n\n            if (7 / $Defense * rand(1) <= 0.925)\n            {\n                print \"SHOT BLOCKED. $Opponent\\'S BALL.\\n\";\n                last;\n            }\n\n            print \"CHARGING FOUL.  DARTMOUTH LOSES THE BALL.\\n\";\n            last;\n        }\n    }\n    $ConTeam = \"opp\";\n}\n\nsub get_defense\n{\n    $Defense = 0;\n    do {\n        print \"YOUR NEW DEFENSIVE ALLIGNMENT IS (6, 6.5, 7. 7.5): \";\n        chomp($Defense = <>);\n        ($Defense) =~ m/(\\d(\\.\\d)?)/;\n    } while ($Defense < 6.0 || $Defense > 7.5)\n}\n\nsub opponent_play\n{\n    $Player = 1;\n    print \"\\n\";\n    while (1)\n    {\n        $Timer++;\n        if ($Timer == 50) { end_first_half(); return; }\n        if ($Timer == 92) { two_min_left(); }\n\n        if ($ShotType <= 2.0)\n        {\n            print \"JUMP SHOT.\\n\";\n            if (8.0 / $Defense * rand(1) <= 0.35)\n            {\n                print \"SHOT IS GOOD.\\n\";\n                opp_score();\n                last;\n            }\n\n            if (8.0 / $Defense * rand(1) <=  0.75)\n            {\n                print \"SHOT IS OFF RIM.\\n\";\n                opp_missed();\n                return; # for possible new ShotType or team change\n            }\n\n            if (8.0 / $Defense * rand(1) <= 0.9)\n            {\n                print \"PLAYER FOULED.  TWO SHOTS.\\n\";\n                foul_shooting();\n                last;\n            }\n            print \"OFFENSIVE FOUL.  DARTMOUTH'S BALL.\\n\";\n            last;\n        }\n        else # ShotType >= 3\n        {\n            print ($ShotType > 3 ? \"SET SHOT.\\n\" : \"LAY UP.\\n\");\n            if (7.0 / $Defense * rand(1) > 0.413)\n            {\n                print \"SHOT IS MISSED.\\n\";\n                {\n                    opp_missed();\n                    return; # for possible new ShotType or team change\n                }\n            }\n            else\n            {\n                print \"SHOT IS GOOD.\\n\";\n                opp_score();\n                last;\n            }\n        }\n    }\n    $ConTeam = \"dart\";\n}\n\nsub opp_missed\n{\n    if ($Defense / 6.0 * rand(1) <= 0.5)\n    {\n        print \"DARTMOUTH CONTROLS THE REBOUND.\\n\";\n        $ConTeam = \"dart\";\n    }\n    else\n    {\n        print \"$Opponent CONTROLS THE REBOUND.\\n\";\n        if ($Defense == 6)\n        {\n            if (rand(1) <= 0.75)\n            {\n                print \"BALL STOLEN.  EASY LAY UP FOR DARTMOUTH.\\n\";\n                dartmouth_score();\n                #$ConTeam = \"opp\";\n                return; # for possible new ShotType\n            }\n        }\n        if (rand(1) <= 0.5)\n        {\n            print \"PASS BACK TO $Opponent GUARD.\\n\";\n            #$ConTeam = \"opp\";\n            return; # for possible new ShotType\n        }\n        $ShotType = (rand(1) <= 0.5) ? 3 : 4;\n    }\n}\n\nsub opp_score\n{\n    $Score[0] += 2;\n    print_score();\n}\n\nsub dartmouth_score\n{\n    $Score[1] += 2;\n    print_score();\n}\n\nsub print_score\n{\n    print \"SCORE: $Score[1] TO $Score[0]\\n\";\n    print \"TIME: $Timer\\n\";\n}\n\nsub end_first_half\n{\n    print \"\\n   ***** END OF FIRST HALF *****\\n\\n\";\n    print \"SCORE: DARTMOUTH: $Score[1]   $Opponent: $Score[0]\\n\\n\\n\";\n    $ConTeam = center_jump();\n}\n\nsub get_your_shot\n{\n    $ShotType = -1;\n    while ($ShotType < 0 || $ShotType > 4)\n    {\n        print \"YOUR SHOT (0-4): \";\n        chomp($ShotType = <>);\n        $ShotType = int($ShotType);\n        if ($ShotType < 0 || $ShotType > 4)\n        {\n            print \"INCORRECT ANSWER.  RETYPE IT. \";\n        }\n    }\n}\n\nsub center_jump\n{\n    print \"CENTER JUMP\\n\";\n    if (rand(1) <= 0.6)\n    {\n        print \"$Opponent CONTROLS THE TAP.\\n\";\n        return \"opp\";\n    }\n    print \"DARTMOUTH CONTROLS THE TAP.\\n\";\n    return \"dart\";\n}\n\nsub check_end_game\n{\n    print \"\\n\";\n    if ($Score[1] != $Score[0])\n    {\n        print \"   ***** END OF GAME *****\\n\";\n        print \"FINAL SCORE: DARTMOUTH: $Score[1]    $Opponent: $Score[0]\\n\\n\";\n        $DoPlay = 0;\n    }\n    else\n    {\n        print \"\\n   ***** END OF SECOND HALF *****\\n\";\n        print \"SCORE AT END OF REGULATION TIME:\\n\";\n        print \"        DARTMOUTH: $Score[1]    $Opponent: $Score[0]\\n\\n\";\n        print \"BEGIN TWO MINUTE OVERTIME PERIOD\\n\";\n    }\n}\n\nsub two_min_left\n{\n    print \"\\n   *** TWO MINUTES LEFT IN THE GAME ***\\n\\n\";\n}\n\nsub foul_shooting\n{\n    if (rand(1) > 0.49)\n    {\n        if (rand(1) > 0.75)\n        {\n            print \"BOTH SHOTS MISSED.\\n\";\n        }\n        else\n        {\n            print \"SHOOTER MAKES ONE SHOT AND MISSES ONE.\\n\";\n            $Score[1 - $Player]++;\n        }\n    }\n    else\n    {\n        print \"SHOOTER MAKES BOTH SHOTS.\\n\";\n        $Score[1 - $Player] += 2;\n    }\n\n    print_score();\n}\n"
  },
  {
    "path": "07_Basketball/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "07_Basketball/python/basketball.py",
    "content": "\"\"\"\nThe basketball class is a computer game that allows you to play as\nDartmouth College's captain and playmaker\nThe game uses set probabilites to simulate outcomes of each posession\nYou are able to choose your shot types as well as defensive formations\n\"\"\"\n\nimport random\nfrom typing import List, Literal, Optional\n\n\ndef print_intro() -> None:\n    print(\"\\t\\t\\t Basketball\")\n    print(\"\\t Creative Computing  Morristown, New Jersey\\n\\n\\n\")\n    print(\"This is Dartmouth College basketball. \")\n    print(\"Υou will be Dartmouth captain and playmaker.\")\n    print(\"Call shots as follows:\")\n    print(\n        \"1. Long (30ft.) Jump Shot; \"\n        \"2. Short (15 ft.) Jump Shot; \"\n        \"3. Lay up; 4. Set Shot\"\n    )\n    print(\"Both teams will use the same defense. Call Defense as follows:\")\n    print(\"6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None.\")\n    print(\"To change defense, just type 0 as your next shot.\")\n    print(\"Your starting defense will be? \", end=\"\")\n\n\nclass Basketball:\n    def __init__(self) -> None:\n        self.time = 0\n        self.score = [0, 0]  # first value is opponents score, second is home\n        self.defense_choices: List[float] = [6, 6.5, 7, 7.5]\n        self.shot: Optional[int] = None\n        self.shot_choices: List[Literal[0, 1, 2, 3, 4]] = [0, 1, 2, 3, 4]\n        self.z1: Optional[float] = None\n\n        print_intro()\n\n        self.defense = get_defense_choice(self.defense_choices)\n\n        self.opponent = get_opponents_name()\n        self.start_of_period()\n\n    def add_points(self, team: Literal[0, 1], points: Literal[0, 1, 2]) -> None:\n        \"\"\"\n        Add points to the score.\n\n        Team can take 0 or 1, for opponent or Dartmouth, respectively\n        \"\"\"\n        self.score[team] += points\n        self.print_score()\n\n    def ball_passed_back(self) -> None:\n        print(\"Ball passed back to you. \", end=\"\")\n        self.dartmouth_ball()\n\n    def change_defense(self) -> None:\n        \"\"\"change defense, called when the user enters 0 for their shot\"\"\"\n        defense = None\n\n        while defense not in self.defense_choices:\n            print(\"Your new defensive allignment is? \")\n            try:\n                defense = float(input())\n            except ValueError:\n                continue\n        assert isinstance(defense, float)\n        self.defense = defense\n        self.dartmouth_ball()\n\n    def foul_shots(self, team: Literal[0, 1]) -> None:\n        \"\"\"Simulate two foul shots for a player and adds the points.\"\"\"\n        print(\"Shooter fouled.  Two shots.\")\n        if random.random() > 0.49:\n            if random.random() > 0.75:\n                print(\"Both shots missed.\")\n            else:\n                print(\"Shooter makes one shot and misses one.\")\n                self.score[team] += 1\n        else:\n            print(\"Shooter makes both shots.\")\n            self.score[team] += 2\n\n        self.print_score()\n\n    def halftime(self) -> None:\n        \"\"\"called when t = 50, starts a new period\"\"\"\n        print(\"\\n   ***** End of first half *****\\n\")\n        self.print_score()\n        self.start_of_period()\n\n    def print_score(self) -> None:\n        \"\"\"Print the current score\"\"\"\n        print(f\"Score:  {self.score[1]} to {self.score[0]}\\n\")\n\n    def start_of_period(self) -> None:\n        \"\"\"Simulate a center jump for posession at the beginning of a period\"\"\"\n        print(\"Center jump\")\n        if random.random() > 0.6:\n            print(\"Dartmouth controls the tap.\\n\")\n            self.dartmouth_ball()\n        else:\n            print(self.opponent + \" controls the tap.\\n\")\n            self.opponent_ball()\n\n    def two_minute_warning(self) -> None:\n        \"\"\"called when t = 92\"\"\"\n        print(\"   *** Two minutes left in the game ***\")\n\n    def dartmouth_jump_shot(self) -> None:\n        \"\"\"called when the user enters 1 or 2 for their shot\"\"\"\n        self.time += 1\n        if self.time == 50:\n            self.halftime()\n        elif self.time == 92:\n            self.two_minute_warning()\n        print(\"Jump Shot.\")\n        # simulates chances of different possible outcomes\n        if random.random() > 0.341 * self.defense / 8:\n            if random.random() > 0.682 * self.defense / 8:\n                if random.random() > 0.782 * self.defense / 8:\n                    if random.random() > 0.843 * self.defense / 8:\n                        print(\"Charging foul. Dartmouth loses ball.\\n\")\n                    else:\n                        # player is fouled\n                        self.foul_shots(1)\n                    self.opponent_ball()\n                elif random.random() > 0.5:\n                    print(\n                        \"Shot is blocked. Ball controlled by \"\n                        + self.opponent\n                        + \".\\n\"\n                    )\n                    self.opponent_ball()\n                else:\n                    print(\"Shot is blocked. Ball controlled by Dartmouth.\")\n                    self.dartmouth_ball()\n            else:\n                print(\"Shot is off target.\")\n                if self.defense / 6 * random.random() > 0.45:\n                    print(f\"Rebound to {self.opponent}\\n\")\n                    self.opponent_ball()\n                else:\n                    print(\"Dartmouth controls the rebound.\")\n                    if random.random() > 0.4:\n                        if self.defense == 6 and random.random() > 0.6:\n                            print(f\"Pass stolen by {self.opponent}, easy lay up\")\n                            self.add_points(0, 2)\n                            self.dartmouth_ball()\n                        else:\n                            # ball is passed back to you\n                            self.ball_passed_back()\n                    else:\n                        print()\n                        self.dartmouth_non_jump_shot()\n        else:\n            print(\"Shot is good.\")\n            self.add_points(1, 2)\n            self.opponent_ball()\n\n    def dartmouth_non_jump_shot(self) -> None:\n        \"\"\"\n        Lay up, set shot, or defense change\n\n        called when the user enters 0, 3, or 4\n        \"\"\"\n        self.time += 1\n        if self.time == 50:\n            self.halftime()\n        elif self.time == 92:\n            self.two_minute_warning()\n\n        if self.shot == 4:\n            print(\"Set shot.\")\n        elif self.shot == 3:\n            print(\"Lay up.\")\n        elif self.shot == 0:\n            self.change_defense()\n\n        # simulates different outcomes after a lay up or set shot\n        if 7 / self.defense * random.random() > 0.4:\n            if 7 / self.defense * random.random() > 0.7:\n                if 7 / self.defense * random.random() > 0.875:\n                    if 7 / self.defense * random.random() > 0.925:\n                        print(\"Charging foul. Dartmouth loses the ball.\\n\")\n                    else:\n                        print(f\"Shot blocked. {self.opponent}'s ball.\\n\")\n                else:\n                    self.foul_shots(1)\n                self.opponent_ball()\n            else:\n                print(\"Shot is off the rim.\")\n                if random.random() > 2 / 3:\n                    print(\"Dartmouth controls the rebound.\")\n                    if random.random() > 0.4:\n                        print(\"Ball passed back to you.\\n\")\n                        self.dartmouth_ball()\n                    else:\n                        self.dartmouth_non_jump_shot()\n                else:\n                    print(self.opponent + \" controls the rebound.\\n\")\n                    self.opponent_ball()\n        else:\n            print(\"Shot is good. Two points.\")\n            self.add_points(1, 2)\n            self.opponent_ball()\n\n    def dartmouth_ball(self) -> None:\n        \"\"\"plays out a Dartmouth posession, starting with your choice of shot\"\"\"\n        shot = get_dartmouth_ball_choice(self.shot_choices)\n        self.shot = shot\n\n        if self.time < 100 or random.random() < 0.5:\n            if self.shot in [1, 2]:\n                self.dartmouth_jump_shot()\n            else:\n                self.dartmouth_non_jump_shot()\n        elif self.score[0] == self.score[1]:\n            print(\"\\n   ***** End Of Second Half *****\")\n            print(\"Score at end of regulation time:\")\n            print(\n                \"     Dartmouth: \"\n                + str(self.score[1])\n                + \" \"\n                + self.opponent\n                + \": \"\n                + str(self.score[0])\n            )\n            print(\"Begin two minute overtime period\")\n            self.time = 93\n            self.start_of_period()\n\n        else:\n            print(\"\\n   ***** End Of Game *****\")\n            print(\n                \"Final Score: Dartmouth: \"\n                + str(self.score[1])\n                + \"  \"\n                + self.opponent\n                + \": \"\n                + str(self.score[0])\n            )\n\n    def opponent_jumpshot(self) -> None:\n        \"\"\"Simulate the opponents jumpshot\"\"\"\n        print(\"Jump Shot.\")\n        if 8 / self.defense * random.random() > 0.35:\n            if 8 / self.defense * random.random() > 0.75:\n                if 8 / self.defense * random.random() > 0.9:\n                    print(\"Offensive foul. Dartmouth's ball.\\n\")\n                else:\n                    self.foul_shots(0)\n                self.dartmouth_ball()\n            else:\n                print(\"Shot is off the rim.\")\n                if self.defense / 6 * random.random() > 0.5:\n                    print(f\"{self.opponent} controls the rebound.\")\n                    if (\n                        self.defense == 6\n                        and random.random() <= 0.75\n                        and random.random() > 0.5\n                    ):\n                        print()\n                        self.opponent_non_jumpshot()\n                    elif (\n                        self.defense == 6\n                        and random.random() <= 0.75\n                        and random.random() <= 0.5\n                        or self.defense != 6\n                        and random.random() <= 0.5\n                    ):\n                        print(f\"Pass back to {self.opponent} guard.\\n\")\n                        self.opponent_ball()\n                    elif self.defense == 6 and random.random() > 0.75:\n                        print(\"Ball stolen. Easy lay up for Dartmouth.\")\n                        self.add_points(1, 2)\n                        self.opponent_ball()\n                    else:\n                        self.opponent_non_jumpshot()\n                else:\n                    print(\"Dartmouth controls the rebound.\\n\")\n                    self.dartmouth_ball()\n        else:\n            print(\"Shot is good.\")\n            self.add_points(0, 2)\n            self.dartmouth_ball()\n\n    def opponent_non_jumpshot(self) -> None:\n        \"\"\"Simulate opponents lay up or set shot.\"\"\"\n        if self.z1 > 3:  # type: ignore\n            print(\"Set shot.\")\n        else:\n            print(\"Lay up\")\n        if 7 / self.defense * random.random() > 0.413:\n            print(\"Shot is missed.\")\n            if self.defense / 6 * random.random() > 0.5:\n                print(f\"{self.opponent} controls the rebound.\")\n                if (\n                    self.defense == 6\n                    and random.random() <= 0.75\n                    and random.random() > 0.5\n                    or self.defense != 6\n                    and random.random() > 0.5\n                ):\n                    print()\n                    self.opponent_non_jumpshot()\n                elif (\n                    self.defense == 6\n                    and random.random() <= 0.75\n                    and random.random() <= 0.5\n                ):\n                    print(f\"Pass back to {self.opponent} guard.\\n\")\n                    self.opponent_ball()\n                elif self.defense == 6 and random.random() > 0.75:\n                    print(\"Ball stolen. Easy lay up for Dartmouth.\")\n                    self.add_points(1, 2)\n                    self.opponent_ball()\n                else:\n                    print(f\"Pass back to {self.opponent} guard\\n\")\n                    self.opponent_ball()\n            else:\n                print(\"Dartmouth controls the rebound.\\n\")\n                self.dartmouth_ball()\n        else:\n            print(\"Shot is good.\")\n            self.add_points(0, 2)\n            self.dartmouth_ball()\n\n    def opponent_ball(self) -> None:\n        \"\"\"\n        Simulate an opponents possesion\n\n        Randomly picks jump shot or lay up / set shot.\n        \"\"\"\n        self.time += 1\n        if self.time == 50:\n            self.halftime()\n        self.z1 = 10 / 4 * random.random() + 1\n        if self.z1 > 2:\n            self.opponent_non_jumpshot()\n        else:\n            self.opponent_jumpshot()\n\n\ndef get_defense_choice(defense_choices: List[float]) -> float:\n    \"\"\"Takes input for a defense\"\"\"\n    try:\n        defense = float(input())\n    except ValueError:\n        defense = None\n\n    # if the input wasn't a valid defense, takes input again\n    while defense not in defense_choices:\n        print(\"Your new defensive allignment is? \", end=\"\")\n        try:\n            defense = float(input())\n        except ValueError:\n            continue\n    assert isinstance(defense, float)\n    return defense\n\n\ndef get_dartmouth_ball_choice(shot_choices: List[Literal[0, 1, 2, 3, 4]]) -> int:\n    print(\"Your shot? \", end=\"\")\n    shot = None\n    try:\n        shot = int(input())\n    except ValueError:\n        shot = None\n\n    while shot not in shot_choices:\n        print(\"Incorrect answer. Retype it. Your shot? \", end=\"\")\n        try:\n            shot = int(input())\n        except Exception:\n            continue\n    assert isinstance(shot, int)\n    return shot\n\n\ndef get_opponents_name() -> str:\n    \"\"\"Take input for opponent's name\"\"\"\n    print(\"\\nChoose your opponent? \", end=\"\")\n    return input()\n\n\nif __name__ == \"__main__\":\n    Basketball()\n"
  },
  {
    "path": "07_Basketball/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "07_Basketball/ruby/basketball.rb",
    "content": "class Basketball\n\n  def initialize\n    @time = 0\n    @score = [0, 0]\n    @defense_choices = [6, 6.5, 7, 7.5]\n    @shot = nil\n    @shot_choices = [0, 1, 2, 3, 4]\n    @z1 = nil\n\n    puts \"Υou will be Dartmouth captain and playmaker.\"\n    puts \"Call shots as follows:\"\n    puts \"1. Long (30ft.) Jump Shot\"\n    puts \"2. Short (15 ft.) Jump Shot\"\n    puts \"3. Lay up; 4. Set Shot\\n\\n\"\n    \n    puts \"Both teams will use the same defense. Call Defense as follows:\"\n    puts \"6. Press\"\n    puts \"6.5 Man-to-Man\"\n    puts \"7. Zone\"\n    puts \"7.5 None.\\n\\n\"\n\n    puts \"To change defense, just type 0 as your next shot.\"\n\n    @defense = get_defense @defense_choices\n\n\n    puts \"\\nChoose your opponent? \"\n    @opponent = gets.chomp!\n    start_of_period\n  end\n\n  def dartmouth_ball\n    while true\n      puts \"Your shot? \" \n      @shot = gets.chomp!\n      if @shot_choices.include? @shot.to_i\n        break\n      end\n    end\n\n    if @time < 100 or Random.rand < 0.5\n      if @shot.to_i == 1 or @shot.to_i == 2\n        dartmouth_jump_shot\n      else\n        dartmouth_non_jump_shot\n      end\n    else\n      if @score[0] != @score[1]\n        puts \"\\n   ***** End Of Game *****\" \n        puts \"Final Score: Dartmouth: #{@score[1].to_s}  #{@opponent}: #{@score[0].to_s}\"\n      else\n        puts \"\\n   ***** End Of Second Half *****\"\n        puts \"Score at end of regulation time:\"\n        puts \"     Dartmouth: #{@score[1]} #{@opponent}: #{@score[0]}\"\n\n        puts \"Begin two minute overtime period\" \n        @time = 93\n        start_of_period\n      end\n    end\n  end\n\n  def add_points team, points\n    @score[team] += points\n    print_score\n  end\n\n  def ball_passed_back\n    puts \"Ball passed back to you\"\n  end\n\n  def change_defense\n    @defense = get_defense @defense_choices, \"new\"\n    dartmouth_ball()\n  end\n\n  def foul_shots team\n    puts \"Shooter fouled.  Two shots.\"\n    if Random.rand > 0.49\n      if Random.rand > 0.75\n        puts \"Both shots missed.\"\n      else\n        puts \"Shooter makes one shot and misses one.\"\n        @score[team] += 1\n      end\n    else\n      puts \"Shooter makes both shots.\"\n      @score[team] += 2\n    end\n  end\n\n  def halftime\n    puts \"\\n   ***** End of first half *****\\n\" \n    print_score\n    start_of_period\n  end\n\n  def print_score\n    puts \"Score:  #{@score[1]} to #{@score[0]}\\n\" \n  end\n\n  def start_of_period\n    puts \"Center jump\" \n    if Random.rand > 0.6\n      puts \"Dartmouth controls the tap.\\n\" \n      dartmouth_ball()\n    else\n      puts \"#{@opponent} controls the tap.\\n\" \n      opponent_ball\n    end\n  end\n\n  def two_minute_warning\n    puts \"   *** Two minutes left in the game ***\" \n  end\n\n  def dartmouth_jump_shot\n    @time += 1\n    if @time == 50\n      halftime\n    elsif @time == 92\n      two_minute_warning\n    end\n    puts \"Jumpshot\"\n\n    if Random.rand > 0.341 * @defense.to_i / 8\n      if Random.rand > 0.682 * @defense.to_i / 8\n        if Random.rand > 0.782 * @defense.to_i / 8\n          if Random.rand > 0.843 * @defense.to_i / 8\n            puts \"Charging foul. Dartmouth loses ball.\\n\" \n            opponent_ball\n          else\n            foul_shots 1\n            opponent_ball\n          end\n        else\n          if Random.rand > 0.5\n            puts \"Shot is blocked. Ball controlled by #{@opponent}\\n\"\n            opponent_ball\n          else\n            puts \"Shot is blocked. Ball controlled by Dartmouth.\"\n            dartmouth_ball()\n          end\n        end\n      else\n        puts \"Shot is off target.\" \n        if @defense.to_i / 6 * Random.rand > 0.45\n          puts \"Rebound to \" + @opponent + \"\\n\" \n          opponent_ball\n        else\n          puts \"Dartmouth controls the rebound.\" \n          if Random.rand > 0.4\n            if @defense.to_i == 6 and Random.rand > 0.6\n              puts \"Pass stolen by #{@opponent}, easy lay up\" \n              add_points(0, 2)\n              dartmouth_ball()\n            else\n              ball_passed_back\n            end\n          else\n            puts \"\\n\" \n            dartmouth_non_jump_shot\n          end\n        end\n      end\n    else\n      puts \"Shot is good.\" \n      add_points(1, 2)\n      opponent_ball\n    end\n  end\n\n  def dartmouth_non_jump_shot\n    @time += 1\n    if @time == 50\n      halftime\n    elsif @time == 92\n      two_minute_warning\n    end\n\n    if @shot.to_i == 4\n      puts \"Set shot.\" \n    elsif @shot.to_i == 3\n      puts \"Lay up.\" \n    elsif @shot.to_i == 0\n      change_defense\n    end\n\n    if 7 / @defense.to_i * Random.rand > 0.4\n      if 7 / @defense.to_i * Random.rand > 0.7\n        if 7 / @defense.to_i * Random.rand > 0.875\n          if 7 / @defense.to_i * Random.rand > 0.925\n            puts \"Charging foul. Dartmouth loses the ball.\\n\"\n            opponent_ball\n          else\n            puts \"Shot blocked. #{@opponent}'s ball.\\n\" \n            opponent_ball\n          end\n        else\n          foul_shots(1)\n          opponent_ball\n        end\n      else\n        puts \"Shot is off the rim.\" \n        if Random.rand > 2 / 3\n          puts \"Dartmouth controls the rebound.\"\n          if Random.rand > 0.4\n            puts \"Ball passed back to you.\\n\"\n            dartmouth_ball()\n          else\n            dartmouth_non_jump_shot\n          end\n        else\n          puts \"#{@opponent} controls the rebound.\\n\"\n          opponent_ball\n        end\n      end\n    else\n      puts \"Shot is good. Two points.\"\n      add_points(1, 2)\n      opponent_ball\n    end\n  end\n\n  def opponent_jumpshot\n    puts \"Jump Shot.\" \n    if 8 / @defense.to_i * Random.rand > 0.35\n      if 8 / @defense.to_i * Random.rand > 0.75\n        if 8 / @defense.to_i * Random.rand > 0.9\n          puts \"Offensive foul. Dartmouth's ball.\\n\" \n          dartmouth_ball()\n        else\n          foul_shots(0)\n          dartmouth_ball()\n        end\n      else\n        puts \"Shot is off the rim.\" \n        if @defense.to_i / 6 * Random.rand > 0.5\n          puts \"#{@opponent} controls the rebound.\" \n          if @defense.to_i == 6\n            if Random.rand > 0.75\n              puts \"Ball stolen. Easy lay up for Dartmouth.\" \n              add_points(1, 2)\n              opponent_ball\n            else\n              if Random.rand > 0.5\n                puts \"\"\n                opponent_non_jumpshot\n              else\n                puts \"Pass back to #{@opponent} guard.\\n\" \n                opponent_ball\n              end\n            end\n          else\n            if Random.rand > 0.5\n              opponent_non_jumpshot\n            else\n              puts \"Pass back to #{@opponent} guard.\\n\" \n              opponent_ball\n            end\n          end\n        else\n          puts \"Dartmouth controls the rebound.\\n\" \n          dartmouth_ball()\n        end\n      end\n    else\n      puts \"Shot is good.\" \n      add_points(0, 2)\n      dartmouth_ball()\n    end\n  end\n\n  def opponent_non_jumpshot\n    if @z1 > 3\n        puts \"Set shot.\" \n    else\n      puts \"Lay up\" \n    end\n\n    if 7 / @defense.to_i * Random.rand > 0.413\n      puts \"Shot is missed.\" \n      if @defense.to_i / 6 * Random.rand > 0.5\n        puts \"#{@opponent} controls the rebound.\" \n        if @defense.to_i == 6\n            if Random.rand > 0.75\n              puts \"Ball stolen. Easy lay up for Dartmouth.\" \n              add_points(1, 2)\n              opponent_ball\n            else\n              if Random.rand > 0.5\n                  puts \"\" \n                  opponent_non_jumpshot\n              else\n                puts \"Pass back to #{@opponent} guard.\\n\" \n                opponent_ball\n              end\n            end\n        else\n          if Random.rand > 0.5\n            puts \"\" \n            opponent_non_jumpshot\n          else\n            puts \"Pass back to #{@opponent} guard\\n\" \n            opponent_ball\n          end\n        end\n      else\n        puts \"Dartmouth controls the rebound.\\n\"\n        dartmouth_ball()\n      end\n    else\n      puts \"Shot is good.\" \n      add_points(0, 2)\n      dartmouth_ball()\n    end\n  end\n\n  def opponent_ball\n    @time += 1\n    if @time == 50\n      halftime\n    end\n\n    @z1 = 10 / 4 * Random.rand + 1\n    \n    if @z1 > 2\n      opponent_non_jumpshot\n    else\n      opponent_jumpshot\n    end\n  end\n\n  def get_defense defense_choices, type = \"starting\"\n    while true\n      puts \"Your #{type} defense will be? [6 - Press] [6.5 - Man-to-Man] [7 - Zone] [7.5 None]\"\n      defense = gets.chomp!\n      if defense_choices.include? defense.to_i\n        break\n      end\n    end \n\n    return defense.to_i\n  end\nend\n\nb = Basketball.new\n"
  },
  {
    "path": "07_Basketball/vbnet/Basketball.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Basketball\", \"Basketball.vbproj\", \"{09C533F2-4874-4BA4-9F80-BBE9E8E17456}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{09C533F2-4874-4BA4-9F80-BBE9E8E17456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{09C533F2-4874-4BA4-9F80-BBE9E8E17456}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{09C533F2-4874-4BA4-9F80-BBE9E8E17456}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{09C533F2-4874-4BA4-9F80-BBE9E8E17456}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "07_Basketball/vbnet/Basketball.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Basketball</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "07_Basketball/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "08_Batnum/README.md",
    "content": "### Batnum\n\nThe game starts with an imaginary pile of objects, coins for example. You and your opponent (the computer) alternately remove objects from the pile. You specify in advance the minimum and maximum number of objects that can be taken on each turn. You also specify in advance how winning is defined:\n1. To take the last object\n2. To avoid taking the last object\n\nYou may also determine whether you or the computer go first.\n\nThe strategy of this game is based on modulo arithmetic. If the maximum number of objects a player may remove in a turn is M, then to gain a winning position a player at the end of his turn must leave a stack of 1 modulo (M+1) coins. If you don’t understand this, play the game 23 Matches first, then BATNUM, and have fun!\n\nBATNUM is a generalized version of a great number of manual remove-the-object games. The original computer version was written by one of the two originators of the BASIC language, John Kemeny of Dartmouth College.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=14)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=29)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- Though the instructions say \"Enter a negative number for new pile size to stop playing,\" this does not actually work.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n"
  },
  {
    "path": "08_Batnum/batnum.bas",
    "content": "10 PRINT TAB(33);\"BATNUM\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n110 PRINT \"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\"\n120 PRINT \"COMPUTER IS YOUR OPPONENT.\"\n130 PRINT\n140 PRINT \"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\"\n150 PRINT \"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\"\n160 PRINT \"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\"\n170 PRINT \"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\"\n180 PRINT \"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\"\n190 PRINT \"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\"\n200 PRINT\n210 GOTO 330\n220 FOR I=1 TO 10\n230 PRINT\n240 NEXT I\n330 INPUT \"ENTER PILE SIZE\";N\n350 IF N>=1 THEN 370\n360 GOTO 330\n370 IF N<>INT(N) THEN 220\n380 IF N<1 THEN 220\n390 INPUT \"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \";M\n410 IF M=1 THEN 430\n420 IF M<>2 THEN 390\n430 INPUT \"ENTER MIN AND MAX \";A,B\n450 IF A>B THEN 430\n460 IF A<1 THEN 430\n470 IF A<>INT(A) THEN 430\n480 IF B<>INT(B) THEN 430\n490 INPUT \"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \";S\n500 PRINT:PRINT\n510 IF S=1 THEN 530\n520 IF S<>2 THEN 490\n530 C=A+B\n540 IF S=2 THEN 570\n550 GOSUB 600\n560 IF W=1 THEN 220\n570 GOSUB 810\n580 IF W=1 THEN 220\n590 GOTO 550\n600 Q=N\n610 IF M=1 THEN 630\n620 Q=Q-1\n630 IF M=1 THEN 680\n640 IF N>A THEN 720\n650 W=1\n660 PRINT \"COMPUTER TAKES\";N;\"AND LOSES.\"\n670 RETURN\n680 IF N>B THEN 720\n690 W=1\n700 PRINT \"COMPUTER TAKES\";N;\"AND WINS.\"\n710 RETURN\n720 P=Q-C*INT(Q/C)\n730 IF P>=A THEN 750\n740 P=A\n750 IF P<=B THEN 770\n760 P=B\n770 N=N-P\n780 PRINT \"COMPUTER TAKES\";P;\"AND LEAVES\";N\n790 W=0\n800 RETURN\n810 PRINT:PRINT \"YOUR MOVE \";\n820 INPUT P\n830 IF P<>0 THEN 870\n840 PRINT \"I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.\"\n850 W=1\n860 RETURN\n870 IF P<>INT(P) THEN 920\n880 IF P>=A THEN 910\n890 IF P=N THEN 960\n900 GOTO 920\n910 IF P<=B THEN 940\n920 PRINT \"ILLEGAL MOVE, REENTER IT \";\n930 GOTO 820\n940 N=N-P\n950 IF N<>0 THEN 1030\n960 IF M=1 THEN 1000\n970 PRINT \"TOUGH LUCK, YOU LOSE.\"\n980 W=1\n990 RETURN\n1000 PRINT \"CONGRATULATIONS, YOU WIN.\"\n1010 W=1\n1020 RETURN\n1030 IF N>=0 THEN 1060\n1040 N=N+P\n1050 GOTO 920\n1060 W=0\n1070 RETURN\n1080 END\n"
  },
  {
    "path": "08_Batnum/csharp/Batnum.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>net5.0</TargetFramework>\r\n    <NeutralLanguage>en-US</NeutralLanguage>\r\n  </PropertyGroup>\r\n\r\n  <ItemGroup>\r\n    <Compile Update=\"Properties\\Resources.Designer.cs\">\r\n      <DesignTime>True</DesignTime>\r\n      <AutoGen>True</AutoGen>\r\n      <DependentUpon>Resources.resx</DependentUpon>\r\n    </Compile>\r\n  </ItemGroup>\r\n\r\n  <ItemGroup>\r\n    <EmbeddedResource Update=\"Properties\\Resources.resx\">\r\n      <Generator>ResXFileCodeGenerator</Generator>\r\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\r\n    </EmbeddedResource>\r\n  </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "08_Batnum/csharp/Batnum.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.31019.35\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Batnum\", \"Batnum.csproj\", \"{64F32165-9D67-42B1-B04C-953CC756A170}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{64F32165-9D67-42B1-B04C-953CC756A170}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{64F32165-9D67-42B1-B04C-953CC756A170}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{64F32165-9D67-42B1-B04C-953CC756A170}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{64F32165-9D67-42B1-B04C-953CC756A170}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {73E40CC2-0E4E-48CF-8BDD-D6B6E995C14F}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "08_Batnum/csharp/BatnumGame.cs",
    "content": "﻿using Batnum.Properties;\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace Batnum\r\n{\r\n    public enum WinOptions\r\n    {\r\n        /// <summary>\r\n        /// Last person to play wins\r\n        /// </summary>\r\n        WinWithTakeLast = 1,\r\n        /// <summary>\r\n        /// Last person to play loses\r\n        /// </summary>\r\n        WinWithAvoidLast = 2\r\n    }\r\n\r\n    public enum Players\r\n    {\r\n        Computer = 1,\r\n        Human = 2\r\n    }\r\n\r\n    public class BatnumGame\r\n    {\r\n        public BatnumGame(int pileSize, WinOptions winCriteria, int minTake, int maxtake, Players firstPlayer, Func<string, int>askPlayerCallback)\r\n        {\r\n            this.pileSize = pileSize;\r\n            this.winCriteria = winCriteria;\r\n            this.minTake = minTake;\r\n            this.maxTake = maxtake;\r\n            this.currentPlayer = firstPlayer;\r\n            this.askPlayerCallback = askPlayerCallback;\r\n        }\r\n\r\n        private int pileSize;\r\n        private WinOptions winCriteria;\r\n        private int minTake;\r\n        private int maxTake;\r\n        private Players currentPlayer;\r\n        private Func<string, int> askPlayerCallback;\r\n\r\n        /// <summary>\r\n        /// Returns true if the game is running\r\n        /// </summary>\r\n        public bool IsRunning => pileSize > 0;\r\n\r\n        /// <summary>\r\n        /// Takes the next turn\r\n        /// </summary>\r\n        /// <returns>A message to be displayed to the player</returns>\r\n        public string TakeTurn()\r\n        {\r\n            //Edge condition - can occur when minTake is more > 1\r\n            if (pileSize < minTake)\r\n            {\r\n                pileSize = 0;\r\n                return string.Format(Resources.END_DRAW, minTake);\r\n            }\r\n            return currentPlayer == Players.Computer ? ComputerTurn() : PlayerTurn();\r\n        }\r\n\r\n        private string PlayerTurn()\r\n        {\r\n            int draw = askPlayerCallback(Resources.INPUT_TURN);\r\n            if (draw == 0)\r\n            {\r\n                pileSize = 0;\r\n                return Resources.INPUT_ZERO;\r\n            }\r\n            if (draw < minTake || draw > maxTake || draw > pileSize)\r\n            {\r\n                return Resources.INPUT_ILLEGAL;\r\n            }\r\n            pileSize = pileSize - draw;\r\n            if (pileSize == 0)\r\n            {\r\n                return winCriteria == WinOptions.WinWithTakeLast ? Resources.END_PLAYERWIN : Resources.END_PLAYERLOSE;\r\n            }\r\n            currentPlayer = Players.Computer;\r\n            return \"\";\r\n        }\r\n\r\n        private string ComputerTurn()\r\n        {\r\n            //first calculate the move to play\r\n            int sumTake = minTake + maxTake;\r\n            int draw = pileSize - sumTake * (int)(pileSize / (float)sumTake);\r\n            draw = Math.Clamp(draw, minTake, maxTake);\r\n\r\n            //detect win/lose conditions\r\n            switch (winCriteria)\r\n            {\r\n                case WinOptions.WinWithAvoidLast when (pileSize == minTake): //lose condition\r\n                    pileSize = 0;\r\n                    return string.Format(Resources.END_COMPLOSE, minTake);\r\n                case WinOptions.WinWithAvoidLast when (pileSize <= maxTake): //avoid automatic loss on next turn\r\n                    draw = Math.Clamp(draw, minTake, pileSize - 1);\r\n                    break;\r\n                case WinOptions.WinWithTakeLast when pileSize <= maxTake: // win condition\r\n                    draw = Math.Min(pileSize, maxTake);\r\n                    pileSize = 0;\r\n                    return string.Format(Resources.END_COMPWIN, draw);\r\n            }\r\n            pileSize -= draw;\r\n            currentPlayer = Players.Human;\r\n            return string.Format(Resources.COMPTURN, draw, pileSize);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "08_Batnum/csharp/ConsoleUtilities.cs",
    "content": "﻿using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace Batnum\r\n{\r\n    public static class ConsoleUtilities\r\n    {\r\n        /// <summary>\r\n        /// Ask the user a question and expects a comma separated pair of numbers representing a number range in response\r\n        /// the range provided must have a maximum which is greater than the minimum\r\n        /// </summary>\r\n        /// <param name=\"question\">The question to ask</param>\r\n        /// <param name=\"minimum\">The minimum value expected</param>\r\n        /// <param name=\"maximum\">The maximum value expected</param>\r\n        /// <returns>A pair of numbers representing the minimum and maximum of the range</returns>\r\n        public static (int min, int max) AskNumberRangeQuestion(string question, Func<int, int, bool> Validate)\r\n        {\r\n            while (true)\r\n            {\r\n                Console.Write(question);\r\n                Console.Write(\" \");\r\n                string[] rawInput = Console.ReadLine().Split(',');\r\n                if (rawInput.Length == 2)\r\n                {\r\n                    if (int.TryParse(rawInput[0], out int min) && int.TryParse(rawInput[1], out int max))\r\n                    {\r\n                        if (Validate(min, max))\r\n                        {\r\n                            return (min, max);\r\n                        }\r\n                    }\r\n                }\r\n                Console.WriteLine();\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Ask the user a question and expects a number in response\r\n        /// </summary>\r\n        /// <param name=\"question\">The question to ask</param>\r\n        /// <param name=\"minimum\">A minimum value expected</param>\r\n        /// <param name=\"maximum\">A maximum value expected</param>\r\n        /// <returns>The number the user entered</returns>\r\n        public static int AskNumberQuestion(string question, Func<int, bool> Validate)\r\n        {\r\n            while (true)\r\n            {\r\n                Console.Write(question);\r\n                Console.Write(\" \");\r\n                string rawInput = Console.ReadLine();\r\n                if (int.TryParse(rawInput, out int number))\r\n                {\r\n                    if (Validate(number))\r\n                    {\r\n                        return number;\r\n                    }\r\n                }\r\n                Console.WriteLine();\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Align content to center of console.\r\n        /// </summary>\r\n        /// <param name=\"content\">Content to center</param>\r\n        /// <returns>Center aligned text</returns>\r\n        public static string CenterText(string content)\r\n        {\r\n            int windowWidth = Console.WindowWidth;\r\n            return String.Format(\"{0,\" + ((windowWidth / 2) + (content.Length / 2)) + \"}\", content);\r\n        }\r\n\r\n        /// <summary>\r\n        ///     Writes the specified data, followed by the current line terminator, to the standard output stream, while wrapping lines that would otherwise break words.\r\n        ///     source: https://stackoverflow.com/questions/20534318/make-console-writeline-wrap-words-instead-of-letters\r\n        /// </summary>\r\n        /// <param name=\"paragraph\">The value to write.</param>\r\n        /// <param name=\"tabSize\">The value that indicates the column width of tab characters.</param>\r\n        public static void WriteLineWordWrap(string paragraph, int tabSize = 4)\r\n        {\r\n            string[] lines = paragraph\r\n                .Replace(\"\\t\", new String(' ', tabSize))\r\n                .Split(new string[] { Environment.NewLine }, StringSplitOptions.None);\r\n\r\n            for (int i = 0; i < lines.Length; i++)\r\n            {\r\n                string process = lines[i];\r\n                List<String> wrapped = new List<string>();\r\n\r\n                while (process.Length > Console.WindowWidth)\r\n                {\r\n                    int wrapAt = process.LastIndexOf(' ', Math.Min(Console.WindowWidth - 1, process.Length));\r\n                    if (wrapAt <= 0) break;\r\n\r\n                    wrapped.Add(process.Substring(0, wrapAt));\r\n                    process = process.Remove(0, wrapAt + 1);\r\n                }\r\n\r\n                foreach (string wrap in wrapped)\r\n                {\r\n                    Console.WriteLine(wrap);\r\n                }\r\n\r\n                Console.WriteLine(process);\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "08_Batnum/csharp/Program.cs",
    "content": "﻿using Batnum;\r\nusing Batnum.Properties;\r\nusing System;\r\n\r\nConsole.WriteLine(ConsoleUtilities.CenterText(Resources.GAME_NAME));\r\nConsole.WriteLine(ConsoleUtilities.CenterText(Resources.INTRO_HEADER));\r\nConsole.WriteLine();\r\nConsole.WriteLine();\r\nConsole.WriteLine();\r\nConsoleUtilities.WriteLineWordWrap(Resources.INTRO_PART1);\r\nConsole.WriteLine();\r\nConsoleUtilities.WriteLineWordWrap(Resources.INTRO_PART2);\r\n\r\nwhile (true)\r\n{\r\n    Console.WriteLine();\r\n    int pileSize = ConsoleUtilities.AskNumberQuestion(Resources.START_QUESTION_PILESIZE, (n) => n > 1);\r\n    WinOptions winOption = (WinOptions)ConsoleUtilities.AskNumberQuestion(Resources.START_QUESTION_WINOPTION, (n) => Enum.IsDefined(typeof(WinOptions), n));\r\n    (int minTake, int maxTake) = ConsoleUtilities.AskNumberRangeQuestion(Resources.START_QUESTION_DRAWMINMAX, (min,max) => min >= 1 && max < pileSize && max > min);\r\n    Players currentPlayer = (Players)ConsoleUtilities.AskNumberQuestion(Resources.START_QUESTION_WHOSTARTS, (n) => Enum.IsDefined(typeof(Players), n));\r\n\r\n    BatnumGame game = new BatnumGame(pileSize, winOption, minTake, maxTake, currentPlayer, (question) => ConsoleUtilities.AskNumberQuestion(question, (c) => true));\r\n    while(game.IsRunning)\r\n    {\r\n        string message = game.TakeTurn();\r\n        Console.WriteLine(message);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "08_Batnum/csharp/Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\r\n// <auto-generated>\r\n//     This code was generated by a tool.\r\n//     Runtime Version:4.0.30319.42000\r\n//\r\n//     Changes to this file may cause incorrect behavior and will be lost if\r\n//     the code is regenerated.\r\n// </auto-generated>\r\n//------------------------------------------------------------------------------\r\n\r\nnamespace Batnum.Properties {\r\n    using System;\r\n\r\n\r\n    /// <summary>\r\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\r\n    /// </summary>\r\n    // This class was auto-generated by the StronglyTypedResourceBuilder\r\n    // class via a tool like ResGen or Visual Studio.\r\n    // To add or remove a member, edit your .ResX file then rerun ResGen\r\n    // with the /str option, or rebuild your VS project.\r\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"16.0.0.0\")]\r\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\r\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\r\n    internal class Resources {\r\n\r\n        private static global::System.Resources.ResourceManager resourceMan;\r\n\r\n        private static global::System.Globalization.CultureInfo resourceCulture;\r\n\r\n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\r\n        internal Resources() {\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Returns the cached ResourceManager instance used by this class.\r\n        /// </summary>\r\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r\n        internal static global::System.Resources.ResourceManager ResourceManager {\r\n            get {\r\n                if (object.ReferenceEquals(resourceMan, null)) {\r\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Batnum.Properties.Resources\", typeof(Resources).Assembly);\r\n                    resourceMan = temp;\r\n                }\r\n                return resourceMan;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Overrides the current thread's CurrentUICulture property for all\r\n        ///   resource lookups using this strongly typed resource class.\r\n        /// </summary>\r\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r\n        internal static global::System.Globalization.CultureInfo Culture {\r\n            get {\r\n                return resourceCulture;\r\n            }\r\n            set {\r\n                resourceCulture = value;\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to COMPUTER TAKES {0} AND LEAVES {1}.\r\n        /// </summary>\r\n        internal static string COMPTURN {\r\n            get {\r\n                return ResourceManager.GetString(\"COMPTURN\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to COMPUTER TAKES {0} AND LOSES.\r\n        /// </summary>\r\n        internal static string END_COMPLOSE {\r\n            get {\r\n                return ResourceManager.GetString(\"END_COMPLOSE\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to COMPUTER TAKES {0} AND WINS.\r\n        /// </summary>\r\n        internal static string END_COMPWIN {\r\n            get {\r\n                return ResourceManager.GetString(\"END_COMPWIN\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to ITS A DRAW, THERE ARE ONLY {0} PIECES LEFT.\r\n        /// </summary>\r\n        internal static string END_DRAW {\r\n            get {\r\n                return ResourceManager.GetString(\"END_DRAW\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to TOUGH LUCK, YOU LOSE..\r\n        /// </summary>\r\n        internal static string END_PLAYERLOSE {\r\n            get {\r\n                return ResourceManager.GetString(\"END_PLAYERLOSE\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to CONGRATULATIONS, YOU WIN..\r\n        /// </summary>\r\n        internal static string END_PLAYERWIN {\r\n            get {\r\n                return ResourceManager.GetString(\"END_PLAYERWIN\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to BATNUM.\r\n        /// </summary>\r\n        internal static string GAME_NAME {\r\n            get {\r\n                return ResourceManager.GetString(\"GAME_NAME\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to ILLEGAL MOVE, RENETER IT.\r\n        /// </summary>\r\n        internal static string INPUT_ILLEGAL {\r\n            get {\r\n                return ResourceManager.GetString(\"INPUT_ILLEGAL\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to YOUR MOVE ?.\r\n        /// </summary>\r\n        internal static string INPUT_TURN {\r\n            get {\r\n                return ResourceManager.GetString(\"INPUT_TURN\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT..\r\n        /// </summary>\r\n        internal static string INPUT_ZERO {\r\n            get {\r\n                return ResourceManager.GetString(\"INPUT_ZERO\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to CREATIVE COMPUTING MORRISTOWN, NEW JERSEY.\r\n        /// </summary>\r\n        internal static string INTRO_HEADER {\r\n            get {\r\n                return ResourceManager.GetString(\"INTRO_HEADER\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to THIS PROGRAM IS A &apos;BATTLE&apos; OF NUMBERS GAME, WHERE THE COMPUTER IS YOUR OPPONENT.\r\n        /// </summary>\r\n        internal static string INTRO_PART1 {\r\n            get {\r\n                return ResourceManager.GetString(\"INTRO_PART1\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. WINNNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINING CONDITIONS. DON&apos;T USER ZERO, HOWWEVER, IN PLAYING THE GAME..\r\n        /// </summary>\r\n        internal static string INTRO_PART2 {\r\n            get {\r\n                return ResourceManager.GetString(\"INTRO_PART2\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to ENTER MIN AND MAX ?.\r\n        /// </summary>\r\n        internal static string START_QUESTION_DRAWMINMAX {\r\n            get {\r\n                return ResourceManager.GetString(\"START_QUESTION_DRAWMINMAX\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to ENTER PILE SIZE ?.\r\n        /// </summary>\r\n        internal static string START_QUESTION_PILESIZE {\r\n            get {\r\n                return ResourceManager.GetString(\"START_QUESTION_PILESIZE\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ?.\r\n        /// </summary>\r\n        internal static string START_QUESTION_WHOSTARTS {\r\n            get {\r\n                return ResourceManager.GetString(\"START_QUESTION_WHOSTARTS\", resourceCulture);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        ///   Looks up a localized string similar to ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ?.\r\n        /// </summary>\r\n        internal static string START_QUESTION_WINOPTION {\r\n            get {\r\n                return ResourceManager.GetString(\"START_QUESTION_WINOPTION\", resourceCulture);\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "08_Batnum/csharp/Properties/Resources.en.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!--\r\n    Microsoft ResX Schema\r\n\r\n    Version 2.0\r\n\r\n    The primary goals of this format is to allow a simple XML format\r\n    that is mostly human readable. The generation and parsing of the\r\n    various data types are done through the TypeConverter classes\r\n    associated with the data types.\r\n\r\n    Example:\r\n\r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n\r\n    There are any number of \"resheader\" rows that contain simple\r\n    name/value pairs.\r\n\r\n    Each data row contains a name, and value. The row also contains a\r\n    type or mimetype. Type corresponds to a .NET class that support\r\n    text/value conversion through the TypeConverter architecture.\r\n    Classes that don't support this are serialized and stored with the\r\n    mimetype set.\r\n\r\n    The mimetype is used for serialized objects, and tells the\r\n    ResXResourceReader how to depersist the object. This is currently not\r\n    extensible. For a given mimetype the value must be set accordingly:\r\n\r\n    Note - application/x-microsoft.net.object.binary.base64 is the format\r\n    that the ResXResourceWriter will generate, however the reader can\r\n    read any of the formats listed below.\r\n\r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with\r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with\r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array\r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <data name=\"COMPTURN\" xml:space=\"preserve\">\r\n    <value>COMPUTER TAKES {0} AND LEAVES {1}</value>\r\n  </data>\r\n  <data name=\"END_COMPLOSE\" xml:space=\"preserve\">\r\n    <value>COMPUTER TAKES {0} AND LOSES</value>\r\n  </data>\r\n  <data name=\"END_COMPWIN\" xml:space=\"preserve\">\r\n    <value>COMPUTER TAKES {0} AND WINS</value>\r\n  </data>\r\n  <data name=\"END_DRAW\" xml:space=\"preserve\">\r\n    <value>ITS A DRAW, THERE ARE ONLY {0} PIECES LEFT</value>\r\n  </data>\r\n  <data name=\"END_PLAYERLOSE\" xml:space=\"preserve\">\r\n    <value>TOUGH LUCK, YOU LOSE.</value>\r\n  </data>\r\n  <data name=\"END_PLAYERWIN\" xml:space=\"preserve\">\r\n    <value>CONGRATULATIONS, YOU WIN.</value>\r\n  </data>\r\n  <data name=\"GAME_NAME\" xml:space=\"preserve\">\r\n    <value>BATNUM</value>\r\n  </data>\r\n  <data name=\"INPUT_ILLEGAL\" xml:space=\"preserve\">\r\n    <value>ILLEGAL MOVE, RENETER IT</value>\r\n  </data>\r\n  <data name=\"INPUT_TURN\" xml:space=\"preserve\">\r\n    <value>YOUR MOVE ?</value>\r\n  </data>\r\n  <data name=\"INPUT_ZERO\" xml:space=\"preserve\">\r\n    <value>I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.</value>\r\n  </data>\r\n  <data name=\"INTRO_HEADER\" xml:space=\"preserve\">\r\n    <value>CREATIVE COMPUTING MORRISTOWN, NEW JERSEY</value>\r\n  </data>\r\n  <data name=\"INTRO_PART1\" xml:space=\"preserve\">\r\n    <value>THIS PROGRAM IS A 'BATTLE' OF NUMBERS GAME, WHERE THE COMPUTER IS YOUR OPPONENT</value>\r\n  </data>\r\n  <data name=\"INTRO_PART2\" xml:space=\"preserve\">\r\n    <value>THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. WINNNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINING CONDITIONS. DON'T USER ZERO, HOWWEVER, IN PLAYING THE GAME.</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_DRAWMINMAX\" xml:space=\"preserve\">\r\n    <value>ENTER MIN AND MAX ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_PILESIZE\" xml:space=\"preserve\">\r\n    <value>ENTER PILE SIZE ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_WHOSTARTS\" xml:space=\"preserve\">\r\n    <value>ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_WINOPTION\" xml:space=\"preserve\">\r\n    <value>ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ?</value>\r\n  </data>\r\n</root>\r\n"
  },
  {
    "path": "08_Batnum/csharp/Properties/Resources.fr.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!--\r\n    Microsoft ResX Schema\r\n\r\n    Version 2.0\r\n\r\n    The primary goals of this format is to allow a simple XML format\r\n    that is mostly human readable. The generation and parsing of the\r\n    various data types are done through the TypeConverter classes\r\n    associated with the data types.\r\n\r\n    Example:\r\n\r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n\r\n    There are any number of \"resheader\" rows that contain simple\r\n    name/value pairs.\r\n\r\n    Each data row contains a name, and value. The row also contains a\r\n    type or mimetype. Type corresponds to a .NET class that support\r\n    text/value conversion through the TypeConverter architecture.\r\n    Classes that don't support this are serialized and stored with the\r\n    mimetype set.\r\n\r\n    The mimetype is used for serialized objects, and tells the\r\n    ResXResourceReader how to depersist the object. This is currently not\r\n    extensible. For a given mimetype the value must be set accordingly:\r\n\r\n    Note - application/x-microsoft.net.object.binary.base64 is the format\r\n    that the ResXResourceWriter will generate, however the reader can\r\n    read any of the formats listed below.\r\n\r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with\r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with\r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array\r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <data name=\"COMPTURN\" xml:space=\"preserve\">\r\n    <value>L'ORDINATEUR PREND {0} ET LAISSE {1}</value>\r\n  </data>\r\n  <data name=\"END_COMPLOSE\" xml:space=\"preserve\">\r\n    <value>L'ORDINATEUR PREND {0} ET PERD</value>\r\n  </data>\r\n  <data name=\"END_COMPWIN\" xml:space=\"preserve\">\r\n    <value>L'ORDINATEUR PREND {0} ET GAGNE</value>\r\n  </data>\r\n  <data name=\"END_DRAW\" xml:space=\"preserve\">\r\n    <value>MATCH NUL, IL RESTE SEULEMENT {0} PIECES</value>\r\n  </data>\r\n  <data name=\"END_PLAYERLOSE\" xml:space=\"preserve\">\r\n    <value>PAS DE CHANCE. TU AS PERDU.</value>\r\n  </data>\r\n  <data name=\"END_PLAYERWIN\" xml:space=\"preserve\">\r\n    <value>BRAVO! TU AS GAGNE</value>\r\n  </data>\r\n  <data name=\"GAME_NAME\" xml:space=\"preserve\">\r\n    <value>BATNUM</value>\r\n  </data>\r\n  <data name=\"INPUT_ILLEGAL\" xml:space=\"preserve\">\r\n    <value>CE COUP EST INTERDIT. RE-ESSAIE</value>\r\n  </data>\r\n  <data name=\"INPUT_TURN\" xml:space=\"preserve\">\r\n    <value>TON TOUR ?</value>\r\n  </data>\r\n  <data name=\"INPUT_ZERO\" xml:space=\"preserve\">\r\n    <value>JE TE DIS DE NE PAS UTILISER LE ZERO! L'ORDINATEUR GAGNE PAR DEFAUT.</value>\r\n  </data>\r\n  <data name=\"INTRO_HEADER\" xml:space=\"preserve\">\r\n    <value>CREATIVE COMPUTING MORRISTOWN, NEW JERSEY</value>\r\n  </data>\r\n  <data name=\"INTRO_PART1\" xml:space=\"preserve\">\r\n    <value>CE PROGRAMME EST UN JEU 'BATAILLE' DE NOMBRES, OU L'ORDINATEUR EST TON ADVERSAIRE</value>\r\n  </data>\r\n  <data name=\"INTRO_PART2\" xml:space=\"preserve\">\r\n    <value>LE JEU COMMENCE AVEC UNE NOMBRE D'OBJETS DEFINI. TOI ET TON ADVERSAIRE ENLEVEZ EN ALTERNANCE UN NOMBRE D'OBJETS. LES CONDITIONS DE VICTOIRE SON DÉFINIES À L'AVANCE COMME PRENDRE OU NE PAS PRENDRE LE DERNIER OBJET. VOUS POUVEZ ÉGALEMENT PRÉCISER D'AUTRES CONDITIONS DES LE DÉBUT. TOUTEFOIS, N'UTILISEZ PAS LE CHIFFRE ZERO.</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_DRAWMINMAX\" xml:space=\"preserve\">\r\n    <value>ENTRE LE MINIMUM ET MAXIMUM D'OBJETS A RETIRER POUR CHAQUE TOUR ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_PILESIZE\" xml:space=\"preserve\">\r\n    <value>ENTRE LE NOMBRE D'OBJETS ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_WHOSTARTS\" xml:space=\"preserve\">\r\n    <value>ENTRE QUI COMMENCE - 1 L'ORDINATEUR, 2 TOI ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_WINOPTION\" xml:space=\"preserve\">\r\n    <value>ENTRE LA CONDITION DE VICTOIRE - 1 PRENDRE LA DERNIERE PIECE, 2 EVITER LA DERNIERE PIECE ?</value>\r\n  </data>\r\n</root>\r\n"
  },
  {
    "path": "08_Batnum/csharp/Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!--\r\n    Microsoft ResX Schema\r\n\r\n    Version 2.0\r\n\r\n    The primary goals of this format is to allow a simple XML format\r\n    that is mostly human readable. The generation and parsing of the\r\n    various data types are done through the TypeConverter classes\r\n    associated with the data types.\r\n\r\n    Example:\r\n\r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n\r\n    There are any number of \"resheader\" rows that contain simple\r\n    name/value pairs.\r\n\r\n    Each data row contains a name, and value. The row also contains a\r\n    type or mimetype. Type corresponds to a .NET class that support\r\n    text/value conversion through the TypeConverter architecture.\r\n    Classes that don't support this are serialized and stored with the\r\n    mimetype set.\r\n\r\n    The mimetype is used for serialized objects, and tells the\r\n    ResXResourceReader how to depersist the object. This is currently not\r\n    extensible. For a given mimetype the value must be set accordingly:\r\n\r\n    Note - application/x-microsoft.net.object.binary.base64 is the format\r\n    that the ResXResourceWriter will generate, however the reader can\r\n    read any of the formats listed below.\r\n\r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with\r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with\r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array\r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <data name=\"COMPTURN\" xml:space=\"preserve\">\r\n    <value>COMPUTER TAKES {0} AND LEAVES {1}</value>\r\n  </data>\r\n  <data name=\"END_COMPLOSE\" xml:space=\"preserve\">\r\n    <value>COMPUTER TAKES {0} AND LOSES</value>\r\n  </data>\r\n  <data name=\"END_COMPWIN\" xml:space=\"preserve\">\r\n    <value>COMPUTER TAKES {0} AND WINS</value>\r\n  </data>\r\n  <data name=\"END_DRAW\" xml:space=\"preserve\">\r\n    <value>ITS A DRAW, THERE ARE ONLY {0} PIECES LEFT</value>\r\n  </data>\r\n  <data name=\"END_PLAYERLOSE\" xml:space=\"preserve\">\r\n    <value>TOUGH LUCK, YOU LOSE.</value>\r\n  </data>\r\n  <data name=\"END_PLAYERWIN\" xml:space=\"preserve\">\r\n    <value>CONGRATULATIONS, YOU WIN.</value>\r\n  </data>\r\n  <data name=\"GAME_NAME\" xml:space=\"preserve\">\r\n    <value>BATNUM</value>\r\n  </data>\r\n  <data name=\"INPUT_ILLEGAL\" xml:space=\"preserve\">\r\n    <value>ILLEGAL MOVE, RENETER IT</value>\r\n  </data>\r\n  <data name=\"INPUT_TURN\" xml:space=\"preserve\">\r\n    <value>YOUR MOVE ?</value>\r\n  </data>\r\n  <data name=\"INPUT_ZERO\" xml:space=\"preserve\">\r\n    <value>I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.</value>\r\n  </data>\r\n  <data name=\"INTRO_HEADER\" xml:space=\"preserve\">\r\n    <value>CREATIVE COMPUTING MORRISTOWN, NEW JERSEY</value>\r\n  </data>\r\n  <data name=\"INTRO_PART1\" xml:space=\"preserve\">\r\n    <value>THIS PROGRAM IS A 'BATTLE' OF NUMBERS GAME, WHERE THE COMPUTER IS YOUR OPPONENT</value>\r\n  </data>\r\n  <data name=\"INTRO_PART2\" xml:space=\"preserve\">\r\n    <value>THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. WINNNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINING CONDITIONS. DON'T USER ZERO, HOWWEVER, IN PLAYING THE GAME.</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_DRAWMINMAX\" xml:space=\"preserve\">\r\n    <value>ENTER MIN AND MAX ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_PILESIZE\" xml:space=\"preserve\">\r\n    <value>ENTER PILE SIZE ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_WHOSTARTS\" xml:space=\"preserve\">\r\n    <value>ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ?</value>\r\n  </data>\r\n  <data name=\"START_QUESTION_WINOPTION\" xml:space=\"preserve\">\r\n    <value>ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ?</value>\r\n  </data>\r\n</root>\r\n"
  },
  {
    "path": "08_Batnum/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\nThis conversion uses C#9 and is built for .net 5.0\n\nFunctional changes from Original\n- handle edge condition for end game where the minimum draw amount is greater than the number of items remaining in the pile\n- Takes into account the width of the console\n- Mulilingual Support (English/French currently)\n"
  },
  {
    "path": "08_Batnum/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "08_Batnum/java/src/BatNum.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of BatNum\n * <p>\n * Based on the Basic game of BatNum here\n * https://github.com/coding-horror/basic-computer-games/blob/main/08%20Batnum/batnum.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class BatNum {\n\n    private enum GAME_STATE {\n        STARTING,\n        START_GAME,\n        CHOOSE_PILE_SIZE,\n        SELECT_WIN_OPTION,\n        CHOOSE_MIN_AND_MAX,\n        SELECT_WHO_STARTS_FIRST,\n        PLAYERS_TURN,\n        COMPUTERS_TURN,\n        ANNOUNCE_WINNER,\n        GAME_OVER\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private int pileSize;\n\n    // How to win the game options\n    enum WIN_OPTION {\n        TAKE_LAST,\n        AVOID_LAST\n    }\n\n    // Tracking the winner\n    enum WINNER {\n        COMPUTER,\n        PLAYER\n    }\n\n    private WINNER winner;\n\n    private WIN_OPTION winOption;\n\n    private int minSelection;\n    private int maxSelection;\n\n    // Used by computer for optimal move\n    private int rangeOfRemovals;\n\n    public BatNum() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction and optional instructions the first time the game is played.\n                case STARTING:\n                    intro();\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Start new game\n                case START_GAME:\n                    gameState = GAME_STATE.CHOOSE_PILE_SIZE;\n                    break;\n\n                case CHOOSE_PILE_SIZE:\n                    System.out.println();\n                    System.out.println();\n                    pileSize = displayTextAndGetNumber(\"ENTER PILE SIZE \");\n                    if (pileSize >= 1) {\n                        gameState = GAME_STATE.SELECT_WIN_OPTION;\n                    }\n                    break;\n\n                case SELECT_WIN_OPTION:\n                    int winChoice = displayTextAndGetNumber(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \");\n                    if (winChoice == 1) {\n                        winOption = WIN_OPTION.TAKE_LAST;\n                        gameState = GAME_STATE.CHOOSE_MIN_AND_MAX;\n                    } else if (winChoice == 2) {\n                        winOption = WIN_OPTION.AVOID_LAST;\n                        gameState = GAME_STATE.CHOOSE_MIN_AND_MAX;\n                    }\n                    break;\n\n                case CHOOSE_MIN_AND_MAX:\n                    String range = displayTextAndGetInput(\"ENTER MIN AND MAX \");\n                    minSelection = getDelimitedValue(range, 0);\n                    maxSelection = getDelimitedValue(range, 1);\n                    if (maxSelection > minSelection && minSelection >= 1) {\n                        gameState = GAME_STATE.SELECT_WHO_STARTS_FIRST;\n                    }\n\n                    // Used by computer in its turn\n                    rangeOfRemovals = minSelection + maxSelection;\n                    break;\n\n                case SELECT_WHO_STARTS_FIRST:\n                    int playFirstChoice = displayTextAndGetNumber(\"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \");\n                    if (playFirstChoice == 1) {\n                        gameState = GAME_STATE.COMPUTERS_TURN;\n                    } else if (playFirstChoice == 2) {\n                        gameState = GAME_STATE.PLAYERS_TURN;\n                    }\n                    break;\n\n                case PLAYERS_TURN:\n                    int playersMove = displayTextAndGetNumber(\"YOUR MOVE \");\n\n                    if (playersMove == 0) {\n                        System.out.println(\"I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.\");\n                        winner = WINNER.COMPUTER;\n                        gameState = GAME_STATE.ANNOUNCE_WINNER;\n                        break;\n                    }\n\n                    if (playersMove == pileSize && winOption == WIN_OPTION.AVOID_LAST) {\n                        winner = WINNER.COMPUTER;\n                        gameState = GAME_STATE.ANNOUNCE_WINNER;\n                        break;\n                    }\n\n                    // Check if players move is with the min and max possible\n                    if (playersMove >= minSelection && playersMove <= maxSelection) {\n                        // Valid so reduce pileSize by amount player entered\n                        pileSize -= playersMove;\n\n                        // Did this move result in there being no more objects on pile?\n                        if (pileSize == 0) {\n                            // Was the game setup so the winner was whoever took the last object\n                            if (winOption == WIN_OPTION.TAKE_LAST) {\n                                // Player won\n                                winner = WINNER.PLAYER;\n                            } else {\n                                // Computer one\n                                winner = WINNER.COMPUTER;\n                            }\n                            gameState = GAME_STATE.ANNOUNCE_WINNER;\n                        } else {\n                            // There are still items left.\n                            gameState = GAME_STATE.COMPUTERS_TURN;\n                        }\n                    } else {\n                        // Invalid move\n                        System.out.println(\"ILLEGAL MOVE, REENTER IT \");\n                    }\n                    break;\n\n                case COMPUTERS_TURN:\n                    int pileSizeLeft = pileSize;\n                    if (winOption == WIN_OPTION.TAKE_LAST) {\n                        if (pileSize > maxSelection) {\n\n                            int objectsToRemove = calculateComputersTurn(pileSizeLeft);\n\n                            pileSize -= objectsToRemove;\n                            System.out.println(\"COMPUTER TAKES \" + objectsToRemove + \" AND LEAVES \" + pileSize);\n                            gameState = GAME_STATE.PLAYERS_TURN;\n                        } else {\n                            System.out.println(\"COMPUTER TAKES \" + pileSize + \" AND WINS.\");\n                            winner = WINNER.COMPUTER;\n                            gameState = GAME_STATE.ANNOUNCE_WINNER;\n                        }\n                    } else {\n                        pileSizeLeft--;\n                        if (pileSize > minSelection) {\n                            int objectsToRemove = calculateComputersTurn(pileSizeLeft);\n                            pileSize -= objectsToRemove;\n                            System.out.println(\"COMPUTER TAKES \" + objectsToRemove + \" AND LEAVES \" + pileSize);\n                            gameState = GAME_STATE.PLAYERS_TURN;\n                        } else {\n                            System.out.println(\"COMPUTER TAKES \" + pileSize + \" AND LOSES.\");\n                            winner = WINNER.PLAYER;\n                            gameState = GAME_STATE.ANNOUNCE_WINNER;\n                        }\n                    }\n                    break;\n\n                case ANNOUNCE_WINNER:\n                    switch (winner) {\n                        case PLAYER:\n                            System.out.println(\"CONGRATULATIONS, YOU WIN.\");\n                            break;\n                        case COMPUTER:\n                            System.out.println(\"TOUGH LUCK, YOU LOSE.\");\n                            break;\n                    }\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Figure out the computers turn - i.e. how many objects to remove\n     *\n     * @param pileSizeLeft current size\n     * @return the number of objects to remove.\n     */\n    private int calculateComputersTurn(int pileSizeLeft) {\n        int computersNumberToRemove = pileSizeLeft - rangeOfRemovals * (pileSizeLeft / rangeOfRemovals);\n        if (computersNumberToRemove < minSelection) {\n            computersNumberToRemove = minSelection;\n        }\n        if (computersNumberToRemove > maxSelection) {\n            computersNumberToRemove = maxSelection;\n        }\n\n        return computersNumberToRemove;\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(33) + \"BATNUM\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\");\n        System.out.println(\"COMPUTER IS YOUR OPPONENT.\");\n        System.out.println();\n        System.out.println(\"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\");\n        System.out.println(\"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\");\n        System.out.println(\"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\");\n        System.out.println(\"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\");\n        System.out.println(\"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\");\n        System.out.println(\"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\");\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /**\n     * Accepts a string delimited by comma's and returns the nth delimited\n     * value (starting at count 0).\n     *\n     * @param text - text with values separated by comma's\n     * @param pos  - which position to return a value for\n     * @return the int representation of the value\n     */\n    private int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        return Integer.parseInt(tokens[pos]);\n    }\n}\n"
  },
  {
    "path": "08_Batnum/java/src/BatNumGame.java",
    "content": "public class BatNumGame {\n\n    public static void main(String[] args) {\n\n        BatNum batNum = new BatNum();\n        batNum.play();\n    }\n}\n"
  },
  {
    "path": "08_Batnum/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "08_Batnum/javascript/batnum.html",
    "content": "<html>\n<head>\n<title>BATNUM</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"batnum.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "08_Batnum/javascript/batnum.js",
    "content": "// BATNUM\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"BATNUM\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\\n\");\n    print(\"COMPUTER IS YOUR OPPONENT.\\n\");\n    print(\"\\n\");\n    print(\"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\\n\");\n    print(\"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\\n\");\n    print(\"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\\n\");\n    print(\"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\\n\");\n    print(\"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\\n\");\n    print(\"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\\n\");\n    print(\"\\n\");\n    first_time = 1;\n    while (1) {\n        while (1) {\n            if (first_time == 1) {\n                first_time = 0;\n            } else {\n                for (i = 1; i <= 10; i++)\n                    print(\"\\n\");\n            }\n            print(\"ENTER PILE SIZE\");\n            n = parseInt(await input());\n            if (n >= 1)\n                break;\n        }\n        while (1) {\n            print(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \");\n            m = parseInt(await input());\n            if (m == 1 || m == 2)\n                break;\n        }\n        while (1) {\n            print(\"ENTER MIN AND MAX \");\n            str = await input();\n            a = parseInt(str);\n            b = parseInt(str.substr(str.indexOf(\",\") + 1));\n            if (a <= b && a >= 1)\n                break;\n        }\n        while (1) {\n            print(\"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \");\n            s = parseInt(await input());\n            print(\"\\n\");\n            print(\"\\n\");\n            if (s == 1 || s == 2)\n                break;\n        }\n        w = 0;\n        c = a + b;\n        while (1) {\n            if (s == 1) {\n                // Computer's turn\n                q = n;\n                if (m != 1)\n                    q--;\n                if (m != 1 && n <= a) {\n                    w = 1;\n                    print(\"COMPUTER TAKES \" + n + \" AND LOSES.\\n\");\n                } else if (m == 1 && n <= b) {\n                    w = 1;\n                    print(\"COMPUTER TAKES \" + n + \" AND WINS.\\n\");\n                } else {\n                    p = q - c * Math.floor(q / c);\n                    if (p < a)\n                        p = a;\n                    if (p > b)\n                        p = b;\n                    n -= p;\n                    print(\"COMPUTER TAKES \" + p + \" AND LEAVES \" + n + \"\\n\");\n                    w = 0;\n                }\n                s = 2;\n            }\n            if (w)\n                break;\n            if (s == 2) {\n                while (1) {\n                    print(\"\\n\");\n                    print(\"YOUR MOVE \");\n                    p = parseInt(await input());\n                    if (p == 0) {\n                        print(\"I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.\\n\");\n                        w = 1;\n                        break;\n                    } else if (p >= a && p <= b && n - p >= 0) {\n                        break;\n                    }\n                }\n                if (p != 0) {\n                    n -= p;\n                    if (n == 0) {\n                        if (m != 1) {\n                            print(\"TOUGH LUCK, YOU LOSE.\\n\");\n                        } else {\n                            print(\"CONGRATULATIONS, YOU WIN.\\n\");\n                        }\n                        w = 1;\n                    } else {\n                        w = 0;\n                    }\n                }\n                s = 1;\n            }\n            if (w)\n                break;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "08_Batnum/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "08_Batnum/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "08_Batnum/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "08_Batnum/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/) by [Austin White](https://github.com/austinwhite)\n"
  },
  {
    "path": "08_Batnum/perl/batnum.pl",
    "content": "use strict;\nuse warnings;\n\nmy %WIN_OPTIONS = (\n    \"UNDEFINED\" => 0,\n    \"TAKE_LAST\" => 1,\n    \"AVOID_LAST\" => 2,\n);\n\nmy %START_OPTIONS = (\n    \"UNDEFINED\" => 0,\n    \"COMPUTER_FIRST\" => 1,\n    \"PLAYER_FIRST\" => 2,\n);\n\n\nsub run {\n    # input:        no input perameters\n    #\n    # output:       nothing returned\n    #\n    # description:  This is the primary game loop. Once a game is concluded\n    #               another will begin right away until the exeecution\n    #               is terminated.\n\n    my $pile_size = undef;\n    my $min_select = undef;\n    my $max_select = undef;\n    my $win_option = undef;\n    my $start_option = undef;\n\n    while (1) {\n        write_intro();\n\n        ($pile_size, $min_select, $max_select, $win_option, $start_option)\n            = &get_user_input();\n\n        if ($pile_size < 0) {\n            last;\n        }\n\n        play($pile_size, $min_select, $max_select, $win_option, $start_option);\n\n        printf \"\\n\";\n    }\n}\n\n\nsub write_intro {\n    # input:        no input perameters\n    #\n    # output:       nothing returned\n    #\n    # description:  This subroutine prints the intro and rules.\n\n    printf \"%33s\", \"BATNUM\\n\";\n    printf \"%15s\", \"CREATIVE COMPUTING  MORRISSTOWN, NEW JERSEY\\n\";\n    printf \"%s\", \"\\n\";\n    printf \"%s\", \"\\n\";\n    printf \"%s\", \"\\n\";\n    printf \"%s\", \"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\\n\";\n    printf \"%s\", \"COMPUTER IS YOUR OPPONENT.\\n\";\n    printf \"%s\", \"\\n\";\n    printf \"%s\", \"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\\n\";\n    printf \"%s\", \"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\\n\";\n    printf \"%s\", \"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\\n\";\n    printf \"%s\", \"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\\n\";\n    printf \"%s\", \"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\\n\";\n    printf \"%s\", \"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\\n\";\n    printf \"%s\", \"\\n\";\n}\n\n\nsub get_user_input {\n    # input:        no input perameters\n    #\n    # output:       (int) pile_size\n    #               (int) min_select\n    #               (int) max_select\n    #               (int) win_option\n    #               (int) start_option\n    #\n    # description:  This subroutine gets the necessary perametes from the player.\n    #\n    #               pile_size (int > 0)\n    #               min_select (int > 0) max_select (int > 0)\n    #                   -> min/max, space delimated\n    #               win_option (int 1|2)\n    #               start_option (int 1|2)\n\n    my $pile_size = 0;\n    my $min_select = 0;\n    my $max_select = 0;\n    my $win_option = $WIN_OPTIONS{ \"UNDEFINED\" };\n    my $start_option = $START_OPTIONS{ \"UNDEFINED\" };\n\n    while ($pile_size < 1) {\n        printf \"%s\", \"ENTER PILE SIZE: \";\n        $pile_size = <STDIN>;\n        if ($pile_size < 0) {\n            return ($pile_size);\n        }\n    }\n\n    while ($min_select < 1 || $max_select < 1 || $min_select > $max_select) {\n        printf \"%s\", \"ENTER MIN AND MAX: \";\n        my $raw_input = <STDIN>;\n        ($min_select, $max_select) = split(' ', $raw_input);\n    }\n\n    while ($win_option eq $WIN_OPTIONS{ \"UNDEFINED\" }) {\n        printf \"%s\", \"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \";\n        $win_option = <STDIN>;\n    }\n\n    while ($start_option eq $START_OPTIONS{ \"UNDEFINED\" }) {\n        printf \"%s\", \"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST: \";\n        $start_option = <STDIN>;\n    }\n\n    return ($pile_size, $min_select, $max_select, $win_option, $start_option);\n}\n\n\nsub play {\n    # input:        (int) pile_size\n    #               (int) min_select\n    #               (int) max_select\n    #               (int) win_option\n    #               (int) start_option\n    #\n    # output:       nothing returned\n    #\n    # description:  This is where the game logic lives. The player and computer\n    #               both take turns until the current game is over.\n\n    my $pile_size = shift;\n    my $min_select = shift;\n    my $max_select = shift;\n    my $win_option = shift;\n    my $start_option = shift;\n\n    my $game_over = 0;\n    my $players_turn = $start_option eq $START_OPTIONS{ \"PLAYER_FIRST\" } ? 1 : 0;\n\n    while (!$game_over) {\n        if ($players_turn) {\n            ($game_over, $pile_size) = players_move(\n                $pile_size, $min_select, $max_select, $win_option);\n\n            $players_turn = 0;\n\n            if ($game_over) {\n                return;\n            }\n        } else {\n            ($game_over, $pile_size) = computers_move(\n                $pile_size, $min_select, $max_select, $win_option);\n\n            $players_turn = 1;\n        }\n    }\n\n    return;\n}\n\n\nsub players_move {\n    # input:        (int) pile_size\n    #               (int) min_select\n    #               (int) max_select\n    #               (int) win_option\n    #\n    # output:       (boolean) game is over\n    #               (int) new pile_size\n    #\n    # description:  This subroutine handles the players move.\n\n    my $pile_size = shift;\n    my $min_select = shift;\n    my $max_select = shift;\n    my $win_option = shift;\n\n    my $finished = 0;\n\n    while (!$finished) {\n        my $remove_amount = undef;\n\n        printf \"%s\", \"YOUR MOVE: \";\n        $remove_amount = <>;\n\n        if ($remove_amount eq 0) {\n            printf \"%s\", \"I TOLD YOU NOT TO USE ZERO!  COMPUTER WINS BY FORFEIT.\";\n            return (1, $pile_size);\n        } elsif ($remove_amount > $max_select || $remove_amount < $min_select) {\n            printf \"%s\", \"ILLEGAL MOVE, TRY AGAIN.\\n\";\n            next;\n        } else {\n            $pile_size -= $remove_amount;\n            $finished = 1;\n        }\n\n        if ($pile_size <= 0) {\n            if ($win_option eq $WIN_OPTIONS{ \"AVOID_LAST\" }) {\n                printf \"%s\", \"TOUGH LUCK, YOU LOSE.\\n\";\n            } else {\n                printf \"%s\", \"CONGRATULATIONS, YOU WIN.\\n\";\n            }\n            return (1, $pile_size);\n        }\n    }\n\n    return (0, $pile_size);\n}\n\n\nsub computers_move {\n    # input:        (int) pile_size\n    #               (int) min_select\n    #               (int) max_select\n    #               (int) win_option\n    #\n    # output:       (boolean) game is over\n    #               (int) new pile_size\n    #\n    # description:  This subroutine handles the computers move.\n\n    my $pile_size = shift;\n    my $min_select = shift;\n    my $max_select = shift;\n    my $win_option = shift;\n\n    if ($win_option eq $WIN_OPTIONS{ \"TAKE_LAST\" } && $pile_size <= $max_select) {\n        printf \"COMPUTER TAKES %d AND WINS.\\n\", $pile_size;\n        return (1, $pile_size);\n    }\n\n    if ($win_option eq $WIN_OPTIONS{ \"AVOID_LAST\" } && $pile_size <= $min_select) {\n        printf \"COMPUTER TAKES %d AND LOSES.\\n\", $pile_size;\n        return (1, $pile_size);\n    }\n\n    my $remove_amount = get_computer_remove_amount($min_select, $max_select);\n\n    $pile_size -= $remove_amount;\n\n    if ($pile_size <= 0) {\n        printf \"COMPUTER TAKES %d AND WINS.\\n\", $remove_amount;\n        return (1, $pile_size);\n    } else {\n        printf \"COMPUTER TAKES %d AND LEAVES %d.\\n\", $remove_amount, $pile_size;\n    }\n\n    return (0, $pile_size);\n}\n\n\nsub get_computer_remove_amount {\n    # input:        (int) min_select\n    #               (int) max_select\n    #\n    # output:       (int) random number (x) where,\n    #               min_select <= x <= max_select\n    #\n    # description:  This subroutine generates the amount of items the computer\n    #               will remove.\n\n    my $min_select = shift;\n    my $max_select = shift;\n\n    return (int(rand($max_select - $min_select)) + $min_select);\n}\n\n\n# start the game\nrun();\n"
  },
  {
    "path": "08_Batnum/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "08_Batnum/python/batnum.py",
    "content": "from enum import IntEnum\nfrom typing import Any, Tuple\n\n\nclass WinOptions(IntEnum):\n    Undefined = 0\n    TakeLast = 1\n    AvoidLast = 2\n\n    @classmethod\n    def _missing_(cls, value: Any) -> \"WinOptions\":\n        try:\n            int_value = int(value)\n        except Exception:\n            return WinOptions.Undefined\n        if int_value == 1:\n            return WinOptions.TakeLast\n        elif int_value == 2:\n            return WinOptions.AvoidLast\n        else:\n            return WinOptions.Undefined\n\n\nclass StartOptions(IntEnum):\n    Undefined = 0\n    ComputerFirst = 1\n    PlayerFirst = 2\n\n    @classmethod\n    def _missing_(cls, value: Any) -> \"StartOptions\":\n        try:\n            int_value = int(value)\n        except Exception:\n            return StartOptions.Undefined\n        if int_value == 1:\n            return StartOptions.ComputerFirst\n        elif int_value == 2:\n            return StartOptions.PlayerFirst\n        else:\n            return StartOptions.Undefined\n\n\ndef print_intro() -> None:\n    \"\"\"Print out the introduction and rules for the game.\"\"\"\n    print(\"BATNUM\".rjust(33, \" \"))\n    print(\"CREATIVE COMPUTING  MORRISSTOWN, NEW JERSEY\".rjust(15, \" \"))\n    print()\n    print()\n    print()\n    print(\"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\")\n    print(\"COMPUTER IS YOUR OPPONENT.\")\n    print()\n    print(\"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\")\n    print(\"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\")\n    print(\"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\")\n    print(\"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\")\n    print(\"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\")\n    print(\"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\")\n    print()\n    return\n\n\ndef get_params() -> Tuple[int, int, int, StartOptions, WinOptions]:\n    \"\"\"This requests the necessary parameters to play the game.\n\n    Returns a set with the five game parameters:\n        pile_size - the starting size of the object pile\n        min_select - minimum selection that can be made on each turn\n        max_select - maximum selection that can be made on each turn\n        start_option - 1 if the computer is first\n                      or 2 if the player is first\n        win_option - 1 if the goal is to take the last object\n                    or 2 if the goal is to not take the last object\n    \"\"\"\n    pile_size = get_pile_size()\n    if pile_size < 0:\n        return (-1, 0, 0, StartOptions.Undefined, WinOptions.Undefined)\n    win_option = get_win_option()\n    min_select, max_select = get_min_max()\n    start_option = get_start_option()\n    return (pile_size, min_select, max_select, start_option, win_option)\n\n\ndef get_pile_size() -> int:\n    # A negative number will stop the game.\n    pile_size = 0\n    while pile_size == 0:\n        try:\n            pile_size = int(input(\"ENTER PILE SIZE \"))\n        except ValueError:\n            pile_size = 0\n    return pile_size\n\n\ndef get_win_option() -> WinOptions:\n    win_option: WinOptions = WinOptions.Undefined\n    while win_option == WinOptions.Undefined:\n        win_option = WinOptions(input(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \"))  # type: ignore\n    return win_option\n\n\ndef get_min_max() -> Tuple[int, int]:\n    min_select = 0\n    max_select = 0\n    while min_select < 1 or max_select < 1 or min_select > max_select:\n        (min_select, max_select) = (\n            int(x) for x in input(\"ENTER MIN AND MAX \").split(\" \")\n        )\n    return min_select, max_select\n\n\ndef get_start_option() -> StartOptions:\n    start_option: StartOptions = StartOptions.Undefined\n    while start_option == StartOptions.Undefined:\n        start_option = StartOptions(input(\"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \"))  # type: ignore\n    return start_option\n\n\ndef player_move(\n    pile_size: int, min_select: int, max_select: int, win_option: WinOptions\n) -> Tuple[bool, int]:\n    \"\"\"This handles the player's turn - asking the player how many objects\n    to take and doing some basic validation around that input.  Then it\n    checks for any win conditions.\n\n    Returns a boolean indicating whether the game is over and the new pile_size.\"\"\"\n    player_done = False\n    while not player_done:\n        player_move = int(input(\"YOUR MOVE \"))\n        if player_move == 0:\n            print(\"I TOLD YOU NOT TO USE ZERO!  COMPUTER WINS BY FORFEIT.\")\n            return (True, pile_size)\n        if player_move > max_select or player_move < min_select:\n            print(\"ILLEGAL MOVE, REENTER IT\")\n            continue\n        pile_size = pile_size - player_move\n        player_done = True\n        if pile_size <= 0:\n            if win_option == WinOptions.AvoidLast:\n                print(\"TOUGH LUCK, YOU LOSE.\")\n            else:\n                print(\"CONGRATULATIONS, YOU WIN.\")\n            return (True, pile_size)\n    return (False, pile_size)\n\n\ndef computer_pick(\n    pile_size: int, min_select: int, max_select: int, win_option: WinOptions\n) -> int:\n    \"\"\"This handles the logic to determine how many objects the computer\n    will select on its turn.\n    \"\"\"\n    q = pile_size - 1 if win_option == WinOptions.AvoidLast else pile_size\n    c = min_select + max_select\n    computer_pick = q - (c * int(q / c))\n    computer_pick = max(computer_pick, min_select)\n    return min(computer_pick, max_select)\n\n\ndef computer_move(\n    pile_size: int, min_select: int, max_select: int, win_option: WinOptions\n) -> Tuple[bool, int]:\n    \"\"\"This handles the computer's turn - first checking for the various\n    win/lose conditions and then calculating how many objects\n    the computer will take.\n\n    Returns a boolean indicating whether the game is over and the new pile_size.\"\"\"\n    # First, check for win conditions on this move\n    # In this case, we win by taking the last object and\n    # the remaining pile is less than max select\n    # so the computer can grab them all and win\n    if win_option == WinOptions.TakeLast and pile_size <= max_select:\n        print(f\"COMPUTER TAKES {pile_size} AND WINS.\")\n        return (True, pile_size)\n    # In this case, we lose by taking the last object and\n    # the remaining pile is less than minsize and the computer\n    # has to take all of them.\n    if win_option == WinOptions.AvoidLast and pile_size <= min_select:\n        print(f\"COMPUTER TAKES {min_select} AND LOSES.\")\n        return (True, pile_size)\n\n    # Otherwise, we determine how many the computer selects\n    curr_sel = computer_pick(pile_size, min_select, max_select, win_option)\n    pile_size -= curr_sel\n    print(f\"COMPUTER TAKES {curr_sel} AND LEAVES {pile_size}\")\n    return (False, pile_size)\n\n\ndef play_game(\n    pile_size: int,\n    min_select: int,\n    max_select: int,\n    start_option: StartOptions,\n    win_option: WinOptions,\n) -> None:\n    \"\"\"This is the main game loop - repeating each turn until one\n    of the win/lose conditions is met.\n    \"\"\"\n    game_over = False\n    # players_turn is a boolean keeping track of whether it's the\n    # player's or computer's turn\n    players_turn = start_option == StartOptions.PlayerFirst\n\n    while not game_over:\n        if players_turn:\n            (game_over, pile_size) = player_move(\n                pile_size, min_select, max_select, win_option\n            )\n            players_turn = False\n            if game_over:\n                return\n        if not players_turn:\n            (game_over, pile_size) = computer_move(\n                pile_size, min_select, max_select, win_option\n            )\n            players_turn = True\n\n\ndef main() -> None:\n    while True:\n        print_intro()\n        (pile_size, min_select, max_select, start_option, win_option) = get_params()\n\n        if pile_size < 0:\n            return\n\n        # Just keep playing the game until the user kills it with ctrl-C\n        play_game(pile_size, min_select, max_select, start_option, win_option)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "08_Batnum/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "08_Batnum/ruby/batnum.rb",
    "content": "#!/usr/bin/env ruby\n\ndef instructions\n    puts <<~EOF\n    THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\n    COMPUTER IS YOUR OPPONENT.\n\n    THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\n    AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\n    WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\n    NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\n    DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\n    ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\n    EOF\nend\n\ndef ask_for_pile_size\n    loop do\n        puts \"ENTER PILE SIZE:\"\n        pile_size = gets.to_i\n        break pile_size if pile_size != 0\n    end\nend\n\nGOAL_TAKE_LAST = 1\nGOAL_AVOID_LAST = 2\ndef ask_for_goal\n    loop do\n        puts \"ENTER WIN OPTION - #{GOAL_TAKE_LAST} TO TAKE LAST, #{GOAL_AVOID_LAST} TO AVOID LAST:\"\n        response = gets.to_i\n        break response if [GOAL_TAKE_LAST, GOAL_AVOID_LAST].member? response\n    end\nend\n\ndef ask_for_min_max_take\n    loop do\n        puts \"ENTER MIN AND MAX, SEPARATED BY A COMMA:\"\n        response = gets.split(',').map {|piece| piece.to_i}\n        next if response.length != 2\n        min_take, max_take = response\n        break min_take, max_take if 0 < min_take && min_take <= max_take\n    end\nend\n\nCOMPUTER_MOVE = 1\nPLAYER_MOVE = 2\ndef ask_who_makes_first_move\n    loop do\n        puts \"ENTER START OPTION - #{COMPUTER_MOVE} COMPUTER FIRST, #{PLAYER_MOVE} YOU FIRST:\"\n        response = gets.to_i\n        break response if [COMPUTER_MOVE, PLAYER_MOVE].member? response\n    end\nend\n\ndef ask_for_player_take(min_take:, max_take:)\n    loop do\n        puts \"YOUR MOVE:\"\n        response = gets.to_i\n        break response if response == 0 || response == response.clamp(min_take, max_take)\n        puts \"ILLEGAL MOVE, REENTER IT.\"\n    end\nend\n\ndef battle(pile:, goal:, min_take:, max_take:, first_move:)\n    next_move = first_move\n    loop do\n        if next_move == COMPUTER_MOVE\n            next_move = PLAYER_MOVE\n            take = (\n                if goal == GOAL_TAKE_LAST\n                    pile % (min_take + max_take)\n                else\n                    (pile - 1) % (min_take + max_take)\n                end\n            ).clamp(min_take, max_take)\n            pile = pile - take\n            if pile > 0\n                puts \"COMPUTER TAKES #{take} AND LEAVES #{pile}\"\n            else\n                if goal == GOAL_TAKE_LAST\n                    puts \"COMPUTER TAKES #{take} AND WINS.\"\n                    break\n                else\n                    puts \"COMPUTER TAKES #{take} AND LOSES.\"\n                    break\n                end\n            end\n        else\n            next_move = COMPUTER_MOVE\n            take = ask_for_player_take(min_take: min_take, max_take: max_take)\n            if take == 0\n                puts \"I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.\"\n                break\n            end\n            pile = pile - take\n            if pile > 0\n                puts \"PLAYER TAKES #{take} AND LEAVES #{pile}\"\n            else\n                if goal == GOAL_TAKE_LAST\n                    puts \"CONGRATULATIONS, YOU WIN.\"\n                    break\n                else\n                    puts \"TOUGH LUCK, YOU LOSE.\"\n                    break\n                end\n            end\n        end\n    end\nend\n\n\ndef main\n    instructions\n    loop do\n        pile = ask_for_pile_size\n        break if pile < 0\n        goal = ask_for_goal\n        min_take, max_take = ask_for_min_max_take\n        first_move = ask_who_makes_first_move\n        battle(\n            pile: pile,\n            goal: goal,\n            min_take: min_take,\n            max_take: max_take,\n            first_move: first_move,\n        )\n    end\nend\n\nmain\n"
  },
  {
    "path": "08_Batnum/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "08_Batnum/rust/src/main.rs",
    "content": "use std::io::{self, Write};\n\n/// Print out the introduction and rules for the game.\nfn print_intro() {\n    println!();\n    println!();\n    println!(\"{:>33}\", \"BATNUM\");\n    println!(\"{:>15}\", \"CREATIVE COMPUTING  MORRISSTOWN, NEW JERSEY\");\n    println!();\n    println!();\n    println!();\n    println!(\"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\");\n    println!(\"COMPUTER IS YOUR OPPONENT.\");\n    println!();\n    println!(\"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\");\n    println!(\"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\");\n    println!(\"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\");\n    println!(\"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\");\n    println!(\"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\");\n    println!(\"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\");\n    println!();\n}\n\n/// This requests the necessary parameters to play the game.\n/// five game parameters:\n/// * pile_size - the starting size of the object pile\n/// * min_select - minimum selection that can be made on each turn\n/// * max_select - maximum selection that can be made on each turn\n/// * start_option - computer first or player first\n/// * win_option - goal is to take the last object\n///                or the goal is to not take the last object\nstruct Params {\n    pub pile_size: usize,\n    pub min_select: usize,\n    pub max_select: usize,\n    pub start_option: StartOption,\n    pub win_option: WinOption,\n}\n\n#[derive(PartialEq, Eq)]\nenum StartOption {\n    ComputerFirst,\n    PlayerFirst,\n}\n\n#[derive(PartialEq, Eq)]\nenum WinOption {\n    TakeLast,\n    AvoidLast,\n}\n\nimpl Params {\n    pub fn get_params() -> Self {\n        let pile_size = Self::get_pile_size();\n        let (min_select, max_select) = Self::get_min_max();\n        let start_option = Self::get_start_option();\n        let win_option = Self::get_win_option();\n\n        Self {\n            pile_size,\n            min_select,\n            max_select,\n            start_option,\n            win_option,\n        }\n    }\n\n    fn get_pile_size() -> usize {\n        print!(\"ENTER PILE SIZE \");\n        let _ = io::stdout().flush();\n        read_input_integer()\n    }\n\n    fn get_win_option() -> WinOption {\n        print!(\"ENTER WIN OPTION: 1 TO TAKE LAST, 2 TO AVOID LAST: \");\n        let _ = io::stdout().flush();\n\n        loop {\n            match read_input_integer() {\n                1 => {\n                    return WinOption::TakeLast;\n                }\n                2 => {\n                    return WinOption::AvoidLast;\n                }\n                _ => {\n                    print!(\"Please enter 1 or 2 \");\n                    let _ = io::stdout().flush();\n                    continue;\n                }\n            }\n        }\n    }\n\n    fn get_start_option() -> StartOption {\n        print!(\"ENTER START OPTION: 1 COMPUTER FIRST, 2 YOU FIRST \");\n        let _ = io::stdout().flush();\n\n        loop {\n            match read_input_integer() {\n                1 => {\n                    return StartOption::ComputerFirst;\n                }\n                2 => {\n                    return StartOption::PlayerFirst;\n                }\n                _ => {\n                    print!(\"Please enter 1 or 2 \");\n                    let _ = io::stdout().flush();\n                    continue;\n                }\n            }\n        }\n    }\n\n    fn get_min_max() -> (usize, usize) {\n        print!(\"ENTER MIN \");\n        let _ = io::stdout().flush();\n        let min = read_input_integer();\n\n        print!(\"ENTER MAX \");\n        let _ = io::stdout().flush();\n        let max = read_input_integer();\n\n        (min, max)\n    }\n}\n\nfn read_input_integer() -> usize {\n    loop {\n        let mut input = String::new();\n        io::stdin()\n            .read_line(&mut input)\n            .expect(\"Failed to read line\");\n        match input.trim().parse::<usize>() {\n            Ok(num) => {\n                if num == 0 {\n                    print!(\"Must be greater than zero \");\n                    let _ = io::stdout().flush();\n                    continue;\n                }\n                return num;\n            }\n            Err(_err) => {\n                print!(\"Please enter a number greater than zero \");\n                let _ = io::stdout().flush();\n                continue;\n            }\n        }\n    }\n}\n\nfn player_move(pile_size: &mut usize, params: &Params) -> bool {\n    loop {\n        print!(\"YOUR MOVE \");\n        let _ = io::stdout().flush();\n\n        let player_move = read_input_integer();\n        if player_move == 0 {\n            println!(\"I TOLD YOU NOT TO USE ZERO!  COMPUTER WINS BY FORFEIT.\");\n            return true;\n        }\n        if player_move > params.max_select || player_move < params.min_select {\n            println!(\"ILLEGAL MOVE, REENTER IT\");\n            continue;\n        }\n        *pile_size -= player_move;\n        if *pile_size == 0 {\n            if params.win_option == WinOption::AvoidLast {\n                println!(\"TOUGH LUCK, YOU LOSE.\");\n            } else {\n                println!(\"CONGRATULATIONS, YOU WIN.\")\n            }\n            return true;\n        }\n        return false;\n    }\n}\n\nfn computer_pick(pile_size: usize, params: &Params) -> usize {\n    let q = if params.win_option == WinOption::AvoidLast {\n        pile_size - 1\n    } else {\n        pile_size\n    };\n    let c = params.min_select + params.max_select;\n    let computer_pick = q - (c * (q / c));\n    let computer_pick = if computer_pick < params.min_select {\n        params.min_select\n    } else {\n        computer_pick\n    };\n    if computer_pick > params.max_select {\n        params.max_select\n    } else {\n        computer_pick\n    }\n}\n\nfn computer_move(pile_size: &mut usize, params: &Params) -> bool {\n    if params.win_option == WinOption::TakeLast && *pile_size <= params.max_select {\n        println!(\"COMPUTER TAKES {pile_size} AND WINS.\");\n        return true;\n    }\n    if params.win_option == WinOption::AvoidLast && *pile_size >= params.min_select {\n        println!(\"COMPUTER TAKES {} AND LOSES.\", params.min_select);\n        return true;\n    }\n\n    let curr_sel = computer_pick(*pile_size, params);\n    *pile_size -= curr_sel;\n    println!(\"COMPUTER TAKES {curr_sel} AND LEAVES {pile_size}\");\n    false\n}\n\nfn play_game(params: &Params) {\n    let mut pile_size = params.pile_size;\n\n    if params.start_option == StartOption::ComputerFirst && computer_move(&mut pile_size, params) {\n        return;\n    }\n\n    loop {\n        if player_move(&mut pile_size, params) {\n            return;\n        }\n        if computer_move(&mut pile_size, params) {\n            return;\n        }\n    }\n}\n\nfn main() -> ! {\n    loop {\n        print_intro();\n        let params = Params::get_params();\n        play_game(&params);\n    }\n}\n"
  },
  {
    "path": "08_Batnum/vbnet/Program.vb",
    "content": "Imports System\n\nModule BatNum\n    Enum WinOptions\n        Undefined = 0\n        TakeLast = 1\n        AvoidLast = 2\n    End Enum\n\n    Enum StartOptions\n        Undefined = 0\n        ComputerFirst = 1\n        PlayerFirst = 2\n    End Enum\n\n    Dim pileSize As Integer = 0\n    Dim minSelect As Integer = 0\n    Dim maxSelect As Integer = 0\n    Dim startOption As StartOptions = StartOptions.Undefined\n    Dim winOption As WinOptions = WinOptions.Undefined\n\n    ' <summary>\n    ' Prints the intro and rules of the game.\n    ' </summary>\n    Private Sub PrintIntro()\n        Console.WriteLine(\"BATNUM\".PadLeft(33, \" \"))\n        Console.WriteLine(\"CREATIVE COMPUTING  MORRISSTOWN, NEW JERSEY\".PadLeft(15, \" \"))\n        Console.WriteLine()\n        Console.WriteLine()\n        Console.WriteLine()\n        Console.WriteLine(\"THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE\")\n        Console.WriteLine(\"COMPUTER IS YOUR OPPONENT.\")\n        Console.WriteLine()\n        Console.WriteLine(\"THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU\")\n        Console.WriteLine(\"AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.\")\n        Console.WriteLine(\"WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR\")\n        Console.WriteLine(\"NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.\")\n        Console.WriteLine(\"DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.\")\n        Console.WriteLine(\"ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.\")\n        Console.WriteLine()\n    End Sub\n\n    ' <summary>\n    ' Asks the user for the various parameters necessary\n    ' to play the game.\n    ' </summary>\n    Private Sub GetParams()\n        ' Reset the game parameters\n        pileSize = 0\n        minSelect = 0\n        maxSelect = 0\n        startOption = StartOptions.Undefined\n        winOption = WinOptions.Undefined\n\n        While pileSize < 1\n            Console.Write(\"ENTER PILE SIZE \")\n            pileSize = Convert.ToInt32(Console.ReadLine())\n        End While\n        While winOption = WinOptions.Undefined\n            Console.Write(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: \")\n            winOption = Convert.ToInt32(Console.ReadLine())\n        End While\n        While minSelect < 1 Or maxSelect < 1 Or minSelect > maxSelect\n            Console.Write(\"ENTER MIN AND MAX \")\n            Dim vals = Console.ReadLine().ToString().Split(\" \").[Select](Function(n) Integer.Parse(n)).ToList()\n            If vals.Count() <> 2 Then\n                Continue While\n            End If\n            minSelect = vals(0)\n            maxSelect = vals(1)\n        End While\n        While startOption = StartOptions.Undefined\n            Console.Write(\"ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST \")\n            startOption = Convert.ToInt32(Console.ReadLine())\n        End While\n    End Sub\n\n    '<summary>\n    'This handles the player's turn - asking the player how many objects\n    'to take And doing some basic validation around that input.  Then it\n    'checks for any win conditions.\n    '</summary>\n    '<returns>Returns a Boolean indicating whether the game Is over And the New pileSize.</returns>'\n    Private Function PlayerMove() As Boolean\n        Dim playerDone As Boolean = False\n\n        While Not playerDone\n            Console.WriteLine(\"YOUR MOVE \")\n            Dim playerNum As Integer = Convert.ToInt32(Console.ReadLine())\n            If playerNum = 0 Then\n                Console.WriteLine(\"I TOLD YOU NOT TO USE ZERO!  COMPUTER WINS BY FORFEIT.\")\n                Return True\n            End If\n            If playerNum > maxSelect Or playerNum < minSelect Then\n                Console.WriteLine(\"ILLEGAL MOVE, REENTER IT\")\n                Continue While\n            End If\n\n            pileSize = pileSize - playerNum\n            playerDone = True\n            If pileSize <= 0 Then\n                If winOption = WinOptions.AvoidLast Then\n                    Console.WriteLine(\"TOUGH LUCK, YOU LOSE.\")\n                Else\n                    Console.WriteLine(\"CONGRATULATIONS, YOU WIN.\")\n                End If\n                Return True\n            End If\n        End While\n\n        Return False\n    End Function\n\n    '<summary>\n    'This handles the logic to determine how many objects the computer\n    'will select on its turn.\n    '</summary>\n    Private Function ComputerPick() As Integer\n        Dim q As Integer = IIf(winOption = WinOptions.AvoidLast, pileSize - 1, pileSize)\n        Dim c As Integer = minSelect + maxSelect\n        Dim computerNum As Integer = q - (c * Int(q / c))\n        If computerNum < minSelect Then\n            computerNum = minSelect\n        End If\n        If computerNum > maxSelect Then\n            ComputerPick = maxSelect\n        End If\n\n        Return computerNum\n    End Function\n\n    '<summary>\n    'This handles the computer's turn - first checking for the various\n    'win/lose conditions And then calculating how many objects\n    'the computer will take.\n    '</summary>\n    '<returns>Returns a boolean indicating whether the game is over.</returns>'\n    Private Function ComputerMove() As Boolean\n        ' First, check For win conditions On this move\n        ' In this Case, we win by taking the last Object And\n        ' the remaining pile Is less than max Select\n        ' so the computer can grab them all And win\n        If winOption = WinOptions.TakeLast And pileSize <= maxSelect Then\n            Console.WriteLine($\"COMPUTER TAKES {pileSize} AND WINS.\")\n            Return True\n        End If\n        ' In this Case, we lose by taking the last Object And\n        ' the remaining pile Is less than minsize And the computer\n        ' has To take all Of them.\n        If winOption = WinOptions.AvoidLast And pileSize <= minSelect Then\n            Console.WriteLine($\"COMPUTER TAKES {minSelect} AND LOSES.\")\n            Return True\n        End If\n\n        ' Otherwise, we determine how many the computer selects\n        Dim currSel As Integer = ComputerPick()\n        pileSize = pileSize - currSel\n        Console.WriteLine($\"COMPUTER TAKES {currSel} AND LEAVES {pileSize}\")\n        Return False\n    End Function\n\n    '<summary>\n    'This is the main game loop - repeating each turn until one\n    'of the win/lose conditions Is met.\n    '</summary>\n    Private Sub PlayGame()\n        Dim gameOver As Boolean = False\n        ' playersTurn Is a Boolean keeping track Of whether it's the\n        ' player's or computer's turn\n        Dim playersTurn As Boolean = (startOption = StartOptions.PlayerFirst)\n\n        While Not gameOver\n            If playersTurn Then\n                gameOver = PlayerMove()\n                playersTurn = False\n                If gameOver Then Return\n            End If\n\n            If Not playersTurn Then\n                gameOver = ComputerMove()\n                playersTurn = True\n            End If\n        End While\n    End Sub\n\n    Public Sub Play()\n        While True\n            PrintIntro()\n            GetParams()\n            PlayGame()\n        End While\n    End Sub\nEnd Module\n\nModule Program\n    Sub Main(args As String())\n        BatNum.Play()\n    End Sub\nEnd Module\n"
  },
  {
    "path": "08_Batnum/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "08_Batnum/vbnet/batnum.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{778DAE3C-4631-46EA-AA77-85C1314464D9}\") = \"Batnum\", \"Batnum.vbproj\", \"{D577E429-F84D-4E84-86E7-E6526CFD5FD9}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {426DF7FE-66E7-4319-9AD8-7A2DD3964A2F}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "08_Batnum/vbnet/batnum.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Batnum</RootNamespace>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "09_Battle/README.md",
    "content": "### Battle\n\nBATTLE is based on the popular game Battleship which is primarily played to familiarize people with the location and designation of points on a coordinate plane.\n\nBATTLE first randomly sets up the bad guy’s fleet disposition on a 6 by 6 matrix or grid. The fleet consists of six ships:\n- Two destroyers (ships number 1 and 2) which are two units long\n- Two cruisers (ships number 3 and 4) which are three units long\n- Two aircraft carriers (ships number 5 and 6) which are four units long\n\nThe program then prints out this fleet disposition in a coded or disguised format (see the sample computer print-out). You then proceed to sink the various ships by typing in the coordinates (two digits. each from 1 to 6, separated by a comma) of the place where you want to drop a bomb, if you’ll excuse the expression. The computer gives the appropriate response (splash, hit, etc.) which you should record on a 6 by 6 matrix. You are thus building a representation of the actual fleet disposition which you will hopefully use to decode the coded fleet disposition printed out by the computer. Each time a ship is sunk, the computer prints out which ships have been sunk so far and also gives you a “SPLASH/HIT RATIO.”\n\nThe first thing you should learn is how to locate and designate positions on the matrix, and specifically the difference between “3,4” and “4,3.” Our method corresponds to the location of points on the coordinate plane rather than the location of numbers in a standard algebraic matrix: the first number gives the column counting from left to right and the second number gives the row counting from bottom to top.\n\nThe second thing you should learn about is the splash/hit ratio. “What is a ratio?” A good reply is “It’s a fraction or quotient.” Specifically, the spash/hit ratio is the number of splashes divided by the number of hits. If you had 9 splashes and 15 hits, the ratio would be 9/15 or 3/5, both of which are correct. The computer would give this splash/hit ratio as .6.\n\nThe main objective and primary education benefit of BATTLE comes from attempting to decode the bad guys’ fleet disposition code. To do this, you must make a comparison between the coded matrix and the actual matrix which you construct as you play the game.\n\nThe original author of both the program and these descriptive notes is Ray Westergard of Lawrence Hall of Science, Berkeley, California.\n\n---\n\nAs published in Basic Computer Games (1978)\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=15)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=30)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- The original game has no way to re-view the fleet disposition code once it scrolls out of view.  Ports should consider allowing the user to enter \"?\" at the \"??\" prompt, to reprint the disposition code.  (This is added by the MiniScript port under Alternate Languages, for example.)"
  },
  {
    "path": "09_Battle/battle.bas",
    "content": "5 PRINT TAB(33);\"BATTLE\"\n7 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n10 REM -- BATTLE WRITTEN BY RAY WESTERGARD  10/70\n20 REM COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF.\n30 REM PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY\n40 DIM F(6,6),H(6,6),A(4),B(4),C(6),L(3)\n50 FOR X=1 TO 6\n51 FOR Y=1 TO 6\n52 F(X,Y)=0\n53 NEXT Y\n54 NEXT X\n60 FOR I=1 TO 3\n70 N=4-I\n80 FOR J=1 TO 2\n90 A=INT(6*RND(1)+1)\n100 B=INT(6*RND(1)+1)\n110 D=INT(4*RND(1)+1)\n120 IF F(A,B)>0 THEN 90\n130 M=0\n140 ON D GOTO 150,340,550,740\n150 B(1)=B\n160 B(2)=7:B(3)=7\n170 FOR K=1 TO N\n180 IF M>1 THEN 240\n190 IF B(K)=6 THEN 230\n200 IF F(A,B(K)+1)>0 THEN 230\n210 B(K+1)=B(K)+1\n220 GOTO 280\n230 M=2\n240 IF B(1)<B(2) AND B(1)<B(3) THEN Z=B(1)\n242 IF B(2)<B(1) AND B(2)<B(3) THEN Z=B(2)\n244 IF B(3)<B(1) AND B(3)<B(2) THEN Z=B(3)\n250 IF Z=1 THEN 90\n260 IF F(A,Z-1)>0 THEN 90\n270 B(K+1)=Z-1\n280 NEXT K\n290 F(A,B)=9-2*I-J\n300 FOR K=1 TO N\n310 F(A,B(K+1))=F(A,B)\n320 NEXT K\n330 GOTO 990\n340 A(1)=A\n350 B(1)=B\n360 A(2)=0:A(3)=0:B(2)=0:B(3)=0\n370 FOR K=1 TO N\n380 IF M>1 THEN 460\n390 IF A(K)=1 OR B(K)=1 THEN 450\n400 IF F(A(K)-1,B(K)-1)>0 THEN 450\n410 IF F(A(K)-1,B(K))>0 AND F(A(K)-1,B(K))=F(A(K),B(K)-1) THEN 450\n420 A(K+1)=A(K)-1\n430 B(K+1)=B(K)-1\n440 GOTO 530\n450 M=2\n460 IF A(1)>A(2) AND A(1)>A(3) THEN Z1=A(1)\n462 IF A(2)>A(1) AND A(2)>A(3) THEN Z1=A(2)\n464 IF A(3)>A(1) AND A(3)>A(2) THEN Z1=A(3)\n470 IF B(1)>B(2) AND B(1)>B(3) THEN Z2=B(1)\n474 IF B(2)>B(1) AND B(2)>B(3) THEN Z2=B(2)\n476 IF B(3)>B(1) AND B(3)>B(2) THEN Z2=B(3)\n480 IF Z1=6 OR Z2=6 THEN 90\n490 IF F(Z1+1,Z2+1)>0 THEN 90\n500 IF F(Z1,Z2+1)>0 AND F(Z1,Z2+1)=F(Z1+1,Z2) THEN 90\n510 A(K+1)=Z1+1\n520 B(K+1)=Z2+1\n530 NEXT K\n540 GOTO 950\n550 A(1)=A\n560 A(2)=7:A(3)=7\n570 FOR K=1 TO N\n580 IF M>1 THEN 640\n590 IF A(K)=6 THEN 630\n600 IF F(A(K)+1,B)>0 THEN 630\n610 A(K+1)=A(K)+1\n620 GOTO 680\n630 M=2\n640 IF A(1)<A(2) AND A(1)<A(3) THEN Z=A(1)\n642 IF A(2)<A(1) AND A(2)<A(3) THEN Z=A(2)\n644 IF A(3)<A(1) AND A(3)<A(2) THEN Z=A(3)\n650 IF Z=1 THEN 90\n660 IF F(Z-1,B)>0 THEN 90\n670 A(K+1)=Z-1\n680 NEXT K\n690 F(A,B)=9-2*I-J\n700 FOR K=1 TO N\n710 F(A(K+1),B)=F(A,B)\n720 NEXT K\n730 GOTO 990\n740 A(1)=A\n750 B(1)=B\n760 A(2)=7:A(3)=7\n770 B(2)=0:B(3)=0\n780 FOR K=1 TO N\n790 IF M>1 THEN 870\n800 IF A(K)=6 OR B(K)=1 THEN 860\n810 IF F(A(K)+1,B(K)-1)>0 THEN 860\n820 IF F(A(K)+1,B(K))>0 AND F(A(K)+1,B(K))=F(A(K),B(K)-1) THEN 860\n830 A(K+1)=A(K)+1\n840 B(K+1)=B(K)-1\n850 GOTO 940\n860 M=2\n870 IF A(1)<A(2) AND A(1)<A(3) THEN Z1=A(1)\n872 IF A(2)<A(1) AND A(2)<A(3) THEN Z1=A(2)\n874 IF A(3)<A(1) AND A(3)<A(2) THEN Z1=A(3)\n880 IF B(1)>B(2) AND B(1)>B(3) THEN Z2=B(1)\n882 IF B(2)>B(1) AND B(2)>B(3) THEN Z2=B(2)\n884 IF B(3)>B(1) AND B(3)>B(2) THEN Z2=B(3)\n890 IF Z1=1 OR Z2=6 THEN 90\n900 IF F(Z1-1,Z2+1)>0 THEN 90\n910 IF F(Z1,Z2+1)>0 AND F(Z1,Z2+1)=F(Z1-1,Z2) THEN 90\n920 A(K+1)=Z1-1\n930 B(K+1)=Z2+1\n940 NEXT K\n950 F(A,B)=9-2*I-J\n960 FOR K=1 TO N\n970 F(A(K+1),B(K+1))=F(A,B)\n980 NEXT K\n990 NEXT J\n1000 NEXT I\n1010 PRINT\n1020 PRINT \"THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\"\n1030 PRINT \"HAS BEEN CAPTURED BUT NOT DECODED:\"\n1040 PRINT\n1050 FOR I=1 TO 6\n1051 FOR J=1 TO 6\n1052 H(I,J)=F(J,I)\n1053 NEXT J\n1054 NEXT I\n1060 FOR I=1 TO 6\n1061 FOR J=1 TO 6\n1062 PRINT H(I,J);\n1063 NEXT J\n1064 PRINT\n1065 NEXT I\n1070 PRINT\n1080 PRINT \"DE-CODE IT AND USE IT IF YOU CAN\"\n1090 PRINT \"BUT KEEP THE DE-CODING METHOD A SECRET.\"\n1100 PRINT\n1110 FOR I=1 TO 6\n1111 FOR J=1 TO 6\n1112 H(I,J)=0\n1113 NEXT J\n1114 NEXT I\n1120 FOR I=1 TO 3\n1121 L(I)=0\n1122 NEXT I\n1130 C(1)=2:C(2)=2\n1140 C(3)=1:C(4)=1\n1150 C(5)=0:C(6)=0\n1160 S=0:H=0\n1170 PRINT \"START GAME\"\n1180 INPUT X,Y\n1190 IF X<1 OR X>6 OR INT(X)<>ABS(X) THEN 1210\n1200 IF Y>0 AND Y<7 AND INT(Y)=ABS(Y) THEN 1230\n1210 PRINT \"INVALID INPUT.  TRY AGAIN.\"\n1220 GOTO 1180\n1230 R=7-Y\n1240 C=X\n1250 IF F(R,C)>0 THEN 1290\n1260 S=S+1\n1270 PRINT \"SPLASH!  TRY AGAIN.\"\n1280 GOTO 1180\n1290 IF C(F(R,C))<4 THEN 1340\n1300 PRINT \"THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT.\"\n1310 PRINT \"SPLASH!  TRY AGAIN.\"\n1320 S=S+1\n1330 GOTO 1180\n1340 IF H(R,C)>0 THEN 1420\n1350 H=H+1\n1360 H(R,C)=F(R,C)\n1370 PRINT \"A DIRECT HIT ON SHIP NUMBER\";F(R,C)\n1380 C(F(R,C))=C(F(R,C))+1\n1390 IF C(F(R,C))>=4 THEN 1470\n1400 PRINT \"TRY AGAIN.\"\n1410 GOTO 1180\n1420 PRINT \"YOU ALREADY PUT A HOLE IN SHIP NUMBER\";F(R,C);\n1430 PRINT \"AT THAT POINT.\"\n1440 PRINT \"SPLASH!  TRY AGAIN.\"\n1450 S=S+1\n1460 GOTO 1180\n1470 L((INT(F(R,C)-1)/2)+1)=L((INT(F(R,C)-1)/2)+1)+1\n1480 PRINT \"AND YOU SUNK IT.  HURRAH FOR THE GOOD GUYS.\"\n1490 PRINT \"SO FAR, THE BAD GUYS HAVE LOST\"\n1500 PRINT L(1);\"DESTROYER(S),\";L(2);\"CRUISER(S), AND\";\n1510 PRINT L(3);\"AIRCRAFT CARRIER(S).\"\n1520 PRINT \"YOUR CURRENT SPLASH/HIT RATIO IS\";S/H\n1530 IF (L(1)+L(2)+L(3))<6 THEN 1180\n1540 PRINT\n1550 PRINT \"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET\"\n1560 PRINT \"WITH A FINAL SPLASH/HIT RATIO OF\";S/H\n1570 IF S/H>0 THEN 1590\n1580 PRINT \"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\"\n1590 PRINT\n1600 PRINT \"****************************\"\n1610 PRINT\n1620 GOTO 50\n1630 END\n"
  },
  {
    "path": "09_Battle/csharp/Battle.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "09_Battle/csharp/Battle.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31005.135\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Battle\", \"Battle.csproj\", \"{154E5E43-053B-4FB1-88D0-ED7166464257}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{154E5E43-053B-4FB1-88D0-ED7166464257}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{154E5E43-053B-4FB1-88D0-ED7166464257}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{154E5E43-053B-4FB1-88D0-ED7166464257}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{154E5E43-053B-4FB1-88D0-ED7166464257}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {5CC3AC8C-6CEC-4FD6-B5A0-B2376B37C42F}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "09_Battle/csharp/Game.cs",
    "content": "﻿using System;\nusing System.Linq;\n\nnamespace Battle\n{\n    public class Game\n    {\n        private int[,] field = new int[7, 7];\n\n        private Random random = new Random();\n\n        public void Run()\n        {\n            DisplayIntro();\n\n            while (true)\n            {\n                field = new int[7, 7];\n\n                foreach (var shipType in new []{ 1, 2, 3})\n                {\n                    foreach (var ship in new int[] { 1, 2 })\n                    {\n                        while (!SetShip(shipType, ship)) { }\n                    }\n                }\n\n                UserInteraction();\n            }\n        }\n\n        private bool SetShip(int shipType, int shipNum)\n        {\n            var shipSize = 4 - shipType;\n            int direction;\n            int[] A = new int[5];\n            int[] B = new int[5];\n            int row, col;\n\n            do\n            {\n                row = Rnd(6) + 1;\n                col = Rnd(6) + 1;\n                direction = Rnd(4) + 1;\n            } while (field[row, col] > 0);\n\n            var M = 0;\n\n            switch (direction)\n            {\n                case 1:\n                    B[1] = col;\n                    B[2] = 7;\n                    B[3] = 7;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        if (!(M > 1 || B[K] == 6 || field[row, B[K] + 1] > 0))\n                        {\n                            B[K + 1] = B[K] + 1;\n                            continue;\n                        }\n\n                        M = 2;\n                        var Z = 1;\n\n                        if (B[1] < B[2] && B[1] < B[3]) Z = B[1];\n                        if (B[2] < B[1] && B[2] < B[3]) Z = B[2];\n                        if (B[3] < B[1] && B[3] < B[2]) Z = B[3];\n\n                        if (Z == 1 || field[row, Z - 1] > 0) return false;\n\n                        B[K + 1] = Z - 1;\n                    }\n\n                    field[row, col] = 9 - 2 * shipType - shipNum;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        field[row, B[K + 1]] = field[row, col];\n                    }\n                    break;\n\n                case 2:\n                    A[1] = row;\n                    B[1] = col;\n                    A[2] = 0;\n                    A[3] = 0;\n                    B[2] = 0;\n                    B[3] = 0;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        if (!(M > 1\n                            || A[K] == 1 || B[K] == 1\n                            || field[A[K] - 1, B[K] - 1] > 0\n                            || (field[A[K] - 1, B[K]] > 0 && field[A[K] - 1, B[K]] == field[A[K], B[K] - 1])))\n                        {\n                            A[K + 1] = A[K] - 1;\n                            B[K + 1] = B[K] - 1;\n                            continue;\n                        }\n\n                        M = 2;\n                        var Z1 = 1;\n                        var Z2 = 1;\n\n                        if (A[1] > A[2] && A[1] > A[3]) Z1 = A[1];\n                        if (A[2] > A[1] && A[2] > A[3]) Z1 = A[2];\n                        if (A[3] > A[1] && A[3] > A[2]) Z1 = A[3];\n                        if (B[1] > B[2] && B[1] > B[3]) Z2 = B[1];\n                        if (B[2] > B[1] && B[2] > B[3]) Z2 = B[2];\n                        if (B[3] > B[1] && B[3] > B[2]) Z2 = B[3];\n\n                        if (Z1 == 6 || Z2 == 6\n                            || field[Z1 + 1, Z2 + 1] > 0\n                            || (field[Z1, Z2 + 1] > 0 && field[Z1, Z2 + 1] == field[Z1 + 1, Z2])) return false;\n\n                        A[K + 1] = Z1 + 1;\n                        B[K + 1] = Z2 + 1;\n                    }\n\n                    field[row, col] = 9 - 2 * shipType - shipNum;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        field[A[K + 1], B[K + 1]] = field[row, col];\n                    }\n                    break;\n\n                case 3:\n                    A[1] = row;\n                    A[2] = 7;\n                    A[3] = 7;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        if (!(M > 1 || A[K] == 6\n                            || field[A[K] + 1, col] > 0))\n                        {\n                            A[K + 1] = A[K] + 1;\n                            continue;\n                        }\n\n                        M = 2;\n                        var Z = 1;\n\n                        if (A[1] < A[2] && A[1] < A[3]) Z = A[1];\n                        if (A[2] < A[1] && A[2] < A[3]) Z = A[2];\n                        if (A[3] < A[1] && A[3] < A[2]) Z = A[3];\n\n                        if (Z == 1 || field[Z - 1, col] > 0) return false;\n\n                        A[K + 1] = Z - 1;\n                    }\n\n                    field[row, col] = 9 - 2 * shipType - shipNum;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        field[A[K + 1], col] = field[row, col];\n                    }\n                    break;\n\n                case 4:\n                default:\n                    A[1] = row;\n                    B[1] = col;\n                    A[2] = 7;\n                    A[3] = 7;\n                    B[2] = 0;\n                    B[3] = 0;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        if (!(M > 1 || A[K] == 6 || B[K] == 1\n                            || field[A[K] + 1, B[K] - 1] > 0\n                            || (field[A[K] + 1, B[K]] > 0 && field[A[K] + 1, B[K]] == field[A[K], B[K] - 1])))\n                        {\n                            A[K + 1] = A[K] + 1;\n                            B[K + 1] = B[K] - 1;\n                            continue;\n                        }\n\n                        M = 2;\n                        var Z1 = 1;\n                        var Z2 = 1;\n\n                        if (A[1] < A[2] && A[1] < A[3]) Z1 = A[1];\n                        if (A[2] < A[1] && A[2] < A[3]) Z1 = A[2];\n                        if (A[3] < A[1] && A[3] < A[2]) Z1 = A[3];\n                        if (B[1] > B[2] && B[1] > B[3]) Z2 = B[1];\n                        if (B[2] > B[1] && B[2] > B[3]) Z2 = B[2];\n                        if (B[3] > B[1] && B[3] > B[2]) Z2 = B[3];\n\n                        if (Z1 == 1 || Z2 == 6\n                            || field[Z1 - 1, Z2 + 1] > 0\n                            || (field[Z1, Z2 + 1] > 0 && field[Z1, Z2 + 1] == field[Z1 - 1, Z2])) return false;\n\n                        A[K + 1] = Z1 - 1;\n                        B[K + 1] = Z2 + 1;\n                    }\n\n                    field[row, col] = 9 - 2 * shipType - shipNum;\n\n                    for (var K = 1; K <= shipSize; K++)\n                    {\n                        field[A[K + 1], B[K + 1]] = field[row, col];\n                    }\n\n                    break;\n            }\n\n            return true;\n        }\n\n        public void DisplayIntro()\n        {\n            Console.ForegroundColor = ConsoleColor.Green;\n            Print(Tab(33) + \"BATTLE\");\n            Print(Tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            //-- BATTLE WRITTEN BY RAY WESTERGARD  10 / 70\n            // COPYRIGHT 1971 BY THE REGENTS OF THE UNIV.OF CALIF.\n            // PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY\n        }\n\n        public void UserInteraction()\n        {\n            Print();\n            Print(\"THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\");\n            Print(\"HAS BEEN CAPTURED BUT NOT DECODED:\");\n            Print();\n\n            for (var row = 1; row <= 6; row++)\n            {\n                for (var col = 1; col <= 6; col++)\n                {\n                    Write(field[col, row].ToString());\n                }\n\n                Print();\n            }\n\n            Print();\n            Print(\"DE-CODE IT AND USE IT IF YOU CAN\");\n            Print(\"BUT KEEP THE DE-CODING METHOD A SECRET.\");\n            Print();\n\n            var hit = new int[7, 7];\n            var lost = new int[4];\n            var shipHits = new[] { 0, 2, 2, 1, 1, 0, 0 };\n            var splashes = 0;\n            var hits = 0;\n\n            Print(\"START GAME\");\n\n            do\n            {\n                var input = Console.ReadLine().Split(',').Select(x => int.TryParse(x, out var num) ? num : 0).ToArray();\n\n                if (!IsValid(input))\n                {\n                    Print(\"INVALID INPUT.  TRY AGAIN.\");\n                    continue;\n                }\n\n                var col = input[0];\n                var row = 7 - input[1];\n                var shipNum = field[row, col];\n\n                if (shipNum == 0)\n                {\n                    splashes = splashes + 1;\n                    Print(\"SPLASH!  TRY AGAIN.\");\n                    continue;\n                }\n\n                if (shipHits[shipNum] > 3)\n                {\n                    Print(\"THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT.\");\n                    Print(\"SPLASH!  TRY AGAIN.\");\n                    splashes = splashes + 1;\n                    continue;\n                }\n\n                if (hit[row, col] > 0)\n                {\n                    Print($\"YOU ALREADY PUT A HOLE IN SHIP NUMBER {shipNum} AT THAT POINT.\");\n                    Print(\"SPLASH!  TRY AGAIN.\");\n                    splashes = splashes + 1;\n                    continue;\n                }\n\n                hits = hits + 1;\n                hit[row, col] = shipNum;\n\n                Print($\"A DIRECT HIT ON SHIP NUMBER {shipNum}\");\n                shipHits[shipNum] = shipHits[shipNum] + 1;\n\n                if (shipHits[shipNum] < 4)\n                {\n                    Print(\"TRY AGAIN.\");\n                    continue;\n                }\n\n                var shipType = (shipNum - 1) / 2 + 1;\n                lost[shipType] = lost[shipType] + 1;\n\n                Print(\"AND YOU SUNK IT.  HURRAH FOR THE GOOD GUYS.\");\n                Print(\"SO FAR, THE BAD GUYS HAVE LOST\");\n                Write($\"{lost[1]} DESTROYER(S), {lost[2]} CRUISER(S), AND \");\n                Print($\"{lost[3]} AIRCRAFT CARRIER(S).\");\n                Print($\"YOUR CURRENT SPLASH/HIT RATIO IS {splashes / hits}\");\n\n                if ((lost[1] + lost[2] + lost[3]) < 6) continue;\n\n                Print();\n                Print(\"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET\");\n                Print($\"WITH A FINAL SPLASH/HIT RATIO OF {splashes / hits}\");\n\n                if ((splashes / hits) == 0)\n                {\n                    Print(\"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\");\n                }\n\n                Print();\n                Print(\"****************************\");\n                Print();\n\n                return;\n\n            } while (true);\n        }\n\n        public bool IsValid(int[] input) => input.Length == 2 && input.All(Valid);\n\n        public bool Valid(int value) => value > 0 && value < 7;\n\n        public void Print(string str = \"\") => Console.WriteLine(str);\n\n        public void Write(string value) => Console.Write(value);\n\n        public string Tab(int pos) => new String(' ', pos);\n\n        public int Rnd(int seed) => random.Next(seed);\n    }\n}\n"
  },
  {
    "path": "09_Battle/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Battle\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            new Game().Run();\n        }\n    }\n}\n"
  },
  {
    "path": "09_Battle/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "09_Battle/java/.gitignore",
    "content": "*~\n"
  },
  {
    "path": "09_Battle/java/Battle.java",
    "content": "import java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Random;\nimport java.util.function.Predicate;\nimport java.text.NumberFormat;\n\n\n/* This class holds the game state and the game logic */\npublic class Battle {\n\n    /* parameters of the game */\n    private int seaSize;\n    private int[] sizes;\n    private int[] counts;\n\n    /* The game setup - the ships and the sea */\n    private ArrayList<Ship> ships;\n    private Sea sea;\n\n    /* game state counts */\n    private int[] losses;    // how many of each type of ship have been sunk\n    private int hits;        // how many hits the player has made\n    private int misses;      // how many misses the player has made\n\n    // Names of ships of each size. The game as written has ships of size 3, 4 and 5 but\n    // can easily be modified. It makes no sense to have a ship of size zero though.\n    private static String NAMES_BY_SIZE[] = {\n        \"error\",\n        \"size1\",\n        \"destroyer\",\n        \"cruiser\",\n        \"aircraft carrier\",\n        \"size5\" };\n\n    // Entrypoint\n    public static void main(String args[]) {\n        Battle game = new Battle(6,                        // Sea is 6 x 6 tiles\n                                 new int[] { 2, 3, 4 },    // Ships are of sizes 2, 3, and 4\n                                 new int[] { 2, 2, 2 });   // there are two ships of each size\n        game.play();\n    }\n\n    public Battle(int scale, int[] shipSizes, int[] shipCounts) {\n        seaSize = scale;\n        sizes = shipSizes;\n        counts = shipCounts;\n\n        // validate parameters\n        if (seaSize < 4) throw new RuntimeException(\"Sea Size \" + seaSize + \" invalid, must be at least 4\");\n\n        for (int sz : sizes) {\n            if ((sz < 1) || (sz > seaSize))\n                throw new RuntimeException(\"Ship has invalid size \" + sz);\n        }\n\n        if (counts.length != sizes.length) {\n            throw new RuntimeException(\"Ship counts must match\");\n        }\n\n        // Initialize game state\n        sea = new Sea(seaSize);          // holds what ship if any occupies each tile\n        ships = new ArrayList<Ship>();   // positions and states of all the ships\n        losses = new int[counts.length]; // how many ships of each type have been sunk\n\n        // Build up the list of all the ships\n        int shipNumber = 1;\n        for (int type = 0; type < counts.length; ++type) {\n            for (int i = 0; i < counts[i]; ++i) {\n                ships.add(new Ship(shipNumber++, sizes[type]));\n            }\n        }\n\n        // When we put the ships in the sea, we put the biggest ones in first, or they might\n        // not fit\n        ArrayList<Ship> largestFirst = new ArrayList<>(ships);\n        Collections.sort(largestFirst, Comparator.comparingInt((Ship ship) -> ship.size()).reversed());\n\n        // place each ship into the sea\n        for (Ship ship : largestFirst) {\n            ship.placeRandom(sea);\n        }\n    }\n\n    public void play() {\n        System.out.println(\"The following code of the bad guys' fleet disposition\\nhas been captured but not decoded:\\n\");\n        System.out.println(sea.encodedDump());\n        System.out.println(\"De-code it and use it if you can\\nbut keep the de-coding method a secret.\\n\");\n\n        int lost = 0;\n        System.out.println(\"Start game\");\n        Input input = new Input(seaSize);\n        try {\n            while (lost < ships.size()) {          // the game continues while some ships remain unsunk\n                if (! input.readCoordinates()) {   // ... unless there is no more input from the user\n                    return;\n                }\n\n                // The computer thinks of the sea as a grid of rows, from top to bottom.\n                // However, the user will use X and Y coordinates, with Y going bottom to top\n                int row = seaSize - input.y();\n                int col = input.x() - 1;\n\n                if (sea.isEmpty(col, row)) {\n                    ++misses;\n                    System.out.println(\"Splash!  Try again.\");\n                } else {\n                    Ship ship = ships.get(sea.get(col, row) - 1);\n                    if (ship.isSunk()) {\n                        ++misses;\n                        System.out.println(\"There used to be a ship at that point, but you sunk it.\");\n                        System.out.println(\"Splash!  Try again.\");\n                    } else if (ship.wasHit(col, row)) {\n                        ++misses;\n                        System.out.println(\"You already put a hole in ship number \" + ship.id());\n                        System.out.println(\"Splash!  Try again.\");\n                    } else {\n                        ship.hit(col, row);\n                        ++hits;\n                        System.out.println(\"A direct hit on ship number \" + ship.id());\n\n                        // If a ship was hit, we need to know whether it was sunk.\n                        // If so, tell the player and update our counts\n                        if (ship.isSunk()) {\n                            ++lost;\n                            System.out.println(\"And you sunk it.  Hurrah for the good guys.\");\n                            System.out.print(\"So far, the bad guys have lost \");\n                            ArrayList<String> typeDescription = new ArrayList<>();\n                            for (int i = 0 ; i < sizes.length; ++i) {\n                                if (sizes[i] == ship.size()) {\n                                    ++losses[i];\n                                }\n                                StringBuilder sb = new StringBuilder();\n                                sb.append(losses[i]);\n                                sb.append(\" \");\n                                sb.append(NAMES_BY_SIZE[sizes[i]]);\n                                if (losses[i] != 1)\n                                    sb.append(\"s\");\n                                typeDescription.add(sb.toString());\n                            }\n                            System.out.println(String.join(\", \", typeDescription));\n                            double ratioNum = ((double)misses)/hits;\n                            String ratio = NumberFormat.getInstance().format(ratioNum);\n                            System.out.println(\"Your current splash/hit ratio is \" + ratio);\n\n                            if (lost == ships.size()) {\n                                System.out.println(\"You have totally wiped out the bad guys' fleet\");\n                                System.out.println(\"With a final splash/hit ratio of \" + ratio);\n\n                                if (misses == 0) {\n                                    System.out.println(\"Congratulations - A direct hit every time.\");\n                                }\n\n                                System.out.println(\"\\n****************************\\n\");\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        catch (IOException e) {\n            // This should not happen running from console, but java requires us to check for it\n            System.err.println(\"System error.\\n\" + e);\n        }\n    }\n}\n"
  },
  {
    "path": "09_Battle/java/Input.java",
    "content": "import java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.io.IOException;\nimport java.text.NumberFormat;\n\n// This class handles reading input from the player\n// Each input is an x and y coordinate\n// e.g. 5,3\npublic class Input {\n    private BufferedReader reader;\n    private NumberFormat parser;\n    private int scale;             // size of the sea, needed to validate input\n    private boolean isQuit;        // whether the input has ended\n    private int[] coords;          // the last coordinates read\n\n    public Input(int seaSize) {\n        scale = seaSize;\n        reader = new BufferedReader(new InputStreamReader(System.in));\n        parser = NumberFormat.getIntegerInstance();\n    }\n\n    public boolean readCoordinates() throws IOException {\n        while (true) {\n            // Write a prompt\n            System.out.print(\"\\nTarget x,y\\n> \");\n            String inputLine = reader.readLine();\n            if (inputLine == null) {\n                // If the input stream is ended, there is no way to continue the game\n                System.out.println(\"\\nGame quit\\n\");\n                isQuit = true;\n                return false;\n            }\n\n            // split the input into two fields\n            String[] fields = inputLine.split(\",\");\n            if (fields.length != 2) {\n                // has to be exactly two\n                System.out.println(\"Need two coordinates separated by ','\");\n                continue;\n            }\n\n            coords = new int[2];\n            boolean error = false;\n            // each field should contain an integer from 1 to the size of the sea\n            try {\n                for (int c = 0 ; c < 2; ++c ) {\n                    int val = Integer.parseInt(fields[c].strip());\n                    if ((val < 1) || (val > scale)) {\n                        System.out.println(\"Coordinates must be from 1 to \" + scale);\n                        error = true;\n                    } else {\n                        coords[c] = val;\n                    }\n                }\n            }\n            catch (NumberFormatException ne) {\n                // this happens if the field is not a valid number\n                System.out.println(\"Coordinates must be numbers\");\n                error = true;\n            }\n            if (!error) return true;\n        }\n    }\n\n    public int x() { return coords[0]; }\n    public int y() { return coords[1]; }\n}\n"
  },
  {
    "path": "09_Battle/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "09_Battle/java/Sea.java",
    "content": "// Track the content of the sea\nclass Sea {\n    // the sea is a square grid of tiles. It is a one-dimensional array, and this\n    // class maps x and y coordinates to an array index\n    // Each tile is either empty (value of tiles at index is 0)\n    // or contains a ship (value of tiles at index is the ship number)\n    private int tiles[];\n\n    private int size;\n\n    public Sea(int make_size) {\n        size = make_size;\n        tiles = new int[size*size];\n    }\n\n    public int size() { return size; }\n\n    // This writes out a representation of the sea, but in a funny order\n    // The idea is to give the player the job of working it out\n    public String encodedDump() {\n        StringBuilder out = new StringBuilder();\n        for (int x = 0; x < size; ++x) {\n            for (int y = 0; y < size; ++y)\n                out.append(Integer.toString(get(x, y)));\n            out.append('\\n');\n        }\n        return out.toString();\n    }\n\n    /* return true if x,y is in the sea and empty\n     * return false if x,y is occupied or is out of range\n     * Doing this in one method makes placing ships much easier\n     */\n    public boolean isEmpty(int x, int y) {\n        if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false;\n        return (get(x,y) == 0);\n    }\n\n    /* return the ship number, or zero if no ship.\n     * Unlike isEmpty(x,y), these other methods require that the\n     * coordinates passed be valid\n     */\n    public int get(int x, int y) {\n        return tiles[index(x,y)];\n    }\n\n    public void set(int x, int y, int value) {\n        tiles[index(x, y)] = value;\n    }\n\n    // map the coordinates to the array index\n    private int index(int x, int y) {\n        if ((x < 0) || (x >= size))\n            throw new ArrayIndexOutOfBoundsException(\"Program error: x cannot be \" + x);\n        if ((y < 0) || (y >= size))\n            throw new ArrayIndexOutOfBoundsException(\"Program error: y cannot be \" + y);\n\n        return y*size + x;\n    }\n}\n"
  },
  {
    "path": "09_Battle/java/Ship.java",
    "content": "import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Random;\nimport java.util.function.Predicate;\n\n/** A single ship, with its position and where it has been hit */\nclass Ship {\n    // These are the four directions that ships can be in\n    public static final int ORIENT_E=0;   // goes East from starting position\n    public static final int ORIENT_SE=1;  // goes SouthEast from starting position\n    public static final int ORIENT_S=2;   // goes South from starting position\n    public static final int ORIENT_SW=3;  // goes SouthWest from starting position\n\n    private int id;                   // ship number\n    private int size;                 // how many tiles it occupies\n    private boolean placed;           // whether this ship is in the sea yet\n    private boolean sunk;             // whether this ship has been sunk\n    private ArrayList<Boolean> hits;  // which tiles of the ship have been hit\n\n    private int startX;               // starting position coordinates\n    private int startY;\n    private int orientX;              // x and y deltas from each tile occupied to the next\n    private int orientY;\n\n    public Ship(int i, int sz) {\n        id = i; size = sz;\n        sunk = false; placed = false;\n        hits = new ArrayList<>(Collections.nCopies(size, false));\n    }\n\n    /** @returns the ship number */\n    public int id() { return id; }\n    /** @returns the ship size */\n    public int size() { return size; }\n\n    /* record the ship as having been hit at the given coordinates */\n    public void hit(int x, int y) {\n        // need to work out how many tiles from the ship's starting position the hit is at\n        // that can be worked out from the difference between the starting X coord and this one\n        // unless the ship runs N-S, in which case use the Y coord instead\n        int offset;\n        if (orientX != 0) {\n            offset = (x - startX) / orientX;\n        } else {\n            offset = (y - startY) / orientY;\n        }\n        hits.set(offset, true);\n\n        // if every tile of the ship has been hit, the ship is sunk\n        sunk = hits.stream().allMatch(Predicate.isEqual(true));\n    }\n\n    public boolean isSunk() { return sunk; }\n\n    // whether the ship has already been hit at the given coordinates\n    public boolean wasHit(int x, int y) {\n        int offset;\n        if (orientX != 0) {\n            offset = (x - startX) / orientX;\n        } else {\n            offset = (y - startY) / orientY;\n        }\n        return hits.get(offset);\n    };\n\n    // Place the ship in the sea.\n    // choose a random starting position, and a random direction\n    // if that doesn't fit, keep picking different positions and directions\n    public void placeRandom(Sea s) {\n        Random random = new Random();\n        for (int tries = 0 ; tries < 1000 ; ++tries) {\n            int x = random.nextInt(s.size());\n            int y = random.nextInt(s.size());\n            int orient = random.nextInt(4);\n\n            if (place(s, x, y, orient)) return;\n        }\n\n        throw new RuntimeException(\"Could not place any more ships\");\n    }\n\n    // Attempt to fit the ship into the sea, starting from a given position and\n    // in a given direction\n    // This is by far the most complicated part of the program.\n    // It will start at the position provided, and attempt to occupy tiles in the\n    // requested direction. If it does not fit, either because of the edge of the\n    // sea, or because of ships already in place, it will try to extend the ship\n    // in the opposite direction instead. If that is not possible, it fails.\n    public boolean place(Sea s, int x, int y, int orient) {\n        if (placed) {\n            throw new RuntimeException(\"Program error - placed ship \" + id + \" twice\");\n        }\n        switch(orient) {\n        case ORIENT_E:                 // east is increasing X coordinate\n            orientX = 1; orientY = 0;\n            break;\n        case ORIENT_SE:                // southeast is increasing X and Y\n            orientX = 1; orientY = 1;\n            break;\n        case ORIENT_S:                 // south is increasing Y\n            orientX = 0; orientY = 1;\n            break;\n        case ORIENT_SW:                // southwest is increasing Y but decreasing X\n            orientX = -1; orientY = 1;\n            break;\n        default:\n            throw new RuntimeException(\"Invalid orientation \" + orient);\n        }\n\n        if (!s.isEmpty(x, y)) return false; // starting position is occupied - placing fails\n\n        startX = x; startY = y;\n        int tilesPlaced = 1;\n        int nextX = startX;\n        int nextY = startY;\n        while (tilesPlaced < size) {\n            if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) {\n                // It is clear to extend the ship forwards\n                tilesPlaced += 1;\n                nextX = nextX + orientX;\n                nextY = nextY + orientY;\n            } else {\n                int backX = startX - orientX;\n                int backY = startY - orientY;\n\n                if (extendShip(s, startX, startY, backX, backY)) {\n                    // We can move the ship backwards, so it can be one tile longer\n                    tilesPlaced +=1;\n                    startX = backX;\n                    startY = backY;\n                } else {\n                    // Could not make it longer or move it backwards\n                    return false;\n                }\n            }\n        }\n\n        // Mark in the sea which tiles this ship occupies\n        for (int i = 0; i < size; ++i) {\n            int sx = startX + i * orientX;\n            int sy = startY + i * orientY;\n            s.set(sx, sy, id);\n        }\n\n        placed = true;\n        return true;\n    }\n\n    // Check whether a ship which already occupies the \"from\" coordinates,\n    // can also occupy the \"to\" coordinates.\n    // They must be within the sea area, empty, and not cause the ship to cross\n    // over another ship\n    private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) {\n        if (!s.isEmpty(toX, toY)) return false;                  // no space\n        if ((fromX == toX)||(fromY == toY)) return true;         // horizontal or vertical\n\n        // we can extend the ship without colliding, but we are going diagonally\n        // and it should not be possible for two ships to cross each other on\n        // opposite diagonals.\n\n        // check the two tiles that would cross us here - if either is empty, we are OK\n        // if they both contain different ships, we are OK\n        // but if they both contain the same ship, we are crossing!\n        int corner1 = s.get(fromX, toY);\n        int corner2 = s.get(toX, fromY);\n        if ((corner1 == 0) || (corner1 != corner2)) return true;\n        return false;\n    }\n}\n"
  },
  {
    "path": "09_Battle/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "09_Battle/javascript/battle.html",
    "content": "<html>\n<head>\n<title>BATTLE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"battle.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "09_Battle/javascript/battle.js",
    "content": "// BATTLE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar fa = [];\nvar ha = [];\nvar aa = [];\nvar ba = [];\nvar ca = [];\nvar la = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"BATTLE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    // -- BATTLE WRITTEN BY RAY WESTERGARD  10/70\n    // COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF.\n    // PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY\n    while (1) {\n        for (x = 1; x <= 6; x++) {\n            fa[x] = [];\n            ha[x] = [];\n            for (y = 1; y <= 6; y++) {\n                fa[x][y] = 0;\n                ha[x][y] = 0;\n            }\n        }\n        for (i = 1; i <= 3; i++) {\n            n = 4 - i;\n            for (j = 1; j <= 2; j++) {\n                while (1) {\n                    a = Math.floor(6 * Math.random() + 1);\n                    b = Math.floor(6 * Math.random() + 1);\n                    d = Math.floor(4 * Math.random() + 1);\n                    if (fa[a][b] > 0)\n                        continue;\n                    m = 0;\n                    switch (d) {\n                        case 1:\n                            ba[1] = b;\n                            ba[2] = 7;\n                            ba[3] = 7;\n                            for (k = 1; k <= n; k++) {\n                                if (m <= 1 && ba[k] != 6 && fa[a][ba[k] + 1] <= 0) {\n                                    ba[k + 1] = ba[k] + 1;\n                                } else {\n                                    m = 2;\n                                    if (ba[1] < ba[2] && ba[1] < ba[3])\n                                        z = ba[1];\n                                    if (ba[2] < ba[1] && ba[2] < ba[3])\n                                        z = ba[2];\n                                    if (ba[3] < ba[1] && ba[3] < ba[2])\n                                        z = ba[3];\n                                    if (z == 1)\n                                        break;\n                                    if (fa[a][z - 1] > 0)\n                                        break;\n                                    ba[k + 1] = z - 1;\n                                }\n                            }\n                            if (k <= n)\n                                continue;\n                            fa[a][b] = 9 - 2 * i - j;\n                            for (k = 1; k <= n; k++)\n                                fa[a][ba[k + 1]] = fa[a][b];\n                            break;\n                        case 2:\n                            aa[1] = a;\n                            ba[1] = b;\n                            aa[2] = 0;\n                            aa[3] = 0;\n                            ba[2] = 0;\n                            ba[3] = 0;\n                            for (k = 1; k <= n; k++) {\n                                if (m <= 1 && aa[k] != 1 && ba[k] != 1 && fa[aa[k] - 1][ba[k] - 1] <= 0 && (fa[aa[k] - 1][ba[k]] <= 0 || fa[aa[k] - 1][ba[k]] != fa[aa[k]][ba[k] - 1])) {\n                                    aa[k + 1] = aa[k] - 1;\n                                    ba[k + 1] = ba[k] - 1;\n                                } else {\n                                    m = 2;\n                                    if (aa[1] > aa[2] && aa[1] > aa[3])\n                                        z1 = aa[1];\n                                    if (aa[2] > aa[1] && aa[2] > aa[3])\n                                        z1 = aa[2];\n                                    if (aa[3] > aa[1] && aa[3] > aa[2])\n                                        z1 = aa[3];\n                                    if (ba[1] > ba[2] && ba[1] > ba[3])\n                                        z2 = ba[1];\n                                    if (ba[2] > ba[1] && ba[2] > ba[3])\n                                        z2 = ba[2];\n                                    if (ba[3] > ba[1] && ba[3] > ba[2])\n                                        z2 = ba[3];\n                                    if (z1 == 6 || z2 == 6)\n                                        break;\n                                    if (fa[z1 + 1][z2 + 1] > 0)\n                                        break;\n                                    if (fa[z1][z2 + 1] > 0 && fa[z1][z2 + 1] == fa[z1 + 1][z2])\n                                        break;\n                                    aa[k + 1] = z1 + 1;\n                                    ba[k + 1] = z2 + 1;\n                                }\n                            }\n                            if (k <= n)\n                                continue;\n                            fa[a][b] = 9 - 2 * i - j;\n                            for (k = 1; k <= n; k++)\n                                fa[aa[k + 1]][ba[k + 1]] = fa[a][b];\n                            break;\n                        case 3:\n                            aa[1] = a;\n                            aa[2] = 7;\n                            aa[3] = 7;\n                            for (k = 1; k <= n; k++) {\n                                if (m <= 1 && aa[k] != 6 && fa[aa[k] + 1][b] <= 0) {\n                                    aa[k + 1] = aa[k] + 1;\n                                } else {\n                                    m = 2;\n                                    if (aa[1] < aa[2] && aa[1] < aa[3])\n                                        z = aa[1];\n                                    if (aa[2] < aa[1] && aa[2] < aa[3])\n                                        z = aa[2];\n                                    if (aa[3] < aa[1] && aa[3] < aa[2])\n                                        z = aa[3];\n                                    if (z == 1)\n                                        break;\n                                    if (fa[z - 1][b] > 0)\n                                        break;\n                                    aa[k + 1] = z - 1;\n                                }\n                            }\n                            if (k <= n)\n                                continue;\n                            fa[a][b] = 9 - 2 * i - j;\n                            for (k = 1; k <= n; k++)\n                                fa[aa[k + 1]][b] = fa[a][b];\n                            break;\n                        case 4:\n                            aa[1] = a;\n                            ba[1] = b;\n                            aa[2] = 7;\n                            aa[3] = 7;\n                            ba[2] = 0;\n                            ba[3] = 0;\n                            for (k = 1; k <= n; k++) {\n                                if (m <= 1 && aa[k] != 6 && ba[k] != 1 && fa[aa[k] + 1][ba[k] - 1] <= 0 && (fa[aa[k] + 1][ba[k]] <= 0 || fa[aa[k] + 1][ba[k]] != fa[aa[k]][ba[k] - 1])) {\n                                    aa[k + 1] = aa[k] + 1;\n                                    ba[k + 1] = ba[k] - 1;\n                                } else {\n                                    m = 2;\n                                    if (aa[1] < aa[2] && aa[1] < aa[3])\n                                        z1 = aa[1];\n                                    if (aa[2] < aa[1] && aa[2] < aa[3])\n                                        z1 = aa[2];\n                                    if (aa[3] < aa[1] && aa[3] < aa[2])\n                                        z1 = aa[3];\n                                    if (ba[1] > ba[2] && ba[1] > ba[3])\n                                        z2 = ba[1];\n                                    if (ba[2] > ba[1] && ba[2] > ba[3])\n                                        z2 = ba[2];\n                                    if (ba[3] > ba[1] && ba[3] > ba[2])\n                                        z2 = ba[3];\n                                    if (z1 == 1 || z2 == 6)\n                                        break;\n                                    if (fa[z1 - 1][z2 + 1] > 0)\n                                        break;\n                                    if (fa[z1][z2 + 1] > 0 && fa[z1][z2 + 1] == fa[z1 - 1][z2])\n                                        break;\n                                    aa[k + 1] = z1 - 1;\n                                    ba[k + 1] = z2 + 1;\n                                }\n                            }\n                            if (k <= n)\n                                continue;\n                            fa[a][b] = 9 - 2 * i - j;\n                            for (k = 1; k <= n; k++)\n                                fa[aa[k + 1]][ba[k + 1]] = fa[a][b];\n                            break;\n                    }\n                    break;\n                }\n            }\n        }\n        print(\"\\n\");\n        print(\"THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\\n\");\n        print(\"HAS BEEN CAPTURED BUT NOT DECODED:\\n\");\n        print(\"\\n\");\n        for (i = 1; i <= 6; i++) {\n            for (j = 1; j <= 6; j++) {\n                ha[i][j] = fa[j][i];\n            }\n        }\n        for (i = 1; i <= 6; i++) {\n            str = \"\";\n            for (j = 1; j <= 6; j++) {\n                str += \" \" + ha[i][j] + \" \";\n            }\n            print(str + \"\\n\");\n        }\n        print(\"\\n\");\n        print(\"DE-CODE IT AND USE IT IF YOU CAN\\n\");\n        print(\"BUT KEEP THE DE-CODING METHOD A SECRET.\\n\");\n        print(\"\\n\");\n        for (i = 1; i <= 6; i++) {\n            for (j = 1; j <= 6; j++) {\n                ha[i][j] = 0;\n            }\n        }\n        for (i = 1; i <= 3; i++)\n            la[i] = 0;\n        ca[1] = 2;\n        ca[2] = 2;\n        ca[3] = 1;\n        ca[4] = 1;\n        ca[5] = 0;\n        ca[6] = 0;\n        s = 0;\n        h = 0;\n        print(\"START GAME\\n\");\n        while (1) {\n            str = await input();\n            // Check if user types anything other than a number\n            if (isNaN(str)) {\n                print(\"INVALID INPUT. TRY ENTERING A NUMBER INSTEAD.\\n\");\n                continue;\n            }\n            x = parseInt(str);\n            y = parseInt(str.substr(str.indexOf(\",\") + 1));\n            if (x < 1 || x > 6 || y < 1 || y > 6) {\n                print(\"INVALID INPUT.  TRY AGAIN.\\n\");\n                continue;\n            }\n            r = 7 - y;\n            c = x;\n            if (fa[r][c] <= 0) {\n                s++;\n                print(\"SPLASH!  TRY AGAIN.\\n\");\n                continue;\n            }\n            if (ca[fa[r][c]] >= 4) {\n                print(\"THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT.\\n\");\n                print(\"SPLASH!  TRY AGAIN.\\n\");\n                s++;\n                continue;\n            }\n            if (ha[r][c] > 0) {\n                print(\"YOU ALREADY PUT A HOLE IN SHIP NUMBER \" + fa[r][c] + \" AT THAT POINT.\\n\");\n                print(\"SPLASH!  TRY AGAIN.\\n\");\n                s++;\n                continue;\n            }\n            h++;\n            ha[r][c] = fa[r][c];\n            print(\"A DIRECT HIT ON SHIP NUMBER \" + fa[r][c] + \"\\n\");\n            ca[fa[r][c]]++;\n            if (ca[fa[r][c]] < 4) {\n                print(\"TRY AGAIN.\\n\");\n                continue;\n            }\n            la[Math.floor((fa[r][c] - 1) / 2) + 1]++;\n            print(\"AND YOU SUNK IT.  HURRAH FOR THE GOOD GUYS.\\n\");\n            print(\"SO FAR, THE BAD GUYS HAVE LOST\\n\");\n            print(\" \" + la[1] + \" DESTROYER(S), \" + la[2] + \" CRUISER(S), AND\");\n            print(\" \" + la[3] + \" AIRCRAFT CARRIER(S).\\n\");\n            print(\"YOUR CURRENT SPLASH/HIT RATIO IS \" + s / h + \"\\n\");\n            if (la[1] + la[2] + la[3] < 6)\n                continue;\n            print(\"\\n\");\n            print(\"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET\\n\");\n            print(\"WITH A FINAL SPLASH/HIT RATIO OF \" + s / h + \"\\n\");\n            if (s / h <= 0) {\n                print(\"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\\n\");\n            }\n            print(\"\\n\");\n            print(\"****************************\\n\");\n            print(\"\\n\");\n            break;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "09_Battle/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "09_Battle/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "09_Battle/pascal/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))\n"
  },
  {
    "path": "09_Battle/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "09_Battle/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "09_Battle/python/battle.py",
    "content": "#!/usr/bin/env python3\nfrom random import randrange\nfrom typing import List, Tuple\n\nPointType = Tuple[int, int]\nVectorType = PointType\nSeaType = Tuple[List[int], ...]\n\nSEA_WIDTH = 6\nDESTROYER_LENGTH = 2\nCRUISER_LENGTH = 3\nAIRCRAFT_CARRIER_LENGTH = 4\n\n\ndef random_vector() -> Tuple[int, int]:\n    while True:\n        vector = (randrange(-1, 2), randrange(-1, 2))\n\n        if vector == (0, 0):\n            # We can't have a zero vector, so try again\n            continue\n\n        return vector\n\n\ndef add_vector(point: PointType, vector: VectorType) -> PointType:\n    return (point[0] + vector[0], point[1] + vector[1])\n\n\ndef place_ship(sea: SeaType, size: int, code: int) -> None:\n    while True:\n        start = (randrange(1, SEA_WIDTH + 1), randrange(1, SEA_WIDTH + 1))\n        vector = random_vector()\n\n        # Get potential ship points\n        point = start\n        points = []\n\n        for _ in range(size):\n            point = add_vector(point, vector)\n            points.append(point)\n\n        if not all(is_within_sea(point, sea) for point in points) or any(\n            value_at(point, sea) for point in points\n        ):\n            # ship out of bounds or crosses other ship, trying again\n            continue\n\n        # We found a valid spot, so actually place it now\n        for point in points:\n            set_value_at(code, point, sea)\n\n        break\n\n\ndef print_encoded_sea(sea: SeaType) -> None:\n    for x in range(len(sea)):\n        print(\" \".join([str(sea[y][x]) for y in range(len(sea) - 1, -1, -1)]))\n\n\ndef is_within_sea(point: PointType, sea: SeaType) -> bool:\n    return (1 <= point[0] <= len(sea)) and (1 <= point[1] <= len(sea))\n\n\ndef has_ship(sea: SeaType, code: int) -> bool:\n    return any(code in row for row in sea)\n\n\ndef count_sunk(sea: SeaType, *codes: int) -> int:\n    return sum(not has_ship(sea, code) for code in codes)\n\n\ndef value_at(point: PointType, sea: SeaType) -> int:\n    return sea[point[1] - 1][point[0] - 1]\n\n\ndef set_value_at(value: int, point: PointType, sea: SeaType) -> None:\n    sea[point[1] - 1][point[0] - 1] = value\n\n\ndef get_next_target(sea: SeaType) -> PointType:\n    while True:\n        try:\n            guess = input(\"? \")\n            point_str_list = guess.split(\",\")\n\n            if len(point_str_list) != 2:\n                raise ValueError()\n\n            point = (int(point_str_list[0]), int(point_str_list[1]))\n\n            if not is_within_sea(point, sea):\n                raise ValueError()\n\n            return point\n        except ValueError:\n            print(\n                f\"INVALID. SPECIFY TWO NUMBERS FROM 1 TO {len(sea)}, SEPARATED BY A COMMA.\"\n            )\n\n\ndef setup_ships(sea: SeaType) -> None:\n    place_ship(sea, DESTROYER_LENGTH, 1)\n    place_ship(sea, DESTROYER_LENGTH, 2)\n    place_ship(sea, CRUISER_LENGTH, 3)\n    place_ship(sea, CRUISER_LENGTH, 4)\n    place_ship(sea, AIRCRAFT_CARRIER_LENGTH, 5)\n    place_ship(sea, AIRCRAFT_CARRIER_LENGTH, 6)\n\n\ndef main() -> None:\n    sea = tuple([0 for _ in range(SEA_WIDTH)] for _ in range(SEA_WIDTH))\n    setup_ships(sea)\n    print(\n        \"\"\"\n                BATTLE\nCREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\nTHE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\nHAS BEEN CAPTURED BUT NOT DECODED:\n\n\"\"\"\n    )\n    print_encoded_sea(sea)\n    print(\n        \"\"\"\n\nDE-CODE IT AND USE IT IF YOU CAN\nBUT KEEP THE DE-CODING METHOD A SECRET.\n\nSTART GAME\"\"\"\n    )\n    splashes = 0\n    hits = 0\n\n    while True:\n        target = get_next_target(sea)\n        target_value = value_at(target, sea)\n\n        if target_value < 0:\n            print(\n                f\"YOU ALREADY PUT A HOLE IN SHIP NUMBER {abs(target_value)} AT THAT POINT.\"\n            )\n\n        if target_value <= 0:\n            print(\"SPLASH! TRY AGAIN.\")\n            splashes += 1\n            continue\n\n        print(f\"A DIRECT HIT ON SHIP NUMBER {target_value}\")\n        hits += 1\n        set_value_at(-target_value, target, sea)\n\n        if not has_ship(sea, target_value):\n            print(\"AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS.\")\n            print(\"SO FAR, THE BAD GUYS HAVE LOST\")\n            print(\n                f\"{count_sunk(sea, 1, 2)} DESTROYER(S),\",\n                f\"{count_sunk(sea, 3, 4)} CRUISER(S),\",\n                f\"AND {count_sunk(sea, 5, 6)} AIRCRAFT CARRIER(S).\",\n            )\n\n        if any(has_ship(sea, code) for code in range(1, 7)):\n            print(f\"YOUR CURRENT SPLASH/HIT RATIO IS {splashes}/{hits}\")\n            continue\n\n        print(\n            \"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET \"\n            f\"WITH A FINAL SPLASH/HIT RATIO OF {splashes}/{hits}\"\n        )\n\n        if not splashes:\n            print(\"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\")\n\n        print(\"\\n****************************\")\n        break\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "09_Battle/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "09_Battle/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "09_Battle/rust/src/main.rs",
    "content": "use rand::Rng;\nuse std::{\n    cmp::Ordering,\n    fmt,\n    io::{self, Write},\n};\n\n#[derive(Clone, Copy)]\n#[repr(C)]\nenum ShipLength {\n    Destroyer = 2,\n    Cruiser = 3,\n    AircraftCarrier = 4,\n}\n\n#[derive(Clone, Copy, PartialEq)]\nstruct Point(i8, i8);\n\nimpl core::ops::Add for Point {\n    type Output = Self;\n\n    fn add(self, rhs: Self) -> Self::Output {\n        Self(self.0 + rhs.0, self.1 + rhs.1)\n    }\n}\n\nimpl Point {\n    pub fn is_outside(&self, width: usize) -> bool {\n        let w = width as i8;\n        (!(0..w).contains(&self.0)) || (!(0..w).contains(&self.1))\n    }\n\n    pub fn userinput2coordinate(self) -> Self {\n        Self(self.0 - 1, See::WIDTH as i8 - self.1)\n    }\n}\n\nstruct Ship(Vec<Point>);\n\nimpl Ship {\n    pub fn new(length: ShipLength) -> Self {\n        'try_again: loop {\n            let start = Point(\n                rand::thread_rng().gen_range(0..See::WIDTH) as i8,\n                rand::thread_rng().gen_range(0..See::WIDTH) as i8,\n            );\n            let vector = Self::random_vector();\n\n            let mut ship = vec![start];\n            for _ in 1..length as usize {\n                let last = ship.last().unwrap();\n                let new_part = *last + vector;\n                if new_part.is_outside(See::WIDTH) {\n                    continue 'try_again;\n                }\n                ship.push(new_part);\n            }\n\n            return Self(ship);\n        }\n    }\n\n    fn random_vector() -> Point {\n        loop {\n            let vector = Point(\n                rand::thread_rng().gen_range(-1..2),\n                rand::thread_rng().gen_range(-1..2),\n            );\n            if vector != Point(0, 0) {\n                return vector;\n            }\n        }\n    }\n\n    pub fn collide(&self, see: &[Vec<i8>]) -> bool {\n        self.0.iter().any(|p| see[p.0 as usize][p.1 as usize] != 0)\n    }\n\n    pub fn place(self, see: &mut [Vec<i8>], code: i8) {\n        for p in self.0.iter() {\n            see[p.0 as usize][p.1 as usize] = code;\n        }\n    }\n}\n\nenum Report {\n    Already(i8),\n    Splash,\n    Hit(i8),\n}\n\nstruct See {\n    data: Vec<Vec<i8>>,\n}\n\nimpl See {\n    pub const WIDTH: usize = 6;\n\n    fn place_ship(data: &mut [Vec<i8>], length: ShipLength, code: i8) {\n        let ship = loop {\n            let ship = Ship::new(length);\n            if ship.collide(data) {\n                continue;\n            }\n            break ship;\n        };\n        ship.place(data, code);\n    }\n\n    pub fn new() -> Self {\n        let mut data = vec![vec![0; Self::WIDTH]; Self::WIDTH];\n\n        Self::place_ship(&mut data, ShipLength::Destroyer, 1);\n        Self::place_ship(&mut data, ShipLength::Destroyer, 2);\n        Self::place_ship(&mut data, ShipLength::Cruiser, 3);\n        Self::place_ship(&mut data, ShipLength::Cruiser, 4);\n        Self::place_ship(&mut data, ShipLength::AircraftCarrier, 5);\n        Self::place_ship(&mut data, ShipLength::AircraftCarrier, 6);\n\n        Self { data }\n    }\n\n    pub fn report(&mut self, point: Point) -> Report {\n        let (x, y) = (point.0 as usize, point.1 as usize);\n        let value = self.data[x][y];\n        match value.cmp(&0) {\n            Ordering::Less => Report::Already(-value),\n            Ordering::Equal => Report::Splash,\n            Ordering::Greater => {\n                self.data[x][y] = -value;\n                Report::Hit(value)\n            }\n        }\n    }\n\n    pub fn has_ship(&self, code: i8) -> bool {\n        self.data.iter().any(|v| v.contains(&code))\n    }\n\n    pub fn has_any_ship(&self) -> bool {\n        (1..=6).any(|c| self.has_ship(c))\n    }\n\n    pub fn count_sunk(&self, ship: ShipLength) -> i32 {\n        let codes = match ship {\n            ShipLength::Destroyer => (1, 2),\n            ShipLength::Cruiser => (3, 4),\n            ShipLength::AircraftCarrier => (5, 6),\n        };\n\n        let ret = if self.has_ship(codes.0) { 0 } else { 1 };\n        ret + if self.has_ship(codes.1) { 0 } else { 1 }\n    }\n}\n\nimpl fmt::Display for See {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        for row in &self.data {\n            write!(f, \"\\r\\n\")?;\n            for cell in row {\n                write!(f, \"{:2} \", cell)?;\n            }\n        }\n        write!(f, \"\\r\\n\")\n    }\n}\n\nfn input_point() -> Result<Point, ()> {\n    let mut input = String::new();\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line\");\n    let point_str: Vec<&str> = input.trim().split(',').collect();\n\n    if point_str.len() != 2 {\n        return Err(());\n    }\n\n    let x = point_str[0].parse::<i8>().map_err(|_| ())?;\n    let y = point_str[1].parse::<i8>().map_err(|_| ())?;\n\n    Ok(Point(x, y))\n}\n\nfn get_next_target() -> Point {\n    loop {\n        print!(\"? \");\n        let _ = io::stdout().flush();\n\n        if let Ok(p) = input_point() {\n            let p = p.userinput2coordinate();\n            if !p.is_outside(See::WIDTH) {\n                return p;\n            }\n        }\n\n        println!(\n            \"INVALID. SPECIFY TWO NUMBERS FROM 1 TO {}, SEPARATED BY A COMMA.\",\n            See::WIDTH\n        );\n    }\n}\n\nfn main() {\n    let mut see = See::new();\n    println!(\n        \"\n                BATTLE\nCREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\nTHE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION\nHAS BEEN CAPTURED BUT NOT DECODED:\n        \"\n    );\n\n    println!(\"{see}\");\n\n    println!(\n        \"\n\nDE-CODE IT AND USE IT IF YOU CAN\nBUT KEEP THE DE-CODING METHOD A SECRET.\n\nSTART GAME\n        \"\n    );\n\n    let mut splashes = 0;\n    let mut hits = 0;\n\n    loop {\n        let target = get_next_target();\n\n        let r = see.report(target);\n        if let Report::Hit(c) = r {\n            println!(\"A DIRECT HIT ON SHIP NUMBER {c}\");\n            hits += 1;\n\n            if !see.has_ship(c) {\n                println!(\"AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS.\");\n                println!(\"SO FAR, THE BAD GUYS HAVE LOST\");\n                println!(\"{} DESTROYER(S),\", see.count_sunk(ShipLength::Destroyer));\n                println!(\"{} CRUISER(S),\", see.count_sunk(ShipLength::Cruiser));\n                println!(\n                    \"AND {} AIRCRAFT CARRIER(S),\",\n                    see.count_sunk(ShipLength::AircraftCarrier)\n                );\n            }\n        } else {\n            if let Report::Already(c) = r {\n                println!(\"YOU ALREADY PUT A HOLE IN SHIP NUMBER {c} AT THAT POINT.\");\n            }\n            println!(\"SPLASH! TRY AGAIN.\");\n            splashes += 1;\n            continue;\n        }\n\n        if see.has_any_ship() {\n            println!(\"YOUR CURRENT SPLASH/HIT RATIO IS {splashes}/{hits}\");\n            continue;\n        }\n\n        println!(\"YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET \");\n        println!(\"WITH A FINAL SPLASH/HIT RATIO OF {splashes}/{hits}\");\n\n        if splashes == 0 {\n            println!(\"CONGRATULATIONS -- A DIRECT HIT EVERY TIME.\");\n        }\n\n        println!(\"\\n****************************\");\n        break;\n    }\n}\n"
  },
  {
    "path": "09_Battle/vbnet/Battle.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Battle\", \"Battle.vbproj\", \"{D8475464-CB9B-448F-89A7-5BA15193C495}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D8475464-CB9B-448F-89A7-5BA15193C495}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D8475464-CB9B-448F-89A7-5BA15193C495}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D8475464-CB9B-448F-89A7-5BA15193C495}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D8475464-CB9B-448F-89A7-5BA15193C495}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "09_Battle/vbnet/Battle.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Battle</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "09_Battle/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "10_Blackjack/README.md",
    "content": "### Blackjack\n\nThis is a simulation of the card game of Blackjack or 21, Las Vegas style. This rather comprehensive version allows for up to seven players. On each hand a player may get another card (a hit), stand, split a hand in the event two identical cards were received or double down. Also, the dealer will ask for an insurance bet if he has an exposed ace.\n\nCards are automatically reshuffled as the 51st card is reached. For greater realism, you may wish to change this to the 41st card. Actually, fanatical purists will want to modify the program so it uses three decks of cards instead of just one.\n\nThis program originally surfaced at Digital Equipment Corp.; the author is unknown.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=18)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=33)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n\n#### Porting Notes\n\nThe program makes extensive use of the assumption that a boolean expression evaluates to **-1** for true.  This was the case in some classic BASIC environments but not others; and it is not the case in [JS Basic](https://troypress.com/wp-content/uploads/user/js-basic/index.html), leading to nonsensical results.  In an environment that uses **1** instead of **-1** for truth, you would need to negate the boolean expression in the following lines:\n\t- 10\n\t- 570\n\t- 590\n\t- 2220\n\t- 2850\n\t- 3100\n\t- 3400\n\t- 3410\n\t- 3420\n"
  },
  {
    "path": "10_Blackjack/blackjack.bas",
    "content": "2 PRINT TAB(31);\"BLACK JACK\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 DEF FNA(Q)=Q+11*(Q>=22)\n20 DIM P(15,12),Q(15),C(52),D(52),T(8),S(7),B(15)\n30 DIM R(15)\n40 REM--P(I,J) IS THE JTH CARD IN HAND I, Q(I) IS TOTAL OF HAND I\n50 REM--C IS THE DECK BEING DEALT FROM, D IS THE DISCARD PILE,\n60 REM--T(I) IS THE TOTAL FOR PLAYER I, S(I) IS THE TOTAL THIS HAND FOR\n70 REM--PLAYER I, B(I) IS TH BET FOR HAND I\n80 REM--R(I) IS THE LENGTH OF P(I,*)\n90 GOTO 1500\n100 REM--SUBROUTINE TO GET A CARD.  RESULT IS PUT IN X.\n110 IF C<51 THEN 230\n120 PRINT \"RESHUFFLING\"\n130 FOR D=D TO 1 STEP -1\n140 C=C-1\n150 C(C)=D(D)\n160 NEXT D\n170 FOR C1=52 TO C STEP -1\n180 C2=INT(RND(1)*(C1-C+1))+C\n190 C3=C(C2)\n200 C(C2)=C(C1)\n210 C(C1)=C3\n220 NEXT C1\n230 X=C(C)\n240 C=C+1\n250 RETURN\n300 REM--SUBROUTINE TO EVALUATE HAND I.  TOTAL IS PUT INTO\n310 REM--Q(I). TOTALS HAVE THE FOLLOWING MEANING:\n320 REM--  2-10...HARD 2-10\n330 REM-- 11-21...SOFT 11-21\n340 REM-- 22-32...HARD 11-21\n350 REM--  33+....BUSTED\n360 Q=0\n370 FOR Q2=1 TO R(I)\n380 X=P(I,Q2)\n390 GOSUB 500\n400 NEXT Q2\n410 Q(I)=Q\n420 RETURN\n500 REM--SUBROUTINE TO ADD CARD X TO TOTAL Q.\n510 X1=X: IF X1>10 THEN X1=10:  REM  SAME AS X1=10 MIN X\n520 Q1=Q+X1\n530 IF Q>=11 THEN 590\n540 IF X>1 THEN 570\n550 Q=Q+11\n560 RETURN\n570 Q=Q1-11*(Q1>=11)\n580 RETURN\n590 Q=Q1-(Q<=21 AND Q1>21)\n600 IF Q<33 THEN 620\n610 Q=-1\n620 RETURN\n700 REM--CARD PRINTING SUBROUTINE\n710 REM  D$ DEFINED ELSEWHERE\n720 PRINT MID$(D$,3*X-2,3);\n730 PRINT \"  \";\n740 RETURN\n750 REM--ALTERNATIVE PRINTING ROUTINE\n760 PRINT \" \";MID$(D$,3*X-1,2);\n770 PRINT \"   \";\n780 RETURN\n800 REM--SUBROUTINE TO PLAY OUT A HAND.\n810 REM--NO SPLITTING OR BLACKJACKS ALLOWED\n820 H1=5\n830 GOSUB 1410\n840 H1=3\n850 ON H GOTO 950,930\n860 GOSUB 100\n870 B(I)=B(I)*2\n880 PRINT \"RECEIVED A\";\n890 GOSUB 700\n900 GOSUB 1100\n910 IF Q>0 THEN GOSUB 1300\n920 RETURN\n930 GOSUB 1320\n940 RETURN\n950 GOSUB 100\n960 PRINT \"RECEIVED A\";\n970 GOSUB 700\n980 GOSUB 1100\n990 IF Q<0 THEN 940\n1000 PRINT \"HIT\";\n1010 GOTO 830\n1100 REM--SUBROUTINE TO ADD A CARD TO ROW I\n1110 R(I)=R(I)+1\n1120 P(I,R(I))=X\n1130 Q=Q(I)\n1140 GOSUB 500\n1150 Q(I)=Q\n1160 IF Q>=0 THEN 1190\n1170 PRINT \"...BUSTED\"\n1180 GOSUB 1200\n1190 RETURN\n1200 REM--SUBROUTINE TO DISCARD ROW I\n1210 IF R(I)<>0 THEN 1230\n1220 RETURN\n1230 D=D+1\n1240 D(D)=P(I,R(I))\n1250 R(I)=R(I)-1\n1260 GOTO 1210\n1300 REM--PRINTS TOTAL OF HAND I\n1310 PRINT\n1320 AA=Q(I): GOSUB 3400\n1325 PRINT \"TOTAL IS\";AA\n1330 RETURN\n1400 REM--SUBROUTINE TO READ REPLY\n1410 REM  I$ DEFINED ELSEWHERE\n1420 INPUT H$: H$=LEFT$(H$,1)\n1430 FOR H=1 TO H1 STEP 2\n1440 IF H$=MID$(I$,H,1) THEN 1480\n1450 NEXT H\n1460 PRINT \"TYPE \";MID$(I$,1,H1-1);\" OR \";MID$(I$,H1,2);\" PLEASE\";\n1470 GOTO 1420\n1480 H=(H+1)/2\n1490 RETURN\n1500 REM--PROGRAM STARTS HERE\n1510 REM--INITIALIZE\n1520 D$=\"N A  2  3  4  5  6  7N 8  9 10  J  Q  K\"\n1530 I$=\"H,S,D,/,\"\n1540 FOR I=1 TO 13\n1550 FOR J=4*I-3 TO 4*I\n1560 D(J)=I\n1570 NEXT J\n1580 NEXT I\n1590 D=52\n1600 C=53\n1610 PRINT \"DO YOU WANT INSTRUCTIONS\";\n1620 INPUT H$\n1630 IF LEFT$(H$,1)=\"N\" OR LEFT$(H$,1)=\"n\" THEN 1760\n1640 PRINT \"THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE\"\n1650 PRINT \"GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE\"\n1660 PRINT \"PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE\"\n1670 PRINT \"DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE\"\n1680 PRINT \"FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE\"\n1690 PRINT \"PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS\"\n1700 PRINT \"STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/',\"\n1710 PRINT \"INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE\"\n1720 PRINT \"INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR\"\n1730 PRINT \"'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING\"\n1740 PRINT \"DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR\"\n1750 PRINT \"BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'.\"\n1760 PRINT \"NUMBER OF PLAYERS\";\n1770 INPUT N\n1775 PRINT\n1780 IF N<1 OR N>7 OR N>INT(N) THEN 1760\n1790 FOR I=1 TO 8: T(I)=0: NEXT I\n1800 D1=N+1\n1810 IF 2*D1+C>=52 THEN GOSUB 120\n1820 IF C=2 THEN C=C-1\n1830 FOR I=1 TO N: Z(I)=0: NEXT I\n1840 FOR I=1 TO 15: B(I)=0: NEXT I\n1850 FOR I=1 TO 15: Q(I)=0: NEXT I\n1860 FOR I=1 TO 7: S(I)=0: NEXT I\n1870 FOR I=1 TO 15: R(I)=0: NEXT I\n1880 PRINT \"BETS:\"\n1890 FOR I=1 TO N: PRINT \"#\";I;: INPUT Z(I): NEXT I\n1900 FOR I=1 TO N\n1910 IF Z(I)<=0 OR Z(I)>500 THEN 1880\n1920 B(I)=Z(I)\n1930 NEXT I\n1940 PRINT \"PLAYER\";\n1950 FOR I=1 TO N\n1960 PRINT I;\"   \";\n1970 NEXT I\n1980 PRINT \"DEALER\"\n1990 FOR J=1 TO 2\n2000 PRINT TAB(5);\n2010 FOR I=1 TO D1\n2020 GOSUB 100\n2030 P(I,J)=X\n2040 IF J=1 OR I<=N THEN GOSUB 750\n2050 NEXT I\n2060 PRINT\n2070 NEXT J\n2080 FOR I=1 TO D1\n2090 R(I)=2\n2100 NEXT I\n2110 REM--TEST FOR INSURANCE\n2120 IF P(D1,1)>1 THEN 2240\n2130 PRINT \"ANY INSURANCE\";\n2140 INPUT H$\n2150 IF LEFT$(H$,1)<>\"Y\" THEN 2240\n2160 PRINT \"INSURANCE BETS\"\n2170 FOR I=1 TO N: PRINT \"#\";I;: INPUT Z(I): NEXT I\n2180 FOR I=1 TO N\n2190 IF Z(I)<0 OR Z(I)>B(I)/2 THEN 2160\n2200 NEXT I\n2210 FOR I=1 TO N\n2220 S(I)=Z(I)*(3*(-(P(D1,2)>=10))-1)\n2230 NEXT I\n2240 REM--TEST FOR DEALER BLACKJACK\n2250 L1=1: L2=1\n2252 IF P(D1,1)=1 AND P(D1,2)>9 THEN L1=0: L2=0\n2253 IF P(D1,2)=1 AND P(D1,1)>9 THEN L1=0: L2=0\n2254 IF L1<>0 OR L2<>0 THEN 2320\n2260 PRINT:PRINT \"DEALER HAS A\";MID$(D$,3*P(D1,2)-2,3);\" IN THE HOLE \";\n2270 PRINT \"FOR BLACKJACK\"\n2280 FOR I=1 TO D1\n2290 GOSUB 300\n2300 NEXT I\n2310 GOTO 3140\n2320 REM--NO DEALER BLACKJACK\n2330 IF P(D1,1)>1 AND P(D1,1)<10 THEN 2350\n2340 PRINT:PRINT \"NO DEALER BLACKJACK.\"\n2350 REM--NOW PLAY THE HANDS\n2360 FOR I=1 TO N\n2370 PRINT \"PLAYER\";I;\n2380 H1=7\n2390 GOSUB 1410\n2400 ON H GOTO 2550,2410,2510,2600\n2410 REM--PLAYER WANTS TO STAND\n2420 GOSUB 300\n2430 IF Q(I)<>21 THEN 2490\n2440 PRINT \"BLACKJACK\"\n2450 S(I)=S(I)+1.5*B(I)\n2460 B(I)=0\n2470 GOSUB 1200\n2480 GOTO 2900\n2490 GOSUB 1320\n2500 GOTO 2900\n2510 REM--PLAYER WANTS TO DOUBLE DOWN\n2520 GOSUB 300\n2530 GOSUB 860\n2540 GOTO 2900\n2550 REM--PLAYER WANTS TO BE HIT\n2560 GOSUB 300\n2570 H1=3\n2580 GOSUB 950\n2590 GOTO 2900\n2600 REM--PLAYER WANTS TO SPLIT\n2610 L1=P(I,1): IF P(I,1)>10 THEN L1=10\n2612 L2=P(I,2): IF P(I,2)>10 THEN L2=10\n2614 IF L1=L2 THEN 2640\n2620 PRINT \"SPLITTING NOT ALLOWED.\"\n2630 GOTO 2370\n2640 REM--PLAY OUT SPLIT\n2650 I1=I+D1\n2660 R(I1)=2\n2670 P(I1,1)=P(I,2)\n2680 B(I+D1)=B(I)\n2690 GOSUB 100\n2700 PRINT \"FIRST HAND RECEIVES A\";\n2710 GOSUB 700\n2720 P(I,2)=X\n2730 GOSUB 300\n2740 PRINT\n2750 GOSUB 100\n2760 PRINT \"SECOND HAND RECEIVES A\";\n2770 I=I1\n2780 GOSUB 700\n2790 P(I,2)=X\n2800 GOSUB 300\n2810 PRINT\n2820 I=I1-D1\n2830 IF P(I,1)=1 THEN 2900\n2840 REM--NOW PLAY THE TWO HANDS\n2850 PRINT \"HAND\";1-(I>D1);\n2860 GOSUB 800\n2870 I=I+D1\n2880 IF I=I1 THEN 2850\n2890 I=I1-D1\n2900 NEXT I\n2910 GOSUB 300\n2920 REM--TEST FOR PLAYING DEALER'S HAND\n2930 FOR I=1 TO N\n2940 IF R(I)>0 OR R(I+D1)>0 THEN 3010\n2950 NEXT I\n2960 PRINT \"DEALER HAD A\";\n2970 X=P(D1,2)\n2980 GOSUB 700\n2990 PRINT \" CONCEALED.\"\n3000 GOTO 3140\n3010 PRINT \"DEALER HAS A\";MID$(D$,3*P(D1,2)-2,3);\" CONCEALED \";\n3020 I=D1\n3030 AA=Q(I): GOSUB 3400\n3035 PRINT \"FOR A TOTAL OF\";AA\n3040 IF AA>16 THEN 3130\n3050 PRINT \"DRAWS\";\n3060 GOSUB 100\n3070 GOSUB 750\n3080 GOSUB 1100\n3090 AA=Q: GOSUB 3400\n3095 IF Q>0 AND AA<17 THEN 3060\n3100 Q(I)=Q-(Q<0)/2\n3110 IF Q<0 THEN 3140\n3120 AA=Q: GOSUB 3400\n3125 PRINT \"---TOTAL IS\";AA\n3130 PRINT\n3140 REM--TALLY THE RESULT\n3150 REM\n3160 Z$=\"LOSES PUSHES WINS \"\n3165 PRINT\n3170 FOR I=1 TO N\n3180 AA=Q(I): GOSUB 3400\n3182 AB=Q(I+D1): GOSUB 3410\n3184 AC=Q(D1): GOSUB 3420\n3186 S(I)=S(I)+B(I)*SGN(AA-AC)+B(I+D1)*SGN(AB-AC)\n3188 B(I+D1)=0\n3200 PRINT \"PLAYER\";I;\n3210 PRINT MID$(Z$,SGN(S(I))*6+7,6);\" \";\n3220 IF S(I)<>0 THEN 3250\n3230 PRINT \"      \";\n3240 GOTO 3260\n3250 PRINT ABS(S(I));\n3260 T(I)=T(I)+S(I)\n3270 PRINT \"TOTAL=\";T(I)\n3280 GOSUB 1200\n3290 T(D1)=T(D1)-S(I)\n3300 I=I+D1\n3310 GOSUB 1200\n3320 I=I-D1\n3330 NEXT I\n3340 PRINT \"DEALER'S TOTAL=\";T(D1)\n3345 PRINT\n3350 GOSUB 1200\n3360 GOTO 1810\n3400 AA=AA+11*(AA>=22): RETURN\n3410 AB=AB+11*(AB>=22): RETURN\n3420 AC=AC+11*(AC>=22): RETURN\n"
  },
  {
    "path": "10_Blackjack/csharp/Blackjack.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Blackjack</RootNamespace>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "10_Blackjack/csharp/Blackjack.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Blackjack\", \"Blackjack.csproj\", \"{83253F48-9CCD-475C-A990-8703F1A2E31C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{83253F48-9CCD-475C-A990-8703F1A2E31C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{83253F48-9CCD-475C-A990-8703F1A2E31C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{83253F48-9CCD-475C-A990-8703F1A2E31C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{83253F48-9CCD-475C-A990-8703F1A2E31C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "10_Blackjack/csharp/Card.cs",
    "content": "namespace Blackjack\n{\n    public class Card\n    {\n        private static readonly string[] _names = new[] {\"A\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\"};\n\n        public Card(int index)\n        {\n            Index = index;\n        }\n\n        public int Index { get; private set; }\n\n        public string Name => _names[Index];\n\n        public string IndefiniteArticle => (Index == 0 || Index == 7) ? \"an\" : \"a\";\n\n        public bool IsAce => Index == 0;\n\n        public int Value\n        {\n            get\n            {\n                if (IsAce)\n                    return 11;\n                if (Index > 8)\n                    return 10;\n                return Index + 1;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/Deck.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Blackjack\n{\n    public class Deck\n    {\n        private static readonly Random _random = new Random();\n\n        private readonly List<Card> _cards = new List<Card>(52);\n        private readonly List<Card> _discards = new List<Card>(52);\n\n        public Deck()\n        {\n            for (var index = 0; index < 12; index++)\n            {\n                for (var suit = 0; suit < 4; suit++)\n                {\n                    _discards.Add(new Card(index));\n                }\n            }\n            Reshuffle();\n        }\n\n        private void Reshuffle()\n        {\n            Console.WriteLine(\"Reshuffling\");\n\n            _cards.AddRange(_discards);\n            _discards.Clear();\n\n            for (var index1 = _cards.Count - 1; index1 > 0; index1--)\n            {\n                var index2 = _random.Next(0, index1);\n                var swapCard = _cards[index1];\n                _cards[index1] = _cards[index2];\n                _cards[index2] = swapCard;\n            }\n        }\n\n        public Card DrawCard()\n        {\n            if (_cards.Count < 2)\n                Reshuffle();\n\n            var card = _cards[_cards.Count - 1];\n            _cards.RemoveAt(_cards.Count - 1);\n            return card;\n        }\n\n        public void Discard(IEnumerable<Card> cards)\n        {\n            _discards.AddRange(cards);\n        }\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/Game.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Blackjack\n{\n    public class Game\n    {\n        private readonly Deck _deck = new Deck();\n        private readonly int _numberOfPlayers;\n        private readonly Player[] _players;\n        private readonly Hand _dealerHand;\n\n        public Game(int numberOfPlayers)\n        {\n            _numberOfPlayers = numberOfPlayers;\n            _players = new Player[_numberOfPlayers];\n            for (var playerIndex = 0; playerIndex < _numberOfPlayers; playerIndex++)\n                _players[playerIndex] = new Player(playerIndex);\n            _dealerHand = new Hand();\n        }\n\n        public void PlayGame()\n        {\n            while (true)\n            {\n                PlayRound();\n                TallyResults();\n                ResetRoundState();\n                Console.WriteLine();\n            }\n        }\n\n        public void PlayRound()\n        {\n            GetPlayerBets();\n\n            DealHands();\n\n            // Test for insurance\n            var dealerIsShowingAce = _dealerHand.Cards[0].IsAce;\n            if (dealerIsShowingAce && Prompt.ForYesNo(\"Any insurance?\"))\n            {\n                Console.WriteLine(\"Insurance bets\");\n                var insuranceBets = new int[_numberOfPlayers];\n                foreach (var player in _players)\n                    insuranceBets[player.Index] = Prompt.ForInteger($\"# {player.Index + 1} ?\", 0, player.RoundBet / 2);\n\n                var insuranceEffectMultiplier = _dealerHand.IsBlackjack ? 2 : -1;\n                foreach (var player in _players)\n                    player.RoundWinnings += insuranceBets[player.Index] * insuranceEffectMultiplier;\n            }\n\n            // Test for dealer blackjack\n            var concealedCard = _dealerHand.Cards[0];\n            if (_dealerHand.IsBlackjack)\n            {\n                Console.WriteLine();\n                Console.WriteLine(\"Dealer has {0} {1} in the hole for blackjack.\", concealedCard.IndefiniteArticle, concealedCard.Name);\n                return;\n            }\n            else if (dealerIsShowingAce)\n            {\n                Console.WriteLine();\n                Console.WriteLine(\"No dealer blackjack.\");\n            }\n\n            foreach (var player in _players)\n                PlayHand(player);\n\n            // Dealer hand\n            var allPlayersBusted = _players.All(p => p.Hand.IsBusted && (!p.SecondHand.Exists || p.SecondHand.IsBusted));\n            if (allPlayersBusted)\n                Console.WriteLine(\"Dealer had {0} {1} concealed.\", concealedCard.IndefiniteArticle, concealedCard.Name);\n            else\n            {\n                Console.WriteLine(\"Dealer has {0} {1} concealed for a total of {2}\", concealedCard.IndefiniteArticle, concealedCard.Name, _dealerHand.Total);\n                if (_dealerHand.Total < 17)\n                {\n                    Console.Write(\"Draws\");\n                    while (_dealerHand.Total < 17)\n                    {\n                        var card = _dealerHand.AddCard(_deck.DrawCard());\n                        Console.Write(\"  {0}\", card.Name);\n                    }\n                    if (_dealerHand.IsBusted)\n                        Console.WriteLine(\"  ...Busted\");\n                    else\n                        Console.WriteLine(\"  ---Total is {0}\", _dealerHand.Total);\n                }\n            }\n        }\n\n        private void GetPlayerBets()\n        {\n            Console.WriteLine(\"Bets:\");\n            foreach (var player in _players)\n                player.RoundBet = Prompt.ForInteger($\"# {player.Name} ?\", 1, 500);\n        }\n\n        private void DealHands()\n        {\n            Console.Write(\"Player \");\n            foreach (var player in _players)\n                Console.Write(\"{0}     \", player.Name);\n            Console.WriteLine(\"Dealer\");\n\n            for (var cardIndex = 0; cardIndex < 2; cardIndex++)\n            {\n                Console.Write(\"      \");\n                foreach (var player in _players)\n                    Console.Write(\"  {0,-4}\", player.Hand.AddCard(_deck.DrawCard()).Name);\n                var dealerCard = _dealerHand.AddCard(_deck.DrawCard());\n                Console.Write(\"  {0,-4}\", (cardIndex == 0) ? \"XX\" : dealerCard.Name);\n\n                Console.WriteLine();\n            }\n        }\n\n        private void PlayHand(Player player)\n        {\n            var hand = player.Hand;\n\n            Console.Write(\"Player {0} \", player.Name);\n\n            var playerCanSplit = hand.Cards[0].Value == hand.Cards[1].Value;\n            var command = Prompt.ForCommandCharacter(\"?\", playerCanSplit ? \"HSD/\" : \"HSD\");\n            switch (command)\n            {\n                case \"D\":\n                    player.RoundBet *= 2;\n                    goto case \"H\";\n\n                case \"H\":\n                    while (TakeHit(hand) && PromptForAnotherHit())\n                    { }\n                    if (!hand.IsBusted)\n                        Console.WriteLine(\"Total is {0}\", hand.Total);\n                    break;\n\n                case \"S\":\n                    if (hand.IsBlackjack)\n                    {\n                        Console.WriteLine(\"Blackjack!\");\n                        player.RoundWinnings = (int)(1.5 * player.RoundBet + 0.5);\n                        player.RoundBet = 0;\n                    }\n                    else\n                        Console.WriteLine(\"Total is {0}\", hand.Total);\n                    break;\n\n                case \"/\":\n                    hand.SplitHand(player.SecondHand);\n                    var card = hand.AddCard(_deck.DrawCard());\n                    Console.WriteLine(\"First hand receives {0} {1}\", card.IndefiniteArticle, card.Name);\n                    card = player.SecondHand.AddCard(_deck.DrawCard());\n                    Console.WriteLine(\"Second hand receives {0} {1}\", card.IndefiniteArticle, card.Name);\n\n                    for (int handNumber = 1; handNumber <= 2; handNumber++)\n                    {\n                        hand = (handNumber == 1) ? player.Hand : player.SecondHand;\n\n                        Console.Write(\"Hand {0}\", handNumber);\n                        while (PromptForAnotherHit() && TakeHit(hand))\n                        { }\n                        if (!hand.IsBusted)\n                            Console.WriteLine(\"Total is {0}\", hand.Total);\n                    }\n                    break;\n            }\n        }\n\n        private bool TakeHit(Hand hand)\n        {\n            var card = hand.AddCard(_deck.DrawCard());\n            Console.Write(\"Received {0,-6}\", $\"{card.IndefiniteArticle} {card.Name}\");\n            if (hand.IsBusted)\n            {\n                Console.WriteLine(\"...Busted\");\n                return false;\n            }\n            return true;\n        }\n\n        private bool PromptForAnotherHit()\n        {\n            return String.Equals(Prompt.ForCommandCharacter(\" Hit?\", \"HS\"), \"H\");\n        }\n\n        private void TallyResults()\n        {\n            Console.WriteLine();\n            foreach (var player in _players)\n            {\n                player.RoundWinnings += CalculateWinnings(player, player.Hand);\n                if (player.SecondHand.Exists)\n                    player.RoundWinnings += CalculateWinnings(player, player.SecondHand);\n                player.TotalWinnings += player.RoundWinnings;\n\n                Console.WriteLine(\"Player {0} {1,-6} {2,3}   Total= {3,5}\",\n                        player.Name,\n                        (player.RoundWinnings > 0) ? \"wins\" : (player.RoundWinnings) < 0 ? \"loses\" : \"pushes\",\n                        (player.RoundWinnings != 0) ? Math.Abs(player.RoundWinnings).ToString() : \"\",\n                        player.TotalWinnings);\n            }\n            Console.WriteLine(\"Dealer's total= {0}\", -_players.Sum(p => p.TotalWinnings));\n        }\n\n        private int CalculateWinnings(Player player, Hand hand)\n        {\n            if (hand.IsBusted)\n                return -player.RoundBet;\n            if (hand.Total == _dealerHand.Total)\n                return 0;\n            if (_dealerHand.IsBusted || hand.Total > _dealerHand.Total)\n                return player.RoundBet;\n            return -player.RoundBet;\n        }\n\n        private void ResetRoundState()\n        {\n            foreach (var player in _players)\n            {\n                player.RoundWinnings = 0;\n                player.RoundBet = 0;\n                player.Hand.Discard(_deck);\n                player.SecondHand.Discard(_deck);\n            }\n            _dealerHand.Discard(_deck);\n        }\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/Hand.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Blackjack\n{\n    public class Hand\n    {\n        private readonly List<Card> _cards = new List<Card>(12);\n        private int _cachedTotal = 0;\n\n        public Card AddCard(Card card)\n        {\n            _cards.Add(card);\n            _cachedTotal = 0;\n            return card;\n        }\n\n        public void Discard(Deck deck)\n        {\n            deck.Discard(_cards);\n            _cards.Clear();\n            _cachedTotal = 0;\n        }\n\n        public void SplitHand(Hand secondHand)\n        {\n            if (Count != 2 || secondHand.Count != 0)\n                throw new InvalidOperationException();\n            secondHand.AddCard(_cards[1]);\n            _cards.RemoveAt(1);\n            _cachedTotal = 0;\n        }\n\n        public IReadOnlyList<Card> Cards => _cards;\n\n        public int Count => _cards.Count;\n\n        public bool Exists => _cards.Count > 0;\n\n        public int Total\n        {\n            get\n            {\n                if (_cachedTotal == 0)\n                {\n                    var aceCount = 0;\n                    foreach (var card in _cards)\n                    {\n                        _cachedTotal += card.Value;\n                        if (card.IsAce)\n                            aceCount++;\n                    }\n                    while (_cachedTotal > 21 && aceCount > 0)\n                    {\n                        _cachedTotal -= 10;\n                        aceCount--;\n                    }\n                }\n                return _cachedTotal;\n            }\n        }\n\n        public bool IsBlackjack => Total == 21 && Count == 2;\n\n        public bool IsBusted => Total > 21;\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/Player.cs",
    "content": "namespace Blackjack\n{\n    public class Player\n    {\n        public Player(int index)\n        {\n            Index = index;\n            Name = (index + 1).ToString();\n            Hand = new Hand();\n            SecondHand = new Hand();\n        }\n\n        public int Index { get; private set; }\n\n        public string Name { get; private set; }\n\n        public Hand Hand { get; private set; }\n\n        public Hand SecondHand { get; private set;}\n\n        public int RoundBet { get; set; }\n\n        public int RoundWinnings { get; set; }\n\n        public int TotalWinnings { get; set; }\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Blackjack\n{\n    static class Program\n    {\n        static void Main(string[] args)\n        {\n            Console.WriteLine(\"{0}BLACK JACK\", new string(' ', 31));\n            Console.WriteLine(\"{0}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", new string(' ', 15));\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n\n            OfferInstructions();\n\n            var numberOfPlayers = Prompt.ForInteger(\"Number of players?\", 1, 6);\n            var game = new Game(numberOfPlayers);\n            game.PlayGame();\n        }\n\n        private static void OfferInstructions()\n        {\n            if (!Prompt.ForYesNo(\"Do you want instructions?\"))\n                return;\n\n            Console.WriteLine(\"This is the game of 21. As many as 7 players may play the\");\n            Console.WriteLine(\"game. On each deal, bets will be asked for, and the\");\n            Console.WriteLine(\"players' bets should be typed in. The cards will then be\");\n            Console.WriteLine(\"dealt, and each player in turn plays his hand. The\");\n            Console.WriteLine(\"first response should be either 'D', indicating that the\");\n            Console.WriteLine(\"player is doubling down, 'S', indicating that he is\");\n            Console.WriteLine(\"standing, 'H', indicating he wants another card, or '/',\");\n            Console.WriteLine(\"indicating that he wants to split his cards. After the\");\n            Console.WriteLine(\"initial response, all further responses should be 's' or\");\n            Console.WriteLine(\"'H', unless the cards were split, in which case doubling\");\n            Console.WriteLine(\"down is again permitted. In order to collect for\");\n            Console.WriteLine(\"Blackjack, the initial response should be 'S'.\");\n        }\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/Prompt.cs",
    "content": "using System;\n\nnamespace Blackjack\n{\n    public static class Prompt\n    {\n        public static bool ForYesNo(string prompt)\n        {\n            while(true)\n            {\n                Console.Write(\"{0} \", prompt);\n                var input = Console.ReadLine();\n                if (input.StartsWith(\"y\", StringComparison.InvariantCultureIgnoreCase))\n                    return true;\n                if (input.StartsWith(\"n\", StringComparison.InvariantCultureIgnoreCase))\n                    return false;\n                WriteNotUnderstood();\n            }\n        }\n\n        public static int ForInteger(string prompt, int minimum = 1, int maximum = int.MaxValue)\n        {\n            while (true)\n            {\n                Console.Write(\"{0} \", prompt);\n                if (!int.TryParse(Console.ReadLine(), out var number))\n                    WriteNotUnderstood();\n                else if (number < minimum || number > maximum)\n                    Console.WriteLine(\"Sorry, I need a number between {0} and {1}.\", minimum, maximum);\n                else\n                    return number;\n            }\n        }\n\n        public static string ForCommandCharacter(string prompt, string allowedCharacters)\n        {\n            while (true)\n            {\n                Console.Write(\"{0} \", prompt);\n                var input = Console.ReadLine();\n                if (input.Length > 0)\n                {\n                    var character = input.Substring(0, 1);\n                    var characterIndex = allowedCharacters.IndexOf(character, StringComparison.InvariantCultureIgnoreCase);\n                    if (characterIndex != -1)\n                        return allowedCharacters.Substring(characterIndex, 1);\n                }\n\n                Console.WriteLine(\"Type one of {0} please\", String.Join(\", \", allowedCharacters.ToCharArray()));\n            }\n        }\n\n        private static void WriteNotUnderstood()\n        {\n            Console.WriteLine(\"Sorry, I didn't understand.\");\n        }\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "10_Blackjack/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "10_Blackjack/java/src/Blackjack.java",
    "content": "import java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.util.Collections;\n\n/**\n * Plays a game of blackjack on the terminal. Looking at the code, the reader\n * might conclude that this implementation is \"over engineered.\" We use many\n * techniques and patterns developed for much larger code bases to create more\n * maintainable code, which may not be as relevant for a simple game of\n * Blackjack. To wit, the rules and requirements are not likely to ever change\n * so there is not so much value making the code flexible.\n * \n * Nevertheless, this is meant to be an example that the reader can learn good\n * Java coding techniques from. Furthermore, many of the \"over-engineering\"\n * tactics are as much about testability as they are about maintainability.\n * Imagine trying to manually test infrequent scenarios like Blackjack,\n * insurance, or splitting without any ability to automate a specific scenario\n * and the value of unit testing becomes immediately apparent.\n * \n * Another \"unnecessary\" aspect of this codebase is good Javadoc. Again, this is\n * meant to be educational, but another often overlooked benefit is that most\n * IDEs will display Javadoc in \"autocomplete\" suggestions. This is remarkably\n * helpful when using a class as a quick reminder of what you coded earlier.\n * This is true even if no one ever publishes or reads the HTML output of the\n * javadoc.\n * \n */\npublic class Blackjack {\n\tpublic static void main(String[] args) {\n\t\t// Intuitively it might seem like the main program logic should be right\n\t\t// here in 'main' and that we should just use System.in and System.out\n\t\t// directly whenever we need them.  However, notice that System.out and\n\t\t// System.in are just an OutputStream and InputStream respectively. By\n\t\t// allowing alternate streams to be specified to Game at runtime, we can\n\t\t// write non-interactive tests of the code. See UserIoTest as an\n\t\t// example.\n\t\t// Likewise, by allowing an alternative \"shuffle\" algorithm, test code\n\t\t// can provide a deterministic card ordering.\n\t\ttry (Reader in = new InputStreamReader(System.in)) {\n\t\t\tWriter out = new OutputStreamWriter(System.out);\n\t\t\tUserIo userIo = new UserIo(in, out);\n\t\t\tDeck deck = new Deck(cards -> {\n\t\t\t\tuserIo.println(\"RESHUFFLING\");\n\t\t\t    Collections.shuffle(cards);\n\t\t\t    return cards;\n\t\t\t});\n\t\t\tGame game = new Game(deck, userIo);\n\t\t\tgame.run();\n\t\t} catch (Exception e) {\n\t\t\t// This allows us to elegantly handle CTRL+D / CTRL+Z by throwing an exception.\n\t\t\tSystem.out.println(e.getMessage());\n\t\t\tSystem.exit(1);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "10_Blackjack/java/src/Card.java",
    "content": "/**\n * This is an example of an \"record\" class in Java. That's just a fancy way\n * of saying the properties (value and suit) can't change after the object has\n * been created (it has no 'setter' methods and the properties are implicitly 'final'). \n *\n * Immutability often makes it easier to reason about code logic and avoid\n * certain classes of bugs.\n *\n * Since it would never make sense for a card to change in the middle of a game,\n * this is a good candidate for immutability.\n */\nrecord Card(int value, Suit suit) {\n\n\tpublic enum Suit {\n\t\tHEARTS, DIAMONDS, SPADES, CLUBS;\n\t}\n\n\tpublic Card {\n        if(value < 1 || value > 13) {\n            throw new IllegalArgumentException(\"Invalid card value \" + value);\n        }\n        if(suit == null) {\n            throw new IllegalArgumentException(\"Card suit must be non-null\");\n        }\n\t}\n\n    public String toString() {\n        StringBuilder result = new StringBuilder(2); \n        if(value == 1) {\n            result.append(\"A\");\n        } else if(value < 11) {\n            result.append(value);\n        } else if(value == 11) {\n            result.append('J');\n        } else if(value == 12) {\n            result.append('Q');\n        } else if(value == 13) {\n            result.append('K');\n        }\n        // Uncomment to include the suit in output. Useful for debugging, but\n        // doesn't match the original BASIC behavior.\n        // result.append(suit.name().charAt(0));\n        return result.toString();\n    }\n\n    /**\n     * Returns the value of {@link #toString()} preceded by either \"AN \" or \"A \" depending on which is gramatically correct.\n     * \n     * @return \"AN [x]\" when [x] is \"an\" ace or \"an\" 8, and \"A [X]\" otherwise.\n     */\n    public String toProseString() {\n\t\tif(value == 1 || value == 8) {\n            return \"AN \" + toString();\n        } else {\n            return \"A \" + toString();\n        }\n    }\n\n}"
  },
  {
    "path": "10_Blackjack/java/src/Deck.java",
    "content": "import java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Function;\n\npublic class Deck {\n\n    private LinkedList<Card> cards;\n    private Function<LinkedList<Card>, LinkedList<Card>> shuffleAlgorithm;\n    \n    /**\n     * Initialize the game deck with the given number of standard decks.\n     * e.g. if you want to play with 2 decks, then {@code new Decks(2)} will\n     * initialize 'cards' with 2 copies of a standard 52 card deck.\n     * \n     * @param shuffleAlgorithm A function that takes the initial sorted card\n     * list and returns a shuffled list ready to deal.\n     * \n     */\n    public Deck(Function<LinkedList<Card>, LinkedList<Card>> shuffleAlgorithm) {\n        this.shuffleAlgorithm = shuffleAlgorithm;\n    }\n\n    /**\n     * Deals one card from the deck, removing it from this object's state. If\n     * the deck is empty, it will be reshuffled before dealing a new card.\n     * \n     * @return The card that was dealt.\n     */\n    public Card deal() {\n        if(cards == null || cards.isEmpty()) {\n            reshuffle();\n        }\n        return cards.pollFirst();\n    }\n\n    /**\n     * Shuffle the cards in this deck using the shuffleAlgorithm.\n     */\n    public void reshuffle() {\n        LinkedList<Card> newCards = new LinkedList<>();\n        for(Card.Suit suit : Card.Suit.values()) {\n            for(int value = 1; value < 14; value++) {\n                newCards.add(new Card(value, suit));\n            }\n        }\n        this.cards = this.shuffleAlgorithm.apply(newCards);\n    }\n\n    /**\n     * Get the number of cards in this deck.\n     * @return The number of cards in this deck. For example, 52 for a single deck.\n     */\n    public int size() {\n        return cards.size();\n    }\n\n    /**\n     * Returns the cards in this deck.\n     * @return An immutable view of the cards in this deck.\n     */\n    public List<Card> getCards() {\n        // The returned list is immutable because we don't want other code messing with the deck.\n        return Collections.unmodifiableList(cards);\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/java/src/Game.java",
    "content": "import java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.text.DecimalFormat;\n\n/**\n * This is the primary class that runs the game itself.\n */\npublic class Game {\n    \n    private Deck deck;\n    private UserIo userIo;\n\n    public Game(Deck deck, UserIo userIo) {\n        this.deck = deck;\n        this.userIo = userIo;\n    }\n\n\t/**\n\t * Run the game, running rounds until ended with CTRL+D/CTRL+Z or CTRL+C\n\t */\n    public void run() {\n\t\tuserIo.println(\"BLACK JACK\", 31);\n\t\tuserIo.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\", 15);\n\t\tif(userIo.promptBoolean(\"DO YOU WANT INSTRUCTIONS\")){\n\t\t\tuserIo.println(\"THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE\");\n\t\t\tuserIo.println(\"GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE\");\n\t\t\tuserIo.println(\"PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE\");\n\t\t\tuserIo.println(\"DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE\");\n\t\t\tuserIo.println(\"FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE\");\n\t\t\tuserIo.println(\"PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS\");\n\t\t\tuserIo.println(\"STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/',\");\n\t\t\tuserIo.println(\"INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE\");\n\t\t\tuserIo.println(\"INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR\");\n\t\t\tuserIo.println(\"'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING\");\n\t\t\tuserIo.println(\"DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR\");\n\t\t\tuserIo.println(\"BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'.\");\n\t\t}\n\n\t\tint nPlayers = 0;\n\t\twhile(nPlayers < 1 || nPlayers > 7) {\n\t\t\tnPlayers = userIo.promptInt(\"NUMBER OF PLAYERS\");\n\t\t}\n\n\t\tdeck.reshuffle();\n\n\t\tPlayer dealer = new Player(0); //Dealer is Player 0\n\t\t\n\t\tList<Player> players = new ArrayList<>();\n\t\tfor(int i = 0; i < nPlayers; i++) {\n\t\t\tplayers.add(new Player(i + 1));\n\t\t}\n\n\t\twhile(true) {\n\t\t\twhile(!betsAreValid(players)){\n\t\t\t\tuserIo.println(\"BETS:\");\n\t\t\t\tfor(int i = 0; i < nPlayers; i++) {\n\t\t\t\t\tdouble bet = userIo.promptDouble(\"#\" + (i + 1)); // 1st player is \"Player 1\" not \"Player 0\"\n\t\t\t\t\tplayers.get(i).setCurrentBet(bet);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// It doesn't *really* matter whether we deal two cards at once to each player\n\t\t\t// or one card to each and then a second card to each, but this technically\n\t\t\t// mimics the way a deal works in real life.\n\t\t\tfor(int i = 0; i < 2; i++){\n\t\t\t\tfor(Player player : players){\n\t\t\t\t\tplayer.dealCard(deck.deal());\n\t\t\t\t}\n\t\t\t\tdealer.dealCard(deck.deal());\n\t\t\t}\n\n\t\t\tprintInitialDeal(players, dealer);\n\n\t\t\tif(dealer.getHand().get(0).value() == 1) {\n\t\t\t\tcollectInsurance(players);\n\t\t\t}\n\n\t\t\tif(ScoringUtils.scoreHand(dealer.getHand()) == 21) {\n\t\t\t\tuserIo.println(\"DEALER HAS \" + dealer.getHand().get(1).toProseString() + \" IN THE HOLE\");\n\t\t\t\tuserIo.println(\"FOR BLACKJACK\");\n\t\t\t} else {\n\t\t\t\tCard dealerFirstCard = dealer.getHand().get(0);\n\t\t\t\tif(dealerFirstCard.value() == 1 || dealerFirstCard.value() > 9) {\n\t\t\t\t\tuserIo.println(\"\");\n\t\t\t\t\tuserIo.println(\"NO DEALER BLACKJACK.\");\n\t\t\t\t} // else dealer blackjack is imposible\n\t\t\t\tfor(Player player : players){\n\t\t\t\t\tplay(player);\n\t\t\t\t}\n\n\t\t\t\tif(shouldPlayDealer(players)){\n\t\t\t\t\tplayDealer(dealer);\n\t\t\t\t} else {\n\t\t\t\t\tuserIo.println(\"DEALER HAD \" + dealer.getHand().get(1).toProseString() + \" CONCEALED.\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tevaluateRound(players, dealer);\n\t\t} \n    }\n\n\tprotected void collectInsurance(Iterable<Player> players) {\n\t\tboolean isInsurance = userIo.promptBoolean(\"ANY INSURANCE\");\n\t\tif(isInsurance) {\n\t\t\tuserIo.println(\"INSURANCE BETS\");\n\t\t\tfor(Player player : players) {\n\t\t\t\twhile(true) {\n\t\t\t\t\tdouble insuranceBet = userIo.promptDouble(\"# \" + player.getPlayerNumber() + \" \");\n\t\t\t\t\t// 0 indicates no insurance for that player.\n\t\t\t\t\tif(insuranceBet >= 0 && insuranceBet <= (player.getCurrentBet() / 2)) {\n\t\t\t\t\t\tplayer.setInsuranceBet(insuranceBet);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Print the cards for each player and the up card for the dealer.\n\t * Prints the initial deal in the following format:\n\t *\t\t\n\t *\tPLAYER 1     2    DEALER\n     *         7    10     4   \n     *         2     A   \n\t */\n\tprivate void printInitialDeal(List<Player> players, Player dealer) {\n\t\n        StringBuilder output = new StringBuilder(); \n\t\toutput.append(\"PLAYERS \");\n\t\tfor (Player player : players) {\n\t\t\toutput.append(player.getPlayerNumber() + \"\\t\");\n\t\t}\n\t\toutput.append(\"DEALER\\n\");\n\t\t//Loop through two rows of cards\t\t\n        for (int j = 0; j < 2; j++) {\n\t\t\toutput.append(\"\\t\");\n\t\t\tfor (Player player : players) {\n\t\t\t\toutput.append(player.getHand().get(j).toString()).append(\"\\t\");\n\t\t\t}\n\t\t\tif(j == 0 ){\n\t\t\t\toutput.append(dealer.getHand().get(j).toString());\n\t\t\t}\n\t\t\toutput.append(\"\\n\");\n\t\t}\n\t\tuserIo.print(output.toString());\n\t}\n\n\t/**\n\t * Plays the players turn. Prompts the user to hit (H), stay (S), or if\n\t * appropriate, split (/) or double down (D), and then performs those\n\t * actions. On a hit, prints \"RECEIVED A  [x]  HIT? \"\n\t * \n\t * @param player\n\t */\n\tprotected void play(Player player) {\n\t\tplay(player, 1);\n\t}\n\n\tprivate void play(Player player, int handNumber) {\n\t\tString action;\n\t\tif(player.isSplit()){\n\t\t\taction = userIo.prompt(\"HAND \" + handNumber);\n\t\t} else {\n\t\t\taction = userIo.prompt(\"PLAYER \" + player.getPlayerNumber() + \" \");\n\t\t}\n\t\twhile(true){\n\t\t\tif(action.equalsIgnoreCase(\"H\")){ // HIT\n\t\t\t\tCard c = deck.deal();\n\t\t\t\tplayer.dealCard(c, handNumber);\n\t\t\t\tif(ScoringUtils.scoreHand(player.getHand(handNumber)) > 21){\n\t\t\t\t\tuserIo.println(\"RECEIVED \" + c.toProseString() + \"  ...BUSTED\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\taction = userIo.prompt(\"RECEIVED \" + c.toProseString() + \" HIT\");\n\t\t\t} else if(action.equalsIgnoreCase(\"S\")){ // STAY\n\t\t\t\tbreak;\n\t\t\t} else if(action.equalsIgnoreCase(\"D\") && player.canDoubleDown(handNumber)) { // DOUBLE DOWN\n\t\t\t\tCard c = deck.deal();\n\t\t\t\tplayer.doubleDown(c, handNumber);\n\t\t\t\tif(ScoringUtils.scoreHand(player.getHand(handNumber)) > 21){\n\t\t\t\t\tuserIo.println(\"RECEIVED \" + c.toProseString() + \"  ...BUSTED\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tuserIo.println(\"RECEIVED \" + c.toProseString());\n\t\t\t\tbreak;\n\t\t\t} else if(action.equalsIgnoreCase(\"/\")) { // SPLIT\n\t\t\t\tif(player.isSplit()) {\n\t\t\t\t\t// The original basic code printed different output\n\t\t\t\t\t// if a player tries to split twice vs if they try to split\n\t\t\t\t\t// a non-pair hand.\n\t\t\t\t\taction = userIo.prompt(\"TYPE H, S OR D, PLEASE\");\n\t\t\t\t} else if(player.canSplit()) {\n\t\t\t\t\tplayer.split();\n\t\t\t\t\tCard card = deck.deal();\n\t\t\t\t\tplayer.dealCard(card, 1);\n\t\t\t\t\tuserIo.println(\"FIRST HAND RECEIVES \" + card.toProseString());\n\t\t\t\t\tcard = deck.deal();\n\t\t\t\t\tplayer.dealCard(card, 2);\n\t\t\t\t\tuserIo.println(\"SECOND HAND RECEIVES \" + card.toProseString());\t\t\t\t\t\n\t\t\t\t\tif(player.getHand().get(0).value() > 1){ //Can't play after splitting aces\n\t\t\t\t\t\tplay(player, 1);\n\t\t\t\t\t\tplay(player, 2);\n\t\t\t\t\t}\n\t\t\t\t\treturn; // Don't fall out of the while loop and print another total\n\t\t\t\t} else {\n\t\t\t\t\tuserIo.println(\"SPLITTING NOT ALLOWED\");\n\t\t\t\t\taction = userIo.prompt(\"PLAYER \" + player.getPlayerNumber() + \" \");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(player.getHand(handNumber).size() == 2) {\n\t\t\t\t\taction = userIo.prompt(\"TYPE H,S,D, OR /, PLEASE\");\n\t\t\t\t} else {\n\t\t\t\t\taction = userIo.prompt(\"TYPE H, OR S, PLEASE\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tint total = ScoringUtils.scoreHand(player.getHand(handNumber));\n\t\tif(total == 21) {\n\t\t\tuserIo.println(\"BLACKJACK\");\n\t\t} else {\n\t\t\tuserIo.println(\"TOTAL IS \" + total);\n\t\t}\n\t}\n\n\t/**\n\t * Check the Dealer's hand should be played out. If every player has either busted or won with natural Blackjack,\n\t * the Dealer doesn't need to play.\n\t * \n\t * @param players\n\t * @return boolean whether the dealer should play\n\t */\n\tprotected boolean shouldPlayDealer(List<Player> players){\n\t\tfor(Player player : players){\n\t\t\tint score = ScoringUtils.scoreHand(player.getHand());\n\t\t\tif(score < 21 || (score == 21 && player.getHand().size() > 2)){\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif(player.isSplit()){\t\t\t\t\n\t\t\t\tint splitScore = ScoringUtils.scoreHand(player.getHand(2));\n\t\t\t\tif(splitScore < 21 || (splitScore == 21 && player.getHand(2).size() > 2)){\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\t\n\n\t/**\n\t * Play the dealer's hand. The dealer draws until they have >=17 or busts. Prints each draw as in the following example:\n\t * \n\t * DEALER HAS A  5 CONCEALED FOR A TOTAL OF 11 \n\t * DRAWS 10   ---TOTAL IS 21\n\t *  \n\t * @param dealerHand\n\t */\n\tprotected void playDealer(Player dealer) {\n\t\tint score = ScoringUtils.scoreHand(dealer.getHand());\n\t\tuserIo.println(\"DEALER HAS \" + dealer.getHand().get(1).toProseString() + \" CONCEALED FOR A TOTAL OF \" + score);\n\n\t\tif(score < 17){\n\t\t\tuserIo.print(\"DRAWS\");\n\t\t}\n\t\twhile(score < 17) {\n\t\t\tCard dealtCard = deck.deal();\n\t\t\tdealer.dealCard(dealtCard);\n\t\t\tscore = ScoringUtils.scoreHand(dealer.getHand());\n\t\t\tuserIo.print(\"  \" + String.format(\"%-4s\", dealtCard.toString()));\n\t\t}\n\t\t\n\t\tif(score > 21) {\n\t\t\tuserIo.println(\"...BUSTED\\n\");\n\t\t} else {\n\t\t\tuserIo.println(\"---TOTAL IS \" + score + \"\\n\");\n\t\t}\n\t}\n\n\t/**\n\t * Evaluates the result of the round, prints the results, and updates player/dealer totals.\n\t * \n\t *\tPLAYER 1 LOSES   100 TOTAL=-100 \n\t *\tPLAYER 2  WINS   150 TOTAL= 150\n\t *\tDEALER'S TOTAL= 200\n\t  *\n\t * @param players\n\t * @param dealerHand\n\t */\n\tprotected void evaluateRound(List<Player> players, Player dealer) {\n\t\tDecimalFormat formatter = new DecimalFormat(\"0.#\"); //Removes trailing zeros\n\t\tfor(Player player : players){\n\t\t\tint result = ScoringUtils.compareHands(player.getHand(), dealer.getHand());\n\t\t\tdouble totalBet = 0;\n\t\t\tif(result > 0) {\n\t\t\t\ttotalBet += player.getCurrentBet();\n\t\t\t} else if(result < 0){\n\t\t\t\ttotalBet -= player.getCurrentBet();\n\t\t\t}\n\t\t\tif(player.isSplit()) {\n\t\t\t\tint splitResult = ScoringUtils.compareHands(player.getHand(2), dealer.getHand());\n\t\t\t\tif(splitResult > 0){\n\t\t\t\t\ttotalBet += player.getSplitBet();\n\t\t\t\t} else if(splitResult < 0){\n\t\t\t\t\ttotalBet -= player.getSplitBet();\n\t\t\t\t} \n\t\t\t}\n\t\t\tif(player.getInsuranceBet() != 0){\n\t\t\t\tint dealerResult = ScoringUtils.scoreHand(dealer.getHand());\n\t\t\t\tif(dealerResult == 21 && dealer.getHand().size() == 2){\n\t\t\t\t\ttotalBet += (player.getInsuranceBet() * 2);\n\t\t\t\t} else {\n\t\t\t\t\ttotalBet -= player.getInsuranceBet();\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tuserIo.print(\"PLAYER \" + player.getPlayerNumber());\n\t\t\tif(totalBet < 0) {\n\t\t\t\tuserIo.print(\" LOSES \" + String.format(\"%6s\", formatter.format(Math.abs(totalBet)))); \n\t\t\t} else if(totalBet > 0) {\n\t\t\t\tuserIo.print(\"  WINS \" + String.format(\"%6s\", formatter.format(totalBet))); \n\t\t\t} else {\n\t\t\t\tuserIo.print(\" PUSHES      \");\n\t\t\t}\n\t\t\tplayer.recordRound(totalBet);\n\t\t\tdealer.recordRound(totalBet * (-1));\n\t\t\tuserIo.println(\" TOTAL= \" + formatter.format(player.getTotal()));\n\t\t\tplayer.resetHand();\n\t\t}\n\t\tuserIo.println(\"DEALER'S TOTAL= \" + formatter.format(dealer.getTotal()) + \"\\n\");\n\t\tdealer.resetHand();\n\t}\n\n\t/**\n\t * Validates that all bets are between 0 (exclusive) and 500 (inclusive). Fractional bets are valid.\n\t * \n\t * @param players The players with their current bet set.\n\t * @return true if all bets are valid, false otherwise.\n\t */\n\tpublic boolean betsAreValid(Collection<Player> players) {\n\t\treturn players.stream()\n\t\t\t.map(Player::getCurrentBet)\n\t\t\t.allMatch(bet -> bet > 0 && bet <= 500);\n\t}\n}\n"
  },
  {
    "path": "10_Blackjack/java/src/Player.java",
    "content": "import java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Represents a player and data related to them (number, bets, cards).\n */\npublic class Player {\n\n    private int playerNumber;     // e.g. playerNumber = 1 means \"this is Player 1\"\n    private double currentBet;\n    private double insuranceBet; // 0 when the player has not made an insurance bet (either it does not apply or they chose not to)\n    private double splitBet; // 0 whenever the hand is not split\n    private double total;\n    private LinkedList<Card> hand;\n    private LinkedList<Card> splitHand; // null whenever the hand is not split\n\n    /**\n    * Represents a player in the game with cards, bets, total and a playerNumber. \n    */\n    public Player(int playerNumber) {\n        this.playerNumber = playerNumber;\n        currentBet = 0;\n        insuranceBet = 0;\n        splitBet = 0;\n        total = 0;\n        hand = new LinkedList<>();\n        splitHand = null;\n    }\n\n    public int getPlayerNumber() {\n        return this.playerNumber;\n    }\n    \n    public double getCurrentBet() {\n        return this.currentBet;\n    }\n\n    public void setCurrentBet(double currentBet) {\n        this.currentBet = currentBet;\n    }\n\n    public double getSplitBet() {\n        return splitBet;\n    }\n\n    public double getInsuranceBet() {\n        return insuranceBet;\n    }\n\n    public void setInsuranceBet(double insuranceBet) {\n        this.insuranceBet = insuranceBet;\n    }\n\n    /**\n    * RecordRound adds input paramater 'totalBet' to 'total' and then \n    * sets 'currentBet', 'splitBet', and 'insuranceBet' to zero\n    */\n    public void recordRound(double totalBet) {\n        this.total = this.total + totalBet;\n        this.currentBet = 0;\n        this.splitBet = 0;\n        this.insuranceBet = 0;\n    }\n\n    /**\n     * Returns the total of all bets won/lost.\n     * @return Total value\n     */\n    public double getTotal() {\n        return this.total;\n    }\n\n    /**\n     * Add the given card to the players main hand.\n     * \n     * @param card The card to add.\n     */\n    public void dealCard(Card card) {\n        dealCard(card, 1);\n    }\n    \n    /**\n     * Adds the given card to the players hand or split hand depending on the handNumber.\n     * \n     * @param card The card to add\n     * @param handNumber 1 for the \"first\" hand and 2 for the \"second\" hand in a split hand scenario.\n     */\n    public void dealCard(Card card, int handNumber) {\n        if(handNumber == 1) {\n            hand.add(card);\n        } else if (handNumber == 2) {\n            splitHand.add(card);\n        } else {\n            throw new IllegalArgumentException(\"Invalid hand number \" + handNumber);\n        }\n    }\n\n    /**\n     * Determines whether the player is eligible to split.\n     * @return True if the player has not already split, and their hand is a pair. False otherwise.\n     */\n    public boolean canSplit() {\n        if(isSplit()) {\n            // Can't split twice\n            return false;\n        } else {\n            boolean isPair = this.hand.get(0).value() == this.hand.get(1).value();\n            return isPair;\n        }\n    }\n\n    /**\n     * Determines whether the player has already split their hand.\n     * @return false if splitHand is null, true otherwise.\n     */\n    public boolean isSplit() {\n        return this.splitHand != null;\n    }\n\n    /**\n     * Removes first card from hand to add it to new split hand\n     */\n    public void split() {\n        this.splitBet = this.currentBet;\n        this.splitHand = new LinkedList<>();\n        splitHand.add(hand.pop());\n    }\n\n    /**\n     * Determines whether the player can double down.\n     * \n     * @param handNumber\n     * @return\n     */\n    public boolean canDoubleDown(int handNumber) {\n        if(handNumber == 1){\n            return this.hand.size() == 2;\n        } else if(handNumber == 2){\n            return this.splitHand.size() == 2;\n        } else {\n            throw new IllegalArgumentException(\"Invalid hand number \" + handNumber);\n        }\n    }\n\n    /**\n     * Doubles down on the given hand. Specifically, this method doubles the bet for the given hand and deals the given card.\n     * \n     * @param card The card to deal\n     * @param handNumber The hand to deal to and double the bet for\n     */\n    public void doubleDown(Card card, int handNumber) {\n        if(handNumber == 1){\n            this.currentBet = this.currentBet * 2;\n        } else if(handNumber == 2){\n            this.splitBet = this.splitBet * 2;\n        } else {\n            throw new IllegalArgumentException(\"Invalid hand number \" + handNumber);\n        }\n        this.dealCard(card, handNumber);\n    }\n\n    /**\n     * Resets the hand to an empty list and the splitHand to null.\n     */\n    public void resetHand() {\n        this.hand = new LinkedList<>();\n        this.splitHand = null;\n    }\n\n    public List<Card> getHand() {\n        return getHand(1);\n    }\n\n    /**\n     * Returns the given hand\n     * @param handNumber 1 for the \"first\" of a split hand (or the main hand when there is no split) or 2 for the \"second\" hand of a split hand.\n     * @return The hand specified by handNumber\n     */\n    public List<Card> getHand(int handNumber) {\n        if(handNumber == 1){\n            return Collections.unmodifiableList(this.hand);\n        } else if(handNumber == 2){\n            return Collections.unmodifiableList(this.splitHand);\n        } else {\n            throw new IllegalArgumentException(\"Invalid hand number \" + handNumber);\n        }\n    }\n\n}"
  },
  {
    "path": "10_Blackjack/java/src/ScoringUtils.java",
    "content": "import java.util.List;\n\npublic final class ScoringUtils {\n\n\t/**\n\t * Calculates the value of a hand. When the hand contains aces, it will\n\t * count one of them as 11 if that does not result in a bust.\n\t * \n\t * @param hand the hand to evaluate\n\t * @return The numeric value of a hand. A value over 21 indicates a bust.\n\t */\n\tpublic static final int scoreHand(List<Card> hand) {\n\t\tint nAces = (int) hand.stream().filter(c -> c.value() == 1).count();\n\t\tint value = hand.stream()\n\t\t\t\t.mapToInt(Card::value)\n\t\t\t\t.filter(v -> v != 1) // start without aces\n\t\t\t\t.map(v -> v > 10 ? 10 : v) // all face cards are worth 10. The 'expr ? a : b' syntax is called the\n\t\t\t\t\t\t\t\t\t\t\t// 'ternary operator'\n\t\t\t\t.sum();\n\t\tvalue += nAces; // start by treating all aces as 1\n\t\tif (nAces > 0 && value <= 11) {\n\t\t\tvalue += 10; // We can use one of the aces to an 11\n\t\t\t// You can never use more than one ace as 11, since that would be 22 and a bust.\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Compares two hands accounting for natural blackjacks and busting using the\n\t * java.lang.Comparable convention of returning positive or negative integers\n\t * \n\t * @param handA hand to compare\n\t * @param handB other hand to compare\n\t * @return a negative integer, zero, or a positive integer as handA is less\n\t *         than, equal to, or greater than handB.\n\t */\n\tpublic static final int compareHands(List<Card> handA, List<Card> handB) {\n\t\tint scoreA = scoreHand(handA);\n\t\tint scoreB = scoreHand(handB);\n\t\tif (scoreA == 21 && scoreB == 21) {\n\t\t\tif (handA.size() == 2 && handB.size() != 2) {\n\t\t\t\treturn 1; // Hand A wins with a natural blackjack\n\t\t\t} else if (handA.size() != 2 && handB.size() == 2) {\n\t\t\t\treturn -1; // Hand B wins with a natural blackjack\n\t\t\t} else {\n\t\t\t\treturn 0; // Tie\n\t\t\t}\n\t\t} else if (scoreA > 21 || scoreB > 21) {\n\t\t\tif (scoreA > 21 && scoreB > 21) {\n\t\t\t\treturn 0; // Tie, both bust\n\t\t\t} else if (scoreB > 21) {\n\t\t\t\treturn 1; // A wins, B busted\n\t\t\t} else {\n\t\t\t\treturn -1; // B wins, A busted\n\t\t\t}\n\t\t} else {\n\t\t\treturn Integer.compare(scoreA, scoreB);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "10_Blackjack/java/src/UserIo.java",
    "content": "import java.io.BufferedReader;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Reader;\nimport java.io.UncheckedIOException;\nimport java.io.Writer;\nimport java.util.stream.IntStream;\n\n/**\n * This class is responsible for printing output to the screen and reading input\n * from the user. It must be initialized with a reader to get input data from\n * and a writer to send output to. Typically these will wrap System.in and\n * System.out respectively, but can be a StringReader and StringWriter when\n * running in test code.\n */\npublic class UserIo {\n\n    private BufferedReader in;\n    private PrintWriter out;\n\n\t/**\n\t * Initializes the UserIo with the given reader/writer. The reader will be\n\t * wrapped in a BufferedReader and so should <i>not</i> be a BufferedReader\n\t * already (to avoid double buffering).\n\t * \n\t * @param in Typically an InputStreamReader wrapping System.in or a StringReader\n\t * @param out Typically an OuputStreamWriter wrapping System.out or a StringWriter\n\t */\n    public UserIo(Reader in, Writer out) {\n        this.in = new BufferedReader(in);\n        this.out = new PrintWriter(out, true);\n    }\n\n\t/**\n\t * Print the line of text to output including a trailing linebreak.\n\t * \n\t * @param text the text to print\n\t */\n\tpublic void println(String text) {\n\t\tout.println(text);\n\t}\n\n\t/**\n\t * Print the given text left padded with spaces.\n\t * \n\t * @param text The text to print\n\t * @param leftPad The number of spaces to pad with.\n\t */\n\tpublic void println(String text, int leftPad) {\n\t\tIntStream.range(0, leftPad).forEach((i) -> out.print(' '));\n\t\tout.println(text);\n\t}\n\n\t/**\n\t * Print the given text <i>without</i> a trailing linebreak.\n\t * \n\t * @param text The text to print.\n\t */\n\tpublic void print(String text) {\n\t\tout.print(text);\n\t\tout.flush();\n\t}\n\n\t/**\n\t * Reads a line of text from input.\n\t * \n\t * @return The line entered into input.\n\t * @throws UncheckedIOException if the line is null (CTRL+D or CTRL+Z was pressed)\n\t */\n\tprivate String readLine() {\n\t\ttry {\n\t\t\tString line = in.readLine();\n\t\t\tif(line == null) {\n\t\t\t\tthrow new UncheckedIOException(\"!END OF INPUT\", new EOFException());\n\t\t\t}\n\t\t\treturn line;\n\t\t} catch (IOException e) {\n\t\t\tthrow new UncheckedIOException(e);\n\t\t}\n\t}\n\n\t/**\n\t * Prompt the user via input.\n\t * \n\t * @param prompt The text to display as a prompt. A question mark and space will be added to the end, so if prompt = \"EXAMPLE\" then the user will see \"EXAMPLE? \".\n\t * @return The line read from input.\n\t */\n\tpublic String prompt(String prompt) {\n\t\tprint(prompt + \"? \");\n\t\treturn readLine();\n\t}\n\n\t/**\n\t * Prompts the user for a \"Yes\" or \"No\" answer.\n\t * @param prompt The prompt to display to the user on STDOUT.\n\t * @return false if the user enters a value beginning with \"N\" or \"n\"; true otherwise.\n\t */\n\tpublic boolean promptBoolean(String prompt) {\n\t\tprint(prompt + \"? \");\n\n\t\tString input = readLine();\n\n\t\tif(input.toLowerCase().startsWith(\"n\")) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Prompts the user for an integer.  As in Vintage Basic, \"the optional\n\t * prompt string is followed by a question mark and a space.\" and if the\n\t * input is non-numeric, \"an error will be generated and the user will be\n\t * re-prompted.\"\"\n\t *\n\t * @param prompt The prompt to display to the user.\n\t * @return the number given by the user.\n\t */\n\tpublic int promptInt(String prompt) {\n\t\tprint(prompt + \"? \");\n\n\t\twhile(true) {\n\t\t\tString input = readLine();\n\t\t\ttry {\n\t\t\t\treturn Integer.parseInt(input);\n\t\t\t} catch(NumberFormatException e) {\n\t\t\t\t// Input was not numeric.\n\t\t\t\tprintln(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n\t\t\t\tprint(\"? \");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Prompts the user for a double.  As in Vintage Basic, \"the optional\n\t * prompt string is followed by a question mark and a space.\" and if the\n\t * input is non-numeric, \"an error will be generated and the user will be\n\t * re-prompted.\"\"\n\t *\n\t * @param prompt The prompt to display to the user.\n\t * @return the number given by the user.\n\t */\n\tpublic double promptDouble(String prompt) {\n\t\tprint(prompt + \"? \");\n\n\t\twhile(true) {\n\t\t\tString input = readLine();\n\t\t\ttry {\n\t\t\t\treturn Double.parseDouble(input);\n\t\t\t} catch(NumberFormatException e) {\n\t\t\t\t// Input was not numeric.\n\t\t\t\tprintln(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n\t\t\t\tprint(\"? \");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "10_Blackjack/java/test/DeckTest.java",
    "content": "import static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertAll;\nimport org.junit.jupiter.api.Test;\n\npublic class DeckTest {\n\n    @Test\n    void testInit() {\n        // When\n        Deck deck = new Deck((cards) -> cards);\n        deck.reshuffle();\n\n        // Then\n        long nCards = deck.size();\n        long nSuits = deck.getCards().stream()\n                .map(card -> card.suit())\n                .distinct()\n                .count();\n        long nValues = deck.getCards().stream()\n                .map(card -> card.value())\n                .distinct()\n                .count();\n\n        assertAll(\"deck\",\n            () -> assertEquals(52, nCards, \"Expected 52 cards in a deck, but got \" + nCards),\n            () -> assertEquals(4, nSuits, \"Expected 4 suits, but got \" + nSuits),\n            () -> assertEquals(13, nValues, \"Expected 13 values, but got \" + nValues)\n        );\n        \n    }\n\n}\n"
  },
  {
    "path": "10_Blackjack/java/test/GameTest.java",
    "content": "import org.junit.jupiter.api.Test;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.DisplayName;\n\nimport static org.junit.jupiter.api.Assertions.assertAll;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport java.io.EOFException;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.UncheckedIOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\n\npublic class GameTest {\n\n    private StringReader in;\n    private StringWriter out;\n    private Game game;\n\n    private StringBuilder playerActions;\n    private LinkedList<Card> cards;\n\n    @BeforeEach\n    public void resetIo() {\n        in = null;\n        out = null;\n        game = null;\n        playerActions = new StringBuilder();\n        cards = new LinkedList<>();\n    }\n\n    private void playerGets(int value, Card.Suit suit) {\n        cards.add(new Card(value, suit));\n    }\n\n    private void playerSays(String action) {\n        playerActions.append(action).append(System.lineSeparator());\n    }\n\n    private void initGame() {\n        System.out.printf(\"Running game with input: %s\\tand cards: %s\\n\",playerActions.toString(), cards);\n        in = new StringReader(playerActions.toString());\n        out = new StringWriter();\n        UserIo userIo = new UserIo(in, out);\n        Deck deck = new Deck((c) -> cards);\n        game = new Game(deck, userIo);\n    }\n\n    @AfterEach\n    private void printOutput() {\n        System.out.println(out.toString());\n    }\n\n    @Test\n    public void shouldQuitOnCtrlD() {\n        // Given\n        playerSays(\"\\u2404\"); // U+2404 is \"End of Transmission\" sent by CTRL+D (or CTRL+Z on Windows)\n        initGame();\n\n        // When\n        Exception e = assertThrows(UncheckedIOException.class, game::run);\n\n        // Then\n        assertTrue(e.getCause() instanceof EOFException);\n        assertEquals(\"!END OF INPUT\", e.getMessage());\n    }\n\n    @Test\n    @DisplayName(\"collectInsurance() should not prompt on N\")\n    public void collectInsuranceNo(){\n        // Given\n        List<Player> players = Collections.singletonList(new Player(1));\n        playerSays(\"N\");\n        initGame();\n\n        // When\n        game.collectInsurance(players);\n\n        // Then\n        assertAll(\n            () -> assertTrue(out.toString().contains(\"ANY INSURANCE\")),\n            () -> assertFalse(out.toString().contains(\"INSURANCE BETS\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"collectInsurance() should collect on Y\")\n    public void collectInsuranceYes(){\n        // Given\n        List<Player> players = Collections.singletonList(new Player(1));\n        players.get(0).setCurrentBet(100);\n        playerSays(\"Y\");\n        playerSays(\"50\");\n        initGame();\n\n        // When\n        game.collectInsurance(players);\n\n        // Then\n        assertAll(\n            () -> assertTrue(out.toString().contains(\"ANY INSURANCE\")),\n            () -> assertTrue(out.toString().contains(\"INSURANCE BETS\")),\n            () -> assertEquals(50, players.get(0).getInsuranceBet())\n        );\n    }\n\n    @Test\n    @DisplayName(\"collectInsurance() should not allow more than 50% of current bet\")\n    public void collectInsuranceYesTooMuch(){\n        // Given\n        List<Player> players = Collections.singletonList(new Player(1));\n        players.get(0).setCurrentBet(100);\n        playerSays(\"Y\");\n        playerSays(\"51\");\n        playerSays(\"50\");\n        initGame();\n\n        // When\n        game.collectInsurance(players);\n\n        // Then\n        assertAll(\n            () -> assertEquals(50, players.get(0).getInsuranceBet()),\n            () -> assertTrue(out.toString().contains(\"# 1 ? # 1 ?\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"collectInsurance() should not allow negative bets\")\n    public void collectInsuranceYesNegative(){\n        // Given\n        List<Player> players = Collections.singletonList(new Player(1));\n        players.get(0).setCurrentBet(100);\n        playerSays(\"Y\");\n        playerSays(\"-1\");\n        playerSays(\"1\");\n        initGame();\n\n        // When\n        game.collectInsurance(players);\n\n        // Then\n        assertAll(\n            () -> assertEquals(1, players.get(0).getInsuranceBet()),\n            () -> assertTrue(out.toString().contains(\"# 1 ? # 1 ?\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"collectInsurance() should prompt all players\")\n    public void collectInsuranceYesTwoPlayers(){\n        // Given\n        List<Player> players = Arrays.asList(\n            new Player(1),\n            new Player(2)\n        );\n        players.get(0).setCurrentBet(100);\n        players.get(1).setCurrentBet(100);\n\n        playerSays(\"Y\");\n        playerSays(\"50\");\n        playerSays(\"25\");\n        initGame();\n\n        // When\n        game.collectInsurance(players);\n\n        // Then\n        assertAll(\n            () -> assertEquals(50, players.get(0).getInsuranceBet()),\n            () -> assertEquals(25, players.get(1).getInsuranceBet()),\n            () -> assertTrue(out.toString().contains(\"# 1 ? # 2 ?\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"play() should end on STAY\")\n    public void playEndOnStay(){\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(3, Card.Suit.CLUBS));\n        player.dealCard(new Card(2, Card.Suit.SPADES));\n        playerSays(\"S\"); // \"I also like to live dangerously.\"\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().startsWith(\"PLAYER 1 ? TOTAL IS 5\"));\n    }\n\n    @Test\n    @DisplayName(\"play() should allow HIT until BUST\")\n    public void playHitUntilBust() {\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(10, Card.Suit.HEARTS));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n\n        playerSays(\"H\");\n        playerGets(1, Card.Suit.SPADES); // 20\n        playerSays(\"H\");\n        playerGets(1, Card.Suit.HEARTS); // 21\n        playerSays(\"H\");\n        playerGets(1, Card.Suit.CLUBS); // 22 - D'oh!\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"BUSTED\"));\n    }\n\n    @Test\n    @DisplayName(\"Should allow double down on initial turn\")\n    public void playDoubleDown(){\n        // Given\n        Player player = new Player(1);\n        player.setCurrentBet(100);\n        player.dealCard(new Card(10, Card.Suit.HEARTS));\n        player.dealCard(new Card(4, Card.Suit.SPADES));\n\n        playerSays(\"D\");\n        playerGets(7, Card.Suit.SPADES);\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(player.getCurrentBet() == 200);\n        assertTrue(player.getHand().size() == 3);\n    }\n\n    @Test\n    @DisplayName(\"Should NOT allow double down after initial deal\")\n    public void playDoubleDownLate(){\n        // Given\n        Player player = new Player(1);\n        player.setCurrentBet(100);\n        player.dealCard(new Card(10, Card.Suit.HEARTS));\n        player.dealCard(new Card(2, Card.Suit.SPADES));\n\n        playerSays(\"H\");\n        playerGets(7, Card.Suit.SPADES);\n        playerSays(\"D\");\n        playerSays(\"S\");\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"TYPE H, OR S, PLEASE\"));\n    }\n\n    @Test\n    @DisplayName(\"play() should end on STAY after split\")\n    public void playSplitEndOnStay(){\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(1, Card.Suit.CLUBS));\n        player.dealCard(new Card(1, Card.Suit.SPADES));\n\n        playerSays(\"/\");\n        playerGets(2, Card.Suit.SPADES); // First hand\n        playerSays(\"S\");\n        playerGets(2, Card.Suit.SPADES); // Second hand\n        playerSays(\"S\");\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"FIRST HAND RECEIVES\"));\n        assertTrue(out.toString().contains(\"SECOND HAND RECEIVES\"));\n    }\n\n    @Test\n    @DisplayName(\"play() should allow HIT until BUST after split\")\n    public void playSplitHitUntilBust() {\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(10, Card.Suit.HEARTS));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n\n        playerSays(\"/\");\n        playerGets(12, Card.Suit.SPADES); // First hand has 20\n        playerSays(\"H\");\n        playerGets(12, Card.Suit.HEARTS); // First hand busted\n        playerGets(10, Card.Suit.HEARTS); // Second hand gets a 10\n        playerSays(\"S\");\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"BUSTED\"));\n    }\n\n    @Test\n    @DisplayName(\"play() should allow HIT on split hand until BUST\")\n    public void playSplitHitUntilBustHand2() {\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(10, Card.Suit.HEARTS));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n\n        playerSays(\"/\");\n        playerGets(1, Card.Suit.CLUBS); // First hand is 21\n        playerSays(\"S\");\n        playerGets(12, Card.Suit.SPADES); // Second hand is 20\n        playerSays(\"H\");\n        playerGets(12, Card.Suit.HEARTS); // Busted\n        playerSays(\"H\");\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"BUSTED\"));\n    }\n\n    @Test\n    @DisplayName(\"play() should allow double down on split hands\")\n    public void playSplitDoubleDown(){\n        // Given\n        Player player = new Player(1);\n        player.setCurrentBet(100);\n        player.dealCard(new Card(9, Card.Suit.HEARTS));\n        player.dealCard(new Card(9, Card.Suit.SPADES));\n\n        playerSays(\"/\");\n        playerGets(5, Card.Suit.DIAMONDS); // First hand is 14\n        playerSays(\"D\");\n        playerGets(6, Card.Suit.HEARTS); // First hand is 20\n        playerGets(7, Card.Suit.CLUBS); // Second hand is 16\n        playerSays(\"D\");\n        playerGets(4, Card.Suit.CLUBS); // Second hand is 20\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertAll(\n            () -> assertEquals(200, player.getCurrentBet(), \"Current bet should be doubled\"),\n            () -> assertEquals(200, player.getSplitBet(), \"Split bet should be doubled\"),\n            () -> assertEquals(3, player.getHand(1).size(), \"First hand should have exactly three cards\"),\n            () -> assertEquals(3, player.getHand(2).size(), \"Second hand should have exactly three cards\")\n        );\n    }\n\n    @Test\n    @DisplayName(\"play() should NOT allow re-splitting first split hand\")\n    public void playSplitTwice(){\n        // Given\n        Player player = new Player(1);\n        player.setCurrentBet(100);\n        player.dealCard(new Card(2, Card.Suit.HEARTS));\n        player.dealCard(new Card(2, Card.Suit.SPADES));\n\n        playerSays(\"/\");\n        playerGets(13, Card.Suit.CLUBS); // First hand\n        playerSays(\"/\"); // Not allowed\n        playerSays(\"S\");\n        playerGets(13, Card.Suit.SPADES); // Second hand\n        playerSays(\"S\");\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"TYPE H, S OR D, PLEASE\"));\n    }\n\n    @Test\n    @DisplayName(\"play() should NOT allow re-splitting second split hand\")\n    public void playSplitTwiceHand2(){\n        // Given\n        Player player = new Player(1);\n        player.setCurrentBet(100);\n        player.dealCard(new Card(10, Card.Suit.HEARTS));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n\n        playerSays(\"/\");\n        playerGets(13, Card.Suit.CLUBS); // First hand\n        playerSays(\"S\");\n        playerGets(13, Card.Suit.SPADES); // Second hand\n        playerSays(\"/\"); // Not allowed\n        playerSays(\"S\");\n        initGame();\n\n        // When\n        game.play(player);\n\n        // Then\n        assertTrue(out.toString().contains(\"TYPE H, S OR D, PLEASE\"));\n    }\n\n    @Test\n    @DisplayName(\"evaluateRound() should total both hands when split\")\n    public void evaluateRoundWithSplitHands(){\n        // Given\n        Player dealer = new Player(0); //Dealer\n        dealer.dealCard(new Card(1, Card.Suit.HEARTS));\n        dealer.dealCard(new Card(1, Card.Suit.SPADES));\n\n        Player player = new Player(1);\n        player.recordRound(200);//Set starting total\n        player.setCurrentBet(50);\n        player.dealCard(new Card(1, Card.Suit.HEARTS));\n        player.dealCard(new Card(1, Card.Suit.SPADES));\n        \n        playerSays(\"/\");\n        playerGets(13, Card.Suit.CLUBS); // First hand\n        playerSays(\"S\");\n        playerGets(13, Card.Suit.SPADES); // Second hand\n        playerSays(\"S\");\n        initGame();\n\n        // When\n        game.play(player);\n        game.evaluateRound(Arrays.asList(player), dealer);\n\n        // Then\n        assertAll(\n            () -> assertTrue(out.toString().contains(\"PLAYER 1  WINS    100 TOTAL= 300\")),\n            () -> assertTrue(out.toString().contains(\"DEALER'S TOTAL= -100\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"evaluateRound() should total add twice insurance bet\")\n    public void evaluateRoundWithInsurance(){\n        // Given\n        Player dealer = new Player(0); //Dealer\n        dealer.dealCard(new Card(10, Card.Suit.HEARTS));\n        dealer.dealCard(new Card(1, Card.Suit.SPADES));\n\n        Player player = new Player(1);\n        player.setCurrentBet(50);\n        player.setInsuranceBet(10);\n        player.dealCard(new Card(2, Card.Suit.HEARTS));\n        player.dealCard(new Card(1, Card.Suit.SPADES));\n        initGame();\n\n        // When\n        game.evaluateRound(Arrays.asList(player), dealer);\n\n        // Then\n        // Loses current bet (50) and wins 2*10 for total -30\n        assertAll(\n            () -> assertTrue(out.toString().contains(\"PLAYER 1 LOSES     30 TOTAL= -30\")),\n            () -> assertTrue(out.toString().contains(\"DEALER'S TOTAL= 30\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"evaluateRound() should push with no total change\")\n    public void evaluateRoundWithPush(){\n        // Given\n        Player dealer = new Player(0);\n        dealer.dealCard(new Card(10, Card.Suit.HEARTS));\n        dealer.dealCard(new Card(8, Card.Suit.SPADES)); \n\n        Player player = new Player(1);\n        player.setCurrentBet(10);\n        player.dealCard(new Card(9, Card.Suit.HEARTS));\n        player.dealCard(new Card(9, Card.Suit.SPADES));\n        initGame();\n\n        // When (Dealer and Player both have 19)\n        game.evaluateRound(Arrays.asList(player), dealer);\n\n        // Then        \n        assertAll(\n            () -> assertTrue(out.toString().contains(\"PLAYER 1 PUSHES       TOTAL= 0\")),\n            () -> assertTrue(out.toString().contains(\"DEALER'S TOTAL= 0\"))\n        );\n    }\n\n    @Test\n    @DisplayName(\"shouldPlayDealer() return false when players bust\")\n    public void shouldPlayDealerBust(){\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n        player.split();\n        player.dealCard(new Card(5, Card.Suit.SPADES));\n        player.dealCard(new Card(8, Card.Suit.SPADES));//First hand Busted\n\n        player.dealCard(new Card(5, Card.Suit.SPADES),2);\n        player.dealCard(new Card(8, Card.Suit.SPADES),2);//Second hand Busted\n\n        Player playerTwo = new Player(2);\n        playerTwo.dealCard(new Card(7, Card.Suit.HEARTS));\n        playerTwo.dealCard(new Card(8, Card.Suit.HEARTS));\n        playerTwo.dealCard(new Card(9, Card.Suit.HEARTS));\n        initGame();\n\n        // When \n        boolean result = game.shouldPlayDealer(Arrays.asList(player,playerTwo));\n\n        // Then        \n        assertFalse(result);\n    }\n\n    @Test\n    @DisplayName(\"shouldPlayDealer() return false when players bust\")\n    public void ShouldPlayer(){\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n        player.split();\n        player.dealCard(new Card(5, Card.Suit.SPADES));\n        player.dealCard(new Card(8, Card.Suit.SPADES));//First hand Busted\n\n        player.dealCard(new Card(5, Card.Suit.SPADES),2);\n        player.dealCard(new Card(8, Card.Suit.SPADES),2);//Second hand Busted\n\n        Player playerTwo = new Player(2);\n        playerTwo.dealCard(new Card(7, Card.Suit.HEARTS));\n        playerTwo.dealCard(new Card(8, Card.Suit.HEARTS));\n        playerTwo.dealCard(new Card(9, Card.Suit.HEARTS));\n        initGame();\n\n        // When \n        boolean result = game.shouldPlayDealer(Arrays.asList(player,playerTwo));\n\n        // Then        \n        assertFalse(result);\n    }\n\n    @Test\n    @DisplayName(\"shouldPlayDealer() return true when player has non-natural blackjack\")\n    public void shouldPlayDealerNonNaturalBlackjack(){\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(5, Card.Suit.SPADES));\n        player.dealCard(new Card(6, Card.Suit.DIAMONDS));\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n\n        initGame();\n\n        // When \n        boolean result = game.shouldPlayDealer(Arrays.asList(player));\n\n        // Then        \n        assertTrue(result);\n    }\n\n    @Test\n    @DisplayName(\"shouldPlayDealer() return true when player doesn't have blackjack\")\n    public void shouldPlayDealerNonBlackjack(){\n        // Given\n        Player player = new Player(1);\n        player.dealCard(new Card(10, Card.Suit.SPADES));\n        player.dealCard(new Card(6, Card.Suit.DIAMONDS));\n        initGame();\n\n        // When \n        boolean result = game.shouldPlayDealer(Arrays.asList(player));\n\n        // Then        \n        assertTrue(result);\n    }\n\n\n    @Test\n    @DisplayName(\"playDealer() should DRAW on less than 17 intial deal\")\n    public void playDealerLessThanSeventeen(){\n        // Given\n        Player dealer = new Player(0);\n        dealer.dealCard(new Card(10, Card.Suit.SPADES));\n        dealer.dealCard(new Card(6, Card.Suit.DIAMONDS));\n        playerGets(11, Card.Suit.DIAMONDS);\n        initGame();\n\n        // When \n       game.playDealer(dealer);\n\n        // Then        \n        assertTrue(out.toString().contains(\"DRAWS\"));\n        assertTrue(out.toString().contains(\"BUSTED\"));\n    }\n\n    @Test\n    @DisplayName(\"playDealer() should stay on more than 17 intial deal\")\n    public void playDealerMoreThanSeventeen(){\n        // Given\n        Player dealer = new Player(0);\n        dealer.dealCard(new Card(10, Card.Suit.SPADES));\n        dealer.dealCard(new Card(8, Card.Suit.DIAMONDS));\n        initGame();\n\n        // When \n       game.playDealer(dealer);\n\n        // Then        \n        assertFalse(out.toString().contains(\"DRAWS\"));\n        assertFalse(out.toString().contains(\"BUSTED\"));\n        assertTrue(out.toString().contains(\"---TOTAL IS\"));\n    }\n\n}\n"
  },
  {
    "path": "10_Blackjack/java/test/ScoringUtilsTest.java",
    "content": "import org.junit.jupiter.api.Test;\n\nimport org.junit.jupiter.api.DisplayName;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.LinkedList;\n\npublic class ScoringUtilsTest {\n\n    @Test\n    @DisplayName(\"scoreHand should score aces as 1 when using 11 would bust\")\n    public void scoreHandHardAce() {\n        // Given\n        LinkedList<Card> hand = new LinkedList<>();\n        hand.add(new Card(10, Card.Suit.SPADES));\n        hand.add(new Card(9, Card.Suit.SPADES));\n        hand.add(new Card(1, Card.Suit.SPADES));\n\n        // When\n        int result = ScoringUtils.scoreHand(hand);\n\n        // Then\n        assertEquals(20, result);\n    }\n\n    @Test\n    @DisplayName(\"scoreHand should score 3 aces as 13\")\n    public void scoreHandMultipleAces() {\n        // Given\n        LinkedList<Card> hand = new LinkedList<>();\n        hand.add(new Card(1, Card.Suit.SPADES));\n        hand.add(new Card(1, Card.Suit.CLUBS));\n        hand.add(new Card(1, Card.Suit.HEARTS));\n\n        // When\n        int result = ScoringUtils.scoreHand(hand);\n\n        // Then\n        assertEquals(13, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return 1 meaning A beat B, 20 to 12\")\n    public void compareHandsAWins() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(10, Card.Suit.SPADES));\n        handA.add(new Card(10, Card.Suit.CLUBS));\n\n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(1, Card.Suit.SPADES));\n        handB.add(new Card(1, Card.Suit.CLUBS));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(1, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return -1 meaning B beat A, 18 to 4\")\n    public void compareHandsBwins() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(2, Card.Suit.SPADES));\n        handA.add(new Card(2, Card.Suit.CLUBS));\n\n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(5, Card.Suit.SPADES));\n        handB.add(new Card(6, Card.Suit.HEARTS));\n        handB.add(new Card(7, Card.Suit.CLUBS));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(-1, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return 1 meaning A beat B, natural Blackjack to Blackjack\")\n    public void compareHandsAWinsWithNaturalBlackJack() {\n        //Hand A wins with natural BlackJack, B with Blackjack\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(10, Card.Suit.SPADES));\n        handA.add(new Card(1, Card.Suit.CLUBS));\n\n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(6, Card.Suit.SPADES));\n        handB.add(new Card(7, Card.Suit.HEARTS));\n        handB.add(new Card(8, Card.Suit.CLUBS));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(1, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return -1 meaning B beat A, natural Blackjack to Blackjack\")\n    public void compareHandsBWinsWithNaturalBlackJack() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(6, Card.Suit.SPADES));\n        handA.add(new Card(7, Card.Suit.HEARTS));\n        handA.add(new Card(8, Card.Suit.CLUBS));\n        \n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(1, Card.Suit.CLUBS));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(-1, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return 0, hand A and B tied with a Blackjack\")\n    public void compareHandsTieBothBlackJack() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(11, Card.Suit.SPADES));\n        handA.add(new Card(10, Card.Suit.CLUBS));\n        \n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(11, Card.Suit.CLUBS));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(0, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return 0, hand A and B tie without a Blackjack\")\n    public void compareHandsTieNoBlackJack() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(10, Card.Suit.DIAMONDS));\n        handA.add(new Card(10, Card.Suit.HEARTS));\n        \n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(10, Card.Suit.CLUBS));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(0, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return 0, hand A and B tie when both bust\")\n    public void compareHandsTieBust() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(10, Card.Suit.DIAMONDS));\n        handA.add(new Card(10, Card.Suit.HEARTS));\n        handA.add(new Card(3, Card.Suit.HEARTS));\n        \n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(11, Card.Suit.SPADES));\n        handB.add(new Card(4, Card.Suit.SPADES));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(0, result);\n    }\n    @Test\n    @DisplayName(\"compareHands should return -1, meaning B beat A, A busted\")\n    public void compareHandsABusted() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(10, Card.Suit.DIAMONDS));\n        handA.add(new Card(10, Card.Suit.HEARTS));\n        handA.add(new Card(3, Card.Suit.HEARTS));\n        \n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(10, Card.Suit.SPADES));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(-1, result);\n    }\n\n    @Test\n    @DisplayName(\"compareHands should return 1, meaning A beat B, B busted\")\n    public void compareHandsBBusted() {\n        LinkedList<Card> handA = new LinkedList<>();\n        handA.add(new Card(10, Card.Suit.DIAMONDS));\n        handA.add(new Card(3, Card.Suit.HEARTS));\n        \n        LinkedList<Card> handB = new LinkedList<>();\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(10, Card.Suit.SPADES));\n        handB.add(new Card(5, Card.Suit.SPADES));\n\n        int result = ScoringUtils.compareHands(handA,handB);\n\n        assertEquals(1, result);\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/java/test/UserIoTest.java",
    "content": "import static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\n\nimport org.junit.jupiter.api.DisplayName;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.CsvSource;\nimport org.junit.jupiter.params.provider.ValueSource;\n\npublic class UserIoTest {\n\n    @ParameterizedTest(name = \"''{0}'' is accepted as ''no''\")\n    @ValueSource(strings = {\"N\", \"n\", \"No\", \"NO\", \"no\"})\n    public void testPromptBooleanAcceptsNo(String response) {\n        // Given\n        Reader in = new StringReader(response + \"\\n\");\n        StringWriter out = new StringWriter();\n        UserIo userIo = new UserIo(in, out);\n\n        // When\n        boolean result = userIo.promptBoolean(\"TEST\");\n\n        // Then\n        assertEquals(\"TEST? \", out.toString());\n        assertFalse(result);\n    }\n\n    @ParameterizedTest(name = \"''{0}'' is accepted as ''yes''\")\n    @ValueSource(strings = {\"Y\", \"y\", \"Yes\", \"YES\", \"yes\", \"\", \"foobar\"})\n    public void testPromptBooleanAcceptsYes(String response) {\n        // Given\n        Reader in = new StringReader(response + \"\\n\");\n        StringWriter out = new StringWriter();\n        UserIo userIo = new UserIo(in, out);\n\n        // When\n        boolean result = userIo.promptBoolean(\"TEST\");\n\n        // Then\n        assertEquals(\"TEST? \", out.toString());\n        assertTrue(result);\n    }\n\n    @ParameterizedTest(name = \"''{0}'' is accepted as number\")\n    @CsvSource({\n        \"1,1\",\n        \"0,0\",\n        \"-1,-1\",\n    })\n    public void testPromptIntAcceptsNumbers(String response, int expected) {\n        // Given\n        Reader in = new StringReader(response + \"\\n\");\n        StringWriter out = new StringWriter();\n        UserIo userIo = new UserIo(in, out);\n\n        // When\n        int result = userIo.promptInt(\"TEST\");\n\n        // Then\n        assertEquals(\"TEST? \", out.toString());\n        assertEquals(expected, result);\n    }\n\n    @Test\n    @DisplayName(\"promptInt should print an error and reprompt if given a non-numeric response\")\n    public void testPromptIntRepromptsOnNonNumeric() {\n        // Given\n        Reader in = new StringReader(\"foo\" + System.lineSeparator() +\"1\"); // word, then number\n        StringWriter out = new StringWriter();\n        UserIo userIo = new UserIo(in, out);\n\n        // When\n        int result = userIo.promptInt(\"TEST\");\n\n        // Then\n        assertEquals(\"TEST? !NUMBER EXPECTED - RETRY INPUT LINE\" + System.lineSeparator() +\"? \", out.toString());\n        assertEquals(1, result);\n    }\n}\n"
  },
  {
    "path": "10_Blackjack/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "10_Blackjack/javascript/blackjack.html",
    "content": "<html>\n<head>\n<title>BLACKJACK</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"blackjack.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "10_Blackjack/javascript/blackjack.js",
    "content": "// BLACKJACK\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar da = [];\n\nvar pa = [];\nvar qa = [];\nvar ca = [];\nvar ta = [];\nvar sa = [];\nvar ba = [];\nvar za = [];\nvar ra = [];\n\nvar ds = \"N A  2  3  4  5  6  7N 8  9 10  J  Q  K\";\nvar is = \"H,S,D,/,\"\n\nvar q;\nvar aa;\nvar ab;\nvar ac;\nvar h;\nvar h1;\n\nfunction af(q) {\n    return q >= 22 ? q - 11 : q;\n}\n\nfunction reshuffle()\n{\n    print(\"RESHUFFLING\\n\");\n    for (; d >= 1; d--)\n        ca[--c] = da[d];\n    for (c1 = 52; c1 >= c; c1--) {\n        c2 = Math.floor(Math.random() * (c1 - c + 1)) + c;\n        c3 = ca[c2];\n        ca[c2] = ca[c1];\n        ca[c1] = c3;\n    }\n}\n\n// Subroutine to get a card.\nfunction get_card()\n{\n    if (c >= 51)\n        reshuffle();\n    return ca[c++];\n}\n\n// Card printing subroutine\nfunction card_print(x)\n{\n    print(ds.substr(3 * x - 3, 3) + \"  \");\n}\n\n// Alternate card printing subroutine\nfunction alt_card_print(x)\n{\n    print(\" \" + ds.substr(3 * x - 2, 2) + \"   \");\n}\n\n// Subroutine to add card 'which' to total 'q'\nfunction add_card(which)\n{\n    x1 = which;\n    if (x1 > 10)\n        x1 = 10;\n    q1 = q + x1;\n    if (q < 11) {\n        if (which <= 1) {\n            q += 11;\n            return;\n        }\n        if (q1 >= 11)\n            q = q1 + 11;\n        else\n            q = q1;\n        return;\n    }\n    if (q <= 21 && q1 > 21)\n        q = q1 + 1;\n    else\n        q = q1;\n    if (q >= 33)\n        q = -1;\n}\n\n// Subroutine to evaluate hand 'which'. Total is put into\n// qa[which]. Totals have the following meaning:\n//  2-10...hard 2-10\n// 11-21...soft 11-21\n// 22-32...hard 11-21\n//  33+....busted\nfunction evaluate_hand(which)\n{\n    q = 0;\n    for (q2 = 1; q2 <= ra[which]; q2++) {\n        add_card(pa[i][q2]);\n    }\n    qa[which] = q;\n}\n\n// Subroutine to add a card to row i\nfunction add_card_to_row(i, x) {\n    ra[i]++;\n    pa[i][ra[i]] = x;\n    q = qa[i];\n    add_card(x);\n    qa[i] = q;\n    if (q < 0) {\n        print(\"...BUSTED\\n\");\n        discard_row(i);\n    }\n}\n\n// Subroutine to discard row i\nfunction discard_row(i) {\n    while (ra[i]) {\n        d++;\n        da[d] = pa[i][ra[i]];\n        ra[i]--;\n    }\n}\n\n// Prints total of hand i\nfunction print_total(i) {\n    print(\"\\n\");\n    aa = qa[i];\n    total_aa();\n    print(\"TOTAL IS \" + aa + \"\\n\");\n}\n\nfunction total_aa()\n{\n    if (aa >= 22)\n        aa -= 11;\n}\n\nfunction total_ab()\n{\n    if (ab >= 22)\n        ab -= 11;\n}\n\nfunction total_ac()\n{\n    if (ac >= 22)\n        ac -= 11;\n}\n\nfunction process_input(str)\n{\n    str = str.substr(0, 1);\n    for (h = 1; h <= h1; h += 2) {\n        if (str == is.substr(h - 1, 1))\n            break;\n    }\n    if (h <= h1) {\n        h = (h + 1) / 2;\n        return 0;\n    }\n    print(\"TYPE \" + is.substr(0, h1 - 1) + \" OR \" + is.substr(h1 - 1, 2) + \" PLEASE\");\n    return 1;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(31) + \"BLACK JACK\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // --pa[i][j] IS THE JTH CARD IN HAND I, qa[i] IS TOTAL OF HAND I\n    // --C IS THE DECK BEING DEALT FROM, D IS THE DISCARD PILE,\n    // --ta[i] IS THE TOTAL FOR PLAYER I, sa[i] IS THE TOTAL THIS HAND FOR\n    // --PLAYER I, ba[i] IS TH BET FOR HAND I\n    // --ra[i] IS THE LENGTH OF pa[I,*]\n\n    // --Program starts here\n    // --Initialize\n    for (i = 1; i <= 15; i++)\n        pa[i] = [];\n    for (i = 1; i <= 13; i++)\n        for (j = 4 * i - 3; j <= 4 * i; j++)\n            da[j] = i;\n    d = 52;\n    c = 53;\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    str = await input();\n    if (str.toUpperCase().substr(0, 1) != \"N\") {\n        print(\"THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE\\n\");\n        print(\"GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE\\n\");\n        print(\"PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE\\n\");\n        print(\"DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE\\n\");\n        print(\"FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE\\n\");\n        print(\"PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS\\n\");\n        print(\"STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/',\\n\");\n        print(\"INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE\\n\");\n        print(\"INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR\\n\");\n        print(\"'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING\\n\");\n        print(\"DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR\\n\");\n        print(\"BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'.\\n\");\n    }\n    while (1) {\n        print(\"NUMBER OF PLAYERS\");\n        n = parseInt(await input());\n        print(\"\\n\");\n        if (n < 1 || n > 7)\n            continue;\n        else\n            break;\n    }\n    for (i = 1; i <= 8; i++)\n        ta[i] = 0;\n    d1 = n + 1;\n    while (1) {\n        if (2 * d1 + c >= 52) {\n            reshuffle();\n        }\n        if (c == 2)\n            c--;\n        for (i = 1; i <= n; i++)\n            za[i] = 0;\n        for (i = 1; i <= 15; i++)\n            ba[i] = 0;\n        for (i = 1; i <= 15; i++)\n            qa[i] = 0;\n        for (i = 1; i <= 7; i++)\n            sa[i] = 0;\n        for (i = 1; i <= 15; i++)\n            ra[i] = 0;\n        print(\"BETS:\\n\");\n        for (i = 1; i <= n; i++) {\n            do {\n                print(\"#\" + i + \" \");\n                za[i] = parseFloat(await input());\n            } while (za[i] <= 0 || za[i] > 500) ;\n        }\n        for (i = 1; i <= n; i++)\n            ba[i] = za[i];\n        print(\"PLAYER\");\n        for (i = 1; i <= n; i++) {\n            print(\" \" + i + \"    \");\n        }\n        print(\"DEALER\\n\");\n        for (j = 1; j <= 2; j++) {\n            print(tab(5));\n            for (i = 1; i <= d1; i++) {\n                pa[i][j] = get_card();\n                if (j == 1 || i <= n)\n                    alt_card_print(pa[i][j]);\n            }\n            print(\"\\n\");\n        }\n        for (i = 1; i <= d1; i++)\n            ra[i] = 2;\n        // --Test for insurance\n        if (pa[d1][1] <= 1) {\n            print(\"ANY INSURANCE\");\n            str = await input();\n            if (str.substr(0, 1) == \"Y\") {\n                print(\"INSURANCE BETS\\n\");\n                for (i = 1; i <= n; i++) {\n                    do {\n                        print(\"#\" + i + \" \");\n                        za[i] = parseFloat(await input());\n                    } while (za[i] < 0 || za[i] > ba[i] / 2) ;\n                }\n                for (i = 1; i <= n; i++)\n                    sa[i] = za[i] * ((pa[d1][2] >= 10 ? 3 : 0) - 1);\n            }\n        }\n        // --Test for dealer blackjack\n        l1 = 1;\n        l2 = 1;\n        if (pa[d1][1] == 1 && pa[d1][2] > 9) {\n            l1 = 0;\n            l2 = 0;\n        }\n        if (pa[d1][2] == 1 && pa[d1][1] > 9) {\n            l1 = 0;\n            l2 = 0;\n        }\n        if (l1 == 0 && l2 == 0) {\n            print(\"\\n\");\n            print(\"DEALER HAS A\" + ds.substr(3 * pa[d1][2] - 3, 3) + \" IN THE HOLE FOR BLACKJACK\\n\");\n            for (i = 1; i <= d1; i++)\n                evaluate_hand(i);\n        } else {\n            // --No dealer blackjack\n            if (pa[d1][1] <= 1 || pa[d1][1] >= 10) {\n                print(\"\\n\");\n                print(\"NO DEALER BLACKJACK.\\n\");\n            }\n            // --Now play the hands\n            for (i = 1; i <= n; i++) {\n                print(\"PLAYER \" + i + \" \");\n                h1 = 7;\n                do {\n                    str = await input();\n                } while (process_input(str)) ;\n                if (h == 1) {   // Player wants to be hit\n                    evaluate_hand(i);\n                    h1 = 3;\n                    x = get_card();\n                    print(\"RECEIVED A\");\n                    card_print(x);\n                    add_card_to_row(i, x);\n                    if (q > 0)\n                        print_total(i);\n                } else if (h == 2) {    // Player wants to stand\n                    evaluate_hand(i);\n                    if (qa[i] == 21) {\n                        print(\"BLACKJACK\\n\");\n                        sa[i] = sa[i] + 1.5 * ba[i];\n                        ba[i] = 0;\n                        discard_row(i);\n                    } else {\n                        print_total(i);\n                    }\n                } else if (h == 3) {    // Player wants to double down\n                    evaluate_hand(i);\n                    h1 = 3;\n                    h = 1;\n                    while (1) {\n                        if (h == 1) {   // Hit\n                            x = get_card();\n                            print(\"RECEIVED A\");\n                            card_print(x);\n                            add_card_to_row(i, x);\n                            if (q < 0)\n                                break;\n                            print(\"HIT\");\n                        } else if (h == 2) {    // Stand\n                            print_total(i);\n                            break;\n                        }\n                        do {\n                            str = await input();\n                        } while (process_input(str)) ;\n                        h1 = 3;\n                    }\n                } else if (h == 4) {    // Player wants to split\n                    l1 = pa[i][1];\n                    if (l1 > 10)\n                        l1 = 10;\n                    l2 = pa[i][2];\n                    if (l2 > 10)\n                        l2 = 10;\n                    if (l1 != l2) {\n                        print(\"SPLITTING NOT ALLOWED.\\n\");\n                        i--;\n                        continue;\n                    }\n                    // --Play out split\n                    i1 = i + d1;\n                    ra[i1] = 2;\n                    pa[i1][1] = pa[i1][2];\n                    ba[i + d1] = ba[i];\n                    x = get_card();\n                    print(\"FIRST HAND RECEIVES A\");\n                    card_print(x);\n                    pa[i][2] = x;\n                    evaluate_hand(i);\n                    print(\"\\n\");\n                    x = get_card();\n                    print(\"SECOND HAND RECEIVES A\");\n                    i = i1;\n                    card_print(x);\n                    pa[i][2] = x;\n                    evaluate_hand(i);\n                    print(\"\\n\");\n                    i = i1 - d1;\n                    if (pa[i][1] != 1) {\n                        // --Now play the two hands\n                        do {\n\n                            print(\"HAND \" + (i > d1 ? 2 : 1) + \" \");\n                            h1 = 5;\n                            while (1) {\n                                do {\n                                    str = await input();\n                                } while (process_input(str)) ;\n                                h1 = 3;\n                                if (h == 1) {   // Hit\n                                    x = get_card();\n                                    print(\"RECEIVED A\");\n                                    card_print(x);\n                                    add_card_to_row(i, x);\n                                    if (q < 0)\n                                        break;\n                                    print(\"HIT\");\n                                } else if (h == 2) {    // Stand\n                                    print_total(i);\n                                    break;\n                                } else {    // Double\n                                    x = get_card();\n                                    ba[i] *= 2;\n                                    print(\"RECEIVED A\");\n                                    card_print(x);\n                                    add_card_to_row(i, x);\n                                    if (q > 0)\n                                        print_total(i);\n                                    break;\n                                }\n                            }\n                            i += d1;\n                        } while (i == i1) ;\n                        i = i1 - d1;\n                    }\n                }\n            }\n            // --Test for playing dealer's hand\n            evaluate_hand(i);\n            for (i = 1; i <= n; i++) {\n                if (ra[i] > 0 || ra[i + d1] > 0)\n                    break;\n            }\n            if (i > n) {\n                print(\"DEALER HAD A\");\n                x = pa[d1][2];\n                card_print(x);\n                print(\" CONCEALED.\\n\");\n            } else {\n                print(\"DEALER HAS A\" + ds.substr(3 * pa[d1][2] - 3, 3) + \" CONCEALED \");\n                i = d1;\n                aa = qa[i];\n                total_aa();\n                print(\"FOR A TOTAL OF \" + aa + \"\\n\");\n                if (aa <= 16) {\n                    print(\"DRAWS\");\n                    do {\n\n                        x = get_card();\n                        alt_card_print(x);\n                        add_card_to_row(i, x);\n                        aa = q;\n                        total_aa();\n                    } while (q > 0 && aa < 17) ;\n                    if (q < 0) {\n                        qa[i] = q + 0.5;\n                    } else {\n                        qa[i] = q;\n                    }\n                    if (q >= 0) {\n                        aa = q;\n                        total_aa();\n                        print(\"---TOTAL IS \" + aa + \"\\n\");\n                    }\n                }\n                print(\"\\n\");\n            }\n        }\n        // --TALLY THE RESULT\n        str = \"LOSES PUSHES WINS \"\n        print(\"\\n\");\n        for (i = 1; i <= n; i++) {\n            aa = qa[i]\n            total_aa();\n            ab = qa[i + d1];\n            total_ab();\n            ac = qa[d1];\n            total_ac();\n            signaaac = aa - ac;\n            if (signaaac) {\n                if (signaaac < 0)\n                    signaaac = -1;\n                else\n                    signaaac = 1;\n            }\n            signabac = ab - ac;\n            if (signabac) {\n                if (signabac < 0)\n                    signabac = -1;\n                else\n                    signabac = 1;\n            }\n            sa[i] = sa[i] + ba[i] * signaaac + ba[i + d1] * signabac;\n            ba[i + d1] = 0;\n            print(\"PLAYER \" + i + \" \");\n            signsai = sa[i];\n            if (signsai) {\n                if (signsai < 0)\n                    signsai = -1;\n                else\n                    signsai = 1;\n            }\n            print(str.substr(signsai * 6 + 6, 6) + \" \");\n            if (sa[i] == 0)\n                print(\"      \");\n            else\n                print(\" \" + Math.abs(sa[i]) + \" \");\n            ta[i] = ta[i] + sa[i];\n            print(\"TOTAL= \" + ta[i] + \"\\n\");\n            discard_row(i);\n            ta[d1] = ta[d1] - sa[i];\n            i += d1;\n            discard_row(i);\n            i -= d1;\n        }\n        print(\"DEALER'S TOTAL= \" + ta[d1] + \"\\n\");\n        print(\"\\n\");\n        discard_row(i);\n    }\n}\n\nmain();\n"
  },
  {
    "path": "10_Blackjack/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "10_Blackjack/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "10_Blackjack/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "10_Blackjack/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "10_Blackjack/python/blackjack.py",
    "content": "\"\"\"\nBlackjack\n\nPorted by Martin Thoma in 2022,\nusing the rust implementation of AnthonyMichaelTDM\n\"\"\"\n\nimport enum\nimport random\nfrom dataclasses import dataclass\nfrom typing import List, NamedTuple\n\n\nclass PlayerType(enum.Enum):\n    Player = \"Player\"\n    Dealer = \"Dealer\"\n\n\nclass Play(enum.Enum):\n    Stand = enum.auto()\n    Hit = enum.auto()\n    DoubleDown = enum.auto()\n    Split = enum.auto()\n\n\nclass Card(NamedTuple):\n    name: str\n\n    @property\n    def value(self) -> int:\n        \"\"\"\n        returns the value associated with a card with the passed name\n        return 0 if the passed card name doesn't exist\n        \"\"\"\n        return {\n            \"ACE\": 11,\n            \"2\": 2,\n            \"3\": 3,\n            \"4\": 4,\n            \"5\": 5,\n            \"6\": 6,\n            \"7\": 7,\n            \"8\": 8,\n            \"9\": 9,\n            \"10\": 10,\n            \"JACK\": 10,\n            \"QUEEN\": 10,\n            \"KING\": 10,\n        }.get(self.name, 0)\n\n\nclass Hand(NamedTuple):\n    cards: List[Card]\n\n    def add_card(self, card: Card) -> None:\n        \"\"\"add a passed card to this hand\"\"\"\n        self.cards.append(card)\n\n    def get_total(self) -> int:\n        \"\"\"returns the total points of the cards in this hand\"\"\"\n        total: int = sum(int(card.value) for card in self.cards)\n        # if there is an ACE, and the hand would otherwise bust,\n        # treat the ace like it's worth 1\n        if total > 21 and any(card.name == \"ACE\" for card in self.cards):\n            total -= 10\n\n        return total\n\n    def discard_hand(self, deck: \"Decks\") -> None:\n        \"\"\"adds the cards in hand into the discard pile\"\"\"\n        _len = len(self.cards)\n        for _i in range(_len):\n            if len(self.cards) == 0:\n                raise ValueError(\"hand empty\")\n            deck.discard_pile.append(self.cards.pop())\n\n\nclass Decks(NamedTuple):\n    deck: List[Card]\n    discard_pile: List[Card]\n\n    @classmethod\n    def new(cls) -> \"Decks\":\n        \"\"\"creates a new full and shuffled deck, and an empty discard pile\"\"\"\n        # returns a number of full decks of 52 cards, shuffles them\n        deck = Decks(deck=[], discard_pile=[])\n        number_of_decks = 3\n\n        # fill deck\n        for _n in range(number_of_decks):\n            # fill deck with number_of_decks decks worth of cards\n            for card_name in CARD_NAMES:\n                # add 4 of each card, totaling one deck with 4 of each card\n                for _ in range(4):\n                    deck.deck.append(Card(name=card_name))\n\n        deck.shuffle()\n        return deck\n\n    def shuffle(self) -> None:\n        \"\"\"shuffles the deck\"\"\"\n        random.shuffle(self.deck)\n\n    def draw_card(self) -> Card:\n        \"\"\"\n        draw card from deck, and return it\n        if deck is empty, shuffles discard pile into it and tries again\n        \"\"\"\n        if len(self.deck) != 0:\n            return self.deck.pop()\n        _len = len(self.discard_pile)\n\n        if _len <= 0:\n            # discard pile and deck are empty, should never happen\n            raise Exception(\"discard pile empty\")\n        # deck is empty, shuffle discard pile into deck and try again\n        print(\"deck is empty, shuffling\")\n        for _i in range(_len):\n            if len(self.discard_pile) == 0:\n                raise ValueError(\"discard pile is empty\")\n            self.deck.append(self.discard_pile.pop())\n        self.shuffle()\n        return self.draw_card()\n\n\n@dataclass\nclass Player:\n    hand: Hand\n    balance: int\n    bet: int\n    wins: int\n    player_type: PlayerType\n    index: int\n\n    @classmethod\n    def new(cls, player_type: PlayerType, index: int) -> \"Player\":\n        \"\"\"creates a new player of the given type\"\"\"\n        return Player(\n            hand=Hand(cards=[]),\n            balance=STARTING_BALANCE,\n            bet=0,\n            wins=0,\n            player_type=player_type,\n            index=index,\n        )\n\n    def get_name(self) -> str:\n        return f\"{self.player_type}{self.index}\"\n\n    def get_bet(self) -> None:\n        \"\"\"gets a bet from the player\"\"\"\n        if PlayerType.Player == self.player_type:\n            if self.balance < 1:\n                print(f\"{self.get_name()} is out of money :(\")\n                self.bet = 0\n            self.bet = get_number_from_user_input(\n                f\"{self.get_name()}\\tWhat is your bet\", 1, self.balance\n            )\n\n    def hand_as_string(self, hide_dealer: bool) -> str:\n        \"\"\"\n        returns a string of the players hand\n\n        if player is a dealer, returns the first card in the hand followed\n        by *'s for every other card\n        if player is a player, returns every card and the total\n        \"\"\"\n        if hide_dealer and self.player_type == PlayerType.Dealer:\n            return \"\".join(f\"{c.name}\\t\" for c in self.hand.cards[1::-1])\n        elif (\n            hide_dealer\n            and self.player_type == PlayerType.Player\n            or not hide_dealer\n        ):\n            s = \"\".join(\n                f\"{cards_in_hand.name}\\t\"\n                for cards_in_hand in self.hand.cards[::-1]\n            )\n            s += f\"total points = {self.hand.get_total()}\"\n            return s\n        raise Exception(\"This is unreachable\")\n\n    def get_play(self) -> Play:\n        \"\"\"get the players 'play'\"\"\"\n        # do different things depending on what type of player this is:\n        # if it's a dealer, use an algorithm to determine the play\n        # if it's a player, ask user for input\n        if self.player_type == PlayerType.Dealer:\n            return Play.Stand if self.hand.get_total() > 16 else Play.Hit\n        elif self.player_type == PlayerType.Player:\n            valid_results: List[str]\n            if len(self.hand.cards) > 2:\n                # if there are more than 2 cards in the hand,\n                # at least one turn has happened, so splitting and\n                # doubling down are not allowed\n                valid_results = [\"s\", \"h\"]\n            else:\n                valid_results = [\"s\", \"h\", \"d\", \"/\"]\n            play = get_char_from_user_input(\"\\tWhat is your play?\", valid_results)\n            if play == \"s\":\n                return Play.Stand\n            elif play == \"h\":\n                return Play.Hit\n            elif play == \"d\":\n                return Play.DoubleDown\n            elif play == \"/\":\n                return Play.Split\n            else:\n                raise ValueError(f\"got invalid character {play}\")\n        raise Exception(\"This is unreachable\")\n\n\n@dataclass\nclass Game:\n    players: List[Player]  # last item in this is the dealer\n    decks: Decks\n    games_played: int\n\n    @classmethod\n    def new(cls, num_players: int) -> \"Game\":\n        players: List[Player] = [Player.new(PlayerType.Dealer, 0)]\n\n        # create human player(s) (at least one)\n        players.append(Player.new(PlayerType.Player, 1))\n        players.extend(Player.new(PlayerType.Player, i) for i in range(2, num_players))\n        if get_char_from_user_input(\"Do you want instructions\", [\"y\", \"n\"]) == \"y\":\n            print_instructions()\n        print()\n\n        return Game(players=players, decks=Decks.new(), games_played=0)\n\n    def _print_stats(self) -> None:\n        \"\"\"prints the score of every player\"\"\"\n        print(f\"{self.stats_as_string()}\")\n\n    def stats_as_string(self) -> str:\n        \"\"\"returns a string of the wins, balance, and bets of every player\"\"\"\n        s = \"\"\n        for p in self.players:\n            # format the presentation of player stats\n            if p.player_type == PlayerType.Dealer:\n                s += f\"{p.get_name()} Wins:\\t{p.wins}\\n\"\n            elif p.player_type == PlayerType.Player:\n                s += f\"{p.get_name()} \"\n                s += f\"Wins:\\t{p.wins}\\t\\t\"\n                s += f\"Balance:\\t{p.balance}\\t\\tBet\\t{p.bet}\\n\"\n        return f\"Scores:\\n{s}\"\n\n    def play_game(self) -> None:\n        \"\"\"plays a round of blackjack\"\"\"\n        game = self.games_played\n        player_hands_message: str = \"\"\n\n        # deal two cards to each player\n        for _i in range(2):\n            for player in self.players:\n                player.hand.add_card(self.decks.draw_card())\n\n        # get everyones bets\n        for player in self.players:\n            player.get_bet()\n        scores = self.stats_as_string()\n\n        # play game for each player\n        for player in self.players:\n            # turn loop, ends when player finishes their turn\n            while True:\n                clear()\n                print_welcome_screen()\n                print(f\"\\n\\t\\t\\tGame {game}\")\n                print(scores)\n                print(player_hands_message)\n                print(f\"{player.get_name()} Hand:\\t{player.hand_as_string(True)}\")\n\n                if PlayerType.Player == player.player_type and player.bet == 0:\n                    break\n\n                # play through turn\n                # check their hand value for a blackjack(21) or bust\n                score = player.hand.get_total()\n                if score >= 21:\n                    if score == 21:\n                        print(\"\\tBlackjack! (21 points)\")\n                    else:\n                        print(f\"\\tBust      ({score} points)\")\n                    break\n\n                # get player move\n                play = player.get_play()\n                # process play\n                if play == Play.Stand:\n                    print(f\"\\t{play}\")\n                    break\n                elif play == Play.Hit:\n                    print(f\"\\t{play}\")\n                    player.hand.add_card(self.decks.draw_card())\n                elif play == Play.DoubleDown:\n                    print(f\"\\t{play}\")\n\n                    # double their balance if there's enough money,\n                    # othewise go all-in\n                    if player.bet * 2 < player.balance:\n                        player.bet *= 2\n                    else:\n                        player.bet = player.balance\n                    player.hand.add_card(self.decks.draw_card())\n            # add player to score cache thing\n            player_hands_message += (\n                f\"{player.get_name()} Hand:\\t{player.hand_as_string(True)}\\n\"\n            )\n\n        # determine winner\n        top_score = 0\n\n        # player with the highest points\n        num_winners = 1\n\n        non_burst_players = [\n            player for player in self.players if player.hand.get_total() <= 21\n        ]\n        for player in non_burst_players:\n            score = player.hand.get_total()\n            if score > top_score:\n                top_score = score\n                num_winners = 1\n            elif score == top_score:\n                num_winners += 1\n\n        # show winner(s)\n        top_score_players = [\n            player\n            for player in non_burst_players\n            if player.hand.get_total() == top_score\n        ]\n        for x in top_score_players:\n            print(f\"{x.get_name()} \")\n            x.wins += 1\n            # increment their wins\n        if num_winners > 1:\n            print(f\"all tie with {top_score}\\n\\n\\n\")\n        else:\n            print(\n                f\"wins with {top_score}!\\n\\n\\n\",\n            )\n\n        # handle bets\n        # remove money from losers\n        losers = [\n            player for player in self.players if player.hand.get_total() != top_score\n        ]\n        for loser in losers:\n            loser.balance -= loser.bet\n        # add money to winner\n        winners = [\n            player for player in self.players if player.hand.get_total() == top_score\n        ]\n        for winner in winners:\n            winner.balance += winner.bet\n\n        # discard hands\n        for player in self.players:\n            player.hand.discard_hand(self.decks)\n\n        # increment games_played\n        self.games_played += 1\n\n\nCARD_NAMES: List[str] = [\n    \"ACE\",\n    \"2\",\n    \"3\",\n    \"4\",\n    \"5\",\n    \"6\",\n    \"7\",\n    \"8\",\n    \"9\",\n    \"10\",\n    \"JACK\",\n    \"QUEEN\",\n    \"KING\",\n]\nSTARTING_BALANCE: int = 100\n\n\ndef main() -> None:\n    game: Game\n\n    print_welcome_screen()\n\n    # create game\n    game = Game.new(\n        get_number_from_user_input(\"How many players should there be\", 1, 7)\n    )\n\n    # game loop, play game until user wants to stop\n    char = \"y\"\n    while char == \"y\":\n        game.play_game()\n        char = get_char_from_user_input(\"Play Again?\", [\"y\", \"n\"])\n\n\ndef print_welcome_screen() -> None:\n    print(\n        \"\"\"\n                            BLACK JACK\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n    \\n\\n\"\"\"\n    )\n\n\ndef print_instructions() -> None:\n    print(\n        \"\"\"\n    THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE\n    GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE\n    PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE\n    DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE\n    FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE\n    PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS\n    STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/',\n    INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE\n    INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR\n    'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING\n    DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR\n    BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'.\n    NUMBER OF PLAYERS\n\n    NOTE:'/' (splitting) is not currently implemented, and does nothing\n\n    PRESS ENTER TO CONTINUE\n    \"\"\"\n    )\n    input()\n\n\ndef get_number_from_user_input(prompt: str, min_value: int, max_value: int) -> int:\n    \"\"\"gets a int integer from user input\"\"\"\n    # input loop\n    user_input = None\n    while user_input is None or user_input < min_value or user_input > max_value:\n        raw_input = input(f\"{prompt} ({min_value}-{max_value})? \")\n\n        try:\n            user_input = int(raw_input)\n            if user_input < min_value or user_input > max_value:\n                print(\"Invalid input, please try again\")\n        except ValueError:\n            print(\"Invalid input, please try again\")\n    return user_input\n\n\ndef get_char_from_user_input(prompt: str, valid_results: List[str]) -> str:\n    \"\"\"returns the first character they type\"\"\"\n    user_input = None\n    while user_input not in valid_results:\n        user_input = input(f\"{prompt} {valid_results}? \").lower()\n        if user_input not in valid_results:\n            print(\"Invalid input, please try again\")\n    assert user_input is not None\n    return user_input\n\n\ndef clear() -> None:\n    \"\"\"clear std out\"\"\"\n    print(\"\\x1b[2J\\x1b[0;0H\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "10_Blackjack/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "10_Blackjack/ruby/blackjack.rb",
    "content": "require_relative \"./game.rb\"\n\ndef intro\n    puts \"Welcome to Blackjack\"\nend\n\ndef ask_for_players_count\n    puts \"How many of you want to join the table?\"\n    return gets.to_i\nend\n\nbegin\n    intro\n    players_count = ask_for_players_count\n    Game.new(players_count).start\nrescue SystemExit, Interrupt\n    exit\nrescue => exception\n   p exception\nend\n"
  },
  {
    "path": "10_Blackjack/ruby/game.rb",
    "content": "require_relative \"./model/hand.rb\"\nrequire_relative \"./model/player.rb\"\nrequire_relative \"./model/card_kind.rb\"\nrequire_relative \"./model/pack.rb\"\n\nclass Game\n\n  ALLOWED_HAND_ACTIONS = {\n    \"hit\" => [\"H\", \"S\"],\n    \"split\" => [\"H\", \"S\", \"D\"],\n    \"normal\" => [\"H\", \"S\", \"/\", \"D\"]\n  }\n\n  def initialize(players_count)\n    @pack = Model::Pack.new\n    @dealer_balance = 0\n    @dealer_hand = nil\n    @players = 1.upto(players_count).map { |id| Model::Player.new(id) }\n  end\n\n  def start\n    loop do\n      collect_bets_and_deal\n      play_players\n      check_for_insurance_bets\n      play_dealer\n      settle\n    end\n  end\n\n  private\n\n  def collect_bets_and_deal\n    puts \"BETS\"\n\n    @players.each_entry do |player|\n      print \"# #{player.id} ? \"\n      bet = gets.to_i\n      player.deal_initial_hand Model::Hand.new(bet, [@pack.draw, @pack.draw])\n    end\n\n    @dealer_hand = Model::Hand.new(0, [@pack.draw, @pack.draw])\n    print_players_and_dealer_hands\n  end\n\n  def play_players\n    @players.each_entry do |player|\n      play_hand player, player.hand\n    end\n  end\n\n  def check_for_insurance_bets\n    return if @dealer_hand.cards[0].label != \"A\"\n\n    print \"ANY INSURANCE? \"\n    return if gets.strip != \"Y\"\n\n    @players.each_entry do |player|\n      print \"PLAYER #{player.id} INSURANCE BET? \"\n      player.bet_insurance(gets.to_i)\n    end\n  end\n\n  def play_dealer\n    puts \"DEALER HAS A \\t#{@dealer_hand.cards[1].label} CONCEALED FOR A TOTAL OF #{@dealer_hand.total}\"\n\n    while @dealer_hand.total(is_dealer: true) < 17\n      card = @pack.draw\n      @dealer_hand.hit card\n\n      puts \"DRAWS #{card.label} \\t---TOTAL = #{@dealer_hand.total}\"\n    end\n\n    if !@dealer_hand.is_busted?\n      @dealer_hand.stand\n    end\n  end\n\n  def settle\n    @players.each_entry do |player|\n      player_balance_update = player.update_balance @dealer_hand\n      @dealer_balance -= player_balance_update\n\n      puts \"PLAYER #{player.id} #{player_balance_update < 0 ? \"LOSES\" : \"WINS\"} \\t#{player_balance_update} \\tTOTAL=#{player.balance}\"\n    end\n\n    puts \"DEALER'S TOTAL = #{@dealer_balance}\"\n  end\n\n\n  def print_players_and_dealer_hands\n    puts \"PLAYER\\t#{@players.map(&:id).join(\"\\t\")}\\tDEALER\"\n    puts \"      \\t#{@players.map {|p| p.hand.cards[0].label}.join(\"\\t\")}\\t#{@dealer_hand.cards[0].label}\"\n    puts \"      \\t#{@players.map {|p| p.hand.cards[1].label}.join(\"\\t\")}\"\n  end\n\n  def play_hand player, hand\n    allowed_actions = ALLOWED_HAND_ACTIONS[(hand.is_split_hand || !hand.can_split?) ? \"split\" : \"normal\"]\n    name = \"PLAYER #{player.id}\"\n    if hand.is_split_hand\n      name += \" - HAND #{hand === player.hand ? 1 : 2}\"\n    end\n\n    did_hit = false\n\n    while hand.is_playing?\n      print \"#{name}? \"\n\n      action = gets.strip\n\n      if !allowed_actions.include?(action)\n        puts \"Possible actions: #{allowed_actions.join(\", \")}\"\n        next\n      end\n\n      if action === \"/\"\n        player.split\n\n        play_hand player, player.hand\n        play_hand player, player.split_hand\n\n        return\n      end\n\n      if action === \"S\"\n        hand.stand\n      end\n\n      if action === \"D\"\n        card = @pack.draw\n        hand.double_down card\n\n        puts \"RECEIVED #{card.label}\"\n      end\n\n      if action === \"H\"\n        did_hit = true\n        allowed_actions = ALLOWED_HAND_ACTIONS[\"hit\"]\n        card = @pack.draw\n        hand.hit card\n\n        puts \"RECEIVED #{card.label}\"\n      end\n    end\n\n    puts \"TOTAL IS #{hand.total}\"\n\n    if hand.is_busted?\n      puts \"... BUSTED\"\n    end\n  end\nend\n"
  },
  {
    "path": "10_Blackjack/ruby/model/card_kind.rb",
    "content": "module Model\nclass CardKind\n  def initialize(label, value)\n    @label = label\n    @value = value\n  end\n  \n  private_class_method :new\n\n  TWO = self.new(\"2\", 2)\n  THREE = self.new(\"3\", 3)\n  FOUR = self.new(\"4\", 4)\n  FIVE = self.new(\"5\", 5)\n  SIX = self.new(\"6\", 6)\n  SEVEN = self.new(\"7\", 7)\n  EIGHT = self.new(\"8\", 8)\n  NINE = self.new(\"9\", 9)\n  TEN = self.new(\"10\", 10)\n  JACK = self.new(\"J\", 10)\n  QUEEN = self.new(\"Q\", 10)\n  KING = self.new(\"K\", 10)\n  ACE = self.new(\"A\", 11)\n\n  KINDS_SET = [\n    TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN,\n    JACK, QUEEN, KING, ACE\n  ]\n\n  def same_value?(other_card)\n    value == other_card.value\n  end\n\n  def +(other)\n    throw \"other doesn't respond to +\" unless other.responds_to? :+\n\n    other.+(@value)\n  end \n\n  attr_reader :label, :value\nend\nend\n"
  },
  {
    "path": "10_Blackjack/ruby/model/hand.rb",
    "content": "require_relative \"./card_kind.rb\"\n\nmodule Model\nclass Hand\n  HAND_STATE_PLAYING = :hand_playing\n  HAND_STATE_BUSTED = :hand_busted\n  HAND_STATE_STAND = :hand_stand\n  HAND_STATE_DOUBLED_DOWN = :hand_doubled_down\n\n  def initialize(bet, cards, is_split_hand: false)\n    @state = HAND_STATE_PLAYING\n    @bet = bet\n    @cards = cards\n    @total = nil\n    @is_split_hand = is_split_hand\n  end\n\n  attr_reader :bet, :cards, :is_split_hand\n\n  def is_playing?\n    @state == HAND_STATE_PLAYING\n  end\n\n  def is_busted?\n    @state == HAND_STATE_BUSTED\n  end\n\n  def is_standing?\n    @state == HAND_STATE_STAND\n  end\n\n  def is_blackjack?\n    total == 21 && @cards.length == 2\n  end\n\n  def total(is_dealer: false)\n    return @total unless @total.nil?\n    \n    @total = @cards.reduce(0) {|sum, card| sum + card.value}\n\n    if @total > 21\n      aces_count = @cards.count {|c| c == CardKind::ACE}\n      while ((!is_dealer && @total > 21) || (is_dealer && @total < 16)) && aces_count > 0 do\n        @total -= 10\n        aces_count -= 1\n      end\n    end\n\n    @total\n  end\n\n  ## Hand actions\n\n  def can_split?\n    not @is_split_hand and @cards.length == 2 && @cards[0].same_value?(cards[1])\n  end\n\n  def split\n    throw \"can't split\" unless can_split?\n    [\n      Hand.new(@bet, @cards[0...1], is_split_hand: true),\n      Hand.new(@bet, @cards[1..1], is_split_hand: true)\n    ]\n  end\n\n  def hit(card)\n    throw \"can't hit\" unless is_playing?\n\n    @cards.push(card)\n    @total = nil\n\n    check_busted\n  end\n\n  def double_down(card)\n    throw \"can't double down\" unless is_playing?\n\n    @bet *= 2\n    hit card\n\n    @state = HAND_STATE_DOUBLED_DOWN\n  end\n\n  def stand\n    throw \"can't stand\" unless is_playing?\n\n    @state = HAND_STATE_STAND\n  end\n\n\n  private\n\n  def check_busted\n    @state = HAND_STATE_BUSTED if total > 21\n  end\nend\nend\n"
  },
  {
    "path": "10_Blackjack/ruby/model/pack.rb",
    "content": "require_relative \"./card_kind.rb\"\n\nmodule Model\nclass Pack\n  def initialize\n    @cards = []\n    reshuffle\n  end\n\n  def reshuffle_if_necessary\n    return if @cards.count > 2\n    reshuffle\n  end\n\n  def draw\n    reshuffle_if_necessary\n    @cards.pop\n  end\n\n  private\n\n  def reshuffle\n    puts \"RESHUFFLING\"\n    @cards = 4.times.map {|_| CardKind::KINDS_SET}.flatten\n    @cards.shuffle!\n  end\nend\nend\n"
  },
  {
    "path": "10_Blackjack/ruby/model/player.rb",
    "content": "require_relative \"./hand.rb\"\n\nmodule Model\nclass Player\n  def initialize(id)\n    @id = id\n    @balance = 0\n    @original_bet = 0\n    @insurance = 0\n\n    @hand = nil\n    @split_hand = nil\n  end\n\n  attr_reader :id, :balance, :hand, :split_hand, :insurance\n\n  ## Begining of hand dealing actions\n  def deal_initial_hand(hand)\n    @hand = hand\n    @split_hand = nil\n    @max_insurance = @hand.bet / 2\n    @insurance = 0\n  end\n\n  def has_split_hand?\n    !@split_hand.nil?\n  end\n\n  def can_split?\n    not has_split_hand? and @hand.can_split?\n  end\n\n  def split\n    throw \"can't split\" unless can_split?\n\n    @hand, @split_hand = @hand.split\n  end\n\n  def bet_insurance(bet)\n    if bet < 0\n      bet = 0\n      puts \"NEGATIVE BET -- using 0 insurance bet\"\n    end\n\n    if bet > @max_insurance\n      bet = @max_insurance\n      puts \"TOO HIGH -- using max insurance bet of #{bet}\"\n    end\n\n    @insurance = bet\n  end\n\n  ## End of hand dealing actions\n\n  def update_balance(dealer_hand)\n    balance_update = 0\n\n    balance_update += get_balance_update(@hand, dealer_hand)\n    if has_split_hand? then\n      balance_update += get_balance_update(@split_hand, dealer_hand)\n    end\n\n    if dealer_hand.is_blackjack?\n      balance_update += 2 * @insurance\n    else\n      balance_update -= @insurance\n    end\n\n    @balance += balance_update\n\n    balance_update\n  end\n\n\n  private\n\n  def get_balance_update(hand, dealer_hand)\n    if hand.is_busted?\n      return -hand.bet\n    elsif dealer_hand.is_busted?\n      return hand.bet\n    elsif dealer_hand.total == hand.total\n      return 0\n    else\n      return (dealer_hand.total < hand.total ? 1 : -1) * hand.bet\n    end\n  end\nend\nend\n"
  },
  {
    "path": "10_Blackjack/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "10_Blackjack/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "10_Blackjack/rust/src/main.rs",
    "content": "use rand::{prelude::{thread_rng, SliceRandom}};\nuse std::{io, io::{stdout, Write}};\n\n/**\n * todo list:\n *\n * allow splitting\n */\n\n\n//DATA\n//enums\nenum PlayerType {\n    Player,\n    Dealer,\n}\nimpl ToString for PlayerType {\n    fn to_string(&self) -> String {\n        match self {\n            &PlayerType::Dealer => return String::from(\"Dealer\"),\n            &PlayerType::Player => return String::from(\"Player\"),\n        }\n    }\n}\nenum Play {\n    Stand,\n    Hit,\n    DoubleDown,\n    Split,\n}\nimpl ToString for Play {\n    fn to_string(&self) -> String {\n        match self {\n            &Play::Hit => return String::from(\"Hit\"),\n            &Play::Stand => return String::from(\"Stand\"),\n            &Play::DoubleDown => return String::from(\"Double Down\"),\n            &Play::Split => return String::from(\"Split\")\n        }\n    }\n}\n//structs\nstruct CARD<'a> {\n    name: &'a str,\n    value: u8,\n}\nimpl<'a> CARD<'a> {\n    /**\n     * creates a new card from the passed card name\n     */\n    fn new(card_name: &str) -> CARD {\n        return CARD { name: card_name, value: CARD::determine_value_from_name(card_name) };\n    }\n\n    /**\n     * returns the value associated with a card with the passed name\n     * return 0 if the passed card name doesn't exist\n     */\n    fn determine_value_from_name(card_name: &str) -> u8 {\n        //DATA\n        let value:u8;\n\n        match card_name.to_ascii_uppercase().as_str() {\n            \"ACE\" => value = 11,\n            \"2\" => value = 2,\n            \"3\" => value = 3,\n            \"4\" => value = 4,\n            \"5\" => value = 5,\n            \"6\" => value = 6,\n            \"7\" => value = 7,\n            \"8\" => value = 8,\n            \"9\" => value = 9,\n            \"10\" => value = 10,\n            \"JACK\" => value = 10,\n            \"QUEEN\" => value = 10,\n            \"KING\" => value = 10,\n            _ => value = 0,\n        }\n\n        return value;\n    }\n}\nstruct HAND<'a> {\n    cards: Vec<CARD<'a>>,\n}\nimpl<'a> HAND<'a> {\n    /**\n     * returns a new empty hand\n     */\n    fn new() -> HAND<'a> {\n        return HAND { cards: Vec::new()};\n    }\n\n    /**\n     * add a passed card to this hand\n     */\n    fn add_card(&mut self, card: CARD<'a>) {\n        self.cards.push(card);\n    }\n\n    /**\n     * returns the total points of the cards in this hand\n     */\n    fn get_total(&self) -> usize {\n        let mut total:usize = 0;\n        for card in &self.cards {\n            total += card.value as usize;\n        }\n\n        //if there is an ACE, and the hand would otherwise bust, treat the ace like it's worth 1\n        if total > 21 && self.cards.iter().any(|c| -> bool {*c.name == *\"ACE\"}) {\n            total -= 10;\n        }\n\n        return total;\n    }\n\n    /**\n     * adds the cards in hand into the discard pile\n     */\n    fn discard_hand(&mut self, deck: &mut DECKS<'a>) {\n        let len = self.cards.len();\n        for _i in 0..len {\n            deck.discard_pile.push(self.cards.pop().expect(\"hand empty\"));\n        }\n    }\n}\nstruct DECKS<'a> {\n    deck: Vec<CARD<'a>>, //cards in the deck\n    discard_pile: Vec<CARD<'a>> //decks discard pile\n}\nimpl<'a> DECKS<'a> {\n    /**\n     * creates a new full and shuffled deck, and an empty discard pile\n     */\n    fn new() -> DECKS<'a> {\n        //returns a number of full decks of 52 cards, shuffles them\n        //DATA\n        let mut deck = DECKS{deck: Vec::new(), discard_pile: Vec::new()};\n        let number_of_decks = 3;\n\n        //fill deck\n        for _n in 0..number_of_decks { //fill deck with number_of_decks decks worth of cards\n            for card_name in CARD_NAMES { //add 4 of each card, totaling one deck with 4 of each card\n                deck.deck.push( CARD::new(card_name) );\n                deck.deck.push( CARD::new(card_name) );\n                deck.deck.push( CARD::new(card_name) );\n                deck.deck.push( CARD::new(card_name) );\n            }\n        }\n\n        //shuffle deck\n        deck.shuffle();\n\n        //return deck\n        return deck;\n    }\n\n    /**\n     * shuffles the deck\n     */\n    fn shuffle(&mut self) {\n        self.deck.shuffle(&mut thread_rng());\n    }\n\n    /**\n     * draw card from deck, and return it\n     * if deck is empty, shuffles discard pile into it and tries again\n     */\n    fn draw_card(&mut self) -> CARD<'a> {\n        match self.deck.pop() {\n            Some(card) => return card,\n            None => {\n                let len = self.discard_pile.len();\n\n                if len > 0 {//deck is empty, shuffle discard pile into deck and try again\n                    println!(\"deck is empty, shuffling\");\n                    for _i in 0..len {\n                        self.deck.push( self.discard_pile.pop().expect(\"discard pile empty\") )\n                    }\n                    self.shuffle();\n                    return self.draw_card();\n                } else { //discard pile and deck are empty, should never happen\n                    panic!(\"discard pile empty\");\n                }\n            }\n        }\n    }\n}\n\nstruct PLAYER<'a> {\n    hand: HAND<'a>,\n    balance: usize,\n    bet: usize,\n    wins: usize,\n    player_type: PlayerType,\n    index: usize,\n\n}\nimpl<'a> PLAYER<'a> {\n    /**\n     * creates a new player of the given type\n     */\n    fn new(player_type: PlayerType, index: usize) -> PLAYER<'a> {\n        return PLAYER { hand: HAND::new(), balance: STARTING_BALANCE, bet: 0, wins: 0, player_type: player_type, index: index};\n    }\n\n    fn get_name(&self) -> String {\n        format!(\"{}{}\", self.player_type.to_string(),self.index)\n    }\n\n    /**\n     * gets a bet from the player\n     */\n    fn get_bet(&mut self) {\n        if let PlayerType::Player = self.player_type {\n            if self.balance < 1 {\n                println!(\"{} is out of money :(\", self.get_name());\n                self.bet = 0;\n            }\n            self.bet = get_number_from_user_input(format!(\"{}\\tBet?\",self.get_name()).as_str(), 1, self.balance);\n        }\n    }\n\n    /**\n     * returns a string of the players hand\n     *\n     * if player is a dealer, returns the first card in the hand followed by *'s for every other card\n     * if player is a player, returns every card and the total\n     */\n    fn hand_as_string(&self, hide_dealer:bool) -> String {\n        if !hide_dealer {\n            return format!(\n                \"{}\\n\\ttotal points = {}\", //message\n                { //cards in hand\n                    let mut s:String = String::new();\n                    for cards_in_hand in self.hand.cards.iter().rev() {\n                        s += format!(\"{}\\t\", cards_in_hand.name).as_str();\n                    }\n                    s\n                },\n                self.hand.get_total() //total points in hand\n            );\n        }\n        else {\n            match &self.player_type {\n                &PlayerType::Dealer =>  { //if this is a dealer\n                    return format!(\n                        \"{}*\",//message\n                        { //*'s for other cards\n                            let mut s:String = String::new();\n                            let mut cards_in_hand = self.hand.cards.iter();\n                            cards_in_hand.next();//consume first card drawn\n                            for c in cards_in_hand.rev() {\n                                s += format!(\"{}\\t\", c.name).as_str();\n                            }\n                            s\n                        }\n                    );\n                },\n                &PlayerType::Player => { //if this is a player\n                    return format!(\n                        \"{}\\n\\ttotal points = {}\", //message\n                        { //cards in hand\n                            let mut s:String = String::new();\n                            for cards_in_hand in self.hand.cards.iter().rev() {\n                                s += format!(\"{}\\t\", cards_in_hand.name).as_str();\n                            }\n                            s\n                        },\n                        self.hand.get_total() //total points in hand\n                    );\n                }\n            }\n        }\n    }\n\n    /**\n     * get the players 'play'\n     */\n    fn get_play(&self) -> Play {\n        /*\n         do different things depending on what type of player this is:\n         if it's a dealer, use an algorithm to determine the play\n         if it's a player, ask user for input\n         */\n        match &self.player_type {\n            &PlayerType::Dealer => {\n                if self.hand.get_total() > 16 { // if total value of hand is greater than 16, stand\n                    return Play::Stand;\n                } else { //otherwise hit\n                    return Play::Hit;\n                }\n            },\n            &PlayerType::Player => {\n                let valid_results:Vec<char>;\n                if self.hand.cards.len() > 2 {//if there are more than 2 cards in the hand, at least one turn has happened, so splitting and doubling down are not allowed\n                    valid_results = vec!['s','S','h','H'];\n                } else {\n                    valid_results = vec!['s','S','h','H','d','D','/'];\n                }\n                let play = get_char_from_user_input(\"\\tWhat is your play?\", &valid_results);\n                match play {\n                    's' | 'S' => return Play::Stand,\n                    'h' | 'H' => return Play::Hit,\n                    'd' | 'D' => return Play::DoubleDown,\n                    '/'       => return Play::Split,\n                    _ => panic!(\"get_char_from_user_input() returned invalid character\"),\n                }\n            },\n        }\n    }\n}\n\nstruct GAME<'a> {\n    players: Vec<PLAYER<'a>>, //last item in this is the dealer\n    decks: DECKS<'a>,\n    games_played:usize,\n}\nimpl<'a> GAME<'a> {\n    /**\n     * creates a new game\n     */\n    fn new(num_players:usize) -> GAME<'a> {\n        //DATA\n        let mut players: Vec<PLAYER> = Vec::new();\n\n        //add dealer\n        players.push(PLAYER::new(PlayerType::Dealer,0));\n        //create human player(s) (at least one)\n        players.push(PLAYER::new(PlayerType::Player,1));\n        for i in 2..=num_players { //one less than num_players players\n            players.push(PLAYER::new(PlayerType::Player,i));\n        }\n\n        //ask if they want instructions\n        if let 'y'|'Y' = get_char_from_user_input(\"Do you want instructions? (y/n)\", &vec!['y','Y','n','N']) {\n            instructions();\n        }\n        println!();\n\n        //return a game\n        return GAME { players: players, decks: DECKS::new(), games_played: 0}\n    }\n\n    /**\n     * prints the score of every player\n     */\n    fn _print_stats(&self) {\n        println!(\"{}\", self.stats_as_string());\n    }\n\n    /**\n     * returns a string of the wins, balance, and bets of every player\n     */\n    fn stats_as_string(&self) -> String {\n        format!(\"Scores:\\n{}\",{\n            let mut s = String::new();\n            self.players.iter().for_each(|p| {\n                //format the presentation of player stats\n                match p.player_type {\n                    PlayerType::Player => s+= format!(\"{} Wins:\\t{}\\t\\tBalance:\\t{}\\t\\tBet\\t{}\\n\",p.get_name(),p.wins,p.balance,p.bet).as_str(),\n                    PlayerType::Dealer => s+= format!(\"{} Wins:\\t{}\\n\",p.get_name(),p.wins).as_str()\n                }\n            });\n            s\n        })\n    }\n\n    /**\n     * plays a round of blackjack\n     */\n    fn play_game(&mut self) {\n        //DATA\n        let scores;\n        let game = self.games_played; //save it here so we don't have borrowing issues\n        let mut player_hands_message: String = String::new();//cache it here so we don't have borrowing issues\n\n        //deal cards to each player\n        for _i in 0..2 { // do this twice\n            //draw card for each player\n            self.players.iter_mut().for_each(|player| {player.hand.add_card( self.decks.draw_card() );});\n        }\n\n        //get everyones bets\n        self.players.iter_mut().for_each(|player| player.get_bet());\n        scores = self.stats_as_string(); //save it here so we don't have borrowing issues later\n\n        //play game for each player\n        for player in self.players.iter_mut() {\n            //turn loop, ends when player finishes their turn\n            loop{\n                //clear screen\n                clear();\n                //print welcome\n                welcome();\n                //print game state\n                println!(\"\\n\\t\\t\\tGame {}\", game);\n                //print scores\n                println!(\"{}\",scores);\n                //print hands of all players\n                print!(\"{}\", player_hands_message);\n                println!(\"{} Hand:\\t{}\", player.get_name(), player.hand_as_string(true));\n\n                if let PlayerType::Player = player.player_type { //player isn't the dealer\n                    if player.bet == 0 {//player is out of money\n                        break;//exit turn loop\n                    }\n                }\n\n                //play through turn\n                //check their hand value for a blackjack(21) or bust\n                let score = player.hand.get_total();\n                if score >= 21 {\n                    if score == 21 { // == 21\n                        println!(\"\\tBlackjack! (21 points)\");\n                    } else { // > 21\n                        println!(\"\\tBust      ({} points)\", score);\n                    }\n                    break; //end turn\n                }\n\n                //get player move\n                let play = player.get_play();\n                //process play\n                match play {\n                    Play::Stand => {\n                        println!(\"\\t{}\", play.to_string());\n                        break; //end turn\n                    },\n                    Play::Hit => {\n                        println!(\"\\t{}\", play.to_string());\n                        //give them a card\n                        player.hand.add_card( self.decks.draw_card() );\n                    },\n                    Play::DoubleDown => {\n                        println!(\"\\t{}\", play.to_string());\n\n                        //double their balance if there's enough money, othewise go all-in\n                        if player.bet * 2 < player.balance {\n                            player.bet *= 2;\n                        }\n                        else {\n                            player.bet = player.balance;\n                        }\n                        //give them a card\n                        player.hand.add_card( self.decks.draw_card() );\n                    },\n                    Play::Split => {\n\n                    },\n                }\n            }\n\n            //add player to score cache thing\n            player_hands_message += format!(\"{} Hand:\\t{}\\n\", player.get_name(), player.hand_as_string(true)).as_str();\n        }\n\n        //determine winner\n        let mut top_score = 0; //player with the highest points\n        let mut num_winners = 1;\n        for player in self.players.iter_mut().enumerate().filter( |x| -> bool {x.1.hand.get_total()<=21}) { //players_who_didnt_bust\n            let score = player.1.hand.get_total();\n            if score > top_score {\n                top_score = score;\n                num_winners = 1;\n            } else if score == top_score {\n                num_winners += 1;\n            }\n        }\n\n        //print winner(s)\n        self.players.iter_mut().filter(|x|->bool{x.hand.get_total()==top_score}).for_each(|x| {//for each player with the top score\n            print!(\"{} \", x.get_name());//print name\n            x.wins += 1;//increment their wins\n        });\n        if num_winners > 1 {println!(\"all tie with {}\\n\\n\\n\", top_score);}\n        else {println!(\"wins with {}!\\n\\n\\n\",top_score);}\n\n        //handle bets\n        //remove money from losers\n        self.players.iter_mut().filter(|p| p.hand.get_total()!=top_score).for_each( |p| p.balance -= p.bet); //for every player who didn't get the winning score, remove their bet from their balance\n        //add money to winner\n        self.players.iter_mut().filter(|p| p.hand.get_total()==top_score).for_each(|p| p.balance += p.bet); //for each player who got the winning score, add their bet to their balance\n\n        //discard hands\n        self.players.iter_mut().for_each(|player| {player.hand.discard_hand(&mut self.decks);});\n\n        //increment games_played\n        self.games_played += 1;\n    }\n\n\n\n}\n\nconst CARD_NAMES: [&str;13] = [\"ACE\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"JACK\",\"QUEEN\",\"KING\"];\nconst STARTING_BALANCE: usize = 100;\n\nfn main() {\n    //DATA\n    let mut game: GAME;\n\n    //print welcome message\n    welcome();\n\n    //create game\n    game = GAME::new( get_number_from_user_input(\"How many players should there be (at least 1)?\", 1, 7) );\n\n    //game loop, play game until user wants to stop\n    loop {\n        //play round\n        game.play_game();\n\n        //ask if they want to play again\n        match get_char_from_user_input(\"Play Again? (y/n)\", &vec!['y','Y','n','N']) {\n            'y' | 'Y' => continue,\n            'n' | 'N' => break,\n            _ => break,\n        }\n    }\n}\n\n/**\n * prints the welcome screen\n */\nfn welcome() {\n    //welcome message\n    print!(\"\n                            BLACK JACK\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n    \\n\\n\");\n}\n\n/**\n * prints the instructions\n */\nfn instructions() {\n    println!(\"\n    THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE\n    GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE\n    PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE\n    DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE\n    FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE\n    PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS\n    STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/',\n    INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE\n    INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR\n    'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING\n    DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR\n    BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'.\n    NUMBER OF PLAYERS\n\n    NOTE:'/' (splitting) is not currently implemented, and does nothing\n\n    PRESS ENTER TO CONTINUE\n    \");\n    io::stdin().read_line(&mut String::new()).expect(\"Failed to read line\");\n}\n\n/**\n * gets a usize integer from user input\n */\nfn get_number_from_user_input(prompt: &str, min:usize, max:usize) -> usize {\n    //input loop\n    return loop {\n        let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n        //print prompt\n        println!(\"{}\", prompt);\n        stdout().flush().expect(\"Failed to flush to stdout.\");\n        //read user input from standard input, and store it to raw_input\n        //raw_input.clear(); //clear input\n        io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n        //from input, try to read a number\n        match raw_input.trim().parse::<usize>() {\n            Ok(i) => {\n                if i < min || i > max { //input out of desired range\n                    println!(\"INPUT OUT OF VALID RANGE.  TRY AGAIN.  {}-{}\",min,max);\n                    continue; // run the loop again\n                }\n                else {\n                    break i;// this escapes the loop, returning i\n                }\n            },\n            Err(e) => {\n                println!(\"INVALID INPUT.  TRY AGAIN.  {}\", e.to_string().to_uppercase());\n                continue; // run the loop again\n            }\n        };\n    };\n}\n\n/**\n * gets a character from user input\n * returns the first character they type\n */\nfn get_char_from_user_input(prompt: &str, valid_results: &Vec<char>) -> char {\n    //input loop\n    return loop {\n        let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n        //print prompt\n        println!(\"{}\", prompt);\n        stdout().flush().expect(\"Failed to flush to stdout.\");\n        //read user input from standard input, and store it to raw_input\n        //raw_input.clear(); //clear input\n        io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n        //from input, try to read a valid character\n        match raw_input.trim().chars().nth(0) {\n            Some(i) => {\n                if !valid_results.contains(&i) { //input out of desired range\n                    println!(\"INPUT IS NOT VALID CHARACTER.  TRY AGAIN.\");\n                    continue; // run the loop again\n                }\n                else {\n                    break i;// this escapes the loop, returning i\n                }\n            },\n            None => {\n                println!(\"INVALID INPUT.  TRY AGAIN.\");\n                continue; // run the loop again\n            }\n        };\n    };\n}\n\n/**\n * clear std out\n */\nfn clear() {\n    println!(\"\\x1b[2J\\x1b[0;0H\");\n}\n"
  },
  {
    "path": "10_Blackjack/vbnet/Blackjack.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Blackjack\", \"Blackjack.vbproj\", \"{B112CA5F-142B-46E9-92CB-5E3A84816AAE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B112CA5F-142B-46E9-92CB-5E3A84816AAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B112CA5F-142B-46E9-92CB-5E3A84816AAE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B112CA5F-142B-46E9-92CB-5E3A84816AAE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B112CA5F-142B-46E9-92CB-5E3A84816AAE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "10_Blackjack/vbnet/Blackjack.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Blackjack</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "10_Blackjack/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "11_Bombardment/README.md",
    "content": "### Bombardment\n\nBOMBARDMENT is played on two, 5x5 grids or boards with 25 outpost locations numbered 1 to 25. Both you and the computer have four platoons of troops that can be located at any four outposts on your respective grids.\n\nAt the start of the game, you locate (or hide) your four platoons on your grid. The computer does the same on its grid. You then take turns firing missiles or bombs at each other’s outposts trying to destroy all four platoons. The one who finds all four opponents’ platoons first, wins.\n\nThis program was slightly modified from the original written by Martin Burdash of Parlin, New Jersey.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=22)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=37)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- Though the instructions say you can't place two platoons on the same outpost, the code does not enforce this.  So the player can \"cheat\" and guarantee a win by entering the same outpost number two or more times.\n\n#### Porting Notes\n\n- To ensure the instructions don't scroll off the top of the screen, we may want to insert a \"(Press Return)\" or similar prompt before printing the tear-off matrix.\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "11_Bombardment/bombardment.bas",
    "content": "10 PRINT TAB(33);\"BOMBARDMENT\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\"\n110 PRINT \"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\"\n120 PRINT \"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\"\n130 PRINT \"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\"\n135 PRINT\n140 PRINT \"THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\"\n150 PRINT \"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\"\n160 PRINT \"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\"\n170 PRINT \"FIRST IS THE WINNER.\"\n180 PRINT\n190 PRINT \"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\"\n200 PRINT\n210 PRINT \"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\"\n220 FOR R=1 TO 5: PRINT: NEXT R\n260 DIM M(100)\n270 FOR R=1 TO 5\n280 I=(R-1)*5+1\n290 PRINT I,I+1,I+2,I+3,I+4\n300 NEXT R\n350 FOR R=1 TO 10: PRINT: NEXT R\n380 C=INT(RND(1)*25)+1\n390 D=INT(RND(1)*25)+1\n400 E=INT(RND(1)*25)+1\n410 F=INT(RND(1)*25)+1\n420 IF C=D THEN 390\n430 IF C=E THEN 400\n440 IF C=F THEN 410\n450 IF D=E THEN 400\n460 IF D=F THEN 410\n470 IF E=F THEN 410\n480 PRINT \"WHAT ARE YOUR FOUR POSITIONS\";\n490 INPUT G,H,K,L\n495 PRINT\n500 PRINT \"WHERE DO YOU WISH TO FIRE YOUR MISSLE\";\n510 INPUT Y\n520 IF Y=C THEN 710\n530 IF Y=D THEN 710\n540 IF Y=E THEN 710\n550 IF Y=F THEN 710\n560 GOTO 630\n570 M=INT(RND(1)*25)+1\n575 GOTO 1160\n580 IF X=G THEN 920\n590 IF X=H THEN 920\n600 IF X=L THEN 920\n610 IF X=K THEN 920\n620 GOTO 670\n630 PRINT \"HA, HA YOU MISSED. MY TURN NOW:\"\n640 PRINT: PRINT: GOTO 570\n670 PRINT \"I MISSED YOU, YOU DIRTY RAT. I PICKED\";M\". YOUR TURN:\"\n680 PRINT: PRINT: GOTO 500\n710 Q=Q+1\n720 IF Q=4 THEN 890\n730 PRINT \"YOU GOT ONE OF MY OUTPOSTS!\"\n740 IF Q=1 THEN 770\n750 IF Q=2 THEN 810\n760 IF Q=3 THEN 850\n770 PRINT \"ONE DOWN, THREE TO GO.\"\n780 PRINT: PRINT: GOTO 570\n810 PRINT \"TWO DOWN, TWO TO GO.\"\n820 PRINT: PRINT: GOTO 570\n850 PRINT \"THREE DOWN, ONE TO GO.\"\n860 PRINT: PRINT: GOTO 570\n890 PRINT \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\"\n900 PRINT \"MY TRANSISTO&S RECUP%RA*E!\"\n910 GOTO 1235\n920 Z=Z+1\n930 IF Z=4 THEN 1110\n940 PRINT \"I GOT YOU. IT WON'T BE LONG NOW. POST\";X;\"WAS HIT.\"\n950 IF Z=1 THEN 990\n960 IF Z=2 THEN 1030\n970 IF Z=3 THEN 1070\n990 PRINT \"YOU HAVE ONLY THREE OUTPOSTS LEFT.\"\n1000 PRINT: PRINT: GOTO 500\n1030 PRINT \"YOU HAVE ONLY TWO OUTPOSTS LEFT.\"\n1040 PRINT: PRINT: GOTO 500\n1070 PRINT \"YOU HAVE ONLY ONE OUTPOST LEFT.\"\n1080 PRINT: PRINT: GOTO 500\n1110 PRINT \"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT\";X;\". HA, HA, HA.\"\n1120 PRINT \"BETTER LUCK NEXT TIME.\"\n1150 GOTO 1235\n1160 P=P+1\n1170 N=P-1\n1180 FOR T=1 TO N\n1190 IF M=M(T) THEN 570\n1200 NEXT T\n1210 X=M\n1220 M(P)=M\n1230 GOTO 580\n1235 END\n"
  },
  {
    "path": "11_Bombardment/csharp/Bombardment.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Bombardment\n{\n    // <summary>\n    // Game of Bombardment\n    // Based on the Basic game of Bombardment here\n    // https://github.com/coding-horror/basic-computer-games/blob/main/11%20Bombardment/bombardment.bas\n    // Note:  The idea was to create a version of the 1970's Basic game in C#, without introducing\n    // new features - no additional text, error checking, etc has been added.\n    // </summary>\n    internal class Bombardment\n    {\n        private static int MAX_GRID_SIZE = 25;\n        private static int MAX_PLATOONS = 4;\n        private static Random random = new Random();\n        private List<int> computerPositions = new List<int>();\n        private List<int> playerPositions = new List<int>();\n        private List<int> computerGuesses = new List<int>();\n\n        private void PrintStartingMessage()\n        {\n            Console.WriteLine(\"{0}BOMBARDMENT\", new string(' ', 33));\n            Console.WriteLine(\"{0}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", new string(' ', 15));\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n\n            Console.WriteLine(\"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\");\n            Console.WriteLine(\"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\");\n            Console.WriteLine(\"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\");\n            Console.WriteLine(\"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\");\n            Console.WriteLine();\n            Console.WriteLine(\"THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\");\n            Console.WriteLine(\"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\");\n            Console.WriteLine(\"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\");\n            Console.WriteLine(\"FIRST IS THE WINNER.\");\n            Console.WriteLine();\n            Console.WriteLine(\"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\");\n            Console.WriteLine();\n            Console.WriteLine(\"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\");\n\n            // As an alternative to repeating the call to WriteLine(),\n            // we can print the new line character five times.\n            Console.Write(new string('\\n', 5));\n\n            // Print a sample board (presumably the game was originally designed to be\n            // physically printed on paper while played).\n            for (var i = 1; i <= 25; i += 5)\n            {\n                // The token replacement can be padded by using the format {tokenPosition, padding}\n                // Negative values for the padding cause the output to be left-aligned.\n                Console.WriteLine(\"{0,-3}{1,-3}{2,-3}{3,-3}{4,-3}\", i, i + 1, i + 2, i + 3, i + 4);\n            }\n\n            Console.WriteLine(\"\\n\");\n        }\n\n        // Generate 5 random positions for the computer's platoons.\n        private void PlaceComputerPlatoons()\n        {\n            do\n            {\n                var nextPosition = random.Next(1, MAX_GRID_SIZE);\n                if (!computerPositions.Contains(nextPosition))\n                {\n                    computerPositions.Add(nextPosition);\n                }\n\n            } while (computerPositions.Count < MAX_PLATOONS);\n        }\n\n        private void StoreHumanPositions()\n        {\n            Console.WriteLine(\"WHAT ARE YOUR FOUR POSITIONS\");\n\n            // The original game assumed that the input would be five comma-separated values, all on one line.\n            // For example: 12,22,1,4,17\n            var input = Console.ReadLine();\n            var playerPositionsAsStrings = input.Split(\",\");\n            foreach (var playerPosition in playerPositionsAsStrings) {\n                playerPositions.Add(int.Parse(playerPosition));\n            }\n        }\n\n        private void HumanTurn()\n        {\n            Console.WriteLine(\"WHERE DO YOU WISH TO FIRE YOUR MISSLE\");\n            var input = Console.ReadLine();\n            var humanGuess = int.Parse(input);\n\n            if(computerPositions.Contains(humanGuess))\n            {\n                Console.WriteLine(\"YOU GOT ONE OF MY OUTPOSTS!\");\n                computerPositions.Remove(humanGuess);\n\n                switch(computerPositions.Count)\n                {\n                    case 3:\n                        Console.WriteLine(\"ONE DOWN, THREE TO GO.\");\n                        break;\n                    case 2:\n                        Console.WriteLine(\"TWO DOWN, TWO TO GO.\");\n                        break;\n                    case 1:\n                        Console.WriteLine(\"THREE DOWN, ONE TO GO.\");\n                        break;\n                    case 0:\n                        Console.WriteLine(\"YOU GOT ME, I'M GOING FAST.\");\n                        Console.WriteLine(\"BUT I'LL GET YOU WHEN MY TRANSISTO&S RECUP%RA*E!\");\n                        break;\n                }\n            }\n            else\n            {\n                Console.WriteLine(\"HA, HA YOU MISSED. MY TURN NOW:\");\n            }\n        }\n\n        private int GenerateComputerGuess()\n        {\n            int computerGuess;\n            do\n            {\n                computerGuess = random.Next(1, 25);\n            }\n            while(computerGuesses.Contains(computerGuess));\n            computerGuesses.Add(computerGuess);\n\n            return computerGuess;\n        }\n\n        private void ComputerTurn()\n        {\n            var computerGuess = GenerateComputerGuess();\n\n            if (playerPositions.Contains(computerGuess))\n            {\n                Console.WriteLine(\"I GOT YOU. IT WON'T BE LONG NOW. POST {0} WAS HIT.\", computerGuess);\n                playerPositions.Remove(computerGuess);\n\n                switch(playerPositions.Count)\n                {\n                    case 3:\n                        Console.WriteLine(\"YOU HAVE ONLY THREE OUTPOSTS LEFT.\");\n                        break;\n                    case 2:\n                        Console.WriteLine(\"YOU HAVE ONLY TWO OUTPOSTS LEFT.\");\n                        break;\n                    case 1:\n                        Console.WriteLine(\"YOU HAVE ONLY ONE OUTPOST LEFT.\");\n                        break;\n                    case 0:\n                        Console.WriteLine(\"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {0}. HA, HA, HA.\", computerGuess);\n                        Console.WriteLine(\"BETTER LUCK NEXT TIME.\");\n                        break;\n                }\n            }\n            else\n            {\n                Console.WriteLine(\"I MISSED YOU, YOU DIRTY RAT. I PICKED {0}. YOUR TURN:\", computerGuess);\n            }\n        }\n\n        public void Play()\n        {\n            PrintStartingMessage();\n            PlaceComputerPlatoons();\n            StoreHumanPositions();\n\n            while (playerPositions.Count > 0 && computerPositions.Count > 0)\n            {\n                HumanTurn();\n\n                if (computerPositions.Count > 0)\n                {\n                    ComputerTurn();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "11_Bombardment/csharp/Bombardment.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>netcoreapp2.1</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "11_Bombardment/csharp/Bombardment.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bombardment\", \"Bombardment.csproj\", \"{1DCFD283-9300-405B-A2B4-231F30265730}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1DCFD283-9300-405B-A2B4-231F30265730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1DCFD283-9300-405B-A2B4-231F30265730}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1DCFD283-9300-405B-A2B4-231F30265730}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1DCFD283-9300-405B-A2B4-231F30265730}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "11_Bombardment/csharp/Program.cs",
    "content": "﻿using System;\r\n\r\nnamespace Bombardment\r\n{\r\n    class Program\r\n    {\r\n        static void Main(string[] args)\r\n        {\r\n            var bombardment = new Bombardment();\r\n            bombardment.Play();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "11_Bombardment/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "11_Bombardment/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "11_Bombardment/java/src/Bombardment.java",
    "content": "import java.util.HashSet;\nimport java.util.Scanner;\n\n/**\n * Game of Bombardment\n * <p>\n * Based on the Basic game of Bombardment here\n * https://github.com/coding-horror/basic-computer-games/blob/main/11%20Bombardment/bombardment.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Bombardment {\n\n    public static final int MAX_GRID_SIZE = 25;\n    public static final int PLATOONS = 4;\n\n    private enum GAME_STATE {\n        STARTING,\n        DRAW_BATTLEFIELD,\n        GET_PLAYER_CHOICES,\n        PLAYERS_TURN,\n        COMPUTER_TURN,\n        PLAYER_WON,\n        PLAYER_LOST,\n        GAME_OVER\n    }\n\n    private GAME_STATE gameState;\n\n    public static final String[] PLAYER_HIT_MESSAGES = {\"ONE DOWN, THREE TO GO.\",\n            \"TWO DOWN, TWO TO GO.\", \"THREE DOWN, ONE TO GO.\"};\n\n    public static final String[] COMPUTER_HIT_MESSAGES = {\"YOU HAVE ONLY THREE OUTPOSTS LEFT.\",\n            \"YOU HAVE ONLY TWO OUTPOSTS LEFT.\", \"YOU HAVE ONLY ONE OUTPOST LEFT.\"};\n\n    private HashSet<Integer> computersPlatoons;\n    private HashSet<Integer> playersPlatoons;\n\n    private HashSet<Integer> computersGuesses;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    public Bombardment() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    init();\n                    intro();\n                    gameState = GAME_STATE.DRAW_BATTLEFIELD;\n                    break;\n\n                // Enter the players name\n                case DRAW_BATTLEFIELD:\n                    drawBattlefield();\n                    gameState = GAME_STATE.GET_PLAYER_CHOICES;\n                    break;\n\n                // Get the players 4 locations for their platoons\n                case GET_PLAYER_CHOICES:\n                    String playerChoices = displayTextAndGetInput(\"WHAT ARE YOUR FOUR POSITIONS? \");\n\n                    // Store the 4 player choices that were entered separated with commas\n                    for (int i = 0; i < PLATOONS; i++) {\n                        playersPlatoons.add(getDelimitedValue(playerChoices, i));\n                    }\n\n                    gameState = GAME_STATE.PLAYERS_TURN;\n                    break;\n\n                // Players turn to pick a location\n                case PLAYERS_TURN:\n\n                    int firePosition = getDelimitedValue(\n                            displayTextAndGetInput(\"WHERE DO YOU WISH TO FIRE YOUR MISSILE? \"), 0);\n\n                    if (didPlayerHitComputerPlatoon(firePosition)) {\n                        // Player hit a player platoon\n                        int hits = updatePlayerHits(firePosition);\n                        // How many hits has the player made?\n                        if (hits != PLATOONS) {\n                            showPlayerProgress(hits);\n                            gameState = GAME_STATE.COMPUTER_TURN;\n                        } else {\n                            // Player has obtained 4 hits, they win\n                            gameState = GAME_STATE.PLAYER_WON;\n                        }\n                    } else {\n                        // Player missed\n                        System.out.println(\"HA, HA YOU MISSED. MY TURN NOW:\");\n                        System.out.println();\n                        gameState = GAME_STATE.COMPUTER_TURN;\n                    }\n\n                    break;\n\n                // Computers time to guess a location\n                case COMPUTER_TURN:\n\n                    // Computer takes a guess of a location\n                    int computerFirePosition = uniqueComputerGuess();\n                    if (didComputerHitPlayerPlatoon(computerFirePosition)) {\n                        // Computer hit a player platoon\n                        int hits = updateComputerHits(computerFirePosition);\n                        // How many hits has the computer made?\n                        if (hits != PLATOONS) {\n                            showComputerProgress(hits, computerFirePosition);\n                            gameState = GAME_STATE.PLAYERS_TURN;\n                        } else {\n                            // Computer has obtained 4 hits, they win\n                            System.out.println(\"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT \" + computerFirePosition\n                                    + \". HA, HA, HA.\");\n                            gameState = GAME_STATE.PLAYER_LOST;\n                        }\n                    } else {\n                        // Computer missed\n                        System.out.println(\"I MISSED YOU, YOU DIRTY RAT. I PICKED \" + computerFirePosition\n                                + \". YOUR TURN:\");\n                        System.out.println();\n                        gameState = GAME_STATE.PLAYERS_TURN;\n                    }\n\n                    break;\n\n                // The player won\n                case PLAYER_WON:\n                    System.out.println(\"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\");\n                    System.out.println(\"MY TRANSISTO&S RECUP%RA*E!\");\n                    gameState = GAME_STATE.GAME_OVER;\n                    break;\n\n                case PLAYER_LOST:\n                    System.out.println(\"BETTER LUCK NEXT TIME.\");\n                    gameState = GAME_STATE.GAME_OVER;\n                    break;\n\n                // GAME_OVER State does not specifically have a case\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Calculate computer guess.  Make that the computer does not guess the same\n     * location twice\n     *\n     * @return location of the computers guess that has not been guessed previously\n     */\n    private int uniqueComputerGuess() {\n\n        boolean validGuess = false;\n        int computerGuess;\n        do {\n            computerGuess = randomNumber();\n\n            if (!computersGuesses.contains(computerGuess)) {\n                validGuess = true;\n            }\n        } while (!validGuess);\n\n        computersGuesses.add(computerGuess);\n\n        return computerGuess;\n    }\n\n    /**\n     * Create four unique platoons locations for the computer\n     * We are using a hashset which guarantees uniqueness so\n     * all we need to do is keep trying to add a random number\n     * until all four are in the hashset\n     *\n     * @return 4 locations of computers platoons\n     */\n    private HashSet<Integer> computersChosenPlatoons() {\n\n        // Initialise contents\n        HashSet<Integer> tempPlatoons = new HashSet<>();\n\n        boolean allPlatoonsAdded = false;\n\n        do {\n            tempPlatoons.add(randomNumber());\n\n            // All four created?\n            if (tempPlatoons.size() == PLATOONS) {\n                // Exit when we have created four\n                allPlatoonsAdded = true;\n            }\n\n        } while (!allPlatoonsAdded);\n\n        return tempPlatoons;\n    }\n\n    /**\n     * Shows a different message for each number of hits\n     *\n     * @param hits total number of hits by player on computer\n     */\n    private void showPlayerProgress(int hits) {\n\n        System.out.println(\"YOU GOT ONE OF MY OUTPOSTS!\");\n        showProgress(hits, PLAYER_HIT_MESSAGES);\n    }\n\n    /**\n     * Shows a different message for each number of hits\n     *\n     * @param hits total number of hits by computer on player\n     */\n    private void showComputerProgress(int hits, int lastGuess) {\n\n        System.out.println(\"I GOT YOU. IT WON'T BE LONG NOW. POST \" + lastGuess + \" WAS HIT.\");\n        showProgress(hits, COMPUTER_HIT_MESSAGES);\n    }\n\n    /**\n     * Prints a message from the passed array based on the value of hits\n     *\n     * @param hits     - number of hits the player or computer has made\n     * @param messages - an array of string with messages\n     */\n    private void showProgress(int hits, String[] messages) {\n        System.out.println(messages[hits - 1]);\n    }\n\n    /**\n     * Update a player hit - adds a hit the player made on the computers platoon.\n     *\n     * @param fireLocation - computer location that got hit\n     * @return number of hits the player has inflicted on the computer in total\n     */\n    private int updatePlayerHits(int fireLocation) {\n\n        // N.B. only removes if present, so its redundant to check if it exists first\n        computersPlatoons.remove(fireLocation);\n\n        // return number of hits in total\n        return PLATOONS - computersPlatoons.size();\n    }\n\n    /**\n     * Update a computer hit - adds a hit the computer made on the players platoon.\n     *\n     * @param fireLocation - player location that got hit\n     * @return number of hits the player has inflicted on the computer in total\n     */\n    private int updateComputerHits(int fireLocation) {\n\n        // N.B. only removes if present, so its redundant to check if it exists first\n        playersPlatoons.remove(fireLocation);\n\n        // return number of hits in total\n        return PLATOONS - playersPlatoons.size();\n    }\n\n    /**\n     * Determine if the player hit one of the computers platoons\n     *\n     * @param fireLocation the players choice of location to fire on\n     * @return true if a computer platoon was at that position\n     */\n    private boolean didPlayerHitComputerPlatoon(int fireLocation) {\n        return computersPlatoons.contains(fireLocation);\n    }\n\n    /**\n     * Determine if the computer hit one of the players platoons\n     *\n     * @param fireLocation the computers choice of location to fire on\n     * @return true if a players platoon was at that position\n     */\n    private boolean didComputerHitPlayerPlatoon(int fireLocation) {\n        return playersPlatoons.contains(fireLocation);\n    }\n\n    /**\n     * Draw the battlefield grid\n     */\n    private void drawBattlefield() {\n        for (int i = 1; i < MAX_GRID_SIZE + 1; i += 5) {\n            System.out.printf(\"%-2s %-2s %-2s %-2s %-2s %n\", i, i + 1, i + 2, i + 3, i + 4);\n        }\n    }\n\n    /**\n     * Basic information about the game\n     */\n    private void intro() {\n        System.out.println(\"BOMBARDMENT\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\");\n        System.out.println(\"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\");\n        System.out.println(\"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\");\n        System.out.println(\"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\");\n        System.out.println();\n        System.out.println(\"THE OBJECT OF THE GAME IS TO FIRE MISSILES AT THE\");\n        System.out.println(\"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\");\n        System.out.println(\"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\");\n        System.out.println(\"FIRST IS THE WINNER.\");\n        System.out.println();\n        System.out.println(\"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\");\n        System.out.println();\n        System.out.println(\"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\");\n        System.out.println();\n        System.out.println();\n    }\n\n    private void init() {\n\n        // Create four locations for the computers platoons.\n        computersPlatoons = computersChosenPlatoons();\n\n        // Players platoons.\n        playersPlatoons = new HashSet<>();\n\n        computersGuesses = new HashSet<>();\n    }\n\n    /**\n     * Accepts a string delimited by comma's and returns the nth delimited\n     * value (starting at count 0).\n     *\n     * @param text - text with values separated by comma's\n     * @param pos  - which position to return a value for\n     * @return the int representation of the value\n     */\n    private int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        return Integer.parseInt(tokens[pos]);\n    }\n\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Generate random number\n     *\n     * @return random number\n     */\n    private int randomNumber() {\n        return (int) (Math.random()\n                * (MAX_GRID_SIZE) + 1);\n    }\n}\n"
  },
  {
    "path": "11_Bombardment/java/src/BombardmentGame.java",
    "content": "public class BombardmentGame {\n\n    public static void main(String[] args) {\n\n        Bombardment bombardment = new Bombardment();\n        bombardment.play();\n    }\n}\n"
  },
  {
    "path": "11_Bombardment/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "11_Bombardment/javascript/bombardment.html",
    "content": "<html>\n<head>\n<title>BOMBARDMENT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bombardment.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "11_Bombardment/javascript/bombardment.js",
    "content": "// BOMBARDMENT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"BOMBARDMENT\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\\n\");\n    print(\"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\\n\");\n    print(\"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\\n\");\n    print(\"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\\n\");\n    print(\"\\n\");\n    print(\"THE OBJECT OF THE GAME IS TO FIRE MISSILES AT THE\\n\");\n    print(\"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\\n\");\n    print(\"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\\n\");\n    print(\"FIRST IS THE WINNER.\\n\");\n    print(\"\\n\");\n    print(\"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\\n\");\n    print(\"\\n\");\n    // \"TEAR OFF\" because it supposed this to be printed on a teletype\n    print(\"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\\n\");\n    for (r = 1; r <= 5; r++)\n        print(\"\\n\");\n    ma = [];\n    for (r = 1; r <= 100; r++)\n        ma[r] = 0;\n    p = 0;\n    q = 0;\n    z = 0;\n    for (r = 1; r <= 5; r++) {\n        i = (r - 1) * 5 + 1;\n        print(i + \"\\t\" + (i + 1) + \"\\t\" + (i + 2) + \"\\t\" + (i + 3) + \"\\t\" + (i + 4) + \"\\n\");\n    }\n    for (r = 1; r <= 10; r++)\n        print(\"\\n\");\n    c = Math.floor(Math.random() * 25) + 1;\n    do {\n        d = Math.floor(Math.random() * 25) + 1;\n        e = Math.floor(Math.random() * 25) + 1;\n        f = Math.floor(Math.random() * 25) + 1;\n    } while (c == d || c == e || c == f || d == e || d == f || e == f) ;\n    print(\"WHAT ARE YOUR FOUR POSITIONS\");\n    str = await input();\n    g = parseInt(str);\n    str = str.substr(str.indexOf(\",\") + 1);\n    h = parseInt(str);\n    str = str.substr(str.indexOf(\",\") + 1);\n    k = parseInt(str);\n    str = str.substr(str.indexOf(\",\") + 1);\n    l = parseInt(str);\n    print(\"\\n\");\n    // Another \"bug\" your outpost can be in the same position as a computer outpost\n    // Let us suppose both live in a different matrix.\n    while (1) {\n        // The original game didn't limited the input to 1-25\n        do {\n            print(\"WHERE DO YOU WISH TO FIRE YOUR MISSLE\");\n            y = parseInt(await input());\n        } while (y < 0 || y > 25) ;\n        if (y == c || y == d || y == e || y == f) {\n\n            // The original game has a bug. You can shoot the same outpost\n            // several times. This solves it.\n            if (y == c)\n                c = 0;\n            if (y == d)\n                d = 0;\n            if (y == e)\n                e = 0;\n            if (y == f)\n                f = 0;\n            q++;\n            if (q == 1) {\n                print(\"ONE DOWN. THREE TO GO.\\n\");\n            } else if (q == 2) {\n                print(\"TWO DOWN. TWO TO GO.\\n\");\n            } else if (q == 3) {\n                print(\"THREE DOWN. ONE TO GO.\\n\");\n            } else {\n                print(\"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\\n\");\n                print(\"MY TRANSISTO&S RECUP%RA*E!\\n\");\n                break;\n            }\n        } else {\n            print(\"HA, HA YOU MISSED. MY TURN NOW:\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        do {\n            m = Math.floor(Math.random() * 25 + 1);\n            p++;\n            n = p - 1;\n            for (t = 1; t <= n; t++) {\n                if (m == ma[t])\n                    break;\n            }\n        } while (t <= n) ;\n        x = m;\n        ma[p] = m;\n        if (x == g || x == h || x == l || x == k) {\n            z++;\n            if (z < 4)\n                print(\"I GOT YOU. IT WON'T BE LONG NOW. POST \" + x + \" WAS HIT.\\n\");\n            if (z == 1) {\n                print(\"YOU HAVE ONLY THREE OUTPOSTS LEFT.\\n\");\n            } else if (z == 2) {\n                print(\"YOU HAVE ONLY TWO OUTPOSTS LEFT.\\n\");\n            } else if (z == 3) {\n                print(\"YOU HAVE ONLY ONE OUTPOST LEFT.\\n\");\n            } else {\n                print(\"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT \" + x + \". HA, HA, HA.\\n\");\n                print(\"BETTER LUCK NEXT TIME.\\n\");\n            }\n        } else {\n            print(\"I MISSED YOU, YOU DIRTY RAT. I PICKED \" + m + \". YOUR TURN:\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "11_Bombardment/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "11_Bombardment/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "11_Bombardment/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "11_Bombardment/perl/bombardment.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\n\n#GLOBAL\nmy %player_bases;\nmy %computer_bases;\nmy %player_choices;\nmy %computer_choices;\n\n&main;\n\nsub main {\n\t&print_intro;\n\t&display_field;\n\t&populate_computer_bases;\n\t&populate_player_bases;\n\t&game_play;\n}\n\nsub game_play {\n\tuntil (keys %computer_bases == 0 || keys %player_bases == 0) {\n\t\t&player_turn;\n\t\tif (keys %computer_bases == 0) {\n\t\t\texit;\n\t\t}\n\t\t&computer_turn;\n\t}\n\texit;\n}\n\nsub computer_turn {\n\t# There is logic in here to ensure that the computer doesn't try to pick a target it has already picked\n\tmy $valid_choice = 0;\n\tuntil ($valid_choice == 1) {\n\t\tmy $target = int(rand(25)+1);\n\t\tif (exists $computer_choices{$target}) {\n\t\t\t$valid_choice = 0;\n\t\t}\n\t\telse {\n\t\t\t$valid_choice = 1;\n\t\t\t$computer_choices{$target}=1;\n\t\t\tif (exists $player_bases{$target}) {\n\t\t\t\tdelete($player_bases{$target});\n\t\t\t\tmy $size = keys %player_bases;\n\t\t\t\tif ($size > 0) {\n\t\t\t\t\tprint \"I GOT YOU.  IT WON'T BE LONG NOW. POST $target WAS HIT.\\n\";\n\t\t\t\t\tif ($size == 3) { print \"YOU HAVE ONLY THREE OUTPOSTS LEFT.\\n\"};\n\t\t\t\t\tif ($size == 2) { print \"YOU HAVE ONLY TWO OUTPOSTS LEFT.\\n\"};\n\t\t\t\t\tif ($size == 1) { print \"YOU HAVE ONLY ONE OUTPOSTS LEFT.\\n\"};\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tprint \"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT $target. HA, HA, HA.\\nBETTER LUCK NEXT TIME\\n\";\n\t\t\t\t}\n\n\t\t\t}\n\t\t\telse {\n\t\t\t\tprint \"I MISSED YOU, YOU DIRTY RAT. I PICKED $target. YOUR TURN:\\n\";\n\t\t\t}\n\t\t}\n\t}\n}\n\nsub player_turn {\n\tprint \"WHERE DO YOU WISH TO FIRE YOUR MISSILE\\n\";\n\tchomp(my $target=<STDIN>);\n\tif (exists $computer_bases{$target}) {\n\t\tprint \"YOU GOT ONE OF MY OUTPOSTS!\\n\";\n\t\tdelete($computer_bases{$target});\n\t\tmy $size = keys %computer_bases;\n\t\tif ($size == 3) { print \"ONE DOWN, THREE TO GO.\\n\"};\n\t\tif ($size == 2) { print \"TWO DOWN, TWO TO GO.\\n\"};\n\t\tif ($size == 1) { print \"THREE DOWN, ONE TO GO.\\n\"};\n\t\tif ($size == 0) { print \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\\nMY TRANSISTO&S RECUP%RA*E!\\n\"};\n\t}\n\telse {\n\t\tprint \"HA, HA YOU MISSED. MY TURN NOW:\\n\";\n\t}\n}\n\nsub populate_player_bases {\n\tprint \"WHAT ARE YOUR FOUR POSITIONS\\n\";\n\tmy $positions=<STDIN>;\n\tchomp($positions);\n\tmy @positions = split/ /,$positions;\n\tforeach my $base (@positions) {\n\t\t$player_bases{$base}=0;\n\t}\n}\n\nsub display_field {\n\tfor my $num (1..25) {\n\t\tif (length($num) < 2) {\n\t\t\t$num = \" $num\";\n\t\t}\n\t\tprint \"$num \";\n\t\tif ($num % 5 == 0) {\n\t\t\tprint \"\\n\";\n\t\t}\n\t}\n}\n\nsub populate_computer_bases {\n\tmy $size = 0;\n\tuntil ($size == 4) {\n\t\tmy $base = int(rand(25)+1);\n\t\t$computer_bases{$base}=0;\n\t\t$size = keys %computer_bases;\n\t}\n}\n\nsub print_intro {\n    print \" \" x 33, \"BOMBARDMENT\\n\";\n    print \" \" x 15, \" CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\n    print \"\\n\\n\";\n    print \"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\\n\";\n    print \"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\\n\";\n    print \"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\\n\";\n    print \"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\\n\\n\";\n    print \"THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\\n\";\n    print \"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\\n\";\n    print \"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\\n\";\n    print \"FIRST IS THE WINNER.\\n\\n\";\n    print \"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\\n\\n\";\n    print \"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\\n\";\n    print \"\\n\\n\\n\\n\";\n}\n"
  },
  {
    "path": "11_Bombardment/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "11_Bombardment/python/bombardment.py",
    "content": "#!/usr/bin/env python3\nimport random\nfrom functools import partial\nfrom typing import Callable, List, Set\n\n\ndef print_intro() -> None:\n    print(\" \" * 33 + \"BOMBARDMENT\")\n    print(\" \" * 15 + \" CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n    print(\"YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\")\n    print(\"HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\")\n    print(\"YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\")\n    print(\"THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\")\n    print()\n    print(\"THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\")\n    print(\"OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\")\n    print(\"THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\")\n    print(\"FIRST IS THE WINNER.\")\n    print()\n    print(\"GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\")\n    print()\n    print(\"TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\")\n    print(\"\\n\" * 4)\n\n\ndef display_field() -> None:\n    for row in range(5):\n        initial = row * 5 + 1\n        print(\"\\t\".join([str(initial + column) for column in range(5)]))\n    print(\"\\n\" * 9)\n\n\ndef positions_list() -> List[int]:\n    return list(range(1, 26, 1))\n\n\ndef generate_enemy_positions() -> Set[int]:\n    \"\"\"Randomly choose 4 'positions' out of a range of 1 to 25\"\"\"\n    positions = positions_list()\n    random.shuffle(positions)\n    return set(positions[:4])\n\n\ndef is_valid_position(pos: int) -> bool:\n    return pos in positions_list()\n\n\ndef prompt_for_player_positions() -> Set[int]:\n    while True:\n        raw_positions = input(\"WHAT ARE YOUR FOUR POSITIONS? \")\n        positions = {int(pos) for pos in raw_positions.split()}\n        # Verify user inputs (for example, if the player gives a\n        # a position for 26, the enemy can never hit it)\n        if len(positions) != 4:\n            print(\"PLEASE ENTER 4 UNIQUE POSITIONS\\n\")\n            continue\n        elif any(not is_valid_position(pos) for pos in positions):\n            print(\"ALL POSITIONS MUST RANGE (1-25)\\n\")\n            continue\n        else:\n            return positions\n\n\ndef prompt_player_for_target() -> int:\n\n    while True:\n        target = int(input(\"WHERE DO YOU WISH TO FIRE YOUR MISSLE? \"))\n        if not is_valid_position(target):\n            print(\"POSITIONS MUST RANGE (1-25)\\n\")\n            continue\n\n        return target\n\n\ndef attack(\n    target: int,\n    positions: Set[int],\n    hit_message: str,\n    miss_message: str,\n    progress_messages: str,\n) -> bool:\n    \"\"\"Performs attack procedure returning True if we are to continue.\"\"\"\n\n    if target in positions:\n        print(hit_message.format(target))\n        positions.remove(target)\n        print(progress_messages[len(positions)].format(target))\n    else:\n        print(miss_message.format(target))\n\n    return len(positions) > 0\n\n\ndef init_enemy() -> Callable[[], int]:\n    \"\"\"\n    Return a closure analogous to prompt_player_for_target.\n\n    Will choose from a unique sequence of positions to avoid picking the\n    same position twice.\n    \"\"\"\n\n    position_sequence = positions_list()\n    random.shuffle(position_sequence)\n    position = iter(position_sequence)\n\n    def choose() -> int:\n        return next(position)\n\n    return choose\n\n\n# Messages correspond to outposts remaining (3, 2, 1, 0)\nPLAYER_PROGRESS_MESSAGES = (\n    \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\\nMY TRANSISTO&S RECUP%RA*E!\",\n    \"THREE DOWN, ONE TO GO.\\n\\n\",\n    \"TWO DOWN, TWO TO GO.\\n\\n\",\n    \"ONE DOWN, THREE TO GO.\\n\\n\",\n)\n\n\nENEMY_PROGRESS_MESSAGES = (\n    \"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {}. HA, HA, HA.\\nBETTER LUCK NEXT TIME.\",\n    \"YOU HAVE ONLY ONE OUTPOST LEFT.\\n\\n\",\n    \"YOU HAVE ONLY TWO OUTPOSTS LEFT.\\n\\n\",\n    \"YOU HAVE ONLY THREE OUTPOSTS LEFT.\\n\\n\",\n)\n\n\ndef main() -> None:\n    print_intro()\n    display_field()\n\n    enemy_positions = generate_enemy_positions()\n    player_positions = prompt_for_player_positions()\n\n    # Build partial functions only requiring the target as input\n    player_attacks = partial(\n        attack,\n        positions=enemy_positions,\n        hit_message=\"YOU GOT ONE OF MY OUTPOSTS!\",\n        miss_message=\"HA, HA YOU MISSED. MY TURN NOW:\\n\\n\",\n        progress_messages=PLAYER_PROGRESS_MESSAGES,\n    )\n\n    enemy_attacks = partial(\n        attack,\n        positions=player_positions,\n        hit_message=\"I GOT YOU. IT WON'T BE LONG NOW. POST {} WAS HIT.\",\n        miss_message=\"I MISSED YOU, YOU DIRTY RAT. I PICKED {}. YOUR TURN:\\n\\n\",\n        progress_messages=ENEMY_PROGRESS_MESSAGES,\n    )\n\n    enemy_position_choice = init_enemy()\n\n    # Play as long as both player_attacks and enemy_attacks allow to continue\n    while player_attacks(prompt_player_for_target()) and enemy_attacks(\n        enemy_position_choice()\n    ):\n        pass\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "11_Bombardment/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "11_Bombardment/ruby/bombardment.rb",
    "content": "require \"set\"\n\nclass Battlefield\n  TOTAL_OUTPOSTS = 25\n  TOTAL_PLATOONS = 4\n\n  class << self\n    def with_random_platoon_placements\n      new((1..TOTAL_OUTPOSTS).to_a.sample(4))\n    end\n\n    def valid_platoon_placement?(i)\n      i.between?(1, TOTAL_OUTPOSTS)\n    end\n  end\n\n  def initialize(platoon_placements)\n    @platoon_placements = Set.new(platoon_placements)\n  end\n\n  # Fires a missile at the specified outpost. Returns true if it hits a\n  # platoon, false otherwise.\n  def fire_missile_at(outpost)\n    !@platoon_placements.delete?(outpost).nil?\n  end\n\n  def remaining_platoons_count\n    @platoon_placements.size\n  end\nend\n\nclass Game\n  def initialize(player_battlefield:, computer_battlefield:)\n    @player_battlefield = player_battlefield\n    @computer_battlefield = computer_battlefield\n  end\n\n  def play\n    player_choice = get_integer_answer_to(\"WHERE DO YOU WISH TO FIRE\")\n\n    if @computer_battlefield.fire_missile_at(player_choice)\n      print_player_success_message\n      return if @computer_battlefield.remaining_platoons_count == 0\n    else\n      puts \"HA, HA YOU MISSED. MY TURN NOW:\"\n    end\n    puts\n\n    computer_choice = rand(1..Battlefield::TOTAL_OUTPOSTS)\n\n    if @player_battlefield.fire_missile_at(computer_choice)\n      print_computer_success_message(computer_choice)\n    else\n      puts \"I MISSED YOU, YOU DIRTY RAT. I PICKED #{computer_choice}. YOUR TURN:\"\n    end\n    puts\n  end\n\n  def finished?\n    @player_battlefield.remaining_platoons_count == 0 ||\n      @computer_battlefield.remaining_platoons_count == 0\n  end\n\n  private\n\n  def get_integer_answer_to(question)\n    puts question\n    $stdin.gets.strip.to_i\n  end\n\n  def print_computer_success_message(computer_choice)\n    if @player_battlefield.remaining_platoons_count == 0\n      puts \"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT #{computer_choice}. HA, HA, HA.\"\n      puts \"BETTER LUCK NEXT TIME.\"\n      return\n    end\n\n    puts \"I GOT YOU. IT WON'T BE LONG NOW. POST #{computer_choice} WAS HIT.\"\n\n    case @player_battlefield.remaining_platoons_count\n    when 1\n      puts \"YOU HAVE ONLY ONE OUTPOST LEFT\"\n    when 2\n      puts \"YOU HAVE ONLY TWO OUTPOSTS LEFT\"\n    when 3\n      puts \"YOU HAVE ONLY THREE OUTPOSTS LEFT\"\n    end\n  end\n\n  def print_player_success_message\n    if @computer_battlefield.remaining_platoons_count == 0\n      puts \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\"\n      puts \"MY TRANSISTO&S RECUP%RA*E!\"\n      return\n    end\n\n    puts \"YOU GOT ONE OF MY OUTPOSTS!\"\n\n    case @computer_battlefield.remaining_platoons_count\n    when 1\n      puts \"THREE DOWN, ONE TO GO.\"\n    when 2\n      puts \"TWO DOWN, TWO TO GO.\"\n    when 3\n      puts \"ONE DOWN, THREE TO GO.\"\n    end\n  end\nend\n\nINTRODUCTION = <<~TEXT\n                                   BOMBARDMENT\n                 CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n  YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\n  HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\n  YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\n  THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\n\n  THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\n  OUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\n  THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\n  FIRST IS THE WINNER.\n\n  GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n\n  TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\nTEXT\n\ndef print_matrix\n  (1..25).each do |i|\n    print i\n    print i % 5 == 0 ? \"\\n\" : \"\\t\"\n  end\nend\n\ndef ask_for_platoon_placements\n  puts \"WAHT ARE YOUR FOUR POSITIONS?\"\n  platoon_placements = $stdin.gets.strip.split(\",\").map(&:to_i)\n\n  if platoon_placements.size == 4 &&\n      platoon_placements.all? { |i| Battlefield.valid_platoon_placement?(i) }\n    platoon_placements\n  else\n    puts \"POSITIONS SHOULD BE BETWEEN 1 TO 25, DELIMITED BY COMMA.\"\n    ask_for_platoon_placements\n  end\nend\n\ndef start_game\n  puts INTRODUCTION\n  puts\n  print_matrix\n  puts\n  platoon_placements = ask_for_platoon_placements\n  puts\n\n  game = Game.new(\n    player_battlefield: Battlefield.new(platoon_placements),\n    computer_battlefield: Battlefield.with_random_platoon_placements\n  )\n\n  game.play until game.finished?\nend\n\nstart_game\n"
  },
  {
    "path": "11_Bombardment/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\nmorristown = \"0.1.4\""
  },
  {
    "path": "11_Bombardment/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by [ugurkupeli](https://github.com/ugurkupeli)\n"
  },
  {
    "path": "11_Bombardment/rust/src/main.rs",
    "content": "use morristown::PromptMultiOption;\nuse rand::{prelude::SliceRandom, thread_rng};\nuse std::time::Duration;\n\nfn main() {\n    morristown::print_intro(\"BOMBARDMENT\");\n\n    println!(\n        r#\"\n\nYOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\nHAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\nYOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\nTHE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\n\nTHE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\nOUTPOSTS OF THE COMPUTER.  IT WILL DO THE SAME TO YOU.\nTHE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\nFIRST IS THE WINNER.\n\nGOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n\nTEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\n\n\n\"#\n    );\n\n    let mut all_positions = Vec::with_capacity(25);\n\n    for i in 1u8..=25 {\n        all_positions.push(i);\n\n        print!(\"{i}\\t\");\n        if (i % 5) == 0 {\n            println!();\n        }\n    }\n\n    let mut player_positions = morristown::prompt_multi_number::<u8>(\n        \"WHAT ARE YOUR FOUR POSITIONS?\\n\",\n        \",\",\n        Some(PromptMultiOption::UnitAmount(4)),\n        Some(1..=25),\n    );\n\n    let mut rng = thread_rng();\n\n    let ai_positions = rand::seq::index::sample(&mut rng, 24, 4).into_vec();\n    let mut ai_positions: Vec<u8> = ai_positions.iter().map(|i| (i + 1) as u8).collect();\n\n    loop {\n        if !player_turn(&mut ai_positions) {\n            break;\n        } else if !ai_turn(&mut all_positions, &mut player_positions) {\n            break;\n        }\n    }\n}\n\nfn player_turn(ai_positions: &mut Vec<u8>) -> bool {\n    let player_missile =\n        morristown::prompt_number_range::<u8>(\"WHERE DO YOU WISH TO FIRE YOUR MISSILE?\", 1..=25);\n\n    if let Some(index) = ai_positions.iter().position(|p| *p == player_missile) {\n        ai_positions.remove(index);\n\n        let remaining = ai_positions.len();\n\n        if remaining > 0 {\n            let down = 4 - remaining;\n\n            println!(\n                \"YOU GOT ONE OF MY OUTPOSTS.\\n{} DOWN, {} TO GO\\n\",\n                get_text_from_number(down),\n                get_text_from_number(remaining)\n            );\n        } else {\n            println!(\n                \"YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN MY TRANSISTO&S RECUP%RA*E!\\n\\n\"\n            );\n            return false;\n        }\n    } else {\n        println!(\"HA, HA YOU MISSED. MY TURN NOW\\n\");\n    }\n    true\n}\n\nfn ai_turn(all_positions: &mut Vec<u8>, player_positions: &mut Vec<u8>) -> bool {\n    std::thread::sleep(Duration::from_secs(1));\n\n    let ai_missile = *all_positions\n        .choose(&mut rand::thread_rng())\n        .expect(\"AI RAN OUT OF OPTIONS!\");\n\n    let index = all_positions\n        .iter()\n        .position(|p| p == &ai_missile)\n        .expect(\"AI CHOOSE AN INVALID POSITION!\");\n\n    all_positions.remove(index);\n\n    if let Some(index) = player_positions.iter().position(|p| p == &ai_missile) {\n        player_positions.remove(index);\n\n        let remaining = player_positions.len();\n\n        if remaining > 0 {\n            println!(\"I GOT YOU. IT WON'T BE LONG NOW. POST {ai_missile} WAS HIT.\");\n            println!(\n                \"YOU HAVE ONLY {} OUTPOST LEFT.\\n\",\n                get_text_from_number(remaining)\n            );\n        } else {\n            println!(\"YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {ai_missile} . HA, HA, HA.\");\n            println!(\"BETTER LUCK NEXT TIME.\");\n            return false;\n        }\n    } else {\n        println!(\"I MISSED YOU, YOU DIRTY RAT. I PICKED {ai_missile} . YOUR TURN.\\n\")\n    }\n\n    true\n}\n\nfn get_text_from_number(n: usize) -> &'static str {\n    match n {\n        1 => \"ONE\",\n        2 => \"TWO\",\n        3 => \"THREE\",\n        _ => panic!(\"INVALID INDEX!\"),\n    }\n}\n"
  },
  {
    "path": "11_Bombardment/vbnet/Bombardment.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bombardment\", \"Bombardment.vbproj\", \"{7C967BC0-101C-413F-92A8-3A8A7D9846FE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7C967BC0-101C-413F-92A8-3A8A7D9846FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7C967BC0-101C-413F-92A8-3A8A7D9846FE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7C967BC0-101C-413F-92A8-3A8A7D9846FE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7C967BC0-101C-413F-92A8-3A8A7D9846FE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "11_Bombardment/vbnet/Bombardment.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bombardment</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "11_Bombardment/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "12_Bombs_Away/README.md",
    "content": "### Bombs Away\n\nIn this program, you fly a World War II bomber for one of the four protagonists of the war. You then pick your target or the type of plane you are flying. Depending on your flying experience and the quality of enemy defenders, you then may accomplish your mission, get shot down, or make it back through enemy fire. In any case, you get a chance to fly again.\n\nDavid Ahl modified the original program which was created by David Sherman while a student at Curtis Jr. High School, Sudbury, Massachusetts.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=24)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=39)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- If you play as Japan and say it is not your first mission, it is impossible to complete your mission; the only possible outcomes are \"you made it through\" or \"boom\".  Moreover, the odds of each outcome depend on a variable (R) that is only set if you played a previous mission as a different side.  It's possible this is an intentional layer of complexity meant to encourage repeat play, but it's more likely just a logical error.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "12_Bombs_Away/bombsaway.bas",
    "content": "8 PRINT \"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\"\n10 INPUT \"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)\";A\n20 IF A>0 AND A<5 THEN 25\n22 PRINT \"TRY AGAIN...\" : GOTO 10\n25 ON A GOTO 30, 110, 200, 220\n30 INPUT \"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)\";B\n40 IF B>0 AND B<4 THEN 45\n42 PRINT \"TRY AGAIN...\" : GOTO 30\n45 PRINT : ON B GOTO 50, 80,90\n50 PRINT \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\"\n60 GOTO 280\n80 PRINT \"BE CAREFUL!!!\" : GOTO 280\n90 PRINT \"YOU'RE GOING FOR THE OIL, EH?\" : GOTO 280\n110 INPUT \"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)\";G\n120 IF G>0 AND G<5 THEN 125\n122 PRINT \"TRY AGAIN...\" : GOTO 110\n125 PRINT : ON G GOTO 130, 150, 170, 190\n130 PRINT \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\" : GOTO 280\n150 PRINT \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\" : GOTO 280\n170 PRINT \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\" : GOTO 280\n190 PRINT \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\"\n195 GOTO 280\n200 PRINT \"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\"\n205 INPUT \"YOUR FIRST KAMIKAZE MISSION(Y OR N)\";F$\n207 IF F$=\"N\" THEN S=0 : GOTO 358\n210 PRINT : IF RND(1)>.65 THEN 325\n215 GOTO 380\n220 PRINT \"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\"\n230 INPUT \"ENGLAND(2), OR FRANCE(3)\";M : IF M>0 AND M<4 THEN 235\n232 PRINT \"TRY AGAIN...\" : GOTO 220\n235 PRINT : ON M GOTO 250, 260, 270\n250 PRINT \"YOU'RE NEARING STALINGRAD.\" : GOTO 280\n260 PRINT \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\" : GOTO 280\n270 PRINT \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\"\n280 PRINT\n285 INPUT \"HOW MANY MISSIONS HAVE YOU FLOWN\";D\n290 IF D<160 THEN 300\n292 PRINT \"MISSIONS, NOT MILES...\"\n295 PRINT \"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\"\n297 PRINT \"NOW THEN, \"; : GOTO 285\n300 PRINT:IF D<100 THEN 310\n305 PRINT \"THAT'S PUSHING THE ODDS!\" : GOTO 320\n310 IF D<25 THEN PRINT \"FRESH OUT OF TRAINING, EH?\"\n320 PRINT : IF D<160*RND(1) THEN 330\n325 PRINT \"DIRECT HIT!!!! \"INT(100*RND(1))\"KILLED.\"\n327 PRINT \"MISSION SUCCESSFUL.\" : GOTO 390\n330 PRINT \"MISSED TARGET BY\"INT(2+30*RND(1))\"MILES!\"\n335 PRINT \"NOW YOU'RE REALLY IN FOR IT !!\" : PRINT\n340 INPUT \"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)\";R\n345 IF R>0 AND R<4 THEN 350\n347 PRINT \"TRY AGAIN...\" : GOTO 340\n350 PRINT : T=0 : IF R=2 THEN 360\n355 INPUT \"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)\";S\n357 IF S<10 THEN PRINT \"YOU LIE, BUT YOU'LL PAY...\": GOTO 380\n358 PRINT\n360 PRINT : IF R>1 THEN T=35\n365 IF S+T>100*RND(1) THEN 380\n370 PRINT \"YOU MADE IT THROUGH TREMENDOUS FLAK!!\" : GOTO 390\n380 PRINT \"* * * * BOOM * * * *\"\n384 PRINT \"YOU HAVE BEEN SHOT DOWN.....\"\n386 PRINT \"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\"\n387 PRINT \"LAST TRIBUTE...\"\n390 PRINT:PRINT:PRINT:INPUT \"ANOTHER MISSION (Y OR N)\";U$\n395 IF U$=\"Y\" THEN 8\n400 PRINT \"CHICKEN !!!\" : PRINT : END\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAway.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"BombsAwayConsole\", \"BombsAwayConsole\\BombsAwayConsole.csproj\", \"{D80015FA-423C-4A16-AA2B-16669245AD59}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"BombsAwayGame\", \"BombsAwayGame\\BombsAwayGame.csproj\", \"{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D80015FA-423C-4A16-AA2B-16669245AD59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D80015FA-423C-4A16-AA2B-16669245AD59}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D80015FA-423C-4A16-AA2B-16669245AD59}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D80015FA-423C-4A16-AA2B-16669245AD59}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {39B2ECFB-037D-4335-BBD2-64892E953DD4}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayConsole/BombsAwayConsole.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\BombsAwayGame\\BombsAwayGame.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs",
    "content": "﻿namespace BombsAwayConsole;\n\n/// <summary>\n/// Implements <see cref=\"BombsAwayGame.IUserInterface\"/> by writing to and reading from <see cref=\"Console\"/>.\n/// </summary>\ninternal class ConsoleUserInterface : BombsAwayGame.IUserInterface\n{\n    /// <summary>\n    /// Write message to console.\n    /// </summary>\n    /// <param name=\"message\">Message to display.</param>\n    public void Output(string message)\n    {\n        Console.WriteLine(message);\n    }\n\n    /// <summary>\n    /// Write choices with affixed indexes, allowing the user to choose by index.\n    /// </summary>\n    /// <param name=\"message\">Message to display.</param>\n    /// <param name=\"choices\">Choices to display.</param>\n    /// <returns>Choice that user picked.</returns>\n    public int Choose(string message, IList<string> choices)\n    {\n        IEnumerable<string> choicesWithIndexes = choices.Select((choice, index) => $\"{choice}({index + 1})\");\n        string choiceText = string.Join(\", \", choicesWithIndexes);\n        Output($\"{message} -- {choiceText}\");\n\n        ISet<ConsoleKey> allowedKeys = ConsoleKeysFromList(choices);\n        ConsoleKey? choice;\n        do\n        {\n            choice = ReadChoice(allowedKeys);\n            if (choice is null)\n            {\n                Output(\"TRY AGAIN...\");\n            }\n        }\n        while (choice is null);\n\n        return ListIndexFromConsoleKey(choice.Value);\n    }\n\n    /// <summary>\n    /// Convert the given list to its <see cref=\"ConsoleKey\"/> equivalents. This generates keys that map\n    /// the first element to <see cref=\"ConsoleKey.D1\"/>, the second element to <see cref=\"ConsoleKey.D2\"/>,\n    /// and so on, up to the last element of the list.\n    /// </summary>\n    /// <param name=\"list\">List whose elements will be converted to <see cref=\"ConsoleKey\"/> equivalents.</param>\n    /// <returns><see cref=\"ConsoleKey\"/> equivalents from <paramref name=\"list\"/>.</returns>\n    private ISet<ConsoleKey> ConsoleKeysFromList(IList<string> list)\n    {\n        IEnumerable<int> indexes = Enumerable.Range((int)ConsoleKey.D1, list.Count);\n        return new HashSet<ConsoleKey>(indexes.Cast<ConsoleKey>());\n    }\n\n    /// <summary>\n    /// Convert the given console key to its list index equivalent. This assumes the key was generated from\n    /// <see cref=\"ConsoleKeysFromList(IList{string})\"/>\n    /// </summary>\n    /// <param name=\"key\">Key to convert to its list index equivalent.</param>\n    /// <returns>List index equivalent of key.</returns>\n    private int ListIndexFromConsoleKey(ConsoleKey key)\n    {\n        return key - ConsoleKey.D1;\n    }\n\n    /// <summary>\n    /// Read a key from the console and return it if it is in the given allowed keys.\n    /// </summary>\n    /// <param name=\"allowedKeys\">Allowed keys.</param>\n    /// <returns>Key read from <see cref=\"Console\"/>, if it is in <paramref name=\"allowedKeys\"/>; null otherwise./></returns>\n    private ConsoleKey? ReadChoice(ISet<ConsoleKey> allowedKeys)\n    {\n        ConsoleKeyInfo keyInfo = ReadKey();\n        return allowedKeys.Contains(keyInfo.Key) ? keyInfo.Key : null;\n    }\n\n    /// <summary>\n    /// Read key from <see cref=\"Console\"/>.\n    /// </summary>\n    /// <returns>Key read from <see cref=\"Console\"/>.</returns>\n    private ConsoleKeyInfo ReadKey()\n    {\n        ConsoleKeyInfo result = Console.ReadKey(intercept: false);\n        // Write a blank line to the console so the displayed key is on its own line.\n        Console.WriteLine();\n        return result;\n    }\n\n    /// <summary>\n    /// Allow user to choose 'Y' or 'N' from <see cref=\"Console\"/>.\n    /// </summary>\n    /// <param name=\"message\">Message to display.</param>\n    /// <returns>True if user chose 'Y', false if user chose 'N'.</returns>\n    public bool ChooseYesOrNo(string message)\n    {\n        Output(message);\n        ConsoleKey? choice;\n        do\n        {\n            choice = ReadChoice(new HashSet<ConsoleKey>(new[] { ConsoleKey.Y, ConsoleKey.N }));\n            if (choice is null)\n            {\n                Output(\"ENTER Y OR N\");\n            }\n        }\n        while (choice is null);\n\n        return choice.Value == ConsoleKey.Y;\n    }\n\n    /// <summary>\n    /// Get integer by reading a line from <see cref=\"Console\"/>.\n    /// </summary>\n    /// <returns>Integer read from <see cref=\"Console\"/>.</returns>\n    public int InputInteger()\n    {\n        bool resultIsValid;\n        int result;\n        do\n        {\n            string? integerText = Console.ReadLine();\n            resultIsValid = int.TryParse(integerText, out result);\n            if (!resultIsValid)\n            {\n                Output(\"PLEASE ENTER A NUMBER\");\n            }\n        }\n        while (!resultIsValid);\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayConsole/Program.cs",
    "content": "﻿using BombsAwayConsole;\nusing BombsAwayGame;\n\n/// Create and play <see cref=\"Game\"/>s using a <see cref=\"ConsoleUserInterface\"/>.\nPlayGameWhileUserWantsTo(new ConsoleUserInterface());\n\nvoid PlayGameWhileUserWantsTo(ConsoleUserInterface ui)\n{\n    do\n    {\n        new Game(ui).Play();\n    }\n    while (UserWantsToPlayAgain(ui));\n}\n\nbool UserWantsToPlayAgain(IUserInterface ui)\n{\n    bool result = ui.ChooseYesOrNo(\"ANOTHER MISSION (Y OR N)?\");\n    if (!result)\n    {\n        Console.WriteLine(\"CHICKEN !!!\");\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Allies protagonist. Can fly missions in a Liberator, B-29, B-17, or Lancaster.\n/// </summary>\ninternal class AlliesSide : MissionSide\n{\n    public AlliesSide(IUserInterface ui)\n        : base(ui)\n    {\n    }\n\n    protected override string ChooseMissionMessage => \"AIRCRAFT\";\n\n    protected override IList<Mission> AllMissions => new Mission[]\n    {\n        new(\"LIBERATOR\", \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\"),\n        new(\"B-29\", \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\"),\n        new(\"B-17\", \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\"),\n        new(\"LANCASTER\", \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\")\n    };\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Represents enemy artillery.\n/// </summary>\n/// <param name=\"Name\">Name of artillery type.</param>\n/// <param name=\"Accuracy\">Accuracy of artillery. This is the `T` variable in the original BASIC.</param>\ninternal record class EnemyArtillery(string Name, int Accuracy);\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/Game.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Plays the Bombs Away game using a supplied <see cref=\"IUserInterface\"/>.\n/// </summary>\npublic class Game\n{\n    private readonly IUserInterface _ui;\n\n    /// <summary>\n    /// Create game instance using the given UI.\n    /// </summary>\n    /// <param name=\"ui\">UI to use for game.</param>\n    public Game(IUserInterface ui)\n    {\n        _ui = ui;\n    }\n\n    /// <summary>\n    /// Play game. Choose a side and play the side's logic.\n    /// </summary>\n    public void Play()\n    {\n        _ui.Output(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\");\n        Side side = ChooseSide();\n        side.Play();\n    }\n\n    /// <summary>\n    /// Represents a <see cref=\"Side\"/>.\n    /// </summary>\n    /// <param name=\"Name\">Name of side.</param>\n    /// <param name=\"CreateSide\">Create instance of side that this descriptor represents.</param>\n    private record class SideDescriptor(string Name, Func<Side> CreateSide);\n\n    /// <summary>\n    /// Choose side and return a new instance of that side.\n    /// </summary>\n    /// <returns>New instance of side that was chosen.</returns>\n    private Side ChooseSide()\n    {\n        SideDescriptor[] sides = AllSideDescriptors;\n        string[] sideNames = sides.Select(a => a.Name).ToArray();\n        int index = _ui.Choose(\"WHAT SIDE\", sideNames);\n        return sides[index].CreateSide();\n    }\n\n    /// <summary>\n    /// All side descriptors.\n    /// </summary>\n    private SideDescriptor[] AllSideDescriptors => new SideDescriptor[]\n    {\n        new(\"ITALY\", () => new ItalySide(_ui)),\n        new(\"ALLIES\", () => new AlliesSide(_ui)),\n        new(\"JAPAN\", () => new JapanSide(_ui)),\n        new(\"GERMANY\", () => new GermanySide(_ui)),\n    };\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Germany protagonist. Can fly missions to Russia, England, and France.\n/// </summary>\ninternal class GermanySide : MissionSide\n{\n    public GermanySide(IUserInterface ui)\n        : base(ui)\n    {\n    }\n\n    protected override string ChooseMissionMessage => \"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR\";\n\n    protected override IList<Mission> AllMissions => new Mission[]\n    {\n        new(\"RUSSIA\", \"YOU'RE NEARING STALINGRAD.\"),\n        new(\"ENGLAND\", \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\"),\n        new(\"FRANCE\", \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\")\n    };\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Represents an interface for supplying data to the game.\n/// </summary>\n/// <remarks>\n/// Abstracting the UI allows us to concentrate its concerns in one part of our code and to change UI behavior\n/// without creating any risk of changing the game logic. It also allows us to supply an automated UI for tests.\n/// </remarks>\npublic interface IUserInterface\n{\n    /// <summary>\n    /// Display the given message.\n    /// </summary>\n    /// <param name=\"message\">Message to display.</param>\n    void Output(string message);\n\n    /// <summary>\n    /// Choose an item from the given choices.\n    /// </summary>\n    /// <param name=\"message\">Message to display.</param>\n    /// <param name=\"choices\">Choices to choose from.</param>\n    /// <returns>Index of choice in <paramref name=\"choices\"/> that user chose.</returns>\n    int Choose(string message, IList<string> choices);\n\n    /// <summary>\n    /// Allow user to choose Yes or No.\n    /// </summary>\n    /// <param name=\"message\">Message to display.</param>\n    /// <returns>True if user chose Yes, false if user chose No.</returns>\n    bool ChooseYesOrNo(string message);\n\n    /// <summary>\n    /// Get integer from user.\n    /// </summary>\n    /// <returns>Integer supplied by user.</returns>\n    int InputInteger();\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Italy protagonist. Can fly missions to Albania, Greece, and North Africa.\n/// </summary>\ninternal class ItalySide : MissionSide\n{\n    public ItalySide(IUserInterface ui)\n        : base(ui)\n    {\n    }\n\n    protected override string ChooseMissionMessage => \"YOUR TARGET\";\n\n    protected override IList<Mission> AllMissions => new Mission[]\n    {\n        new(\"ALBANIA\", \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\"),\n        new(\"GREECE\", \"BE CAREFUL!!!\"),\n        new(\"NORTH AFRICA\", \"YOU'RE GOING FOR THE OIL, EH?\")\n    };\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Japan protagonist. Flies a kamikaze mission, which has a different logic from <see cref=\"MissionSide\"/>s.\n/// </summary>\ninternal class JapanSide : Side\n{\n    public JapanSide(IUserInterface ui)\n        : base(ui)\n    {\n    }\n\n    /// <summary>\n    /// Perform a kamikaze mission. If first kamikaze mission, it will succeed 65% of the time. If it's not\n    /// first kamikaze mission, perform an enemy counterattack.\n    /// </summary>\n    public override void Play()\n    {\n        UI.Output(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\");\n\n        bool isFirstMission = UI.ChooseYesOrNo(\"YOUR FIRST KAMIKAZE MISSION(Y OR N)?\");\n        if (!isFirstMission)\n        {\n            // LINE 207 of original BASIC: hitRatePercent is initialized to 0,\n            // but R, the type of artillery, is not initialized at all. Setting\n            // R = 1, which is to say EnemyArtillery = Guns, gives the same result.\n            EnemyCounterattack(Guns, hitRatePercent: 0);\n        }\n        else if (RandomFrac() > 0.65)\n        {\n            MissionSucceeded();\n        }\n        else\n        {\n            MissionFailed();\n        }\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/Mission.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Represents a mission that can be flown by a <see cref=\"MissionSide\"/>.\n/// </summary>\n/// <param name=\"Name\">Name of mission.</param>\n/// <param name=\"Description\">Description of mission.</param>\ninternal record class Mission(string Name, string Description);\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Represents a protagonist that chooses a standard (non-kamikaze) mission.\n/// </summary>\ninternal abstract class MissionSide : Side\n{\n    /// <summary>\n    /// Create instance using the given UI.\n    /// </summary>\n    /// <param name=\"ui\">UI to use.</param>\n    public MissionSide(IUserInterface ui)\n        : base(ui)\n    {\n    }\n\n    /// <summary>\n    /// Reasonable upper bound for missions flown previously.\n    /// </summary>\n    private const int MaxMissionCount = 160;\n\n    /// <summary>\n    /// Choose a mission and attempt it. If attempt fails, perform an enemy counterattack.\n    /// </summary>\n    public override void Play()\n    {\n        Mission mission = ChooseMission();\n        UI.Output(mission.Description);\n\n        int missionCount = MissionCountFromUI();\n        CommentOnMissionCount(missionCount);\n\n        AttemptMission(missionCount);\n    }\n\n    /// <summary>\n    /// Choose a mission.\n    /// </summary>\n    /// <returns>Mission chosen.</returns>\n    private Mission ChooseMission()\n    {\n        IList<Mission> missions = AllMissions;\n        string[] missionNames = missions.Select(a => a.Name).ToArray();\n        int index = UI.Choose(ChooseMissionMessage, missionNames);\n        return missions[index];\n    }\n\n    /// <summary>\n    /// Message to display when choosing a mission.\n    /// </summary>\n    protected abstract string ChooseMissionMessage { get; }\n\n    /// <summary>\n    /// All aviailable missions to choose from.\n    /// </summary>\n    protected abstract IList<Mission> AllMissions { get; }\n\n    /// <summary>\n    /// Get mission count from UI. If mission count exceeds a reasonable maximum, ask UI again.\n    /// </summary>\n    /// <returns>Mission count from UI.</returns>\n    private int MissionCountFromUI()\n    {\n        const string HowManyMissions = \"HOW MANY MISSIONS HAVE YOU FLOWN?\";\n        string inputMessage = HowManyMissions;\n\n        bool resultIsValid;\n        int result;\n        do\n        {\n            UI.Output(inputMessage);\n            result = UI.InputInteger();\n            if (result < 0)\n            {\n                UI.Output($\"NUMBER OF MISSIONS CAN'T BE NEGATIVE.\");\n                resultIsValid = false;\n            }\n            else if (result > MaxMissionCount)\n            {\n                resultIsValid = false;\n                UI.Output($\"MISSIONS, NOT MILES...{MaxMissionCount} MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\");\n                inputMessage = \"NOW THEN, \" + HowManyMissions;\n            }\n            else\n            {\n                resultIsValid = true;\n            }\n        }\n        while (!resultIsValid);\n\n        return result;\n    }\n\n    /// <summary>\n    /// Display a message about the given mission count, if it is unusually high or low.\n    /// </summary>\n    /// <param name=\"missionCount\">Mission count to comment on.</param>\n    private void CommentOnMissionCount(int missionCount)\n    {\n        if (missionCount >= 100)\n        {\n            UI.Output(\"THAT'S PUSHING THE ODDS!\");\n        }\n        else if (missionCount < 25)\n        {\n            UI.Output(\"FRESH OUT OF TRAINING, EH?\");\n        }\n    }\n\n    /// <summary>\n    /// Attempt mission.\n    /// </summary>\n    /// <param name=\"missionCount\">Number of missions previously flown. Higher mission counts will yield a higher probability of success.</param>\n    private void AttemptMission(int missionCount)\n    {\n        if (missionCount < RandomInteger(0, MaxMissionCount))\n        {\n            MissedTarget();\n        }\n        else\n        {\n            MissionSucceeded();\n        }\n    }\n\n    /// <summary>\n    /// Display message indicating that target was missed. Choose enemy artillery and perform a counterattack.\n    /// </summary>\n    private void MissedTarget()\n    {\n        UI.Output(\"MISSED TARGET BY \" + (2 + RandomInteger(0, 30)) + \" MILES!\");\n        UI.Output(\"NOW YOU'RE REALLY IN FOR IT !!\");\n\n        // Choose enemy and counterattack.\n        EnemyArtillery enemyArtillery = ChooseEnemyArtillery();\n\n        if (enemyArtillery == Missiles)\n        {\n            EnemyCounterattack(enemyArtillery, hitRatePercent: 0);\n        }\n        else\n        {\n            int hitRatePercent = EnemyHitRatePercentFromUI();\n            if (hitRatePercent < MinEnemyHitRatePercent)\n            {\n                UI.Output(\"YOU LIE, BUT YOU'LL PAY...\");\n                MissionFailed();\n            }\n            else\n            {\n                EnemyCounterattack(enemyArtillery, hitRatePercent);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Choose enemy artillery from UI.\n    /// </summary>\n    /// <returns>Artillery chosen.</returns>\n    private EnemyArtillery ChooseEnemyArtillery()\n    {\n        EnemyArtillery[] artilleries = new EnemyArtillery[] { Guns, Missiles, Both };\n        string[] artilleryNames = artilleries.Select(a => a.Name).ToArray();\n        int index = UI.Choose(\"DOES THE ENEMY HAVE\", artilleryNames);\n        return artilleries[index];\n    }\n\n    /// <summary>\n    /// Minimum allowed hit rate percent.\n    /// </summary>\n    private const int MinEnemyHitRatePercent = 10;\n\n    /// <summary>\n    /// Maximum allowed hit rate percent.\n    /// </summary>\n    private const int MaxEnemyHitRatePercent = 50;\n\n    /// <summary>\n    /// Get the enemy hit rate percent from UI. Value must be between zero and <see cref=\"MaxEnemyHitRatePercent\"/>.\n    /// If value is less than <see cref=\"MinEnemyHitRatePercent\"/>, mission fails automatically because the user is\n    /// assumed to be untruthful.\n    /// </summary>\n    /// <returns>Enemy hit rate percent from UI.</returns>\n    private int EnemyHitRatePercentFromUI()\n    {\n        UI.Output($\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS ({MinEnemyHitRatePercent} TO {MaxEnemyHitRatePercent})\");\n\n        bool resultIsValid;\n        int result;\n        do\n        {\n            result = UI.InputInteger();\n            // Let them enter a number below the stated minimum, as they will be caught and punished.\n            if (0 <= result && result <= MaxEnemyHitRatePercent)\n            {\n                resultIsValid = true;\n            }\n            else\n            {\n                resultIsValid = false;\n                UI.Output($\"NUMBER MUST BE FROM {MinEnemyHitRatePercent} TO {MaxEnemyHitRatePercent}\");\n            }\n        }\n        while (!resultIsValid);\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/BombsAwayGame/Side.cs",
    "content": "﻿namespace BombsAwayGame;\n\n/// <summary>\n/// Represents a protagonist in the game.\n/// </summary>\ninternal abstract class Side\n{\n    /// <summary>\n    /// Create instance using the given UI.\n    /// </summary>\n    /// <param name=\"ui\">UI to use.</param>\n    public Side(IUserInterface ui)\n    {\n        UI = ui;\n    }\n\n    /// <summary>\n    /// Play this side.\n    /// </summary>\n    public abstract void Play();\n\n    /// <summary>\n    /// User interface supplied to ctor.\n    /// </summary>\n    protected IUserInterface UI { get; }\n\n    /// <summary>\n    /// Random-number generator for this play-through.\n    /// </summary>\n    private readonly Random _random = new();\n\n    /// <summary>\n    /// Gets a random floating-point number greater than or equal to zero, and less than one.\n    /// </summary>\n    /// <returns>Random floating-point number greater than or equal to zero, and less than one.</returns>\n    protected double RandomFrac() => _random.NextDouble();\n\n    /// <summary>\n    /// Gets a random integer in a range.\n    /// </summary>\n    /// <param name=\"minValue\">The inclusive lower bound of the number returned.</param>\n    /// <param name=\"maxValue\">The exclusive upper bound of the number returned.</param>\n    /// <returns>Random integer in a range.</returns>\n    protected int RandomInteger(int minValue, int maxValue) => _random.Next(minValue: minValue, maxValue: maxValue);\n\n    /// <summary>\n    /// Display messages indicating the mission succeeded.\n    /// </summary>\n    protected void MissionSucceeded()\n    {\n        UI.Output(\"DIRECT HIT!!!! \" + RandomInteger(0, 100) + \" KILLED.\");\n        UI.Output(\"MISSION SUCCESSFUL.\");\n    }\n\n    /// <summary>\n    /// Gets the Guns type of enemy artillery.\n    /// </summary>\n    protected EnemyArtillery Guns { get; } = new(\"GUNS\", 0);\n\n    /// <summary>\n    /// Gets the Missiles type of enemy artillery.\n    /// </summary>\n    protected EnemyArtillery Missiles { get; } = new(\"MISSILES\", 35);\n\n    /// <summary>\n    /// Gets the Both Guns and Missiles type of enemy artillery.\n    /// </summary>\n    protected EnemyArtillery Both { get; } = new(\"BOTH\", 35);\n\n    /// <summary>\n    /// Perform enemy counterattack using the given artillery and hit rate percent.\n    /// </summary>\n    /// <param name=\"artillery\">Enemy artillery to use.</param>\n    /// <param name=\"hitRatePercent\">Hit rate percent for enemy.</param>\n    protected void EnemyCounterattack(EnemyArtillery artillery, int hitRatePercent)\n    {\n        if (hitRatePercent + artillery.Accuracy > RandomInteger(0, 100))\n        {\n            MissionFailed();\n        }\n        else\n        {\n            UI.Output(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\");\n        }\n    }\n\n    /// <summary>\n    /// Display messages indicating the mission failed.\n    /// </summary>\n    protected void MissionFailed()\n    {\n        UI.Output(\"* * * * BOOM * * * *\");\n        UI.Output(\"YOU HAVE BEEN SHOT DOWN.....\");\n        UI.Output(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\");\n        UI.Output(\"LAST TRIBUTE...\");\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "12_Bombs_Away/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "12_Bombs_Away/java/src/BombsAway.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of Bombs Away\n *\n * Based on the Basic game of Bombs Away here\n * https://github.com/coding-horror/basic-computer-games/blob/main/12_Bombs_Away/bombsaway.bas\n *\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without adding new features.\n * Obvious bugs where found have been fixed, but the playability and overlook and feel\n * of the game have been faithfully reproduced.\n *\n * Modern Java coding conventions have been employed and JDK 11 used for maximum compatibility.\n *\n * Java port by https://github.com/journich\n *\n */\npublic class BombsAway {\n\n    public static final int MAX_PILOT_MISSIONS = 160;\n    public static final int MAX_CASUALTIES = 100;\n    public static final int MISSED_TARGET_CONST_1 = 2;\n    public static final int MISSED_TARGET_CONST_2 = 30;\n    public static final int CHANCE_OF_BEING_SHOT_DOWN_BASE = 100;\n    public static final double SIXTY_FIVE_PERCENT = .65;\n\n    private enum GAME_STATE {\n        START,\n        CHOOSE_SIDE,\n        CHOOSE_PLANE,\n        CHOOSE_TARGET,\n        CHOOSE_MISSIONS,\n        CHOOSE_ENEMY_DEFENCES,\n        FLY_MISSION,\n        DIRECT_HIT,\n        MISSED_TARGET,\n        PROCESS_FLAK,\n        SHOT_DOWN,\n        MADE_IT_THROUGH_FLAK,\n        PLAY_AGAIN,\n        GAME_OVER\n    }\n\n    public enum SIDE {\n        ITALY(1),\n        ALLIES(2),\n        JAPAN(3),\n        GERMANY(4);\n\n        private final int value;\n\n        SIDE(int value) {\n            this.value = value;\n        }\n\n        public int getValue() {\n            return value;\n        }\n\n\n    }\n\n    public enum TARGET {\n        ALBANIA(1),\n        GREECE(2),\n        NORTH_AFRICA(3),\n        RUSSIA(4),\n        ENGLAND(5),\n        FRANCE(6);\n\n        private final int value;\n\n        TARGET(int value) {\n            this.value = value;\n        }\n\n        public int getValue() {\n            return value;\n        }\n    }\n\n    public enum ENEMY_DEFENCES {\n        GUNS(1),\n        MISSILES(2),\n        BOTH(3);\n\n        private final int value;\n\n        ENEMY_DEFENCES(int value) {\n            this.value = value;\n        }\n\n        public int getValue() {\n            return value;\n        }\n    }\n\n    public enum AIRCRAFT {\n        LIBERATOR(1),\n        B29(2),\n        B17(3),\n        LANCASTER(4);\n\n        private final int value;\n\n        AIRCRAFT(int value) {\n            this.value = value;\n        }\n\n        public int getValue() {\n            return value;\n        }\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private SIDE side;\n\n    private int missions;\n\n    private int chanceToBeHit;\n    private int percentageHitRateOfGunners;\n    private boolean liar;\n\n    public BombsAway() {\n\n        gameState = GAME_STATE.START;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     *\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case START:\n                    intro();\n                    chanceToBeHit = 0;\n                    percentageHitRateOfGunners = 0;\n                    liar = false;\n\n                    gameState = GAME_STATE.CHOOSE_SIDE;\n                    break;\n\n                case CHOOSE_SIDE:\n                    side = getSide(\"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4) ? \");\n                    if (side == null) {\n                        System.out.println(\"TRY AGAIN...\");\n                    } else {\n                        // Different game paths depending on which side was chosen\n                        switch (side) {\n                            case ITALY:\n                            case GERMANY:\n                                gameState = GAME_STATE.CHOOSE_TARGET;\n                                break;\n                            case ALLIES:\n                            case JAPAN:\n                                gameState = GAME_STATE.CHOOSE_PLANE;\n                                break;\n                        }\n                    }\n                    break;\n\n                case CHOOSE_TARGET:\n                    String prompt;\n                    if (side == SIDE.ITALY) {\n                        prompt = \"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3) ? \";\n                    } else {\n                        // Germany\n                        System.out.println(\"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\");\n                        prompt = \"ENGLAND(2), OR FRANCE(3) ? \";\n                    }\n                    TARGET target = getTarget(prompt);\n                    if (target == null) {\n                        System.out.println(\"TRY AGAIN...\");\n                    } else {\n                        displayTargetMessage(target);\n                        gameState = GAME_STATE.CHOOSE_MISSIONS;\n                    }\n\n                case CHOOSE_MISSIONS:\n                    missions = getNumberFromKeyboard(\"HOW MANY MISSIONS HAVE YOU FLOWN? \");\n\n                    if(missions <25) {\n                        System.out.println(\"FRESH OUT OF TRAINING, EH?\");\n                        gameState = GAME_STATE.FLY_MISSION;\n                    } else if(missions < 100) {\n                        System.out.println(\"THAT'S PUSHING THE ODDS!\");\n                        gameState = GAME_STATE.FLY_MISSION;\n                    } else if(missions >=160) {\n                        System.out.println(\"MISSIONS, NOT MILES...\");\n                        System.out.println(\"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\");\n                        System.out.println(\"NOW THEN, \");\n                    } else {\n                        // No specific message if missions is 100-159, but still valid\n                        gameState = GAME_STATE.FLY_MISSION;\n                    }\n                    break;\n\n                case CHOOSE_PLANE:\n                    switch(side) {\n                        case ALLIES:\n                            AIRCRAFT plane = getPlane(\"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)? \");\n                            if(plane == null) {\n                                System.out.println(\"TRY AGAIN...\");\n                            } else {\n                                switch(plane) {\n\n                                    case LIBERATOR:\n                                        System.out.println(\"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\");\n                                        break;\n                                    case B29:\n                                        System.out.println(\"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\");\n                                        break;\n                                    case B17:\n                                        System.out.println(\"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\");\n                                        break;\n                                    case LANCASTER:\n                                        System.out.println(\"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\");\n                                        break;\n                                }\n\n                                gameState = GAME_STATE.CHOOSE_MISSIONS;\n                            }\n                            break;\n\n                        case JAPAN:\n                            System.out.println(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\");\n                            if(yesEntered(displayTextAndGetInput(\"YOUR FIRST KAMIKAZE MISSION(Y OR N) ? \"))) {\n                                if(randomNumber(1) > SIXTY_FIVE_PERCENT) {\n                                    gameState = GAME_STATE.DIRECT_HIT;\n                                } else {\n                                    // It's a miss\n                                    gameState = GAME_STATE.MISSED_TARGET;\n                                }\n                            } else {\n                                gameState = GAME_STATE.PROCESS_FLAK;\n                            }\n                            break;\n                    }\n                    break;\n\n                case FLY_MISSION:\n                    double missionResult = (MAX_PILOT_MISSIONS * randomNumber(1));\n                    if(missions > missionResult) {\n                        gameState = GAME_STATE.DIRECT_HIT;\n                    } else {\n                        gameState = GAME_STATE.MISSED_TARGET;\n                    }\n\n                    break;\n\n                case DIRECT_HIT:\n                    System.out.println(\"DIRECT HIT!!!! \" + (int) Math.round(randomNumber(MAX_CASUALTIES)) + \" KILLED.\");\n                    System.out.println(\"MISSION SUCCESSFUL.\");\n                    gameState = GAME_STATE.PLAY_AGAIN;\n                    break;\n\n                case MISSED_TARGET:\n                    System.out.println(\"MISSED TARGET BY \" + (int) Math.round(MISSED_TARGET_CONST_1 + MISSED_TARGET_CONST_2 * (randomNumber(1))) + \" MILES!\");\n                    System.out.println(\"NOW YOU'RE REALLY IN FOR IT !!\");\n                    System.out.println();\n                    gameState = GAME_STATE.CHOOSE_ENEMY_DEFENCES;\n                    break;\n\n                case CHOOSE_ENEMY_DEFENCES:\n                    percentageHitRateOfGunners = 0;\n\n                    ENEMY_DEFENCES enemyDefences = getEnemyDefences(\"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3) ? \");\n                    if(enemyDefences == null) {\n                        System.out.println(\"TRY AGAIN...\");\n                    } else {\n                        chanceToBeHit = 35;\n                        switch(enemyDefences) {\n                            case MISSILES:\n                                // MISSILES... An extra 35 but cannot specify percentage hit rate for gunners\n                                break;\n\n                            case GUNS:\n                                    // GUNS...  No extra 35 but can specify percentage hit rate for gunners\n                                chanceToBeHit = 0;\n                                // fall through (no break) on purpose because remaining code is applicable\n                                // for both GUNS and BOTH options.\n\n                            case BOTH:\n                                // BOTH... An extra 35 and percentage hit rate for gunners can be specified.\n                                percentageHitRateOfGunners = getNumberFromKeyboard(\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? \");\n                                if(percentageHitRateOfGunners < 10) {\n                                    System.out.println(\"YOU LIE, BUT YOU'LL PAY...\");\n                                    liar = true;\n                                }\n                                break;\n                        }\n                    }\n                    // If player didn't lie when entering percentage hit rate of gunners continue with game\n                    // Otherwise shoot down the player.\n                    if(!liar) {\n                        gameState = GAME_STATE.PROCESS_FLAK;\n                    } else {\n                        gameState = GAME_STATE.SHOT_DOWN;\n                    }\n                    break;\n\n                // Determine if the player's airplane makes it through the Flak.\n                case PROCESS_FLAK:\n                    double calc = (CHANCE_OF_BEING_SHOT_DOWN_BASE * randomNumber(1));\n\n                    if ((chanceToBeHit + percentageHitRateOfGunners) > calc) {\n                        gameState = GAME_STATE.SHOT_DOWN;\n                    } else {\n                        gameState = GAME_STATE.MADE_IT_THROUGH_FLAK;\n                    }\n                    break;\n\n                case SHOT_DOWN:\n                    System.out.println(\"* * * * BOOM * * * *\");\n                    System.out.println(\"YOU HAVE BEEN SHOT DOWN.....\");\n                    System.out.println(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\");\n                    System.out.println(\"LAST TRIBUTE...\");\n                    gameState = GAME_STATE.PLAY_AGAIN;\n                    break;\n\n                case MADE_IT_THROUGH_FLAK:\n                    System.out.println(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\");\n                    gameState = GAME_STATE.PLAY_AGAIN;\n                    break;\n\n                case PLAY_AGAIN:\n                    if(yesEntered(displayTextAndGetInput(\"ANOTHER MISSION (Y OR N) ? \"))) {\n                        gameState = GAME_STATE.START;\n                    } else {\n                        System.out.println(\"CHICKEN !!!\");\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER) ;\n    }\n\n    /**\n     * Display a (brief) intro\n     */\n    public void intro() {\n        System.out.println(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\");\n    }\n\n    /**\n     * Determine the side the player is going to play on.\n     * @param message displayed before the kb input\n     * @return the SIDE enum selected by the player\n     */\n    private SIDE getSide(String message) {\n        int valueEntered = getNumberFromKeyboard(message);\n        for(SIDE side : SIDE.values()) {\n            if(side.getValue() == valueEntered) {\n                return side;\n            }\n        }\n\n        // Input out of range\n        return null;\n    }\n\n    /**\n     * Determine the target the player is going for.\n     * @param message displayed before the kb input\n     * @return the TARGET enum selected by the player\n     */\n    private TARGET getTarget(String message) {\n        int valueEntered = getNumberFromKeyboard(message);\n\n        for(TARGET target : TARGET.values()) {\n            if(target.getValue() == valueEntered) {\n                return target;\n            }\n        }\n\n        // Input out of range\n        return null;\n    }\n\n    /**\n     * Determine the airplane the player is going to fly.\n     * @param message displayed before the kb input\n     * @return the AIRCRAFT enum selected by the player\n     */\n    private AIRCRAFT getPlane(String message) {\n        int valueEntered = getNumberFromKeyboard(message);\n\n        for(AIRCRAFT plane : AIRCRAFT.values()) {\n            if(plane.getValue() == valueEntered) {\n                return plane;\n            }\n        }\n\n        // Input out of range\n        return null;\n\n    }\n\n    /**\n     * Select the type of enemy defences.\n     *\n     * @param message displayed before kb input\n     * @return the ENEMY_DEFENCES enum as selected by player\n     */\n    private ENEMY_DEFENCES getEnemyDefences(String message) {\n        int valueEntered = getNumberFromKeyboard(message);\n        for (ENEMY_DEFENCES enemyDefences : ENEMY_DEFENCES.values()) {\n            if(enemyDefences.getValue() == valueEntered) {\n                return enemyDefences;\n            }\n        }\n\n        // Input out of range\n        return null;\n    }\n\n    // output a specific message based on the target selected\n    private void displayTargetMessage(TARGET target) {\n\n        switch (target) {\n\n            case ALBANIA:\n                System.out.println(\"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\");\n                break;\n            case GREECE:\n                System.out.println(\"BE CAREFUL!!!\");\n                break;\n            case NORTH_AFRICA:\n                System.out.println(\"YOU'RE GOING FOR THE OIL, EH?\");\n                break;\n            case RUSSIA:\n                System.out.println(\"YOU'RE NEARING STALINGRAD.\");\n                break;\n            case ENGLAND:\n                System.out.println(\"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\");\n                break;\n            case FRANCE:\n                System.out.println(\"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\");\n                break;\n        }\n    }\n\n    /**\n     * Accepts a string from the keyboard, and converts to an int\n     *\n     * @param message displayed text on screen before keyboard input\n     *\n     * @return the number entered by the player\n     */\n    private int getNumberFromKeyboard(String message) {\n\n        String answer = displayTextAndGetInput(message);\n        return Integer.parseInt(answer);\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text  player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case-insensitive.\n     *\n     * @param text source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        // Cycle through the variable number of values and test each\n        for(String val:values) {\n            if(text.equalsIgnoreCase(val)) {\n                return true;\n            }\n        }\n\n        // no matches\n        return false;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Generate random number\n     * Used as a single digit of the computer player\n     *\n     * @return random number\n     */\n    private double randomNumber(int range) {\n        return (Math.random()\n                * (range));\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/java/src/BombsAwayGame.java",
    "content": "public class BombsAwayGame {\n\n    public static void main(String[] args) {\n\n        BombsAway bombsAway = new BombsAway();\n        bombsAway.play();\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "12_Bombs_Away/javascript/bombsaway.html",
    "content": "<html>\n<head>\n<title>BOMBARDMENT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bombsaway.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "12_Bombs_Away/javascript/bombsaway.js",
    "content": "// BOMBS AWAY\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    s = 0;\n    t = 0;\n    while (1) {\n        print(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\\n\");\n        while (1) {\n            print(\"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)\");\n            a = parseInt(await input());\n            if (a < 1 || a > 4)\n                print(\"TRY AGAIN...\\n\");\n            else\n                break;\n        }\n        if (a == 1) {\n            while (1) {\n                print(\"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)\");\n                b = parseInt(await input());\n                if (b < 1 || b > 3)\n                    print(\"TRY AGAIN...\\n\");\n                else\n                    break;\n            }\n            print(\"\\n\");\n            if (b == 1) {\n                print(\"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\\n\");\n            } else if (b == 2) {\n                print(\"BE CAREFUL!!!\\n\");\n            } else {\n                print(\"YOU'RE GOING FOR THE OIL, EH?\\n\");\n            }\n        } else if (a == 2) {\n            while (1) {\n                print(\"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)\");\n                g = parseInt(await input());\n                if (g < 1 || g > 4)\n                    print(\"TRY AGAIN...\\n\");\n                else\n                    break;\n            }\n            print(\"\\n\");\n            if (g == 1) {\n                print(\"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\\n\");\n            } else if (g == 2) {\n                print(\"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\\n\");\n            } else if (g == 3) {\n                print(\"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\\n\");\n            } else {\n                print(\"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\\n\");\n            }\n        } else if (a == 3) {\n            print(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\\n\");\n            print(\"YOUR FIRST KAMIKAZE MISSION(Y OR N)\");\n            str = await input();\n            if (str == \"N\") {\n                s = 0;\n            } else {\n                s = 1;\n                print(\"\\n\");\n            }\n        } else {\n            while (1) {\n                print(\"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\\n\");\n                print(\"ENGLAND(2), OR FRANCE(3)\");\n                m = parseInt(await input());\n                if (m < 1 || m > 3)\n                    print(\"TRY AGAIN...\\n\");\n                else\n                    break;\n            }\n            print(\"\\n\");\n            if (m == 1) {\n                print(\"YOU'RE NEARING STALINGRAD.\\n\");\n            } else if (m == 2) {\n                print(\"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\\n\");\n            } else if (m == 3) {\n                print(\"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\\n\");\n            }\n        }\n        if (a != 3) {\n            print(\"\\n\");\n            while (1) {\n                print(\"HOW MANY MISSIONS HAVE YOU FLOWN\");\n                d = parseInt(await input());\n                if (d < 160)\n                    break;\n                print(\"MISSIONS, NOT MILES...\\n\");\n                print(\"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\\n\");\n                print(\"NOW THEN, \");\n            }\n            print(\"\\n\");\n            if (d >= 100) {\n                print(\"THAT'S PUSHING THE ODDS!\\n\");\n            } else if (d < 25) {\n                print(\"FRESH OUT OF TRAINING, EH?\\n\");\n            }\n            print(\"\\n\");\n            if (d >= 160 * Math.random())\n                hit = true;\n            else\n                hit = false;\n        } else {\n            if (s == 0) {\n                hit = false;\n            } else if (Math.random() > 0.65) {\n                hit = true;\n            } else {\n                hit = false;\n                s = 100;\n            }\n        }\n        if (hit) {\n            print(\"DIRECT HIT!!!! \" + Math.floor(100 * Math.random()) + \" KILLED.\\n\");\n            print(\"MISSION SUCCESSFUL.\\n\");\n        } else {\n            t = 0;\n            if (a != 3) {\n                print(\"MISSED TARGET BY \" + Math.floor(2 + 30 * Math.random()) + \" MILES!\\n\");\n                print(\"NOW YOU'RE REALLY IN FOR IT !!\\n\");\n                print(\"\\n\");\n                while (1) {\n                    print(\"DOES THE ENEMY HAVE GUNS(1), MISSILE(2), OR BOTH(3)\");\n                    r = parseInt(await input());\n                    if (r < 1 || r > 3)\n                        print(\"TRY AGAIN...\\n\");\n                    else\n                        break;\n                }\n                print(\"\\n\");\n                if (r != 2) {\n                    print(\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)\");\n                    s = parseInt(await input());\n                    if (s < 10)\n                        print(\"YOU LIE, BUT YOU'LL PAY...\\n\");\n                    print(\"\\n\");\n                }\n                print(\"\\n\");\n                if (r > 1)\n                    t = 35;\n            }\n            if (s + t <= 100 * Math.random()) {\n                print(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\\n\");\n            } else {\n                print(\"* * * * BOOM * * * *\\n\");\n                print(\"YOU HAVE BEEN SHOT DOWN.....\\n\");\n                print(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\\n\");\n                print(\"LAST TRIBUTE...\\n\");\n            }\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"ANOTHER MISSION (Y OR N)\");\n        str = await input();\n        if (str != \"Y\")\n            break;\n    }\n    print(\"CHICKEN !!!\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "12_Bombs_Away/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "12_Bombs_Away/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "12_Bombs_Away/lua/bombs_away.lua",
    "content": "-- Ported by Brian Wilkins (BrianWilkinsFL)\n-- Influenced by bombsaway.py\n-- Requires: Lua 5.4.x\n\nmissileHitRate = 0\ngunsHitRate = 0\n\nnanMessage = \"Invalid user entry! Please use a number and try again.\"\nfunction has_key(table, key)\n   return table[key]~=nil\nend\n\nfunction choice(prompt, table)\n    resp = getInput(prompt)\n    while not has_key(table, resp) do\n       print(\"TRY AGAIN...\")\n       resp = getInput(prompt)\n    end\n    return resp\nend\n\n-- reused from Bagels.lua\nfunction getInput(prompt)\n    io.write(prompt)\n    io.flush()\n    local input = io.read(\"l\") \n    if not input then  --- test for EOF\n        print(\"GOODBYE\")\n        os.exit(0)\n    end\n    return input\nend\n\nfunction playerSurvived()\n    print(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\")\nend\n\nfunction playerDeath()\n    print(\"* * * * BOOM * * * *\")\n    print(\"YOU HAVE BEEN SHOT DOWN.....\")\n    print(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\")\n    print(\"LAST TRIBUTE...\")\nend\n\n-- Enhancement: Partially killed don't count so floor the float\nfunction missionSuccess()\n   print(\"DIRECT HIT!!!! \" .. math.floor(100*math.random()) .. \" KILLED.\")\n   print(\"MISSION SUCCESSFUL.\")\nend\n\nfunction missionFailure()\n    weapons_choices = {\n        [\"1\"] = \"GUNS\",\n        [\"2\"] = \"MISSILES\",\n        [\"3\"] = \"BOTH\",\n    }\n    print(\"MISSED TARGET BY \" .. math.floor(2 + 30 * math.random()) .. \" MILES!\")\n    print(\"NOW YOU'RE REALLY IN FOR IT !!\")\n    print()\n    enemy_weapons = choice(\"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? \", weapons_choices)\n\n    if enemy_weapons == \"2\" or enemy_weapons == \"3\" then\n        missileHitRate = 35\n    end\n\n    if enemy_weapons == \"2\" then\n       -- gunsHitRate is a reused global variable so\n       -- its possible that previously selected gunsHitRate\n       -- will be used here leading to interesting\n       -- randomness\n       if missileHitRate+gunsHitRate > 100*math.random() then\n          playerDeath()\n       else\n          playerSurvived()\n       end\n    end\n\n    if enemy_weapons == \"1\" or enemy_weapons == \"3\" then\n        while true do\n           resp = getInput(\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? \")\n           if assert(tonumber(resp)) then\n              gunsHitRate = tonumber(resp)\n              break\n           end\n        end\n        if gunsHitRate < 10 then\n           print(\"YOU LIE, BUT YOU'LL PAY...\")\n           playerDeath()\n           return\n        end\n        if missileHitRate+gunsHitRate > 100*math.random() then\n           playerDeath()\n        else\n           playerSurvived()\n        end\n    end\nend\n\n-- override assert so Lua doesn't throw an error\n-- and stack trace\n-- We just want the user to enter in a correct value\nassert = function(truth, message)\n   if not truth then\n      print(message)\n   end\n   return truth\nend\n\n-- Added logic to verify user is actually entering in a number\nfunction commence_non_kamikaze_attack()\n    local numMissions = 0\n    while numMissions < 160 do\n       while numMissions == 0 do\n          resp = getInput(\"HOW MANY MISSIONS HAVE YOU FLOWN? \")\n          if assert(tonumber(resp), nanMessage) then\n             numMissions = tonumber(resp)\n             break\n          end\n       end\n       if numMissions < 160 then break end\n\n       print(\"MISSIONS, NOT MILES...\")\n       print(\"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\")\n       print(\"NOW THEN, \")\n       numMissions = 0\n    end\n\n    if numMissions >= 100 then\n       print(\"THAT'S PUSHING THE ODDS!\")\n    end\n\n    if numMissions < 25 then\n       print(\"FRESH OUT OF TRAINING, EH?\")\n    end\n\n    if numMissions >= 160*math.random() then \n        missionSuccess()\n    else \n        missionFailure() \n    end\nend\n\nfunction playItaly()\n    targets_to_messages = {\n       [\"1\"] = \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\",\n       [\"2\"] = \"BE CAREFUL!!!\",\n       [\"3\"] = \"YOU'RE GOING FOR THE OIL, EH?\",\n    }\n\n    target = choice(\"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)? \", targets_to_messages)\n    print(targets_to_messages[target])\n    commence_non_kamikaze_attack()\nend\n\nfunction playAllies()\n    aircraft_to_message = {\n        [\"1\"] = \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\",\n        [\"2\"] = \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\",\n        [\"3\"] = \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\",\n        [\"4\"] = \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\",\n    }\n    aircraft = choice(\"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)? \", aircraft_to_message)\n    print(aircraft_to_message[aircraft])\n    commence_non_kamikaze_attack()\nend\n\nfunction playJapan()\n    print(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\")\n    first_mission = getInput(\"YOUR FIRST KAMIKAZE MISSION? (Y OR N)? \"):match(\"[yYnN].*\")\n    if first_mission:lower() == \"n\" then\n        return playerDeath()\n    end\n    if math.random() > 0.65 then\n       return missionSuccess()\n    else\n       playerDeath()\n    end\nend\n\nfunction playGermany()\n    targets_to_messages = {\n        [\"1\"] = \"YOU'RE NEARING STALINGRAD.\",\n        [\"2\"] = \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\",\n        [\"3\"] = \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\",\n    }\n    target = choice(\"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\\nENGLAND(2), OR FRANCE(3)? \", targets_to_messages)\n\n    print(targets_to_messages[target])\n    return commence_non_kamikaze_attack()\nend\n\nfunction playGame()\n   sides = {\n        [\"1\"] = playItaly,\n        [\"2\"] = playAllies,\n        [\"3\"] = playJapan,\n        [\"4\"] = playGermany\n   }\n   print(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\")\n\n   target = choice(\"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)? \", sides)\n   sides[target]()\nend\n\nlocal again = true\nwhile again do\n   playGame()\n   again = getInput(\"ANOTHER MISSION (Y OR N)? \"):match(\"[yY].*\")\nend\n\nprint(\"CHICKEN !!!\")"
  },
  {
    "path": "12_Bombs_Away/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "12_Bombs_Away/perl/bombsaway.pl",
    "content": "#!/usr/bin/env perl\nuse v5.24;\nuse warnings;\nuse experimental 'signatures';\nno warnings 'experimental::signatures';\n\nexit main(@ARGV);\n\nsub main {\n   $|++;\n   my $mission = 'y';\n\n   # first-level choices will allow us to select the \"right\" callback\n   # function to start each mission\n   my @choices = (\\&italy, \\&allies, \\&japan, \\&germany);\n\n   # to support being case-insensitive \"the right way\" we apply the fc()\n   # function (i.e. \"fold case\"). This is slightly overkill in this case\n   # but it's better to stick to good habits.\n   while (fc($mission // 'n') eq fc('y')) {\n      say 'YOU ARE A PILOT IN A WORLD WAR II BOMBER.';\n\n      my $side = choose(\n         'WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)', 4);\n\n      # arrays start from 0 in Perl, so our starting-from-1 side value\n      # has to be offset by 1.\n      $choices[$side - 1]->();\n\n      $mission = get_input(\"\\n\\n\\nANOTHER MISSION (Y OR N)\");\n   }\n   __exit();\n}\n\n# unified exit function, make sure to shame the desertor!\nsub __exit ($prefix = '') {\n   say $prefix, \"CHICKEN !!!\\n\";\n   exit 0;\n}\n\n# unified input gathering. Checks if the input is closed (e.g. because the\n# player hit CTRL-D) and __exit()s in case. Gets a prompt for asking a\n# question, returns whatever is input (except spaces).\nsub get_input ($prompt) {\n   print \"$prompt? \";\n   defined(my $input = <STDIN>) or __exit(\"\\n\");\n\n   # remove spaces from the input (including newlines), they are not used\n\n   $input =~ s{\\s+}{}gmxs;\n   return $input;\n}\n\n# structured choosing function, gets a $prompt for asking a question and\n# will iterate asking until the input is a number between 1 and $n_max.\nsub choose ($prompt, $n_max) {\n   while ('necessary') {\n      my $side = get_input($prompt);\n      return $side if $side =~ m{\\A [1-9]\\d* \\z}mxs && $side <= $n_max;\n      say 'TRY AGAIN...';\n   }\n}\n\n# Italy mission has the same structure as Allies and Germany, so it's been\n# refactored into a single \"multiple()\" (pun intended) function, providing\n# the right messaging.\nsub italy {\n   return multiple(\n      'YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)',\n      q{SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.},\n      'BE CAREFUL!!!',\n      q{YOU'RE GOING FOR THE OIL, EH?},\n   );\n}\n\n\n# Allies mission has the same structure as Italy and Germany, so it's been\n# refactored into a single \"multiple()\" (pun intended) function, providing\n# the right messaging.\nsub allies {\n   return multiple(\n      'AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)',\n      q{YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.},\n      q{YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.},\n      q{YOU'RE CHASING THE BISMARK IN THE NORTH SEA.},\n      q{YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.},\n   );\n}\n\n# Japan mission is different from the other three and is coded...\n# differently. The end game phases are the same as other missions though,\n# hence the calls to \"direct_hit()\" and \"endgame()\" functions.\nsub japan {\n   say q{YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.};\n   my $is_first_kamikaze = get_input(q{YOUR FIRST KAMIKAZE MISSION(Y OR N)});\n   if (fc($is_first_kamikaze) eq fc('n')) {\n      our $guns_hit_rate = 0;\n      say '';\n      return endgame();\n   }\n   return direct_hit() if rand(1) > 0.65;\n   return endgame('fail');\n}\n\n# Germany mission has the same structure as Italy and Allies, so it's been\n# refactored into a single \"multiple()\" (pun intended) function, providing\n# the right messaging.\nsub germany {\n   return multiple(\n      \"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\\n\"\n         . 'ENGLAND(2), OR FRANCE(3)',\n      q{YOU'RE NEARING STALINGRAD.},\n      q{NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.},\n      q{NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.}\n   );\n}\n\n# This function implements the workhorse for Italy, Allies and Germany\n# missions, which all have the same structure. It starts with a $question\n# and a few @comments, each commenting every different answer to the\n# $question.\nsub multiple ($question, @comments) {\n   my $target = choose($question, scalar @comments);\n   say \"\\n\", $comments[$target - 1], \"\\n\";\n\n   # we gather the number of missions flown so far so that we can\n   # use it to figure out if *this* mission will be successful. The more\n   # the missions flown, the higher the probability of success.\n   my $missions;\n   while ('necessary') {\n      $missions = get_input('HOW MANY MISSIONS HAVE YOU FLOWN');\n      last if $missions < 160;\n      print 'MISSIONS, NOT MILES...\n150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.\nNOW THEN, ';\n   }\n   say '';\n\n   # a little intermediate comment based on the value of $missions\n   if ($missions < 25) { say \"FRESH OUT OF TRANING, EH?\\n\" }\n   elsif ($missions >= 100) { say \"THAT'S PUSHING THE ODDS!\\n\" }\n\n   # let's roll a 160-faced die and compare to the missions flown so far,\n   # player might not even have to engage in combat!\n   return direct_hit() if $missions >= rand(160);\n\n   # player didn't get a direct hit on the target, so we provide a\n   # feedback about how much it was apart. This is part of the story.\n   my $miss = 2 + int rand(30);\n   say \"MISSED TARGET BY $miss MILES!\";\n   say \"NOW YOU'RE REALLY IN FOR IT !!\\n\";\n\n   # here is where the game shows a little \"weakness\", although it might\n   # have been done on purpose. We use \"our\" variables $missiles_hit_rate\n   # and $guns_hit_rate here because the original BASIC code did not reset\n   # the associated variables (respectively T and S) at every mission, thus\n   # leaking state from one mission to the following ones.\n   #\n   # In particular, both are leaked to the Japan mission(s), and\n   # $guns_hit_rate is leaked to future \"multiple()\" missions that have\n   # missiles only.\n   #\n   # This is what you get when your language only has global variables.\n   #\n   # Of course, this might have been done on purpose, and we'll replicate\n   # this behaviour here because it adds some randomness to the game.\n   our $missiles_hit_rate = 0;\n   my $response = choose(\n      'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3);\n\n   # Apply Gun damage for responses 1 and 3\n   if ($response != 2) { # there's some guns involved, ask more\n      say '';\n\n      # see comment above as to why we have a \"our\" variable here\n      our $guns_hit_rate =\n         get_input(q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)});\n\n      # let's normalize the input a bit\n      $guns_hit_rate = 0 unless $guns_hit_rate =~ m{\\A [1-9]\\d* \\z}mxs;\n\n      # a hit rate this low is not reasonable and is immediately punished!\n      if ($guns_hit_rate < 10) {\n         say q{YOU LIE, BUT YOU'LL PAY...};\n\n         # function endgame() provides the... end game messaging, which is\n         # also used by the Japan mission, so it's been factored out.\n         # Passing 'fail' (or any true value) makes sure that is' a\n         # failure.\n         return endgame('fail'); # sure failure\n      }\n      say '';\n   }\n   # Apply missile damage for responses 2 and 3\n   if ($response > 1 )  {\n      $missiles_hit_rate = 35;  # remember... this is a global variable\n   }\n\n   # hand control over to the \"endgame()\" refactored function (also shared\n   # by the Japan mission).\n   return endgame();\n}\n\nsub direct_hit {\n   my $killed = int rand(100);\n   say \"DIRECT HIT!!!!  $killed KILLED.\\nMISSION SUCCESSFUL\";\n   return;\n}\n\n# This function provides the end game randomization and messages, shared\n# across all missions. If passed a true value $fail, it will make sure that\n# the outcome is... a failure. This allows coping with a few ad-hoc\n# GOTO:s in the original BASIC code, while still preserving a refactored\n# code.\nsub endgame ($fail = 0) {\n   our $missiles_hit_rate //= 0;\n   our $guns_hit_rate //= 0;\n   $fail ||= ($missiles_hit_rate + $guns_hit_rate) > rand(100);\n   if ($fail) {\n      say '* * * * BOOM * * * *\nYOU HAVE BEEN SHOT DOWN.....\nDEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\nLAST TRIBUTE...';\n   }\n   else {\n      say 'YOU MADE IT THROUGH TREMENDOUS FLAK!!';\n   }\n   return;\n}\n"
  },
  {
    "path": "12_Bombs_Away/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "12_Bombs_Away/python/bombs_away.py",
    "content": "\"\"\"\nBombs away\n\nPorted from BASIC to Python3 by Bernard Cooke (bernardcooke53)\nTested with Python 3.8.10, formatted with Black and type checked with mypy.\n\"\"\"\nimport random\nfrom typing import Iterable\n\n\ndef _stdin_choice(prompt: str, *, choices: Iterable[str]) -> str:\n    ret = input(prompt)\n    while ret not in choices:\n        print(\"TRY AGAIN...\")\n        ret = input(prompt)\n    return ret\n\n\ndef player_survived() -> None:\n    print(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\")\n\n\ndef player_death() -> None:\n    print(\"* * * * BOOM * * * *\")\n    print(\"YOU HAVE BEEN SHOT DOWN.....\")\n    print(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\")\n    print(\"LAST TRIBUTE...\")\n\n\ndef mission_success() -> None:\n    print(f\"DIRECT HIT!!!! {int(100 * random.random())} KILLED.\")\n    print(\"MISSION SUCCESSFUL.\")\n\n\ndef death_with_chance(p_death: float) -> bool:\n    \"\"\"\n    Takes a float between 0 and 1 and returns a boolean\n    if the player has survived (based on random chance)\n\n    Returns True if death, False if survived\n    \"\"\"\n    return p_death > random.random()\n\n\ndef commence_non_kamikazi_attack() -> None:\n    while True:\n        try:\n            nmissions = int(input(\"HOW MANY MISSIONS HAVE YOU FLOWN? \"))\n\n            while nmissions >= 160:\n                print(\"MISSIONS, NOT MILES...\")\n                print(\"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS\")\n                nmissions = int(input(\"NOW THEN, HOW MANY MISSIONS HAVE YOU FLOWN? \"))\n            break\n        except ValueError:\n            # In the BASIC implementation this\n            # wasn't accounted for\n            print(\"TRY AGAIN...\")\n            continue\n\n    if nmissions >= 100:\n        print(\"THAT'S PUSHING THE ODDS!\")\n\n    if nmissions < 25:\n        print(\"FRESH OUT OF TRAINING, EH?\")\n\n    print()\n    return (\n        mission_success() if nmissions >= 160 * random.random() else mission_failure()\n    )\n\n\ndef mission_failure() -> None:\n    weapons_choices = {\n        \"1\": \"GUNS\",\n        \"2\": \"MISSILES\",\n        \"3\": \"BOTH\",\n    }\n    print(f\"MISSED TARGET BY {int(2 + 30 * random.random())} MILES!\")\n    print(\"NOW YOU'RE REALLY IN FOR IT !!\")\n    print()\n    enemy_weapons = _stdin_choice(\n        prompt=\"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? \",\n        choices=weapons_choices,\n    )\n\n    # If there are no gunners (i.e. weapon choice 2) then\n    # we say that the gunners have 0 accuracy for the purposes\n    # of calculating probability of player death\n\n    enemy_gunner_accuracy = 0.0\n    if enemy_weapons != \"2\":\n        # If the enemy has guns, how accurate are the gunners?\n        while True:\n            try:\n                enemy_gunner_accuracy = float(\n                    input(\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? \")\n                )\n                break\n            except ValueError:\n                # In the BASIC implementation this\n                # wasn't accounted for\n                print(\"TRY AGAIN...\")\n                continue\n\n        if enemy_gunner_accuracy < 10:\n            print(\"YOU LIE, BUT YOU'LL PAY...\")\n            return player_death()\n\n    missile_threat_weighting = 0 if enemy_weapons == \"1\" else 35\n\n    death = death_with_chance(\n        p_death=(enemy_gunner_accuracy + missile_threat_weighting) / 100\n    )\n\n    return player_survived() if not death else player_death()\n\n\ndef play_italy() -> None:\n    targets_to_messages = {\n        # 1 - ALBANIA, 2 - GREECE, 3 - NORTH AFRICA\n        \"1\": \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\",\n        \"2\": \"BE CAREFUL!!!\",\n        \"3\": \"YOU'RE GOING FOR THE OIL, EH?\",\n    }\n    target = _stdin_choice(\n        prompt=\"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)\",\n        choices=targets_to_messages,\n    )\n\n    print(targets_to_messages[target])\n    return commence_non_kamikazi_attack()\n\n\ndef play_allies() -> None:\n    aircraft_to_message = {\n        \"1\": \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\",\n        \"2\": \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\",\n        \"3\": \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\",\n        \"4\": \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\",\n    }\n    aircraft = _stdin_choice(\n        prompt=\"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): \",\n        choices=aircraft_to_message,\n    )\n\n    print(aircraft_to_message[aircraft])\n    return commence_non_kamikazi_attack()\n\n\ndef play_japan() -> None:\n    print(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\")\n    first_mission = input(\"YOUR FIRST KAMIKAZE MISSION? (Y OR N): \")\n    if first_mission.lower() == \"n\":\n        return player_death()\n    return mission_success() if random.random() > 0.65 else player_death()\n\n\ndef play_germany() -> None:\n    targets_to_messages = {\n        # 1 - RUSSIA, 2 - ENGLAND, 3 - FRANCE\n        \"1\": \"YOU'RE NEARING STALINGRAD.\",\n        \"2\": \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\",\n        \"3\": \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\",\n    }\n    target = _stdin_choice(\n        prompt=\"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\\nENGLAND(2), OR FRANCE(3)? \",\n        choices=targets_to_messages,\n    )\n\n    print(targets_to_messages[target])\n\n    return commence_non_kamikazi_attack()\n\n\ndef play_game() -> None:\n    print(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\")\n    sides = {\"1\": play_italy, \"2\": play_allies, \"3\": play_japan, \"4\": play_germany}\n    side = _stdin_choice(\n        prompt=\"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): \", choices=sides\n    )\n    return sides[side]()\n\n\nif __name__ == \"__main__\":\n    again = True\n    while again:\n        play_game()\n        again = input(\"ANOTHER MISSION? (Y OR N): \").upper() == \"Y\"\n"
  },
  {
    "path": "12_Bombs_Away/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "12_Bombs_Away/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "12_Bombs_Away/rust/src/main.rs",
    "content": "use std::{\n    io::{self, Write},\n    str::FromStr,\n};\n\nuse rand::Rng;\n\nstruct Italy;\nstruct Allies;\nstruct Japan;\nstruct Germany;\n\n#[derive(Debug, PartialEq, Eq)]\nstruct ParseChoiceTargetError;\n\n#[derive(PartialEq)]\nenum ThreeTarget {\n    One,\n    Two,\n    Three,\n}\n\nimpl FromStr for ThreeTarget {\n    type Err = ParseChoiceTargetError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let n = s.parse::<u8>().map_err(|_| ParseChoiceTargetError)?;\n        match n {\n            1 => Ok(Self::One),\n            2 => Ok(Self::Two),\n            3 => Ok(Self::Three),\n            _ => Err(ParseChoiceTargetError),\n        }\n    }\n}\n\nenum FourTarget {\n    One,\n    Two,\n    Three,\n    Four,\n}\n\nimpl FromStr for FourTarget {\n    type Err = ParseChoiceTargetError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let n = s.parse::<u8>().map_err(|_| ParseChoiceTargetError)?;\n        match n {\n            1 => Ok(Self::One),\n            2 => Ok(Self::Two),\n            3 => Ok(Self::Three),\n            4 => Ok(Self::Four),\n            _ => Err(ParseChoiceTargetError),\n        }\n    }\n}\n\npub trait Brefing {\n    type TargetOption;\n    fn prompt<'a>(&self) -> &'a str;\n    fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str;\n}\n\nimpl Brefing for Italy {\n    type TargetOption = ThreeTarget;\n\n    fn prompt<'a>(&self) -> &'a str {\n        \"YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)\"\n    }\n\n    fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str {\n        match target {\n            ThreeTarget::One => \"SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.\",\n            ThreeTarget::Two => \"BE CAREFUL!!!\",\n            ThreeTarget::Three => \"YOU'RE GOING FOR THE OIL, EH?\",\n        }\n    }\n}\n\nimpl Brefing for Allies {\n    type TargetOption = FourTarget;\n\n    fn prompt<'a>(&self) -> &'a str {\n        \"AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): \"\n    }\n\n    fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str {\n        match target {\n            FourTarget::One => \"YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.\",\n            FourTarget::Two => \"YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.\",\n            FourTarget::Three => \"YOU'RE CHASING THE BISMARK IN THE NORTH SEA.\",\n            FourTarget::Four => \"YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.\",\n        }\n    }\n}\n\nimpl Brefing for Germany {\n    type TargetOption = ThreeTarget;\n\n    fn prompt<'a>(&self) -> &'a str {\n        \"A NAZI, EH?  OH WELL.  ARE YOU GOING FOR RUSSIA(1),\\nENGLAND(2), OR FRANCE(3)? \"\n    }\n\n    fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str {\n        match target {\n            ThreeTarget::One => \"YOU'RE NEARING STALINGRAD.\",\n            ThreeTarget::Two => \"NEARING LONDON.  BE CAREFUL, THEY'VE GOT RADAR.\",\n            ThreeTarget::Three => \"NEARING VERSAILLES.  DUCK SOUP.  THEY'RE NEARLY DEFENSELESS.\",\n        }\n    }\n}\n\nenum Side {\n    Italy(Italy),\n    Allies(Allies),\n    Japan(Japan),\n    Germany(Germany),\n}\n\nimpl From<FourTarget> for Side {\n    fn from(value: FourTarget) -> Self {\n        match value {\n            FourTarget::One => Self::Italy(Italy),\n            FourTarget::Two => Self::Allies(Allies),\n            FourTarget::Three => Self::Japan(Japan),\n            FourTarget::Four => Self::Germany(Germany),\n        }\n    }\n}\n\nfn stdin_choice<C: FromStr>(prompt: &str) -> C {\n    let mut buffer = String::new();\n\n    print!(\"{prompt}\");\n    io::stdout().flush().unwrap();\n    io::stdin().read_line(&mut buffer).unwrap();\n    loop {\n        if let Ok(choice) = buffer.trim().parse::<C>() {\n            return choice;\n        }\n        print!(\"TRY AGAIN...\");\n        io::stdout().flush().unwrap();\n        io::stdin().read_line(&mut buffer).unwrap();\n    }\n}\n\nfn stdin_y_or_n(prompt: &str) -> bool {\n    let mut buffer = String::new();\n\n    print!(\"{prompt}\");\n    io::stdout().flush().unwrap();\n    io::stdin().read_line(&mut buffer).unwrap();\n    buffer.trim().to_uppercase() == \"Y\"\n}\n\nfn commence_non_kamikazi_attack() {\n    let nmissions = loop {\n        let nmissions = stdin_choice::<i32>(\"HOW MANY MISSIONS HAVE YOU FLOWN? \");\n        if nmissions < 160 {\n            break nmissions;\n        }\n        println!(\"MISSIONS, NOT MILES...\");\n        println!(\"150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS\");\n        print!(\"NOW THEN, \");\n    };\n\n    if nmissions >= 100 {\n        println!(\"THAT'S PUSHING THE ODDS!\");\n    }\n\n    if nmissions < 25 {\n        println!(\"FRESH OUT OF TRAINING, EH?\");\n    }\n\n    println!();\n\n    let mut rng = rand::thread_rng();\n    let y: f32 = rng.gen();\n\n    if nmissions as f32 >= 160_f32 * y {\n        mission_success();\n    } else {\n        mission_failure();\n    }\n}\n\nfn play_japan() {\n    if !stdin_y_or_n(\"YOUR FIRST KAMIKAZE MISSION? (Y OR N): \") {\n        player_death();\n        return;\n    }\n\n    let mut rng = rand::thread_rng();\n    let y: f32 = rng.gen();\n    if y > 0.65 {\n        mission_success();\n    } else {\n        player_death();\n    }\n}\n\nfn player_death() {\n    println!(\"* * * * BOOM * * * *\");\n    println!(\"YOU HAVE BEEN SHOT DOWN.....\");\n    println!(\"DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR\");\n    println!(\"LAST TRIBUTE...\");\n}\n\nfn mission_success() {\n    let mut rng = rand::thread_rng();\n    let y: f32 = rng.gen();\n\n    let killed = (100f32 * y) as i32;\n    println!(\"DIRECT HIT!!!! {killed} KILLED.\");\n    println!(\"MISSION SUCCESSFUL.\");\n}\n\nfn mission_failure() {\n    let mut rng = rand::thread_rng();\n    let y: f32 = rng.gen();\n    let miles = 2 + (30f32 * y) as i32;\n    println!(\"MISSED TARGET BY {miles} MILES!\");\n    println!(\"NOW YOU'RE REALLY IN FOR IT !!\");\n    println!();\n    let enemy_weapons =\n        stdin_choice::<ThreeTarget>(\"DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? \");\n\n    let enemy_gunner_accuracy = if enemy_weapons != ThreeTarget::Two {\n        let m = loop {\n            let m =\n                stdin_choice::<i32>(\"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? \");\n            if m <= 50 {\n                break m;\n            }\n            println!(\"TRY AGAIN...\");\n        };\n        if m < 10 {\n            println!(\"YOU LIE, BUT YOU'LL PAY...\");\n            player_death();\n            return;\n        }\n        m\n    } else {\n        0\n    };\n\n    let missile_threat_weighting = if enemy_weapons == ThreeTarget::One {\n        0\n    } else {\n        35\n    };\n\n    let death =\n        death_with_chance((enemy_gunner_accuracy + missile_threat_weighting) as f32 / 100f32);\n\n    if death {\n        player_death();\n    } else {\n        player_survived();\n    }\n}\n\nfn player_survived() {\n    println!(\"YOU MADE IT THROUGH TREMENDOUS FLAK!!\");\n}\n\nfn death_with_chance(p_death: f32) -> bool {\n    let mut rng = rand::thread_rng();\n    let y: f32 = rng.gen();\n    p_death > y\n}\n\nfn main() {\n    loop {\n        println!(\"YOU ARE A PILOT IN A WORLD WAR II BOMBER.\");\n        let side: Side =\n            stdin_choice::<FourTarget>(\"WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): \")\n                .into();\n\n        match side {\n            Side::Japan(_) => {\n                println!(\"YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\");\n            }\n            Side::Italy(ref s) => {\n                let target = stdin_choice(s.prompt());\n                println!(\"{}\", s.targets_to_messages(target));\n            }\n            Side::Allies(ref s) => {\n                let target = stdin_choice(s.prompt());\n                println!(\"{}\", s.targets_to_messages(target));\n            }\n            Side::Germany(ref s) => {\n                let target = stdin_choice(s.prompt());\n                println!(\"{}\", s.targets_to_messages(target));\n            }\n        }\n\n        match side {\n            Side::Japan(_) => play_japan(),\n            _ => commence_non_kamikazi_attack(),\n        }\n\n        println!();\n        if !stdin_y_or_n(\"ANOTHER MISSION? (Y OR N): \") {\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "12_Bombs_Away/vbnet/BombsAway.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"BombsAway\", \"BombsAway.vbproj\", \"{7FB28848-EC1C-4594-B823-BA6DB06B34A8}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7FB28848-EC1C-4594-B823-BA6DB06B34A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7FB28848-EC1C-4594-B823-BA6DB06B34A8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7FB28848-EC1C-4594-B823-BA6DB06B34A8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7FB28848-EC1C-4594-B823-BA6DB06B34A8}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "12_Bombs_Away/vbnet/BombsAway.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>BombsAway</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "12_Bombs_Away/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "13_Bounce/README.md",
    "content": "### Bounce\n\nThis program plots a bouncing ball. Most computer plots run along the paper in the terminal (top to bottom); however, this plot is drawn horizontally on the paper (left to right).\n\nYou may specify the initial velocity of the ball and the coefficient of elasticity of the ball (a superball is about 0.85 — other balls are much less). You also specify the time increment to be used in “strobing” the flight of the ball. In other words, it is as though the ball is thrown up in a darkened room and you flash a light at fixed time intervals and photograph the progress of the ball.\n\nThe program was originally written by Val Skalabrin while he was at DEC.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=25)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=40)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "13_Bounce/bounce.bas",
    "content": "10 PRINT TAB(33);\"BOUNCE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n90 DIM T(20)\n100 PRINT \"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\"\n110 PRINT \"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\"\n120 PRINT \"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\"\n130 PRINT \"COEFFICIENCY (LESS THAN 1).\"\n131 PRINT\n132 PRINT \"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\"\n133 PRINT \"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\"\n134 PRINT\n135 INPUT \"TIME INCREMENT (SEC)\";S2\n140 PRINT\n150 INPUT \"VELOCITY (FPS)\";V\n160 PRINT\n170 INPUT \"COEFFICIENT\";C\n180 PRINT\n182 PRINT \"FEET\"\n184 PRINT\n186 S1=INT(70/(V/(16*S2)))\n190 FOR I=1 TO S1\n200 T(I)=V*C^(I-1)/16\n210 NEXT I\n220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5\n221 IF INT(H)<>H THEN 225\n222 PRINT H;\n225 L=0\n230 FOR I=1 TO S1\n240 FOR T=0 TO T(I) STEP S2\n245 L=L+S2\n250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270\n260 PRINT TAB(L/S2);\"0\";\n270 NEXT T\n275 T=T(I+1)/2\n276 IF -16*T^2+V*C^(I-1)*T<H THEN 290\n280 NEXT I\n290 PRINT\n300 NEXT H\n310 PRINT TAB(1);\n320 FOR I=1 TO INT(L+1)/S2+1\n330 PRINT \".\";\n340 NEXT I\n350 PRINT\n355 PRINT \" 0\";\n360 FOR I=1 TO INT(L+.9995)\n380 PRINT TAB(INT(I/S2));I;\n390 NEXT I\n400 PRINT\n410 PRINT TAB(INT(L+1)/(2*S2)-2);\"SECONDS\"\n420 PRINT\n430 GOTO 135\n440 END\n"
  },
  {
    "path": "13_Bounce/csharp/Bounce.cs",
    "content": "namespace Bounce;\n\n/// <summary>\n/// Represents the bounce of the ball, calculating duration, height and position in time.\n/// </summary>\n/// <remarks>\n/// All calculations are derived from the equation for projectile motion: s = vt + 0.5at^2\n/// </remarks>\ninternal class Bounce\n{\n    private const float _acceleration = -32; // feet/s^2\n\n    private readonly float _velocity;\n\n    internal Bounce(float velocity)\n    {\n        _velocity = velocity;\n    }\n\n    public float Duration => -2 * _velocity / _acceleration;\n\n    public float MaxHeight =>\n        (float)Math.Round(-_velocity * _velocity / 2 / _acceleration, MidpointRounding.AwayFromZero);\n\n    public float Plot(Graph graph, float startTime)\n    {\n        var time = 0f;\n        for (; time <= Duration; time += graph.TimeIncrement)\n        {\n            var height = _velocity * time + _acceleration * time * time / 2;\n            graph.Plot(startTime + time, height);\n        }\n\n        return startTime + time;\n    }\n\n    public Bounce Next(float elasticity) => new Bounce(_velocity * elasticity);\n}\n"
  },
  {
    "path": "13_Bounce/csharp/Bounce.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources\\*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "13_Bounce/csharp/Bounce.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bounce\", \"Bounce.csproj\", \"{4A967985-8CB0-49D2-B322-B2668491CA6E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4A967985-8CB0-49D2-B322-B2668491CA6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4A967985-8CB0-49D2-B322-B2668491CA6E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4A967985-8CB0-49D2-B322-B2668491CA6E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4A967985-8CB0-49D2-B322-B2668491CA6E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "13_Bounce/csharp/Game.cs",
    "content": "using static Bounce.Resources.Resource;\n\nnamespace Bounce;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n\n    public Game(IReadWrite io)\n    {\n        _io = io;\n    }\n\n    public void Play(Func<bool> playAgain)\n    {\n        _io.Write(Streams.Title);\n        _io.Write(Streams.Instructions);\n\n        while (playAgain.Invoke())\n        {\n            var timeIncrement = _io.ReadParameter(\"Time increment (sec)\");\n            var velocity = _io.ReadParameter(\"Velocity (fps)\");\n            var elasticity = _io.ReadParameter(\"Coefficient\");\n\n            var bounce = new Bounce(velocity);\n            var bounceCount = (int)(Graph.Row.Width * timeIncrement / bounce.Duration);\n            var graph = new Graph(bounce.MaxHeight, timeIncrement);\n\n            var time = 0f;\n            for (var i = 0; i < bounceCount; i++, bounce = bounce.Next(elasticity))\n            {\n                time = bounce.Plot(graph, time);\n            }\n\n            _io.WriteLine(graph);\n        }\n    }\n}\n"
  },
  {
    "path": "13_Bounce/csharp/Graph.cs",
    "content": "using System.Text;\n\nnamespace Bounce;\n\n/// <summary>\n/// Provides support for plotting a graph of height vs time, and rendering it to a string.\n/// </summary>\ninternal class Graph\n{\n    private readonly Dictionary<int, Row> _rows;\n\n    public Graph(float maxHeight, float timeIncrement)\n    {\n        // 1 row == 1/2 foot + 1 row for zero\n        var rowCount = 2 * (int)Math.Round(maxHeight, MidpointRounding.AwayFromZero) + 1;\n        _rows = Enumerable.Range(0, rowCount)\n            .ToDictionary(x => x, x => new Row(x % 2 == 0 ? $\" {x / 2} \" : \"\"));\n        TimeIncrement = timeIncrement;\n    }\n\n    public float TimeIncrement { get; }\n    public float MaxTimePlotted { get; private set; }\n\n    public void Plot(float time, float height)\n    {\n        var rowIndex = (int)Math.Round(height * 2, MidpointRounding.AwayFromZero);\n        var colIndex = (int)(time / TimeIncrement) + 1;\n        if (_rows.TryGetValue(rowIndex, out var row))\n        {\n            row[colIndex] = '0';\n        }\n        MaxTimePlotted = Math.Max(time, MaxTimePlotted);\n    }\n\n    public override string ToString()\n    {\n        var sb = new StringBuilder().AppendLine(\"Feet\").AppendLine();\n        foreach (var (_, row) in _rows.OrderByDescending(x => x.Key))\n        {\n            sb.Append(row).AppendLine();\n        }\n        sb.Append(new Axis(MaxTimePlotted, TimeIncrement));\n\n        return sb.ToString();\n    }\n\n    internal class Row\n    {\n        public const int Width = 70;\n\n        private readonly char[] _chars = new char[Width + 2];\n        private int nextColumn = 0;\n\n        public Row(string label)\n        {\n            Array.Fill(_chars, ' ');\n            Array.Copy(label.ToCharArray(), _chars, label.Length);\n            nextColumn = label.Length;\n        }\n\n        public char this[int column]\n        {\n            set\n            {\n                if (column >= _chars.Length) { return; }\n                if (column < nextColumn) { column = nextColumn; }\n                _chars[column] = value;\n                nextColumn = column + 1;\n            }\n        }\n\n        public override string ToString() => new string(_chars);\n    }\n\n    internal class Axis\n    {\n        private readonly int _maxTimeMark;\n        private readonly float _timeIncrement;\n        private readonly Labels _labels;\n\n        internal Axis(float maxTimePlotted, float timeIncrement)\n        {\n            _maxTimeMark = (int)Math.Ceiling(maxTimePlotted);\n            _timeIncrement = timeIncrement;\n\n            _labels = new Labels();\n            for (var i = 1; i <= _maxTimeMark; i++)\n            {\n                _labels.Add((int)(i / _timeIncrement), $\" {i} \");\n            }\n        }\n\n        public override string ToString()\n            => new StringBuilder()\n                .Append(' ').Append('.', (int)(_maxTimeMark / _timeIncrement) + 1).AppendLine()\n                .Append(_labels).AppendLine()\n                .Append(' ', (int)(_maxTimeMark / _timeIncrement / 2 - 2)).AppendLine(\"Seconds\")\n                .ToString();\n    }\n\n    internal class Labels : Row\n    {\n        public Labels()\n            : base(\" 0\")\n        {\n        }\n\n        public void Add(int column, string label)\n        {\n            for (var i = 0; i < label.Length; i++)\n            {\n                this[column + i] = label[i];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "13_Bounce/csharp/IReadWriteExtensions.cs",
    "content": "namespace Bounce;\n\ninternal static class IReadWriteExtensions\n{\n    internal static float ReadParameter(this IReadWrite io, string parameter)\n    {\n        var value = io.ReadNumber(parameter);\n        io.WriteLine();\n        return value;\n    }\n}"
  },
  {
    "path": "13_Bounce/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Numbers;\n\nusing Bounce;\n\nnew Game(new ConsoleIO()).Play(() => true);"
  },
  {
    "path": "13_Bounce/csharp/README.md",
    "content": "# Bounce\n\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\n## Conversion notes\n\n### Mode of Operation\n\nThis conversion performs the same function as the original, and provides the same experience, but does it in a different\nway.\n\nThe original BASIC code builds the graph as it writes to the screen, scanning each line for points that need to be\nplotted.\n\nThis conversion steps through time, calculating the position of the ball at each instant, building the graph in memory.\nIt then writes the graph to the output in one go.\n\n### Failure Modes\n\nThe original BASIC code performs no validation of the input parameters. Some combinations of parameters produce no\noutput, others crash the program.\n\nIn the spirit of the original this conversion also performs no validation of the parameters, but it does not attempt to\nreplicate the original's failure modes. It fails quite happily in its own way.\n"
  },
  {
    "path": "13_Bounce/csharp/Resources/Instructions.txt",
    "content": "This simulation lets you specify the initial velocity\nof a ball thrown straight up, and the coefficient of\nelasticity of the ball.  Please use a decimal fraction\ncoefficiency (less than 1).\n\nYou also specify the time increment to be used in\n'strobing' the ball's flight (try .1 initially).\n\n"
  },
  {
    "path": "13_Bounce/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Bounce.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Instructions => GetStream();\n        public static Stream Title => GetStream();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null)\n        => Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Bounce.Resources.{name}.txt\")\n            ?? throw new ArgumentException($\"Resource stream {name} does not exist\", nameof(name));\n}"
  },
  {
    "path": "13_Bounce/csharp/Resources/Title.txt",
    "content": "                                 Bounce\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "13_Bounce/java/Bounce.java",
    "content": "import java.util.Scanner;\nimport java.lang.Math;\n\n/**\n * Game of Bounce\n * <p>\n * Based on the BASIC game of Bounce here\n * https://github.com/coding-horror/basic-computer-games/blob/main/13%20Bounce/bounce.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Bounce {\n\n  private final Scanner scan;  // For user input\n\n  public Bounce() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Bounce\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"BOUNCE\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    double coefficient = 0;\n    double height = 0;\n    double timeIncrement = 0;\n    double timeIndex = 0;\n    double timeTotal = 0;\n    double velocity = 0;\n\n    double[] timeData = new double[21];\n\n    int heightInt = 0;\n    int index = 0;\n    int maxData = 0;\n\n    String lineContent = \"\";\n\n    System.out.println(\"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\");\n    System.out.println(\"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\");\n    System.out.println(\"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\");\n    System.out.println(\"COEFFICIENCY (LESS THAN 1).\");\n    System.out.println(\"\");\n    System.out.println(\"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\");\n    System.out.println(\"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\");\n    System.out.println(\"\");\n\n    // Begin outer while loop\n    while (true) {\n\n      System.out.print(\"TIME INCREMENT (SEC)? \");\n      timeIncrement = Double.parseDouble(scan.nextLine());\n      System.out.println(\"\");\n\n      System.out.print(\"VELOCITY (FPS)? \");\n      velocity = Double.parseDouble(scan.nextLine());\n      System.out.println(\"\");\n\n      System.out.print(\"COEFFICIENT? \");\n      coefficient = Double.parseDouble(scan.nextLine());\n      System.out.println(\"\");\n\n      System.out.println(\"FEET\");\n      System.out.println(\"\");\n\n      maxData = (int)(70 / (velocity / (16 * timeIncrement)));\n\n      for (index = 1; index <= maxData; index++) {\n        timeData[index] = velocity * Math.pow(coefficient, index - 1) / 16;\n      }\n\n      // Begin loop through all rows of y-axis data\n      for (heightInt = (int)(-16 * Math.pow(velocity / 32, 2) + Math.pow(velocity, 2) / 32 + 0.5) * 10;\n           heightInt >= 0; heightInt -= 5) {\n\n        height = heightInt / 10.0;\n\n        lineContent = \"\";\n\n        if ((int)(Math.floor(height)) == height) {\n\n          lineContent += \" \" + (int)(height) + \" \";\n        }\n\n        timeTotal = 0;\n\n        for (index = 1; index <= maxData; index++) {\n\n          for (timeIndex = 0; timeIndex <= timeData[index]; timeIndex += timeIncrement) {\n\n            timeTotal += timeIncrement;\n\n            if (Math.abs(height - (0.5 * (-32) * Math.pow(timeIndex, 2) + velocity\n                * Math.pow(coefficient, index - 1) * timeIndex)) <= 0.25) {\n\n              while (lineContent.length() < (timeTotal / timeIncrement) - 1) {\n                lineContent += \" \";\n              }\n              lineContent += \"0\";\n            }\n          }\n\n          timeIndex = timeData[index + 1] / 2;\n\n          if (-16 * Math.pow(timeIndex, 2) + velocity * Math.pow(coefficient, index - 1) * timeIndex < height) {\n\n            break;\n          }\n        }\n\n        System.out.println(lineContent);\n\n      }  // End loop through all rows of y-axis data\n\n      lineContent = \"\";\n\n      // Show the x-axis\n      for (index = 1; index <= (int)(timeTotal + 1) / timeIncrement + 1; index++) {\n\n        lineContent += \".\";\n      }\n\n      System.out.println(lineContent);\n\n      lineContent = \" 0\";\n\n      for (index = 1; index <= (int)(timeTotal + 0.9995); index++) {\n\n        while (lineContent.length() < (int)(index / timeIncrement)) {\n          lineContent += \" \";\n        }\n        lineContent += index;\n      }\n\n      System.out.println(lineContent);\n\n      System.out.println(\" \".repeat((int)((timeTotal + 1) / (2 * timeIncrement) - 3)) + \"SECONDS\");\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    Bounce game = new Bounce();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class Bounce\n"
  },
  {
    "path": "13_Bounce/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "13_Bounce/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "13_Bounce/javascript/bounce.html",
    "content": "<html>\n<head>\n<title>BOUNCE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bounce.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "13_Bounce/javascript/bounce.js",
    "content": "// BOUNCE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"BOUNCE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    ta = [];\n    print(\"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\\n\");\n    print(\"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\\n\");\n    print(\"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\\n\");\n    print(\"COEFFICIENCY (LESS THAN 1).\\n\");\n    print(\"\\n\");\n    print(\"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\\n\");\n    print(\"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"TIME INCREMENT (SEC)\");\n        s2 = parseFloat(await input());\n        print(\"\\n\");\n        print(\"VELOCITY (FPS)\");\n        v = parseFloat(await input());\n        print(\"\\n\");\n        print(\"COEFFICIENT\");\n        c = parseFloat(await input());\n        print(\"\\n\");\n        print(\"FEET\\n\");\n        print(\"\\n\");\n        s1 = Math.floor(70 / (v / (16 * s2)));\n        for (i = 1; i <= s1; i++)\n            ta[i] = v * Math.pow(c, i - 1) / 16;\n        for (h = Math.floor(-16 * Math.pow(v / 32, 2) + Math.pow(v, 2) / 32 + 0.5); h >= 0; h -= 0.5) {\n            str = \"\";\n            if (Math.floor(h) == h)\n                str += \" \" + h + \" \";\n            l = 0;\n            for (i = 1; i <= s1; i++) {\n                for (t = 0; t <= ta[i]; t += s2) {\n                    l += s2;\n                    if (Math.abs(h - (0.5 * (-32) * Math.pow(t, 2) + v * Math.pow(c, i - 1) * t)) <= 0.25) {\n                        while (str.length < l / s2)\n                            str += \" \";\n                        str += \"0\";\n                    }\n                }\n                t = ta[i + 1] / 2;\n                if (-16 * Math.pow(t, 2) + v * Math.pow(c, i - 1) * t < h)\n                    break;\n            }\n            print(str + \"\\n\");\n        }\n        str = \" \";\n        for (i = 1; i < Math.floor(l + 1) / s2 + 1; i++)\n            str += \".\";\n        print(str + \"\\n\");\n        str = \" 0\";\n        for (i = 1; i < Math.floor(l + 0.9995); i++) {\n            while (str.length < Math.floor(i / s2))\n                str += \" \";\n            str += i;\n        }\n        print(str + \"\\n\");\n        print(tab(Math.floor(l + 1) / (2 * s2) - 2) + \"SECONDS\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "13_Bounce/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "13_Bounce/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "13_Bounce/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nAdded feature so that if \"TIME\" value is \"0\" then it will quit,\nso you don't have to hit Control-C. Also added a little error checking of the input.\n"
  },
  {
    "path": "13_Bounce/perl/bounce.pl",
    "content": "#!/usr/bin/perl\n\n# Bounce program in Perl\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\nprint \"\\n\";\nprint \" \" x 31,\"BOUNCE\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\\n\";\nprint \"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\\n\";\nprint \"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\\n\";\nprint \"COEFFICIENCY (LESS THAN 1).\\n\\n\";\nprint \"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\\n\";\nprint \"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\\n\\n\";\n\n# deal with basic's tab() for line positioning\n#   line = line string we're starting with\n#   pos = position to start writing\n#   s = string to write\n# returns the resultant string, which might not have been changed\nsub line_tab\n{\n    my ($line, $pos, $s) = @_;\n    my $len = length($line);\n    # if curser is past position, do nothing\n    if ($len <= $pos) { $line .= \" \" x ($pos - $len) . $s; }\n    return $line;\n}\n\nwhile (1)\n{\n    my @T;          # time slice?\n    my $time_inc;   # time increment, probably in fractions of seconds\n    my $velocity;   # velocity in feet/sec\n    my $coeff_elas; # coeeficent of elasticity\n    my $line_pos;   # position on line\n    my $S1          # duration in full seconds?\n\n    # get input\n    print \"TIME INCREMENT (SEC, 0=QUIT): \"; chomp($time_inc = <>);\n    last if ($time_inc == 0);\n    print \"VELOCITY (FPS): \"; chomp($velocity = <>);\n    print \"COEFFICIENT: \"; chomp($coeff_elas = <>);\n    if ($coeff_elas >= 1.0 || $coeff_elas <= 0)\n    {\n        print \"COEFFICIENT MUST BE > 0 AND < 1.0\\n\\n\\n\";\n        next;\n    }\n\n    print \"\\nFEET\\n\";\n    $S1 = int(70.0 / ($velocity / (16.0 * $time_inc)));\n    for my $i (1 .. $S1)\n    {\n        $T[$i] = $velocity * $coeff_elas ** ($i - 1) / 16.0;\n    }\n\n    # draw graph\n    for (my $height=int(-16.0 * ($velocity / 32.0) ** 2.0 + $velocity ** 2.0 / 32.0 + .5) ; $height >= 0 ; $height -= .5)\n    {\n        if (int($height) == $height) { print sprintf(\"%2d\", $height); }\n        else                         { print \"  \"; }\n        $line_pos = 0;\n        my $curr_line = \"\";\n        for my $i (1 .. $S1)\n        {\n            my $time;\n            for ($time=0 ; $time <= $T[$i] ; $time += $time_inc)\n            {\n                $line_pos += $time_inc;\n                if (abs($height - (.5 * (-32) * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time)) <= .25)\n                {\n                    $curr_line = line_tab($curr_line, ($line_pos / $time_inc), \"0\");\n                }\n            }\n            $time = ($T[$i + 1] // 0) / 2; # we can reach 1 past the end, use 0 if that happens\n            last if (-16.0 * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time < $height);\n        }\n        print \"$curr_line\\n\";\n    }\n\n    # draw scale\n    print \"  .\";\n    print \".\" x (int($line_pos + 1) / $time_inc + 1), \"\\n\";\n    print \"  0\";\n    my $curr_line = \"\";\n    for my $i (1 .. int($line_pos + .9995))\n    {\n        $curr_line = line_tab($curr_line, int($i / $time_inc), $i);\n    }\n    print \"$curr_line\\n\";\n    print \" \" x (int($line_pos + 1) / (2 * $time_inc) - 2), \"SECONDS\\n\\n\";\n}\n"
  },
  {
    "path": "13_Bounce/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "13_Bounce/python/bounce.py",
    "content": "\"\"\"\nBOUNCE\n\nA physics simulation\n\nPorted by Dave LeCompte\n\"\"\"\n\nfrom typing import Tuple, List\n\nPAGE_WIDTH = 64\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n\ndef print_instructions() -> None:\n    print(\"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\")\n    print(\"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\")\n    print(\"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\")\n    print(\"COEFFICIENCY (LESS THAN 1).\")\n    print()\n    print(\"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\")\n    print(\"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\")\n    print()\n\n\ndef get_initial_conditions() -> Tuple[float, float, float]:\n    delta_t = float(input(\"TIME INCREMENT (SEC)? \"))\n    print()\n    v0 = float(input(\"VELOCITY (FPS)? \"))\n    print()\n    coeff_rest = float(input(\"COEFFICIENT? \"))\n    print()\n\n    return delta_t, v0, coeff_rest\n\n\ndef print_at_tab(line: str, tab: int, s: str) -> str:\n    line += (\" \" * (tab - len(line))) + s\n    return line\n\n\ndef run_simulation(delta_t: float, v0: float, coeff_rest: float) -> None:\n    bounce_time: List[float] = [0] * 20  # time of each bounce\n\n    print(\"FEET\")\n    print()\n\n    sim_dur = int(70 / (v0 / (16 * delta_t)))\n    for i in range(1, sim_dur + 1):\n        bounce_time[i] = v0 * coeff_rest ** (i - 1) / 16\n\n    # Draw the trajectory of the bouncing ball, one slice of height at a time\n    h: float = int(-16 * (v0 / 32) ** 2 + v0**2 / 32 + 0.5)\n    while h >= 0:\n        line = \"\"\n        if int(h) == h:\n            line += str(int(h))\n        total_time: float = 0\n        for i in range(1, sim_dur + 1):\n            tm: float = 0\n            while tm <= bounce_time[i]:\n                total_time += delta_t\n                if (\n                    abs(h - (0.5 * (-32) * tm**2 + v0 * coeff_rest ** (i - 1) * tm))\n                    <= 0.25\n                ):\n                    line = print_at_tab(line, int(total_time / delta_t), \"0\")\n                tm += delta_t\n            tm = bounce_time[i + 1] / 2\n\n            if -16 * tm**2 + v0 * coeff_rest ** (i - 1) * tm < h:\n                break\n        print(line)\n        h -= 0.5\n\n    print(\".\" * (int((total_time + 1) / delta_t) + 1))\n    print\n    line = \" 0\"\n    for i in range(1, int(total_time + 0.9995) + 1):\n        line = print_at_tab(line, int(i / delta_t), str(i))\n    print(line)\n    print()\n    print(print_at_tab(\"\", int((total_time + 1) / (2 * delta_t) - 2), \"SECONDS\"))\n    print()\n\n\ndef main() -> None:\n    print_header(\"BOUNCE\")\n    print_instructions()\n\n    while True:\n        delta_t, v0, coeff_rest = get_initial_conditions()\n\n        run_simulation(delta_t, v0, coeff_rest)\n        break\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "13_Bounce/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "13_Bounce/ruby/bounce.rb",
    "content": "## Global constants\r\n\r\n# Gravity accelaration (F/S^2) ~= 32\r\nG = 32\r\n\r\n# Used to indent the plotting of ball positions\r\n# so that the height digits don't affect\r\n# where we start plotting ball positions\r\nBALL_PLOT_INDENT = \"\\t\"\r\n\r\n# The deviation between current plotted height and the actual\r\n# height of the ball that we will accept to plot the ball in\r\n# that plotted height\r\nBALL_PLOT_DEVIATION = 0.25\r\n\r\n# The step we will take as we move down vertically while\r\n# plotting ball positions\r\nBALL_PLOT_HEIGHT_STEP = 0.5\r\n\r\n\r\n## Helper functions\r\n\r\n# Calculates the bounce speed (up) of the ball for a given\r\n# bounce number and coefficient\r\ndef calc_velocity_for_bounce(v0, bounce, coefficient)\r\n    v = v0 * coefficient**bounce\r\nend\r\n\r\n# Check https://physics.stackexchange.com/a/333436 for nice explanation\r\ndef calc_bounce_total_time(v0, bounce, coefficient)\r\n    v = calc_velocity_for_bounce(v0, bounce, coefficient)\r\n    t = 2 * v / G\r\nend\r\n\r\n# Check https://physics.stackexchange.com/a/333436 for nice explanation\r\ndef calc_ball_height(v0, bounce, coefficient, t)\r\n    v = calc_velocity_for_bounce(v0, bounce, coefficient)\r\n    h = v * t - 0.5 * G * t**2\r\nend\r\n\r\ndef heighest_position_in_next_bounce(time_in_bounce, v0, i, c)\r\n    time_in_next_bounce = time_in_bounce[i+1]\r\n    return -1 if time_in_next_bounce.nil?\r\n    return calc_ball_height(v0, i, c, time_in_next_bounce / 2) unless time_in_next_bounce.nil?\r\nend\r\n\r\ndef intro\r\n    puts <<~INSTRUCTIONS\r\n                    BOUNCE\r\n    CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\r\n\r\n\r\n    THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\r\n    OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\r\n    ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\r\n    COEFFICIENCY (LESS THAN 1).\r\n\r\n    YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\r\n    'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\r\n    INSTRUCTIONS\r\nend\r\n\r\n\r\n## Plottin functions\r\n\r\ndef plot_header\r\n    puts\r\n    puts \"FEET\"\r\nend\r\n\r\ndef plot_bouncing_ball(strobbing_time, v0, c)\r\n    ## Initializing helper values\r\n\r\n    # How many bounces we want to plot\r\n    # original BASIC version is 70 / (V / (16 * S2))\r\n    # 70 is assumed to be an arbitrary number higher than 2G and 16 is 1/2G\r\n    bounces_to_plot = (G**2 / (v0 / strobbing_time)).to_i\r\n\r\n    # Holds the total time the ball spends in the air in every bounce\r\n    time_in_bounce = bounces_to_plot.times.map { |i| calc_bounce_total_time v0, i, c }\r\n\r\n    plot_width = 0\r\n\r\n    # Calculate the highest position for the ball after the very first bounce\r\n    plotted_height = (calc_ball_height(v0, 0, c, v0/G) + 0.5).to_i\r\n\r\n    ## Plotting bouncing ball\r\n    while plotted_height >= 0 do\r\n        # We will print only whole-number heights\r\n        print plotted_height.to_i if plotted_height.to_i === plotted_height\r\n\r\n        print BALL_PLOT_INDENT\r\n\r\n        bounces_to_plot.times { |i|\r\n            (0..time_in_bounce[i]).step(strobbing_time) { |t|\r\n                ball_pos = calc_ball_height v0, i, c, t\r\n\r\n                # If the ball is within the acceptable deviation\r\n                # from the current height, we will plot it\r\n                if (plotted_height - ball_pos).abs <= BALL_PLOT_DEVIATION then\r\n                    print \"0\"\r\n                else\r\n                    print \" \"\r\n                end\r\n\r\n                # Increment the plot width when we are plotting height = 0\r\n                # which will definitely be the longest since it never gets\r\n                # skipped by line 98\r\n                plot_width += 1 if plotted_height == 0\r\n            }\r\n\r\n            if heighest_position_in_next_bounce(time_in_bounce, v0, i, c) < plotted_height then\r\n                # If we got no more ball positions at or above current height in the next bounce,\r\n                # we can skip the rest of the bounces and move down to the next height to plot\r\n                puts\r\n                break\r\n            end\r\n        }\r\n\r\n        plotted_height -= BALL_PLOT_HEIGHT_STEP\r\n    end\r\n\r\n    # Return plot_width to be used by the plot_footer\r\n    plot_width\r\nend\r\n\r\ndef plot_footer (plot_width, strobbing_time)\r\n    # Dotted separator line\r\n    puts\r\n    print BALL_PLOT_INDENT\r\n    (plot_width).times { |_| print \".\" }\r\n    puts\r\n\r\n    # Time values line\r\n    print BALL_PLOT_INDENT\r\n    points_in_sec = (1 / strobbing_time).to_i\r\n    plot_width.times { |i|\r\n        if i % points_in_sec == 0 then\r\n            print (i / points_in_sec).to_i\r\n        else\r\n            print \" \"\r\n        end\r\n    }\r\n    puts\r\n\r\n    # Time unit line\r\n    print BALL_PLOT_INDENT\r\n    (plot_width / 2 - 4).to_i.times { |_| print \" \" }\r\n    puts \"SECONDS\"\r\n    puts\r\nend\r\n\r\ndef game_loop\r\n    # Read strobing, velocity and coefficient parameters from user input\r\n    puts \"TIME INCREMENT (SEC)\"\r\n    strobbing_time = gets.to_f\r\n\r\n    puts \"VELOCITY (FPS)\"\r\n    v0 = gets.to_f\r\n\r\n    puts \"COEFFICIENT\"\r\n    c = gets.to_f\r\n\r\n    # Plotting\r\n    plot_header\r\n\r\n    plot_width = plot_bouncing_ball strobbing_time, v0, c\r\n\r\n    plot_footer plot_width, strobbing_time\r\nend\r\n\r\n\r\n## Entry point\r\n\r\nbegin\r\n    intro\r\n    loop do\r\n        game_loop\r\n    end\r\nrescue SystemExit, Interrupt\r\n    exit\r\nrescue => exception\r\n   p exception\r\nend\r\n"
  },
  {
    "path": "13_Bounce/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n"
  },
  {
    "path": "13_Bounce/rust/src/main.rs",
    "content": "/** BOUNCE GAME \n * https://github.com/coding-horror/basic-computer-games/blob/main/13_Bounce/bounce.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 03/03/25\n*/\n\nuse std::io::Write;\n\nfn input(msg: &str) -> String {\n    print!(\"{}\", msg);\n    let _ =std::io::stdout().flush().unwrap();\n    let mut input = String::new();\n    std::io::stdin().read_line(&mut input).unwrap();\n    return input.trim().to_uppercase();\n}\n\nfn main() {\n    //10 PRINT TAB(33);\"BOUNCE\"\n    //20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    //30 PRINT:PRINT:PRINT\n    print!(\"{}{}\\n{}{}\\n\\n\\n\",\n        \" \".repeat(33),\n        \"BOUNCE\",\n        \" \".repeat(15),\n        \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n\n    //90 DIM T(20)\n    let mut t: Vec<f32> = Vec::with_capacity(20);\n    \n    //100 PRINT \"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\"\n    //110 PRINT \"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\"\n    //120 PRINT \"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\"\n    //130 PRINT \"COEFFICIENCY (LESS THAN 1).\"\n    //131 PRINT\n    //132 PRINT \"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\"\n    //133 PRINT \"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\"\n    //134 PRINT\n    print!(\"{}\\n{}\\n{}\\n{}\\n\\n{}\\n{}\\n\\n\",\n        \"THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\",\n        \"OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\",\n        \"ELASTICITY OF THE BALL.  PLEASE USE A DECIMAL FRACTION\",\n        \"COEFFICIENCY (LESS THAN 1).\",\n        \"YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\",\n        \"'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\",\n    );\n\n    loop {\n       //135 INPUT \"TIME INCREMENT (SEC)\";S2\n        let s2 = input(\"TIME INCREMENT (SEC): \").parse::<f32>().unwrap();\n        //let s2 = 0.2f32;\n\n        //140 PRINT\n        println!();\n        \n        //150 INPUT \"VELOCITY (FPS)\";V\n        let v = input(\"VELOCITY (FPS): \").parse::<f32>().unwrap();\n        //let v = 20.0f32;\n\n        //160 PRINT\n        println!();\n\n        //170 INPUT \"COEFFICIENT\";C\n        let c = input(\"COEFFICIENT: \").parse::<f32>().unwrap();\n        //let c = 0.6f32;\n\n        //180 PRINT\n        //182 PRINT \"FEET\"\n        //184 PRINT\n        print!(\"\\nFEET\\n\\n\");\n\n        //186 S1=INT(70/(V/(16*S2))) // verified\n        let s1 = (70.0 / (v/(16.0*s2))) as i32;\n\n        //190 FOR I=1 TO S1\n        for i in 1..=s1 {\n            //200 T(I)=V*C^(I-1)/16\n            t.push(v * c.powf(i as f32 - 1.0) / 16.0); // verified\n            //210 NEXT I\n        }\n\n        let mut l = 0.0;\n\n        //220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5\n        let mut h = (-16.0 * (v / 32.0).powi(2) + (v.powi(2)) / 32.0 + 0.5).floor();\n        while h >= 0.0 {\n            let mut line_content = String::new();\n            //221 IF INT(H)<>H THEN 225\n            if h.floor() == h {\n                //222 PRINT H;\n                line_content.push_str(h.to_string().as_str());\n                line_content.push(' ');\n            }\n            //225 L=0\n            l = 0.0;\n            //230 FOR I=1 TO S1\n            for i in 1..=s1 {\n                let mut t_val = 0.0;\n                //240 FOR T=0 TO T(I) STEP S2\n                while t_val <= t[(i - 1) as usize] {\n                    //245 L=L+S2\n                    l = l + s2;\n                    \n                    //250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270\n                    let condition = h - (0.5 * (-32.0) * t_val.powf(2.0) + v * c.powf((i-1) as f32) * t_val);\n                    if condition.abs() >= 0.25{\n                        t_val = t_val + s2;\n                        continue;\n                    }\n                    // TABS ARE NOT SPACES, BUT A TERMINAL POSITION\n                    //260 PRINT TAB(L/S2);\"0\";\n                    let spaces = ((l / s2) - 1.0) as usize;\n                    while line_content.len() < spaces  {\n                        line_content.push(' ');\n                    }\n                    line_content.push('0');\n                   \n                    //270 NEXT T\n                    t_val = t_val + s2;\n                }\n                \n                //275 T=T(I+1)/2\n                if i as usize == t.len() { break; }\n                t_val = t[i as usize] / 2.0;\n\n                //276 IF -16*T^2+V*C^(I-1)*T<H THEN 290\n                if -16.0 * t_val.powf(2.0) + v * c.powf(i as f32 -1.0) * t_val <= h {\n                    break;\n                }\n\n                //280 NEXT I\n            }\n            print!(\"{}\", line_content);\n            //290 PRINT\n            println!();\n\n            //300 NEXT H\n            h = h - 0.5;\n        }\n\n        let mut line_content = String::from(\"\");\n\n        //310 PRINT TAB(1);\n        print!(\" \");\n\n        //320 FOR I=1 TO INT(L+1)/S2+1\n        for _ in 1..=((l+1.0) / s2 + 1.0) as i32 {\n            //330 PRINT \".\";\n            line_content.push('.');\n            //340 NEXT I\n        }\n\n        //350 PRINT\n        //355 PRINT \" 0\";\n        println!(\"{}\", line_content);\n\n        line_content = String::from(\" 0\");\n        \n        //360 FOR I=1 TO INT(L+.9995)\n        for i in 1..=((l + 0.9995) as i32) {\n            //380 PRINT TAB(INT(I/S2));I;\n            while line_content.len() < (i as f32 / s2) as usize {\n            line_content.push(' ');\n            }\n            line_content.push_str(i.to_string().as_str());\n            //390 NEXT I\n        }\n\n        println!(\"{}\", line_content);\n\n        //400 PRINT\n        //410 PRINT TAB(INT(L+1)/(2*S2)-2);\"SECONDS\"\n        //420 PRINT\n        let tabs = ((l+1.0) / (2.0 * s2) - 2.0) as usize;\n        println!(\"{}SECONDS\\n\", \" \".repeat(tabs));\n\n        //430 GOTO 135\n        //break;\n    }\n    //440 END\n}"
  },
  {
    "path": "13_Bounce/vbnet/Bounce.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bounce\", \"Bounce.vbproj\", \"{95D84C53-AE4E-4A5A-869A-A49D6FC89618}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{95D84C53-AE4E-4A5A-869A-A49D6FC89618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{95D84C53-AE4E-4A5A-869A-A49D6FC89618}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{95D84C53-AE4E-4A5A-869A-A49D6FC89618}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{95D84C53-AE4E-4A5A-869A-A49D6FC89618}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "13_Bounce/vbnet/Bounce.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bounce</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "13_Bounce/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "14_Bowling/README.md",
    "content": "### Bowling\n\nThis is a simulated bowling game for up to four players. You play 10 frames. To roll the ball, you simply type “ROLL.” After each roll, the computer will show you a diagram of the remaining pins (“0” means the pin is down, “+” means it is still standing), and it will give you a roll analysis:\n- GUTTER\n- STRIKE\n- SPARE\n- ERROR (on second ball if pins still standing)\n\nBowling was written by Paul Peraino while a student at Woodrow Wilson High School, San Francisco, California.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=26)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=41)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- In the original code, scores is not kept accurately in multiplayer games.  It stores scores in F*P, where F is the frame and P is the player.  So, for example, frame 8 player 1 (index 16) clobbers the score from frame 4 player 2 (also index 16).\n\n- Even when scores are kept accurately, they don't match normal bowling rules.  In this game, the score for each ball is just the total number of pins down after that ball, and the third row of scores is a status indicator (3 for strike, 2 for spare, 1 for anything else).\n\n- The program crashes with a \"NEXT without FOR\" error if you elect to play again after the first game.\n\n#### Porting Notes\n\n- The funny control characters in the \"STRIKE!\" string literal are there to make the terminal beep.\n"
  },
  {
    "path": "14_Bowling/bowling.bas",
    "content": "10 PRINT TAB(34);\"BOWL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n270 DIM C(15),A(100,6)\n360 PRINT \"WELCOME TO THE ALLEY\"\n450 PRINT \"BRING YOUR FRIENDS\"\n540 PRINT \"OKAY LET'S FIRST GET ACQUAINTED\"\n630 PRINT \"\"\n720 PRINT \"THE INSTRUCTIONS (Y/N)\"\n810 INPUT Z$\n900 IF Z$=\"Y\" THEN 990\n960 IF Z$=\"N\" THEN 1530\n990 PRINT \"THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME\"\n1080 PRINT \"THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\"\n1170 PRINT \"OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES\"\n1260 PRINT \"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\"\n1350 PRINT \"PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR\"\n1440 PRINT \"SCORES .\"\n1530 PRINT \"FIRST OF ALL...HOW MANY ARE PLAYING\";\n1620 INPUT R\n1710 PRINT\n1800 PRINT \"VERY GOOD...\"\n1890 FOR I=1 TO 100: FOR J=1 TO 6: A(I,J)=0: NEXT J: NEXT I\n1980 F=1\n2070 FOR P=1 TO R\n2160 M=0\n2250 B=1\n2340 M=0: Q=0\n2430 FOR I=1 TO 15: C(I)=0: NEXT I\n2520 REM ARK BALL GENERATOR USING MOD '15' SYSTEM\n2610 PRINT \"TYPE ROLL TO GET THE BALL GOING.\"\n2700 INPUT N$\n2790 K=0: D=0\n2880 FOR I=1 TO 20\n2970 X=INT(RND(1)*100)\n3060 FOR J=1 TO 10\n3150 IF X<15*J THEN 3330\n3240 NEXT J\n3330 C(15*J-X)=1\n3420 NEXT I\n3510 REM ARK PIN DIAGRAM\n3600 PRINT \"PLAYER:\"P;\"FRAME:\";F\"BALL:\"B\n3690 FOR I=0 TO 3\n3780 PRINT\n3870 FOR J=1 TO 4-I\n3960 K=K+1\n4050 IF C(K)=1 THEN 4320\n4140 PRINT TAB(I);\"+ \";\n4230 GOTO 4410\n4320 PRINT TAB(I);\"O \";\n4410 NEXT J\n4500 NEXT I\n4590 PRINT \"\"\n4680 REM ARK ROLL ANALYSIS\n4770 FOR I=1 TO 10\n4860 D=D+C(I)\n4950 NEXT I\n5040 IF D-M <> 0 THEN 5220\n5130 PRINT \"GUTTER!!\"\n5220 IF B<>1 OR D<>10 THEN 5490\n5310 PRINT \"STRIKE!!!!!\u0007\u0007\u0007\u0007\"\n5400 Q=3\n5490 IF B<>2 OR D<>10 THEN 5760\n5580 PRINT \"SPARE!!!!\"\n5670 Q=2\n5760 IF B<>2 OR D>=10 THEN 6030\n5850 PRINT \"ERROR!!!\"\n5940 Q=1\n6030 IF B<>1 OR D>=10 THEN 6210\n6120 PRINT \"ROLL YOUR 2ND BALL\"\n6210 REM ARK STORAGE OF THE SCORES\n6300 PRINT\n6390 A(F*P,B)=D\n6480 IF B=2 THEN 7020\n6570 B=2\n6660 M=D\n6750 IF Q=3 THEN 6210\n6840 A(F*P,B)=D-M\n6930 IF Q=0 THEN 2520\n7020 A(F*P,3)=Q\n7110 NEXT P\n7200 F=F+1\n7290 IF F<11 THEN 2070\n7295 PRINT \"FRAMES\"\n7380 FOR I=1 TO 10\n7470 PRINT I;\n7560 NEXT I\n7650 PRINT\n7740 FOR P=1 TO R\n7830 FOR I=1 TO 3\n7920 FOR J=1 TO 10\n8010 PRINT A(J*P,I);\n8100 NEXT J\n8105 PRINT\n8190 NEXT I\n8280 PRINT\n8370 NEXT P\n8460 PRINT \"DO YOU WANT ANOTHER GAME\"\n8550 INPUT A$\n8640 IF LEFT$(A$,1)=\"Y\" THEN 2610\n8730 END\n"
  },
  {
    "path": "14_Bowling/csharp/Bowling.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bowling\n{\n    public class Bowling\n    {\n        private readonly Pins pins = new();\n\n        private int players;\n\n        public void Play()\n        {\n            ShowBanner();\n            MaybeShowInstructions();\n            Setup();\n            GameLoop();\n        }\n\n        private static void ShowBanner()\n        {\n            Utility.PrintString(34, \"BOWL\");\n            Utility.PrintString(15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Utility.PrintString();\n            Utility.PrintString();\n            Utility.PrintString();\n            Utility.PrintString(\"WELCOME TO THE ALLEY\");\n            Utility.PrintString(\"BRING YOUR FRIENDS\");\n            Utility.PrintString(\"OKAY LET'S FIRST GET ACQUAINTED\");\n            Utility.PrintString();\n        }\n        private static void MaybeShowInstructions()\n        {\n            Utility.PrintString(\"THE INSTRUCTIONS (Y/N)\");\n            if (Utility.InputString() == \"N\") return;\n            Utility.PrintString(\"THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME\");\n            Utility.PrintString(\"THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\");\n            Utility.PrintString(\"OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES\");\n            Utility.PrintString(\"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\");\n            Utility.PrintString(\"PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR\");\n            Utility.PrintString(\"SCORES .\");\n        }\n        private void Setup()\n        {\n            Utility.PrintString(\"FIRST OF ALL...HOW MANY ARE PLAYING\", false);\n            var input = Utility.InputInt();\n            players = input < 1 ? 1 : input;\n            Utility.PrintString();\n            Utility.PrintString(\"VERY GOOD...\");\n        }\n        private void GameLoop()\n        {\n            GameResults[] gameResults = InitGameResults();\n            var done = false;\n            while (!done)\n            {\n                ResetGameResults(gameResults);\n                for (int frame = 0; frame < GameResults.FramesPerGame; ++frame)\n                {\n                    for (int player = 0; player < players; ++player)\n                    {\n                        pins.Reset();\n                        int pinsDownThisFrame = pins.GetPinsDown();\n\n                        int ball = 1;\n                        while (ball == 1 || ball == 2) // One or two rolls\n                        {\n                            Utility.PrintString(\"TYPE ROLL TO GET THE BALL GOING.\");\n                            _ = Utility.InputString();\n\n                            int pinsDownAfterRoll = pins.Roll();\n                            ShowPins(player, frame, ball);\n\n                            if (pinsDownAfterRoll == pinsDownThisFrame)\n                            {\n                                Utility.PrintString(\"GUTTER!!\");\n                            }\n\n                            if (ball == 1)\n                            {\n                                // Store current pin count\n                                gameResults[player].Results[frame].PinsBall1 = pinsDownAfterRoll;\n\n                                // Special handling for strike\n                                if (pinsDownAfterRoll == Pins.TotalPinCount)\n                                {\n                                    Utility.PrintString(\"STRIKE!!!!!\\a\\a\\a\\a\");\n                                    // No second roll\n                                    ball = 0;\n                                    gameResults[player].Results[frame].PinsBall2 = pinsDownAfterRoll;\n                                    gameResults[player].Results[frame].Score = FrameResult.Points.Strike;\n                                }\n                                else\n                                {\n                                    ball = 2; // Roll again\n                                    Utility.PrintString(\"ROLL YOUR SECOND BALL\");\n                                }\n                            }\n                            else if (ball == 2)\n                            {\n                                // Store current pin count\n                                gameResults[player].Results[frame].PinsBall2 = pinsDownAfterRoll;\n                                ball = 0;\n\n                                // Determine the score for the frame\n                                if (pinsDownAfterRoll == Pins.TotalPinCount)\n                                {\n                                    Utility.PrintString(\"SPARE!!!!\");\n                                    gameResults[player].Results[frame].Score = FrameResult.Points.Spare;\n                                }\n                                else\n                                {\n                                    Utility.PrintString(\"ERROR!!!\");\n                                    gameResults[player].Results[frame].Score = FrameResult.Points.Error;\n                                }\n                            }\n                            Utility.PrintString();\n                        }\n                    }\n                }\n                ShowGameResults(gameResults);\n                Utility.PrintString(\"DO YOU WANT ANOTHER GAME\");\n                var a = Utility.InputString();\n                done = a.Length == 0 || a[0] != 'Y';\n            }\n        }\n\n        private GameResults[] InitGameResults()\n        {\n            var gameResults = new GameResults[players];\n            for (int i = 0; i < gameResults.Length; i++)\n            {\n                gameResults[i] = new GameResults();\n            }\n            return gameResults;\n        }\n\n        private void ShowPins(int player, int frame, int ball)\n        {\n            Utility.PrintString($\"FRAME: {frame + 1} PLAYER: {player + 1} BALL: {ball}\");\n            var breakPins = new bool[] { true, false, false, false, true, false, false, true, false, true };\n            var indent = 0;\n            for (int pin = 0; pin < Pins.TotalPinCount; ++pin)\n            {\n                if (breakPins[pin])\n                {\n                    Utility.PrintString(); // End row\n                    Utility.PrintString(indent++, false); // Indent next row\n                }\n                var s = pins[pin] == Pins.State.Down ? \"+ \" : \"o \";\n                Utility.PrintString(s, false);\n            }\n            Utility.PrintString();\n            Utility.PrintString();\n        }\n        private void ResetGameResults(GameResults[] gameResults)\n        {\n            foreach (var gameResult in gameResults)\n            {\n                foreach (var frameResult in gameResult.Results)\n                {\n                    frameResult.Reset();\n                }\n            }\n        }\n        private void ShowGameResults(GameResults[] gameResults)\n        {\n            Utility.PrintString(\"FRAMES\");\n            for (int i = 0; i < GameResults.FramesPerGame; ++i)\n            {\n                Utility.PrintString(Utility.PadInt(i, 3), false);\n            }\n            Utility.PrintString();\n            foreach (var gameResult in gameResults)\n            {\n                foreach (var frameResult in gameResult.Results)\n                {\n                    Utility.PrintString(Utility.PadInt(frameResult.PinsBall1, 3), false);\n                }\n                Utility.PrintString();\n                foreach (var frameResult in gameResult.Results)\n                {\n                    Utility.PrintString(Utility.PadInt(frameResult.PinsBall2, 3), false);\n                }\n                Utility.PrintString();\n                foreach (var frameResult in gameResult.Results)\n                {\n                    Utility.PrintString(Utility.PadInt((int)frameResult.Score, 3), false);\n                }\n                Utility.PrintString();\n                Utility.PrintString();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "14_Bowling/csharp/Bowling.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "14_Bowling/csharp/Bowling.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bowling\", \"Bowling.csproj\", \"{9951637A-8D70-42A4-8CB7-315FA414F960}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9951637A-8D70-42A4-8CB7-315FA414F960}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9951637A-8D70-42A4-8CB7-315FA414F960}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9951637A-8D70-42A4-8CB7-315FA414F960}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9951637A-8D70-42A4-8CB7-315FA414F960}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "14_Bowling/csharp/FrameResult.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bowling\n{\n    public class FrameResult\n    {\n        public enum Points { None, Error, Spare, Strike };\n\n        public int PinsBall1 { get; set; }\n        public int PinsBall2 { get; set; }\n        public Points Score { get; set; }\n\n        public void Reset()\n        {\n            PinsBall1 = PinsBall2 = 0;\n            Score = Points.None;\n        }\n    }\n}\n"
  },
  {
    "path": "14_Bowling/csharp/GameResults.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bowling\n{\n    public class GameResults\n    {\n        public static readonly int FramesPerGame = 10;\n        public FrameResult[] Results { get; set; }\n\n        public GameResults()\n        {\n            Results = new FrameResult[FramesPerGame];\n            for (int i = 0; i < FramesPerGame; ++i)\n            {\n                Results[i] = new FrameResult();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "14_Bowling/csharp/Pins.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bowling\n{\n    public class Pins\n    {\n        public enum State { Up, Down };\n        public static readonly int TotalPinCount = 10;\n        private readonly Random random = new();\n\n        private State[] PinSet { get; set; }\n\n        public Pins()\n        {\n            PinSet = new State[TotalPinCount];\n        }\n        public State this[int i]\n        {\n            get { return PinSet[i]; }\n            set { PinSet[i] = value; }\n        }\n        public int Roll()\n        {\n            // REM ARK BALL GENERATOR USING MOD '15' SYSTEM\n            for (int i = 0; i < 20; ++i)\n            {\n                var x = random.Next(100) + 1;\n                int j;\n                for (j = 1; j <= 10; ++j)\n                {\n                    if (x < 15 * j)\n                        break;\n                }\n                var pindex = 15 * j - x;\n                if (pindex > 0 && pindex <= TotalPinCount)\n                    PinSet[--pindex] = State.Down;\n            }\n            return GetPinsDown();\n        }\n        public void Reset()\n        {\n            for (int i = 0; i < PinSet.Length; ++i)\n            {\n                PinSet[i] = State.Up;\n            }\n        }\n        public int GetPinsDown()\n        {\n            return PinSet.Count(p => p == State.Down);\n        }\n    }\n}\n"
  },
  {
    "path": "14_Bowling/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bowling\n{\n    public static class Program\n    {\n        public static void Main()\n        {\n            new Bowling().Play();\n        }\n    }\n}\n"
  },
  {
    "path": "14_Bowling/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "14_Bowling/csharp/Utility.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bowling\n{\n    internal static class Utility\n    {\n        public static string PadInt(int value, int width)\n        {\n            return value.ToString().PadLeft(width);\n        }\n        public static int InputInt()\n        {\n            while (true)\n            {\n                if (int.TryParse(InputString(), out int i))\n                    return i;\n                else\n                    PrintString(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n            }\n        }\n        public static string InputString()\n        {\n            PrintString(\"? \", false);\n            var input = Console.ReadLine();\n            return input == null ? string.Empty : input.ToUpper();\n        }\n        public static void PrintInt(int value, bool newLine = false)\n        {\n            PrintString($\"{value} \", newLine);\n        }\n        public static void PrintString(bool newLine = true)\n        {\n            PrintString(0, string.Empty);\n        }\n        public static void PrintString(int tab, bool newLine = true)\n        {\n            PrintString(tab, string.Empty, newLine);\n        }\n        public static void PrintString(string value, bool newLine = true)\n        {\n            PrintString(0, value, newLine);\n        }\n        public static void PrintString(int tab, string value, bool newLine = true)\n        {\n            Console.Write(new String(' ', tab));\n            Console.Write(value);\n            if (newLine) Console.WriteLine();\n        }\n    }\n}\n"
  },
  {
    "path": "14_Bowling/java/Bowling.java",
    "content": "import java.util.Scanner;\nimport java.lang.Math;\n\n/**\n * Game of Bowling\n * <p>\n * Based on the BASIC game of Bowling here\n * https://github.com/coding-horror/basic-computer-games/blob/main/14%20Bowling/bowling.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Bowling {\n\n  private final Scanner scan;  // For user input\n\n  public Bowling() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Bowling\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(33) + \"BOWL\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    int ball = 0;\n    int bell = 0;\n    int frame = 0;\n    int ii = 0;  // Loop iterator\n    int jj = 0;  // Loop iterator\n    int kk = 0;  // Loop iterator\n    int numPlayers = 0;\n    int pinsDownBefore = 0;\n    int pinsDownNow = 0;\n    int player = 0;\n    int randVal = 0;\n    int result = 0;\n\n    int[] pins = new int[16];\n\n    int[][] scores = new int[101][7];\n\n    String userResponse = \"\";\n\n    System.out.println(\"WELCOME TO THE ALLEY\");\n    System.out.println(\"BRING YOUR FRIENDS\");\n    System.out.println(\"OKAY LET'S FIRST GET ACQUAINTED\");\n    System.out.println(\"\");\n    System.out.println(\"THE INSTRUCTIONS (Y/N)\");\n    System.out.print(\"? \");\n\n    userResponse = scan.nextLine();\n\n    if (userResponse.toUpperCase().equals(\"Y\")) {\n      printRules();\n    }\n\n    System.out.print(\"FIRST OF ALL...HOW MANY ARE PLAYING? \");\n    numPlayers = Integer.parseInt(scan.nextLine());\n\n    System.out.println(\"\");\n    System.out.println(\"VERY GOOD...\");\n\n    // Begin outer while loop\n    while (true) {\n\n      for (ii = 1; ii <= 100; ii++) {\n        for (jj = 1; jj <= 6; jj++) {\n          scores[ii][jj] = 0;\n        }\n      }\n\n      frame = 1;\n\n      // Begin frame while loop\n      while (frame < 11) {\n\n        // Begin loop through all players\n        for (player = 1; player <= numPlayers; player++) {\n\n          pinsDownBefore = 0;\n          ball = 1;\n          result = 0;\n\n          for (ii = 1; ii <= 15; ii++) {\n            pins[ii] = 0;\n          }\n\n          while (true) {\n\n            // Ball generator using mod '15' system\n\n            System.out.println(\"TYPE ROLL TO GET THE BALL GOING.\");\n            System.out.print(\"? \");\n            scan.nextLine();\n\n            kk = 0;\n            pinsDownNow = 0;\n\n            for (ii = 1; ii <= 20; ii++) {\n\n              randVal = (int)(Math.random() * 100) + 1;\n\n              for (jj = 1; jj <= 10; jj++) {\n\n                if (randVal < 15 * jj) {\n                  break;\n                }\n              }\n              pins[15 * jj - randVal] = 1;\n            }\n\n            // Pin diagram\n\n            System.out.println(\"PLAYER: \" + player + \" FRAME: \" + frame + \" BALL: \" + ball);\n\n            for (ii = 0; ii <= 3; ii++) {\n\n              System.out.println(\"\");\n\n              System.out.print(\" \".repeat(ii));\n\n              for (jj = 1; jj <= 4 - ii; jj++) {\n\n                kk++;\n\n                if (pins[kk] == 1) {\n\n                  System.out.print(\"O \");\n\n                } else {\n\n                  System.out.print(\"+ \");\n                }\n              }\n            }\n\n            System.out.println(\"\");\n\n            // Roll analysis\n\n            for (ii = 1; ii <= 10; ii++) {\n              pinsDownNow += pins[ii];\n            }\n\n            if (pinsDownNow - pinsDownBefore == 0) {\n              System.out.println(\"GUTTER!!\");\n            }\n\n            if (ball == 1 && pinsDownNow == 10) {\n              System.out.println(\"STRIKE!!!!!\");\n\n              // Ring bell\n              for (bell = 1; bell <= 4; bell++) {\n                System.out.print(\"\\007\");\n                try {\n                  Thread.sleep(500);\n                } catch (InterruptedException e) {\n                  Thread.currentThread().interrupt();\n                }\n              }\n              result = 3;\n            }\n\n            if (ball == 2 && pinsDownNow == 10) {\n              System.out.println(\"SPARE!!!!\");\n              result = 2;\n            }\n\n            if (ball == 2 && pinsDownNow < 10) {\n              System.out.println(\"ERROR!!!\");\n              result = 1;\n            }\n\n            if (ball == 1 && pinsDownNow < 10) {\n              System.out.println(\"ROLL YOUR 2ND BALL\");\n            }\n\n            // Storage of the scores\n\n            System.out.println(\"\");\n\n            scores[frame * player][ball] = pinsDownNow;\n\n            if (ball != 2) {\n              ball = 2;\n              pinsDownBefore = pinsDownNow;\n\n              if (result != 3) {\n                scores[frame * player][ball] = pinsDownNow - pinsDownBefore;\n                if (result == 0) {\n                  continue;\n                }\n              } else {\n                scores[frame * player][ball] = pinsDownNow;\n              }\n\n            }\n            break;\n          }\n\n          scores[frame * player][3] = result;\n\n        }  // End loop through all players\n\n        frame++;\n\n      }  // End frame while loop\n\n      System.out.println(\"FRAMES\");\n\n      System.out.print(\" \");\n      for (ii = 1; ii <= 10; ii++) {\n        System.out.print(ii + \" \");\n      }\n\n      System.out.println(\"\");\n\n      for (player = 1; player <= numPlayers; player++) {\n        for (ii = 1; ii <= 3; ii++) {\n          System.out.print(\" \");\n          for (jj = 1; jj <= 10; jj++) {\n            System.out.print (scores[jj * player][ii] + \" \");\n          }\n          System.out.println(\"\");\n        }\n        System.out.println(\"\");\n      }\n\n      System.out.println(\"DO YOU WANT ANOTHER GAME\");\n      System.out.print(\"? \");\n\n      userResponse = scan.nextLine();\n\n      if (!String.valueOf(userResponse.toUpperCase().charAt(0)).equals(\"Y\")) {\n        break;\n      }\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public static void printRules() {\n\n    System.out.println(\"THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME\");\n    System.out.println(\"THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\");\n    System.out.println(\"OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES\");\n    System.out.println(\"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\");\n    System.out.println(\"PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR\");\n    System.out.println(\"SCORES .\");\n\n  }  // End of method printRules\n\n  public static void main(String[] args) {\n\n    Bowling game = new Bowling();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class Bowling\n"
  },
  {
    "path": "14_Bowling/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "14_Bowling/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "14_Bowling/javascript/bowling.html",
    "content": "<html>\n<head>\n<title>BOWLING</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bowling.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "14_Bowling/javascript/bowling.js",
    "content": "// BOWLING\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"BOWL\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    c = [];\n    a = [];\n    for (i = 0; i <= 15; i++)\n        c[i] = 0;\n    print(\"WELCOME TO THE ALLEY\\n\");\n    print(\"BRING YOUR FRIENDS\\n\");\n    print(\"OKAY LET'S FIRST GET ACQUAINTED\\n\");\n    print(\"\\n\");\n    print(\"THE INSTRUCTIONS (Y/N)\\n\");\n    str = await input();\n    if (str.substr(0, 1) == \"Y\") {\n        print(\"THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME\\n\");\n        print(\"THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\\n\");\n        print(\"OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES\\n\");\n        print(\"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\\n\");\n        print(\"PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR\\n\");\n        print(\"SCORES .\\n\");\n    }\n    print(\"FIRST OF ALL...HOW MANY ARE PLAYING\");\n    r = parseInt(await input());\n    while (1) {\n        print(\"\\n\");\n        print(\"VERY GOOD...\\n\");\n        for (i = 1; i <= 100; i++) {\n            a[i] = [];\n            for (j = 1; j <= 6; j++)\n                a[i][j] = 0;\n        }\n        f = 1;\n        do {\n            for (p = 1; p <= r; p++) {\n                // m = 0; // Repeated in original\n                b = 1;\n                m = 0;\n                q = 0;\n                for (i = 1; i <= 15; i++)\n                    c[i] = 0;\n                while (1) {\n                    // Ball generator using mod '15' system\n                    print(\"TYPE ROLL TO GET THE BALL GOING.\\n\");\n                    ns = await input();\n                    k = 0;\n                    d = 0;\n                    for (i = 1; i <= 20; i++) {\n                        x = Math.floor(Math.random() * 100);\n                        for (j = 1; j <= 10; j++)\n                            if (x < 15 * j)\n                                break;\n                        c[15 * j - x] = 1;\n                    }\n                    // Pin diagram\n                    print(\"PLAYER: \" + p + \" FRAME: \" + f + \" BALL: \" + b + \"\\n\");\n                    print(\"\\n\");\n                    for (i = 0; i <= 3; i++) {\n                        str = \"\";\n                        for (j = 1; j <= 4 - i; j++) {\n                            k++;\n                            while (str.length < i)\n                                str += \" \";\n                            if (c[k] == 1)\n                                str += \"O \";\n                            else\n                                str += \"+ \";\n                        }\n                        print(str + \"\\n\");\n                    }\n                    // Roll analysis\n                    for (i = 1; i <= 10; i++)\n                        d += c[i];\n                    if (d - m == 0)\n                        print(\"GUTTER!!\\n\");\n                    if (b == 1 && d == 10) {\n                        print(\"STRIKE!!!!!\\n\");\n                        q = 3;\n                    }\n                    if (b == 2 && d == 10) {\n                        print(\"SPARE!!!!\\n\");\n                        q = 2;\n                    }\n                    if (b == 2 && d < 10) {\n                        print(\"ERROR!!!\\n\");\n                        q = 1;\n                    }\n                    if (b == 1 && d < 10) {\n                        print(\"ROLL YOUR 2ND BALL\\n\");\n                    }\n                    // Storage of the scores\n                    print(\"\\n\");\n                    a[f * p][b] = d;\n                    if (b != 2) {\n                        b = 2;\n                        m = d;\n                        if (q == 3) {\n                            a[f * p][b] = d;\n                        } else {\n                            a[f * p][b] = d - m;\n                            if (q == 0) // ROLL\n                                continue;\n                        }\n                    }\n                    break;\n                }\n                a[f * p][3] = q;\n            }\n        } while (++f < 11) ;\n        print(\"FRAMES\\n\");\n        for (i = 1; i <= 10; i++)\n            print(\" \" + i + \" \");\n        print(\"\\n\");\n        for (p = 1; p <= r; p++) {\n            for (i = 1; i <= 3; i++) {\n                for (j = 1; j <= 10; j++) {\n                    print(\" \" + a[j * p][i] + \" \");\n                }\n                print(\"\\n\");\n            }\n            print(\"\\n\");\n        }\n        print(\"DO YOU WANT ANOTHER GAME\");\n        str = await input();\n        if (str.substr(0, 1) != \"Y\")\n            break;\n        // Bug in original game, jumps to 2610, without restarting P variable\n    }\n}\n\nmain();\n"
  },
  {
    "path": "14_Bowling/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "14_Bowling/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "14_Bowling/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\n###Bowling program in Perl\n\nRun normally, this is a fairly faithful translation of the Basic game.\nThe only real differences are a few trivial fix-ups on the prints to make it\nlook better, and the player/frame/ball line was put before the \"get the ball\ngoing\" line to make it more obvious who's turn it is.\n\nHowever, if you run it with \"-a\" on the command line, it will go into\n\"advanced\" mode, which means that \".\" is used to show pin down and \"!\" for\npin up, current running scores are shown at the end of each frame, and the\nscoring also looks more normal at the end. This is all done because I think it\nlooks better and I wanted to see a score. Having a flag says you can play\nwhichever version of the game you like.\n\nNote, the original code doesn't do the 10th frame correctly, in that it will\nnever do more than 2 balls, so the best score you can get is a 290.\nThis is true in both modes. That being said, it will always give you a mediocre\ngame; I don't think I've ever seen a score over 140.\n"
  },
  {
    "path": "14_Bowling/perl/bowling.pl",
    "content": "#!/usr/bin/perl\n\n# Bowling program in Perl\n#   Run normally, this is a fairly faithful translation of the Basic game.\n#   The only real differences are a few trivial fix-ups on the prints to make it\n#   look better, and the player/frame/ball line was put before the \"get the ball\n#   going\" line to make it more obvious who's turn it is.\n#\n#   However, if you run it with \"-a\" on the command line, it will go into\n#   'advanced' mode, which means that \".\" is used to show pin down and \"!\" for\n#   pin up, current running scores are shown at the end of each frame, and the\n#   scoring also looks more normal at the end. This is all done because I think it\n#   looks better and I wanted to see a score. Having a flag says you can play\n#   whichever version of the game you like.\n#\n#   Note, the original code doesn't do the 10th frame correctly, in that it will\n#   never do more than 2 balls, so the best score you can get is a 290.\n#   This is true in both modes. That being said, it will always give you a mediocre game.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\nprint \"\\n\";\nprint \" \" x 34, \"BASKETBALL\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\n# globals\nmy @C;              # pin position matraix?\nmy @Scores;         # scores: [player num][frame][ball] # ball3 is end-result, ball4 is frame score (advanced mode)\nmy $Answer;         # get answers\nmy $Num_players;    # number of players\nmy $Advanced = 0;   # flag, 1 to use advanced code, 0 for original code\nmy $char_down = '0'; # char to show pin is down\nmy $char_up = '+';   # char to show pin is standing\n\nif ($ARGV[0] && $ARGV[0] eq \"-a\")\n{\n    shift;\n    $Advanced = 1;\n    $char_down = '.';\n    $char_up = '!';\n}\n\nprint \"WELCOME TO THE ALLEY\\n\";\nprint \"BRING YOUR FRIENDS\\n\";\nprint \"OKAY LET'S FIRST GET ACQUAINTED\\n\\n\";\nprint \"SEE THE INSTRUCTIONS (Y/N): \";\nchomp($Answer = uc(<>));\nif ($Answer eq \"Y\")\n{\n    print \"THE GAME OF BOWLING TAKES MIND AND SKILL. DURING THE GAME\\n\";\n    print \"THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\\n\";\n    print \"OTHER PLAYERS[UP TO FOUR]. YOU WILL BE PLAYING TEN FRAMES\\n\";\n    print \"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\\n\";\n    print \"PIN IS STANDING. AFTER THE GAME THE COMPUTER WILL SHOW YOUR SCORES.\\n\";\n}\n\ndo {\n    print \"FIRST OF ALL...HOW MANY ARE PLAYING (1-4): \";\n    $Num_players = int(<>);\n} while ($Num_players < 1 || $Num_players > 4);\n\nprint \"\\nVERY GOOD...\\n\";\n\nwhile (1)\n{\n    # reset all scores\n    for my $p (1 .. $Num_players) # players\n    {\n        for my $f (1 .. 10) # frames\n        {\n            for my $b (1 .. 3) # balls\n            {\n                $Scores[$p][$f][$b] = 0;\n            }\n        }\n    }\n\n    # play the game\n    for my $frame (1 .. 10) # frame\n    {\n        for my $curr_player (1 .. $Num_players) # player\n        {\n            my $last_pins=0;    # pins down for last ball\n            my $ball=1;         # ball number, 1 or 2\n            my $end_result=0;   # result at end of turn: 3=strike, 2=spare, 1=pins-left\n            for my $i (1 .. 15) { $C[$i] = 0 }\n\n            while (1) # another ball\n            {\n                # ARK BALL GENERATOR USING MOD '15' SYSTEM\n                my $K=0;\n                my $curr_pins=0; # pins down for this ball\n                for my $i (1 .. 20)\n                {\n                    my $x = int(rand(1) * 100);\n                    my $j;\n                    for ($j=1 ; $j <= 10 ; $j++)\n                    {\n                        last if ($x < 15 * $j);\n                    }\n                    $C[15 * $j - $x] = 1;\n                }\n\n                # ARK PIN DIAGRAM\n                print \"PLAYER: $curr_player  FRAME: $frame  BALL: $ball\\n\";\n                print \"PRESS ENTER TO GET THE BALL GOING.\";\n                $Answer = <>; # not used, just need an enter\n                for my $i (0 .. 3)\n                {\n                    print \"\\n\";\n                    print \" \" x $i; # avoid the TAB(), just shift each row over for the triangle\n                    for my $j (1 .. 4 - $i)\n                    {\n                        $K++;\n                        print ($C[$K] == 1 ? \" $char_down\" : \" $char_up\");\n                    }\n                }\n                print \"\\n\";\n\n                # ARK ROLL ANALYSIS\n                for my $i (1 .. 10)\n                {\n                    $curr_pins += $C[$i];\n                }\n                if ($curr_pins - $last_pins == 0)\n                {\n                    print \"GUTTER!!\\n\";\n                }\n                if ($ball == 1 && $curr_pins == 10)\n                {\n                    print \"STRIKE!!!!!\\a\\a\\a\\a\\n\"; # \\a is for bell\n                    $end_result = 3;\n                }\n                elsif ($ball == 2 && $curr_pins == 10)\n                {\n                    print \"SPARE!!!!\\n\";\n                    $end_result = 2;\n                }\n                elsif ($ball == 2 && $curr_pins < 10)\n                {\n                    if ($Advanced) { print 10 - $curr_pins, \" PENS LEFT!!!\\n\"; }\n                    else           { print \"ERROR!!!\\n\"; }\n                    $end_result = 1;\n                }\n                if ($ball == 1 && $curr_pins < 10)\n                {\n                    print \"ROLL YOUR 2ND BALL\\n\";\n                }\n                print \"\\n\";\n\n                # ARK STORAGE OF THE SCORES\n                if ($Advanced) { $Scores[$curr_player][$frame][$ball] = $curr_pins - $last_pins; }\n                else           { $Scores[$curr_player][$frame][$ball] = $curr_pins; }\n                if ($ball == 1)\n                {\n                    $ball = 2;\n                    $last_pins = $curr_pins;\n\n                    if ($end_result == 3) # strike, no more rolls, goto last\n                    {\n                        $Scores[$curr_player][$frame][$ball] = $curr_pins;\n                    }\n                    else\n                    {\n                        $Scores[$curr_player][$frame][$ball] = $curr_pins - $last_pins;\n                        next if ($end_result == 0); # next roll\n                    }\n                }\n                last;\n            }\n            $Scores[$curr_player][$frame][3] = $end_result;\n        } # next player\n        if ($Advanced)\n        {\n            print \"Scores:\\n\";\n            for my $p (1 .. $Num_players)\n            {\n                my $total = calc_score($p);\n                print \"\\tPlayer $p: $total\\n\";\n            }\n            print \"\\n\";\n        }\n    } # next frame\n\n    # end of game, show full scoreboard\n    show_scoreboard();\n\n    print \"DO YOU WANT ANOTHER GAME (Y/N): \";\n    chomp($Answer = uc(<>));\n    print \"\\n\";\n    last if ($Answer ne \"Y\");\n}\nexit(0);\n\nsub show_scoreboard\n{\n    print \"FRAMES\\n\";\n    for my $i (1 .. 10)\n    {\n        print \" $i \";\n    }\n    print \"\\n\";\n    my @results = ( \"-\", \".\", \"/\", \"X\" );\n    for my $p (1 .. $Num_players)\n    {\n        print \"Player $p\\n\" if ($Advanced);\n        my $ball_max = ($Advanced ? 4 : 3);\n        for my $b (1 .. $ball_max)\n        {\n            for my $f (1 .. 10)\n            {\n                if ($b != 3) { print sprintf(\"%2d \", $Scores[$p][$f][$b]); }\n                else         { print sprintf(\"%2s \", $results[$Scores[$p][$f][$b]]); }\n            }\n            print \"\\n\";\n        }\n        print \"\\n\";\n    }\n}\n\nsub calc_score\n{\n    my $player = shift;\n    my $total = 0;\n    for my $frame (1 .. 10)\n    {\n        my $score = 0;\n        if ($frame == 10 || $Scores[$player][$frame][3] == 1) # pins\n        {\n            $score = $Scores[$player][$frame][1] + $Scores[$player][$frame][2];\n        }\n        elsif ($Scores[$player][$frame][3] == 2) # spare\n        {\n            $score = 10 + $Scores[$player][$frame+1][1];\n        }\n        elsif ($Scores[$player][$frame][3] == 3) # strike\n        {\n            $score = 10 + $Scores[$player][$frame+1][1];\n            if ($Scores[$player][$frame+1][1] == 10)\n            {\n                $score += ($frame < 9 ? $Scores[$player][$frame+2][1] : $Scores[$player][$frame+1][2]);\n            }\n            else\n            {\n                $score += $Scores[$player][$frame+1][2];\n            }\n        }\n        $Scores[$player][$frame][4] = $score;\n        $total += $score;\n    }\n    return $total;\n}\n"
  },
  {
    "path": "14_Bowling/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "14_Bowling/python/bowling.py",
    "content": "import random\nfrom typing import List\n\n\ndef simulate_roll(pins: List[int]) -> None:\n    for _ in range(20):\n        x = random.randint(0, 14)\n        if x < len(pins):\n            pins[x] = 1\n\n\ndef calculate_score(rolls: List[int]) -> int:\n    score = 0\n    frame = 1\n    b = 1\n    for index, pins in enumerate(rolls):\n        score += pins\n        if b == 1:\n            if pins == 10:  # strike\n                score += sum(rolls[index + 1 : index + 3])\n                frame += 1\n            else:\n                b = 2\n        else:\n            if sum(rolls[index - 1 : index + 1]) == 10:  # spare\n                score += rolls[index + 1]\n            b = 1\n            frame += 1\n        if frame > 10:\n            break\n\n    return score\n\n\nclass Player:\n    def __init__(self, name: str) -> None:\n        self.name = name\n        self.rolls: List[int] = []\n\n    def play_frame(self, frame: int) -> None:\n        extra = 0\n        prev_score = 0\n        pins = [0] * 10  # reset the pins\n        for ball in range(2):\n            simulate_roll(pins)\n            score = sum(pins)\n            self.show(pins)\n            pin_count = score - prev_score\n            self.rolls.append(pin_count)  # log the number of pins toppled this roll\n            print(f\"{pin_count} for {self.name}\")\n            if score - prev_score == 0:\n                print(\"GUTTER!!!\")\n            if ball == 0:\n                if score == 10:\n                    print(\"STRIKE!!!\")\n                    extra = 2\n                    break  # cannot roll more than once in a frame\n                else:\n                    print(f\"next roll {self.name}\")\n            elif score == 10:\n                print(\"SPARE!\")\n                extra = 1\n\n            prev_score = score  # remember previous pins to distinguish ...\n        if frame == 9 and extra > 0:\n            print(f\"Extra rolls for {self.name}\")\n            pins = [0] * 10  # reset the pins\n            score = 0\n            for _ball in range(extra):\n                if score == 10:\n                    pins = [0] * 10\n                simulate_roll(pins)\n                score = sum(pins)\n                self.rolls.append(score)\n\n    def __str__(self) -> str:\n        return f\"{self.name}: {self.rolls}, total:{calculate_score(self.rolls)}\"\n\n    def show(self, pins: List[int]) -> None:\n        pins_iter = iter(pins)\n        print()\n        for row in range(4):\n            print(\" \" * row, end=\"\")\n            for _ in range(4 - row):\n                p = next(pins_iter)\n                print(\"O \" if p else \"+ \", end=\"\")\n            print()\n\n\ndef centre_text(text: str, width: int) -> str:\n    t = len(text)\n    return (\" \" * ((width - t) // 2)) + text\n\n\ndef main() -> None:\n    print(centre_text(\"Bowl\", 80))\n    print(centre_text(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\", 80))\n    print()\n    print(\"WELCOME TO THE ALLEY.\")\n    print(\"BRING YOUR FRIENDS.\")\n    print(\"OKAY LET'S FIRST GET ACQUAINTED.\")\n\n    while True:\n        print()\n        if input(\"THE INSTRUCTIONS (Y/N)? \") in \"yY\":\n            print(\"THE GAME OF BOWLING TAKES MIND AND SKILL. DURING THE GAME\")\n            print(\"THE COMPUTER WILL KEEP SCORE. YOU MAY COMPETE WITH\")\n            print(\"OTHER PLAYERS[UP TO FOUR]. YOU WILL BE PLAYING TEN FRAMES.\")\n            print(\"ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\")\n            print(\"PIN IS STANDING. AFTER THE GAME THE COMPUTER WILL SHOW YOUR\")\n            print(\"SCORES.\")\n\n        total_players = int(input(\"FIRST OF ALL...HOW MANY ARE PLAYING? \"))\n        print()\n        print(\"VERY GOOD...\")\n        player_names = [\n            Player(input(f\"Enter name for player {index + 1}: \"))\n            for index in range(total_players)\n        ]\n        for frame in range(10):\n            for player in player_names:\n                player.play_frame(frame)\n\n        for player in player_names:\n            print(player)\n\n        if input(\"DO YOU WANT ANOTHER GAME? \") not in \"yY\":\n            break\n\n\nif __name__ == \"__main__\":\n    main()\n\n\n############################################################################################\n#\n# This is a fairly straight conversion to python with some exceptions.\n# I have kept most of the upper case text that the program prints.\n# I have added the feature of giving names to players.\n# I have added a Player class to store player data in.\n# This last change works around the problems in the original storing data in a matrix.\n# The original had bugs in calculating indexes which meant that the program\n# would overwrite data in the matrix, so the results printed out contained errors.\n# The last change is to do with the strict rules which allow extra rolls if the player\n# scores a spare or strike in the last frame.\n# This program allows these extra rolls and also calculates the proper score.\n#\n############################################################################################\n"
  },
  {
    "path": "14_Bowling/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "14_Bowling/vbnet/Bowling.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bowling\", \"Bowling.vbproj\", \"{DBEB424A-1538-4F14-BA57-BA4E326EF4D8}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DBEB424A-1538-4F14-BA57-BA4E326EF4D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DBEB424A-1538-4F14-BA57-BA4E326EF4D8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DBEB424A-1538-4F14-BA57-BA4E326EF4D8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DBEB424A-1538-4F14-BA57-BA4E326EF4D8}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "14_Bowling/vbnet/Bowling.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bowling</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "14_Bowling/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "15_Boxing/README.md",
    "content": "### Boxing\n\nThis program simulates a three-round Olympic boxing match. The computer coaches one of the boxers and determines his punches and defences, while you do the same for your boxer. At the start of the match, you may specify your man’s best punch and his vulnerability.\n\nThere are approximately seven major punches per round, although this may be varied. The best out of three rounds wins.\n\nJesse Lynch of St. Paul, Minnesota created this program.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=28)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=43)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The code that handles player punch type 1 checks for opponent weakness type 4; this is almost certainly a mistake.\n\n- Line breaks or finishing messages are omitted in various cases.  For example, if the player does a hook, and that's the opponent's weakness, then 7 points are silently awarded without outputting any description or line break, and the next sub-round will begin on the same line.\n\n- When the opponent selects a hook, control flow falls through to the uppercut case.  Perhaps related, a player weakness of type 2 (hook) never has any effect on the game.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "15_Boxing/boxing.bas",
    "content": "1 PRINT TAB(33);\"BOXING\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\"\n5 J=0\n6 L=0\n8 PRINT\n10 PRINT \"WHAT IS YOUR OPPONENT'S NAME\";\n20 INPUT J$\n30 PRINT \"INPUT YOUR MAN'S NAME\";\n40 INPUT L$\n50 PRINT \"DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\"\n60 PRINT \"WHAT IS YOUR MANS BEST\";\n64 INPUT B\n70 PRINT \"WHAT IS HIS VULNERABILITY\";\n80 INPUT D\n90 B1=INT(4*RND(1)+1)\n100 D1=INT(4*RND(1)+1)\n110 IF B1=D1 THEN 90\n120 PRINT J$;\"'S ADVANTAGE IS\";B1;\"AND VULNERABILITY IS SECRET.\":PRINT\n130 FOR R=1 TO 3\n140 IF J>= 2 THEN 1040\n150 IF L>=2 THEN 1060\n160 X=0\n170 Y=0\n180 PRINT \"ROUND\";R;\"BEGINS...\"\n185 FOR R1= 1 TO 7\n190 I=INT(10*RND(1)+1)\n200 IF I>5 THEN 600\n210 PRINT L$;\"'S PUNCH\";\n220 INPUT P\n221 IF P=B THEN 225\n222 GOTO 230\n225 X=X+2\n230 IF P=1 THEN 340\n240 IF P=2 THEN 450\n250 IF P=3 THEN 520\n270 PRINT L$;\" JABS AT \";J$\"'S HEAD \";\n271 IF D1=4 THEN 290\n275 C=INT(8*RND(1)+1)\n280 IF C<4 THEN 310\n290 X=X+3\n300 GOTO 950\n310 PRINT \"IT'S BLOCKED.\"\n330 GOTO 950\n340 PRINT L$ \" SWINGS AND \";\n341 IF D1=4 THEN 410\n345 X3=INT(30*RND(1)+1)\n350 IF X3<10 THEN 410\n360 PRINT \"HE MISSES \";\n370 PRINT\n375 IF X=1 THEN 950\n380 PRINT\n390 PRINT\n400 GOTO 300\n410 PRINT \"HE CONNECTS!\"\n420 IF X>35 THEN 980\n425 X=X+15\n440 GOTO 300\n450 PRINT L$;\" GIVES THE HOOK... \";\n455 IF D1=2 THEN 480\n460 H1=INT(2*RND(1)+1)\n470 IF H1=1 THEN 500\n475 PRINT \"CONNECTS...\"\n480 X=X+7\n490 GOTO 300\n500 PRINT \"BUT IT'S BLOCKED!!!!!!!!!!!!!\"\n510 GOTO 300\n520 PRINT L$ \" TRIES AN UPPERCUT \";\n530 IF D1=3 THEN 570\n540 D5=INT(100*RND(1)+1)\n550 IF D5<51 THEN 570\n560 PRINT \"AND IT'S BLOCKED (LUCKY BLOCK!)\"\n565 GOTO 300\n570 PRINT \"AND HE CONNECTS!\"\n580 X=X+4\n590 GOTO 300\n600 J7=INT(4*RND(1)+1)\n601 IF J7 =B1 THEN 605\n602 GOTO 610\n605 Y=Y+2\n610 IF J7=1 THEN 720\n620 IF J7=2 THEN 810\n630 IF J7 =3 THEN 860\n640 PRINT J$;\" JABS AND \";\n645 IF D=4 THEN 700\n650 Z4=INT(7*RND(1)+1)\n655 IF Z4>4 THEN 690\n660 PRINT \"IT'S BLOCKED!\"\n670 GOTO 300\n690 PRINT \" BLOOD SPILLS !!!\"\n700 Y=Y+5\n710 GOTO 300\n720 PRINT J$\" TAKES A FULL SWING AND\";\n730 IF D=1 THEN 770\n740 R6=INT(60*RND(1)+1)\n745 IF R6 <30 THEN 770\n750 PRINT \" IT'S BLOCKED!\"\n760 GOTO 300\n770 PRINT \" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\"\n780 IF Y>35 THEN 1010\n790 Y=Y+15\n800 GOTO 300\n810 PRINT J$;\" GETS \";L$;\" IN THE JAW (OUCH!)\"\n820 Y=Y+7\n830 PRINT \"....AND AGAIN!\"\n835 Y=Y+5\n840 IF Y>35 THEN 1010\n850 PRINT\n860 PRINT L$;\" IS ATTACKED BY AN UPPERCUT (OH,OH)...\"\n865 IF D=3 THEN 890\n870 Q4=INT(200*RND(1)+1)\n880 IF Q4>75 THEN 920\n890 PRINT \"AND \";J$;\" CONNECTS...\"\n900 Y=Y+8\n910 GOTO 300\n920 PRINT \" BLOCKS AND HITS \";J$;\" WITH A HOOK.\"\n930 X=X+5\n940 GOTO 300\n950 NEXT R1\n951 IF X>Y THEN 955\n952 PRINT:PRINT J$\" WINS ROUND\" R\n953 J=J+1\n954 GOTO 960\n955 PRINT:PRINT L$\" WINS ROUND\"R\n956 L=L+1\n960 NEXT R\n961 IF J>= 2 THEN 1040\n962 IF L>=2 THEN 1060\n980 PRINT J$ \" IS KNOCKED COLD AND \" L$\" IS THE WINNER AND CHAMP!\";\n1000 GOTO 1080\n1010 PRINT L$ \" IS KNOCKED COLD AND \" J$\" IS THE WINNER AND CHAMP!\";\n1030 GOTO 1000\n1040 PRINT J$ \" WINS (NICE GOING,\" J$;\").\"\n1050 GOTO 1000\n1060 PRINT L$ \" AMAZINGLY WINS!!\"\n1070 GOTO 1000\n1080 PRINT\n1085 PRINT\n1090 PRINT \"AND NOW GOODBYE FROM THE OLYMPIC ARENA.\"\n1100 PRINT\n1110 END\n"
  },
  {
    "path": "15_Boxing/csharp/AttackStrategy.cs",
    "content": "﻿namespace Boxing;\n\npublic abstract class AttackStrategy\n{\n    protected const int KnockoutDamageThreshold = 35;\n    protected readonly Boxer Other;\n    protected readonly Stack<Action> Work;\n    private readonly Action _notifyGameEnded;\n\n    public AttackStrategy(Boxer other, Stack<Action> work, Action notifyGameEnded)\n    {\n        Other = other;\n        Work = work;\n        _notifyGameEnded = notifyGameEnded;\n    }\n\n    public void Attack()\n    {\n        var punch = GetPunch();\n        if (punch.IsBestPunch)\n        {\n            Other.DamageTaken += 2;\n        }\n\n        Work.Push(punch.Punch switch\n        {\n            Punch.FullSwing => FullSwing,\n            Punch.Hook => Hook,\n            Punch.Uppercut => Uppercut,\n            _ => Jab\n        });\n    }\n\n    protected abstract AttackPunch GetPunch();\n    protected abstract void FullSwing();\n    protected abstract void Hook();\n    protected abstract void Uppercut();\n    protected abstract void Jab();\n\n    protected void RegisterKnockout(string knockoutMessage)\n    {\n        Work.Clear();\n        _notifyGameEnded();\n        Console.WriteLine(knockoutMessage);\n    }\n\n    protected record AttackPunch(Punch Punch, bool IsBestPunch);\n}\n"
  },
  {
    "path": "15_Boxing/csharp/Boxer.cs",
    "content": "﻿namespace Boxing;\n\npublic class Boxer\n{\n    private int _wins;\n\n    private string Name { get; set; } = string.Empty;\n\n    public Punch BestPunch { get; set; }\n\n    public Punch Vulnerability { get; set; }\n\n    public void SetName(string prompt)\n    {\n        Console.WriteLine(prompt);\n        string? name;\n        do\n        {\n            name = Console.ReadLine();\n        } while (string.IsNullOrWhiteSpace(name));\n        Name = name;\n    }\n\n    public int DamageTaken { get; set; }\n\n    public void ResetForNewRound() => DamageTaken = 0;\n\n    public void RecordWin() => _wins += 1;\n\n    public bool IsWinner => _wins >= 2;\n\n    public override string ToString() => Name;\n}\n\npublic class Opponent : Boxer\n{\n    public void SetRandomPunches()\n    {\n        do\n        {\n            BestPunch = (Punch) GameUtils.Roll(4); // B1\n            Vulnerability = (Punch) GameUtils.Roll(4); // D1\n        } while (BestPunch == Vulnerability);\n    }\n}\n"
  },
  {
    "path": "15_Boxing/csharp/Boxing.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "15_Boxing/csharp/Boxing.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Boxing\", \"Boxing.csproj\", \"{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "15_Boxing/csharp/OpponentAttackStrategy.cs",
    "content": "﻿using static Boxing.GameUtils;\nusing static System.Console;\n\nnamespace Boxing;\n\npublic class OpponentAttackStrategy : AttackStrategy\n{\n    private readonly Opponent _opponent;\n\n    public OpponentAttackStrategy(Opponent opponent, Boxer player,  Action notifyGameEnded, Stack<Action> work) : base(player, work, notifyGameEnded)\n    {\n        _opponent = opponent;\n    }\n\n    protected override AttackPunch GetPunch()\n    {\n        var punch = (Punch)Roll(4);\n        return new AttackPunch(punch, punch == _opponent.BestPunch);\n    }\n\n    protected override void FullSwing() // 720\n    {\n        Write($\"{_opponent}  TAKES A FULL SWING AND\");\n        if (Other.Vulnerability == Punch.FullSwing)\n        {\n            ScoreFullSwing();\n        }\n        else\n        {\n            if (RollSatisfies(60, x => x < 30))\n            {\n                WriteLine(\" IT'S BLOCKED!\");\n            }\n            else\n            {\n                ScoreFullSwing();\n            }\n        }\n\n        void ScoreFullSwing()\n        {\n            WriteLine(\" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\");\n            if (Other.DamageTaken > KnockoutDamageThreshold)\n            {\n                Work.Push(RegisterOtherKnockedOut);\n            }\n            Other.DamageTaken += 15;\n        }\n    }\n\n    protected override void Hook() // 810\n    {\n        Write($\"{_opponent} GETS {Other} IN THE JAW (OUCH!)\");\n        Other.DamageTaken += 7;\n        WriteLine(\"....AND AGAIN!\");\n        Other.DamageTaken += 5;\n        if (Other.DamageTaken > KnockoutDamageThreshold)\n        {\n            Work.Push(RegisterOtherKnockedOut);\n        }\n    }\n\n    protected override void Uppercut() // 860\n    {\n        Write($\"{Other} IS ATTACKED BY AN UPPERCUT (OH,OH)...\");\n        if (Other.Vulnerability == Punch.Uppercut)\n        {\n            ScoreUppercut();\n        }\n        else\n        {\n            if (RollSatisfies(200, x => x > 75))\n            {\n                WriteLine($\" BLOCKS AND HITS {_opponent} WITH A HOOK.\");\n                _opponent.DamageTaken += 5;\n            }\n            else\n            {\n                ScoreUppercut();\n            }\n        }\n\n        void ScoreUppercut()\n        {\n            WriteLine($\"AND {_opponent} CONNECTS...\");\n            Other.DamageTaken += 8;\n        }\n    }\n\n    protected override void Jab() // 640\n    {\n        Write($\"{_opponent}  JABS AND \");\n        if (Other.Vulnerability == Punch.Jab)\n        {\n            ScoreJab();\n        }\n        else\n        {\n            if (RollSatisfies(7, x => x > 4))\n            {\n                WriteLine(\"BLOOD SPILLS !!!\");\n                ScoreJab();\n            }\n            else\n            {\n                WriteLine(\"IT'S BLOCKED!\");\n            }\n        }\n\n        void ScoreJab() => Other.DamageTaken += 5;\n    }\n\n    private void RegisterOtherKnockedOut()\n        => RegisterKnockout($\"{Other} IS KNOCKED COLD AND {_opponent} IS THE WINNER AND CHAMP!\");\n}\n"
  },
  {
    "path": "15_Boxing/csharp/PlayerAttackStrategy.cs",
    "content": "﻿using static Boxing.GameUtils;\nusing static System.Console;\nnamespace Boxing;\n\npublic class PlayerAttackStrategy : AttackStrategy\n{\n    private readonly Boxer _player;\n\n    public PlayerAttackStrategy(Boxer player, Opponent opponent, Action notifyGameEnded, Stack<Action> work)\n        : base(opponent, work, notifyGameEnded) => _player = player;\n\n    protected override AttackPunch GetPunch()\n    {\n        var punch = GameUtils.GetPunch($\"{_player}'S PUNCH\");\n        return new AttackPunch(punch, punch == _player.BestPunch);\n    }\n\n    protected override void FullSwing() // 340\n    {\n        Write($\"{_player} SWINGS AND \");\n        if (Other.Vulnerability == Punch.FullSwing)\n        {\n            ScoreFullSwing();\n        }\n        else\n        {\n            if (RollSatisfies(30, x => x < 10))\n            {\n                ScoreFullSwing();\n            }\n            else\n            {\n                WriteLine(\"HE MISSES\");\n            }\n        }\n\n        void ScoreFullSwing()\n        {\n            WriteLine(\"HE CONNECTS!\");\n            if (Other.DamageTaken > KnockoutDamageThreshold)\n            {\n                Work.Push(() => RegisterKnockout($\"{Other} IS KNOCKED COLD AND {_player} IS THE WINNER AND CHAMP!\"));\n            }\n            Other.DamageTaken += 15;\n        }\n    }\n\n    protected override void Uppercut() // 520\n    {\n        Write($\"{_player} TRIES AN UPPERCUT \");\n        if (Other.Vulnerability == Punch.Uppercut)\n        {\n            ScoreUpperCut();\n        }\n        else\n        {\n            if (RollSatisfies(100, x => x < 51))\n            {\n                ScoreUpperCut();\n            }\n            else\n            {\n                WriteLine(\"AND IT'S BLOCKED (LUCKY BLOCK!)\");\n            }\n        }\n\n        void ScoreUpperCut()\n        {\n            WriteLine(\"AND HE CONNECTS!\");\n            Other.DamageTaken += 4;\n        }\n    }\n\n    protected override void Hook() // 450\n    {\n        Write($\"{_player} GIVES THE HOOK... \");\n        if (Other.Vulnerability == Punch.Hook)\n        {\n            ScoreHookOnOpponent();\n        }\n        else\n        {\n            if (RollSatisfies(2, x => x == 1))\n            {\n                WriteLine(\"BUT IT'S BLOCKED!!!!!!!!!!!!!\");\n            }\n            else\n            {\n                ScoreHookOnOpponent();\n            }\n        }\n\n        void ScoreHookOnOpponent()\n        {\n            WriteLine(\"CONNECTS...\");\n            Other.DamageTaken += 7;\n        }\n    }\n\n    protected override void Jab()\n    {\n        WriteLine($\"{_player} JABS AT {Other}'S HEAD\");\n        if (Other.Vulnerability == Punch.Jab)\n        {\n            ScoreJabOnOpponent();\n        }\n        else\n        {\n            if (RollSatisfies(8, x => x < 4))\n            {\n                WriteLine(\"IT'S BLOCKED.\");\n            }\n            else\n            {\n                ScoreJabOnOpponent();\n            }\n        }\n\n        void ScoreJabOnOpponent() => Other.DamageTaken += 3;\n    }\n}\n"
  },
  {
    "path": "15_Boxing/csharp/Program.cs",
    "content": "﻿using Boxing;\nusing static Boxing.GameUtils;\nusing static System.Console;\n\nWriteLine(new string('\\t', 33) + \"BOXING\");\nWriteLine(new string('\\t', 15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\nWriteLine(\"{0}{0}{0}BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS){0}\", Environment.NewLine);\n\nvar opponent = new Opponent();\nopponent.SetName(\"WHAT IS YOUR OPPONENT'S NAME\"); // J$\nvar player = new Boxer();\nplayer.SetName(\"INPUT YOUR MAN'S NAME\"); // L$\n\nPrintPunchDescription();\nplayer.BestPunch = GetPunch(\"WHAT IS YOUR MANS BEST\"); // B\nplayer.Vulnerability = GetPunch(\"WHAT IS HIS VULNERABILITY\"); // D\nopponent.SetRandomPunches();\nWriteLine($\"{opponent}'S ADVANTAGE IS {opponent.BestPunch.ToFriendlyString()} AND VULNERABILITY IS SECRET.\");\n\n\nfor (var i = 1; i <= 3; i ++) // R\n{\n    var round = new Round(player, opponent, i);\n    round.Start();\n    round.CheckOpponentWin();\n    round.CheckPlayerWin();\n    if (round.GameEnded) break;\n}\nWriteLine(\"{0}{0}AND NOW GOODBYE FROM THE OLYMPIC ARENA.{0}\", Environment.NewLine);\n"
  },
  {
    "path": "15_Boxing/csharp/Punch.cs",
    "content": "namespace Boxing;\n\npublic enum Punch\n{\n    FullSwing = 1,\n    Hook = 2,\n    Uppercut = 3,\n    Jab = 4\n}\n"
  },
  {
    "path": "15_Boxing/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "15_Boxing/csharp/Round.cs",
    "content": "﻿namespace Boxing;\n\nclass Round\n{\n\n    private readonly Boxer _player;\n    private readonly Boxer _opponent;\n    private readonly int _round;\n    private Stack<Action> _work = new();\n    private readonly PlayerAttackStrategy _playerAttackStrategy;\n    private readonly OpponentAttackStrategy _opponentAttackStrategy;\n\n    public bool GameEnded { get; private set; }\n\n    public Round(Boxer player, Opponent opponent, int round)\n    {\n        _player = player;\n        _opponent = opponent;\n        _round = round;\n        _work.Push(ResetPlayers);\n        _work.Push(CheckOpponentWin);\n        _work.Push(CheckPlayerWin);\n\n        void NotifyGameEnded() => GameEnded = true;\n        _playerAttackStrategy = new PlayerAttackStrategy(player, opponent, NotifyGameEnded, _work);\n        _opponentAttackStrategy = new OpponentAttackStrategy(opponent, player, NotifyGameEnded, _work);\n    }\n\n    public void Start()\n    {\n        while (_work.Count > 0)\n        {\n            var action = _work.Pop();\n            // This delay does not exist in the VB code but it makes a bit easier to follow the game.\n            // I assume the computers at the time were slow enough\n            // so that they did not need this delay...\n            Thread.Sleep(300);\n            action();\n        }\n    }\n\n    public void CheckOpponentWin()\n    {\n        if (_opponent.IsWinner)\n        {\n            Console.WriteLine($\"{_opponent} WINS (NICE GOING, {_opponent}).\");\n            GameEnded = true;\n        }\n    }\n\n    public void CheckPlayerWin()\n    {\n        if (_player.IsWinner)\n        {\n            Console.WriteLine($\"{_player}  AMAZINGLY WINS!!\");\n            GameEnded = true;\n        }\n    }\n\n    private void ResetPlayers()\n    {\n        _player.ResetForNewRound();\n        _opponent.ResetForNewRound();\n        _work.Push(RoundBegins);\n    }\n\n    private void RoundBegins()\n    {\n        Console.WriteLine();\n        Console.WriteLine($\"ROUND {_round} BEGINS...\");\n        _work.Push(CheckRoundWinner);\n        for (var i = 0; i < 7; i++)\n        {\n            _work.Push(DecideWhoAttacks);\n        }\n    }\n\n    private void CheckRoundWinner()\n    {\n        if (_opponent.DamageTaken > _player.DamageTaken)\n        {\n            Console.WriteLine($\"{_player} WINS ROUND {_round}\");\n            _player.RecordWin();\n        }\n        else\n        {\n            Console.WriteLine($\"{_opponent} WINS ROUND {_round}\");\n            _opponent.RecordWin();\n        }\n    }\n\n    private void DecideWhoAttacks()\n    {\n        _work.Push( GameUtils.RollSatisfies(10, x => x > 5) ? _opponentAttackStrategy.Attack : _playerAttackStrategy.Attack );\n    }\n}\n"
  },
  {
    "path": "15_Boxing/csharp/Utils.cs",
    "content": "﻿namespace Boxing;\npublic static class GameUtils\n{\n    private static readonly Random Rnd = new((int) DateTime.UtcNow.Ticks);\n    public static void PrintPunchDescription() =>\n        Console.WriteLine($\"DIFFERENT PUNCHES ARE: {PunchDesc(Punch.FullSwing)}; {PunchDesc(Punch.Hook)}; {PunchDesc(Punch.Uppercut)}; {PunchDesc(Punch.Jab)}.\");\n\n    private static string PunchDesc(Punch punch) => $\"({(int)punch}) {punch.ToFriendlyString()}\";\n\n    public static Punch GetPunch(string prompt)\n    {\n        Console.WriteLine(prompt);\n        Punch result;\n        while (!Enum.TryParse(Console.ReadLine(), out result) || !Enum.IsDefined(typeof(Punch), result))\n        {\n            PrintPunchDescription();\n        }\n        return result;\n    }\n\n    public static Func<int, int> Roll { get;  } =  upperLimit => (int) (upperLimit * Rnd.NextSingle()) + 1;\n\n    public static bool RollSatisfies(int upperLimit, Predicate<int> predicate) => predicate(Roll(upperLimit));\n\n    public static string ToFriendlyString(this Punch punch)\n        => punch switch\n        {\n            Punch.FullSwing => \"FULL SWING\",\n            Punch.Hook => \"HOOK\",\n            Punch.Uppercut => \"UPPERCUT\",\n            Punch.Jab => \"JAB\",\n            _ => throw new ArgumentOutOfRangeException(nameof(punch), punch, null)\n        };\n\n}\n"
  },
  {
    "path": "15_Boxing/java/Basic.java",
    "content": "import java.util.Scanner;\n\n/**\n * It provide some kind of BASIC language behaviour simulations.\n */\nfinal class Basic {\n\n    public static int randomOf(int base) {\n        return (int)Math.round(Math.floor(base* Math.random() + 1));\n    }\n\n    /**\n     * The Console \"simulate\" the message error when input does not match with the expected type.\n     * Specifically for this game if you enter an String when and int was expected.\n     */\n    public static class Console {\n        private final Scanner input = new Scanner(System.in);\n\n        public String readLine() {\n            return input.nextLine();\n        }\n\n        public int readInt() {\n            int ret = -1;\n            boolean failedInput = true;\n            do {\n                boolean b = input.hasNextInt();\n                if (b) {\n                    ret = input.nextInt();\n                    failedInput = false;\n                } else {\n                    input.next(); // discard read\n                    System.out.print(\"!NUMBER EXPECTED - RETRY INPUT LINE\\n? \");\n                }\n\n            } while (failedInput);\n\n            return ret;\n        }\n\n        public void print(String message, Object... args) {\n            System.out.printf(message, args);\n        }\n    }\n}\n"
  },
  {
    "path": "15_Boxing/java/Boxing.java",
    "content": "/**\n * Boxing\n *\n * <p>\n * Based on the Basic game of BatNum here\n * https://github.com/coding-horror/basic-computer-games/tree/main/15%20Boxing\n * <p>\n */\npublic class Boxing {\n\n    private static final Basic.Console console = new Basic.Console();\n\n    private GameSession session;\n\n    public void play() {\n        showIntro();\n\n        loadPlayers();\n\n        console.print(\"%s'S ADVANTAGE IS %d AND VULNERABILITY IS SECRET.\\n\", session.getOpponent().getName(), session.getOpponent().getBestPunch().getCode());\n\n\n        for (int roundNro = 1; roundNro <= 3; roundNro++) {\n            if (session.isOver())\n                break;\n\n            session.resetPoints();\n            console.print(\"\\nROUND %d BEGINS...%n\", roundNro);\n\n            for (int majorPunches = 1; majorPunches <= 7; majorPunches++) {\n                long i = Basic.randomOf(10);\n\n                if (i > 5) {\n                    boolean stopPunches = opponentPunch();\n                    if (stopPunches ) break;\n                } else {\n                    playerPunch();\n                }\n            }\n            showRoundWinner(roundNro);\n        }\n        showWinner();\n    }\n\n    private boolean opponentPunch() {\n        final Punch punch = Punch.random();\n\n        if (punch == session.getOpponent().getBestPunch()) session.addOpponentPoints(2);\n\n        if (punch == Punch.FULL_SWING) {\n            console.print(\"%s TAKES A FULL SWING AND\", session.getOpponent().getName());\n            long r6 = Basic.randomOf(60);\n\n            if (session.getPlayer().hitVulnerability(Punch.FULL_SWING) || r6 < 30) {\n                console.print(\" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\\n\");\n                if (session.getPoints(session.getOpponent()) > 35) {\n\n                    session.setKnocked();\n                    return true;\n                }\n                session.addOpponentPoints(15);\n            } else {\n                console.print(\" IT'S BLOCKED!\\n\");\n            }\n        }\n\n        if (punch == Punch.HOOK  || punch == Punch.UPPERCUT) {\n            if (punch == Punch.HOOK) {\n                console.print(\"%s GETS %s IN THE JAW (OUCH!)\\n\", session.getOpponent().getName(), session.getPlayer().getName());\n\n                session.addOpponentPoints(7);\n                console.print(\"....AND AGAIN!\\n\");\n\n                session.addOpponentPoints(5);\n                if (session.getPoints(session.getOpponent()) > 35) {\n                    session.setKnocked();\n                    return true;\n                }\n                console.print(\"\\n\");\n\n            }\n            console.print(\"%s IS ATTACKED BY AN UPPERCUT (OH,OH)...\\n\", session.getPlayer().getName());\n            long q4 = Basic.randomOf(200);\n            if (session.getPlayer().hitVulnerability(Punch.UPPERCUT) || q4 <= 75) {\n                console.print(\"AND %s CONNECTS...\\n\", session.getOpponent().getName());\n\n                session.addOpponentPoints(8);\n            } else {\n                console.print(\" BLOCKS AND HITS %s WITH A HOOK.\\n\", session.getOpponent().getName());\n\n                session.addPlayerPoints(5);\n            }\n        }\n        else {\n            console.print(\"%s JABS AND \", session.getOpponent().getName());\n            long z4 = Basic.randomOf(7);\n            if (session.getPlayer().hitVulnerability(Punch.JAB))\n\n                session.addOpponentPoints(5);\n            else if (z4 > 4) {\n                console.print(\" BLOOD SPILLS !!!\\n\");\n\n                session.addOpponentPoints(5);\n            } else {\n                console.print(\"IT'S BLOCKED!\\n\");\n            }\n        }\n        return true;\n    }\n\n    private void playerPunch() {\n        console.print(\"%s'S PUNCH? \", session.getPlayer().getName());\n        final Punch punch = Punch.fromCode(console.readInt());\n\n        if (punch == session.getPlayer().getBestPunch()) session.addPlayerPoints(2);\n\n        switch (punch) {\n            case FULL_SWING -> {\n                console.print(\"%s SWINGS AND \", session.getPlayer().getName());\n                if (session.getOpponent().getBestPunch() == Punch.JAB) {\n                    console.print(\"HE CONNECTS!\\n\");\n                    if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15);\n                } else {\n                    long x3 = Basic.randomOf(30);\n                    if (x3 < 10) {\n                        console.print(\"HE CONNECTS!\\n\");\n                        if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15);\n                    } else {\n                        console.print(\"HE MISSES \\n\");\n                        if (session.getPoints(session.getPlayer()) != 1) console.print(\"\\n\\n\");\n                    }\n                }\n            }\n            case HOOK -> {\n                console.print(\"\\n%s GIVES THE HOOK... \", session.getPlayer().getName());\n                long h1 = Basic.randomOf(2);\n                if (session.getOpponent().getBestPunch() == Punch.HOOK) {\n\n                    session.addPlayerPoints(7);\n                } else if (h1 == 1) {\n                    console.print(\"BUT IT'S BLOCKED!!!!!!!!!!!!!\\n\");\n                } else {\n                    console.print(\"CONNECTS...\\n\");\n\n                    session.addPlayerPoints(7);\n                }\n            }\n            case UPPERCUT -> {\n                console.print(\"\\n%s  TRIES AN UPPERCUT \", session.getPlayer().getName());\n                long d5 = Basic.randomOf(100);\n                if (session.getOpponent().getBestPunch() == Punch.UPPERCUT || d5 < 51) {\n                    console.print(\"AND HE CONNECTS!\\n\");\n\n                    session.addPlayerPoints(4);\n                } else {\n                    console.print(\"AND IT'S BLOCKED (LUCKY BLOCK!)\\n\");\n                }\n            }\n            default -> {\n                console.print(\"%s JABS AT %s'S HEAD \\n\", session.getPlayer().getName(), session.getOpponent().getName());\n                if (session.getOpponent().getBestPunch() == Punch.JAB) {\n\n                    session.addPlayerPoints(3);\n                } else {\n                    long c = Basic.randomOf(8);\n                    if (c < 4) {\n                        console.print(\"IT'S BLOCKED.\\n\");\n                    } else {\n\n                        session.addPlayerPoints(3);\n                    }\n                }\n            }\n        }\n    }\n\n    private void showRoundWinner(int roundNro) {\n        if (session.isRoundWinner(session.getPlayer())) {\n            console.print(\"\\n %s WINS ROUND %d\\n\", session.getPlayer().getName(), roundNro);\n            session.addRoundWind(session.getPlayer());\n        } else {\n            console.print(\"\\n %s WINS ROUND %d\\n\", session.getOpponent().getName(), roundNro);\n            session.addRoundWind(session.getOpponent());\n        }\n    }\n\n    private void showWinner() {\n        if (session.isGameWinner(session.getOpponent())) {\n            console.print(\"%s WINS (NICE GOING, \" + session.getOpponent().getName() + \").\", session.getOpponent().getName());\n        } else if (session.isGameWinner(session.getPlayer())) {\n            console.print(\"%s AMAZINGLY WINS!!\", session.getPlayer().getName());\n        } else if (session.isPlayerKnocked()) {\n            console.print(\"%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!\", session.getPlayer().getName(), session.getOpponent().getName());\n        } else {\n            console.print(\"%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!\", session.getOpponent().getName(), session.getPlayer().getName());\n        }\n\n        console.print(\"\\n\\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\\n\");\n    }\n\n    private void loadPlayers() {\n        console.print(\"WHAT IS YOUR OPPONENT'S NAME? \");\n        final String opponentName = console.readLine();\n\n        console.print(\"INPUT YOUR MAN'S NAME? \");\n        final String playerName = console.readLine();\n\n        console.print(\"DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\\n\");\n        console.print(\"WHAT IS YOUR MANS BEST? \");\n\n        final int b = console.readInt();\n\n        console.print(\"WHAT IS HIS VULNERABILITY? \");\n        final int d = console.readInt();\n\n        final Player player = new Player(playerName, Punch.fromCode(b), Punch.fromCode(d));\n        final Player opponent = new Player(opponentName);\n\n        session = new GameSession(player, opponent);\n    }\n\n    private void showIntro () {\n        console.print(\"                                 BOXING\\n\");\n        console.print(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\");\n        console.print(\"BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\\n\\n\");\n    }\n}\n"
  },
  {
    "path": "15_Boxing/java/BoxingGame.java",
    "content": "public class BoxingGame {\n\n    public static void main(String[] args) {\n        new Boxing().play();\n    }\n}\n"
  },
  {
    "path": "15_Boxing/java/GameSession.java",
    "content": "/**\n * Game Session\n * The session store the state of the game\n */\npublic class GameSession {\n    private final Player player;\n    private final Player opponent;\n    private int opponentRoundWins = 0;\n    private int playerRoundWins = 0;\n\n    int playerPoints = 0;\n    int opponentPoints = 0;\n    boolean knocked = false;\n\n    GameSession(Player player, Player opponent) {\n        this.player = player;\n        this.opponent = opponent;\n    }\n\n    public Player getPlayer() { return player;}\n    public Player getOpponent() { return opponent;}\n\n    public void setKnocked() {\n        knocked = true;\n    }\n\n    public void resetPoints() {\n        playerPoints = 0;\n        opponentPoints = 0;\n    }\n\n    public void addPlayerPoints(int ptos) { playerPoints+=ptos;}\n    public void addOpponentPoints(int ptos) { opponentPoints+=ptos;}\n\n    public int getPoints(Player player) {\n        if(player.isPlayer())\n            return playerPoints;\n        else\n            return opponentPoints;\n    }\n\n    public void addRoundWind(Player player) {\n        if(player.isPlayer()) playerRoundWins++; else opponentRoundWins++;\n    }\n\n    public boolean isOver() {\n        return (opponentRoundWins >= 2 || playerRoundWins >= 2);\n    }\n\n    public boolean isRoundWinner(Player player) {\n        if (player.isPlayer())\n            return playerPoints > opponentPoints;\n        else\n            return opponentPoints > playerPoints;\n    }\n\n    public boolean isGameWinner(Player player) {\n        if (player.isPlayer())\n            return playerRoundWins > 2;\n        else\n            return opponentRoundWins > 2;\n    }\n\n    public boolean isPlayerKnocked() {\n        return knocked;\n    }\n}\n"
  },
  {
    "path": "15_Boxing/java/Player.java",
    "content": "/**\n * The Player class model the user and compuer player\n */\npublic class Player {\n    private final String name;\n    private final Punch bestPunch;\n    private final Punch vulnerability;\n    private boolean isPlayer = false;\n\n    public Player(String name, Punch bestPunch, Punch vulnerability) {\n        this.name = name;\n        this.bestPunch = bestPunch;\n        this.vulnerability = vulnerability;\n        this.isPlayer = true;\n    }\n\n    /**\n     * Player with random Best Punch and Vulnerability\n     */\n    public Player(String name) {\n        this.name = name;\n\n        int b1;\n        int d1;\n\n        do {\n            b1 = Basic.randomOf(4);\n            d1 = Basic.randomOf(4);\n        } while (b1 == d1);\n\n        this.bestPunch = Punch.fromCode(b1);\n        this.vulnerability = Punch.fromCode(d1);\n    }\n\n    public boolean isPlayer() { return isPlayer; }\n    public String getName() { return  name; }\n    public Punch getBestPunch() { return bestPunch; }\n\n    public boolean hitVulnerability(Punch punch) {\n        return vulnerability == punch;\n    }\n}\n"
  },
  {
    "path": "15_Boxing/java/Punch.java",
    "content": "import java.util.Arrays;\n\n/**\n * Types of Punches\n */\npublic enum Punch {\n    FULL_SWING(1),\n    HOOK(2),\n    UPPERCUT(3),\n    JAB(4);\n\n    private final int code;\n\n    Punch(int code) {\n        this.code = code;\n    }\n\n    int getCode() { return  code;}\n\n    public static Punch fromCode(int code) {\n        return Arrays.stream(Punch.values()).filter(p->p.code == code).findAny().orElse(null);\n    }\n\n    public static Punch random() {\n        return Punch.fromCode(Basic.randomOf(4));\n    }\n}\n"
  },
  {
    "path": "15_Boxing/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "15_Boxing/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "15_Boxing/javascript/boxing.html",
    "content": "<html>\n<head>\n<title>BOXING</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"boxing.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "15_Boxing/javascript/boxing.js",
    "content": "// BOWLING\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"BOXING\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\\n\");\n    j = 0;\n    l = 0;\n    print(\"\\n\");\n    print(\"WHAT IS YOUR OPPONENT'S NAME\");\n    js = await input();\n    print(\"INPUT YOUR MAN'S NAME\");\n    ls = await input();\n    print(\"DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\\n\");\n    print(\"WHAT IS YOUR MANS BEST\");\n    b = parseInt(await input());\n    print(\"WHAT IS HIS VULNERABILITY\");\n    d = parseInt(await input());\n    do {\n        b1 = Math.floor(4 * Math.random() + 1);\n        d1 = Math.floor(4 * Math.random() + 1);\n    } while (b1 == d1) ;\n    print(js + \"'S ADVANTAGE IS \" + b1 + \" AND VULNERABILITY IS SECRET.\\n\");\n    print(\"\\n\");\n    knocked = 0;\n    for (r = 1; r <= 3; r++) {\n        if (j >= 2)\n            break;\n        if (l >= 2)\n            break;\n        x = 0;\n        y = 0;\n        print(\"ROUND \" + r + \" BEGIN...\\n\");\n        for (r1 = 1; r1 <= 7; r1++) {\n            i = Math.floor(10 * Math.random() + 1);\n            if (i <= 5) {\n                print(ls + \"'S PUNCH\");\n                p = parseInt(await input());\n                if (p == b)\n                    x += 2;\n                if (p == 1) {\n                    print(ls + \" SWINGS AND \");\n                    x3 = Math.floor(30 * Math.random() + 1);\n                    if (d1 == 4 || x3 < 10) {\n                        print(\"HE CONNECTS!\\n\");\n                        if (x > 35) {\n                            r = 3;\n                            break;\n                        }\n                        x += 15;\n                    } else {\n                        print(\"HE MISSES \\n\");\n                        if (x != 1)\n                            print(\"\\n\\n\");\n                    }\n                } else if (p == 2) {\n                    print(ls + \" GIVES THE HOOK... \");\n                    h1 = Math.floor(2 * Math.random() + 1);\n                    if (d1 == 2) {\n                        x += 7;\n                    } else if (h1 != 1) {\n                        print(\"CONNECTS...\\n\");\n                        x += 7;\n                    } else {\n                        print(\"BUT IT'S BLOCKED!!!!!!!!!!!!!\\n\");\n                    }\n                } else if (p == 3) {\n                    print(ls + \" TRIES AN UPPERCUT \");\n                    d5 = Math.floor(100 * Math.random() + 1);\n                    if (d1 == 3 || d5 < 51) {\n                        print(\"AND HE CONNECTS!\\n\");\n                        x += 4;\n                    } else {\n                        print(\"AND IT'S BLOCKED (LUCKY BLOCK!)\\n\");\n                    }\n                } else {\n                    print(ls + \" JABS AT \" + js + \"'S HEAD \");\n                    c = Math.floor(8 * Math.random() + 1);\n                    if (d1 == 4 || c >= 4) {\n                        x += 3;\n                    } else {\n                        print(\"IT'S BLOCKED.\\n\");\n                    }\n                }\n            } else {\n                j7 = Math.random(4 * Math.random() + 1);\n                if (j7 == b1)\n                    y += 2;\n                if (j7 == 1) {\n                    print(js + \" TAKES A FULL SWING AND\");\n                    r6 = Math.floor(60 * Math.random() + 1);\n                    if (d == 1 || r6 < 30) {\n                        print(\" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\\n\");\n                        if (y > 35) {\n                            knocked = 1;\n                            r = 3;\n                            break;\n                        }\n                        y += 15;\n                    } else {\n                        print(\" IT'S BLOCKED!\\n\");\n                    }\n                } else if (j7 == 2 || j7 == 3) {\n                    if (j7 == 2) {\n                        print(js + \" GETS \" + ls + \" IN THE JAW (OUCH!)\\n\");\n                        y += 7;\n                        print(\"....AND AGAIN!\\n\");\n                        y += 5;\n                        if (y > 35) {\n                            knocked = 1;\n                            r = 3;\n                            break;\n                        }\n                        print(\"\\n\");\n                        // From original, it goes over from handling 2 to handling 3\n                    }\n                    print(ls + \" IS ATTACKED BY AN UPPERCUT (OH,OH)...\\n\");\n                    q4 = Math.floor(200 * Math.random() + 1);\n                    if (d == 3 || q4 <= 75) {\n                        print(\"AND \" + js + \" CONNECTS...\\n\");\n                        y += 8;\n                    } else {\n                        print(\" BLOCKS AND HITS \" + js + \" WITH A HOOK.\\n\");\n                        x += 5;\n                    }\n                } else {\n                    print(js + \" JABS AND \");\n                    z4 = Math.floor(7 * Math.random() + 1);\n                    if (d == 4)\n                        y += 5;\n                    else if (z4 > 4) {\n                        print(\" BLOOD SPILLS !!!\\n\");\n                        y += 5;\n                    } else {\n                        print(\"IT'S BLOCKED!\\n\");\n                    }\n                }\n            }\n        }\n        if (x > y) {\n            print(\"\\n\");\n            print(ls + \" WINS ROUND \" + r + \"\\n\");\n            l++;\n        } else {\n            print(\"\\n\");\n            print(js + \" WINS ROUND \" + r + \"\\n\");\n            j++;\n        }\n    }\n    if (j >= 2) {\n        print(js + \" WINS (NICE GOING, \" + js + \").\\n\");\n    } else if (l >= 2) {\n        print(ls + \" AMAZINGLY WINS!!\\n\");\n    } else if (knocked) {\n        print(ls + \" IS KNOCKED COLD AND \" + js + \" IS THE WINNER AND CHAMP!\\n\");\n    } else {\n        print(js + \" IS KNOCKED COLD AND \" + ls + \" IS THE WINNER AND CHAMP!\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"AND NOW GOODBYE FROM THE OLYMPIC ARENA.\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "15_Boxing/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "15_Boxing/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "15_Boxing/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "15_Boxing/perl/boxing.pl",
    "content": "#!/usr/bin/perl\n\n# Boxing program in Perl\n#   Required extensive restructuring to remove all of the GOTO's.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $Opp_won = 0;    # num rounds opponent has won\nmy $You_won = 0;    # num rounds you have won\nmy $Opp_name = \"\";  # opponent name\nmy $Your_name = \"\"; # your name\nmy $Your_best = 0;  # your best punch\nmy $Your_worst = 0; # your worst punch\nmy $Opp_best;       # opponent best punch\nmy $Opp_worst;      # opponent worst punch\nmy $Opp_damage;     # opponent damage ?\nmy $Your_damage;    # your damage ?\n\nsub get_punch\n{\n    my $prompt = shift;\n    my $p;\n    while (1)\n    {\n        print \"$prompt: \";\n        chomp($p = int(<>));\n        last if ($p >= 1 && $p <= 4);\n        print \"DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\\n\";\n    }\n    return $p;\n}\n\nprint \"\\n\";\nprint \" \" x 33, \"BOXING\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\nprint \"BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\\n\\n\";\nprint \"WHAT IS YOUR OPPONENT'S NAME: \";\nchomp($Opp_name = <>);\nprint \"INPUT YOUR MAN'S NAME: \";\nchomp($Your_name = <>);\nprint \"DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\\n\";\n$Your_best = get_punch(\"WHAT IS YOUR MANS BEST\");\n$Your_worst = get_punch(\"WHAT IS HIS VULNERABILITY\");\n\ndo {\n    $Opp_best = int(4*rand(1)+1);\n    $Opp_worst = int(4*rand(1)+1);\n} while ($Opp_best == $Opp_worst);\nprint \"$Opp_name\\'S ADVANTAGE IS $Opp_best AND VULNERABILITY IS SECRET.\\n\\n\";\n\nfor my $R (1 .. 3) # rounds\n{\n    last if ($Opp_won >= 2 || $You_won >= 2);\n    $Opp_damage = 0;\n    $Your_damage = 0;\n    print \"ROUND $R BEGINS...\\n\";\n    for my $R1 (1 .. 7) # 7 events per round?\n    {\n        if (int(10*rand(1)+1) <= 5)\n        {\n            my $your_punch = get_punch(\"$Your_name\\'S PUNCH\");\n            $Opp_damage += 2 if ($your_punch == $Your_best);\n\n            if    ($your_punch == 1) { punch1(); }\n            elsif ($your_punch == 2) { punch2(); }\n            elsif ($your_punch == 3) { punch3(); }\n            else                     { punch4(); }\n            next;\n        }\n\n        my $Opp_punch = int(4*rand(1)+1);\n        $Your_damage += 2 if ($Opp_punch  == $Opp_best);\n            \n        if    ($Opp_punch == 1) { opp1(); }\n        elsif ($Opp_punch == 2) { opp2(); }\n        elsif ($Opp_punch == 3) { opp3(); }\n        else                    { opp4(); }\n    }\n\n    if ($Opp_damage > $Your_damage)\n    {\n        print \"\\n$Your_name WINS ROUND $R\\n\\n\";\n        $You_won++;\n    }\n    else\n    {\n        print \"\\n$Opp_name WINS ROUND $R\\n\\n\";\n        $Opp_won++;\n    }\n}\n\nif ($Opp_won >= 2)\n{\n    done(\"$Opp_name WINS (NICE GOING, $Opp_name).\");\n}\n\n#else # if ($You_won >= 2)\ndone(\"$Your_name AMAZINGLY WINS!!\");\n\n###################################################\n\nsub done\n{\n    my $msg = shift;\n    print $msg;\n    print \"\\n\\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\\n\\n\";\n    exit(0);\n}\n\nsub punch1\n{\n    # $your_punch == 1, full swing\n    print \"$Your_name SWINGS AND \";\n    if ($Opp_worst == 4 || int(30*rand(1)+1) < 10)\n    {\n        print \"HE CONNECTS!\\n\";\n        if ($Opp_damage > 35)\n        {\n            done(\"$Opp_name IS KNOCKED COLD AND $Your_name IS THE WINNER AND CHAMP! \");\n        }\n        $Opp_damage += 15;\n    }\n    else\n    {\n        print \"HE MISSES\\n\";\n        print \"\\n\\n\" if ($Opp_damage != 1);\n    }\n}\n\nsub punch2\n{\n    # $your_punch == 2, hook\n    print \"$Your_name GIVES THE HOOK... \";\n    if ($Opp_worst == 2)\n    {\n        $Opp_damage += 7;\n        return;\n    }\n    if (int(2*rand(1)+1) == 1)\n    {\n        print \"BUT IT'S BLOCKED!!!!!!!!!!!!!\\n\";\n    }\n    else\n    {\n        print \"CONNECTS...\\n\";\n        $Opp_damage += 7;\n    }\n}\n\nsub punch3\n{\n    # $your_punch == 3, uppercut\n    print \"$Your_name TRIES AN UPPERCUT \";\n    if ($Opp_worst == 3 || int(100*rand(1)+1) < 51)\n    {\n        print \"AND HE CONNECTS!\\n\";\n        $Opp_damage += 4;\n    }\n    else\n    {\n        print \"AND IT'S BLOCKED (LUCKY BLOCK!)\\n\";\n    }\n}\n\nsub punch4\n{\n    # $your_punch == 4, jab\n    print \"$Your_name JABS AT $Opp_name\\'S HEAD \";\n    if ($Opp_worst == 4 || (int(8*rand(1)+1)) >= 4)\n    {\n        $Opp_damage += 3;\n        print \"\\n\";\n    }\n    else\n    {\n        print \"IT'S BLOCKED.\\n\";\n    }\n}\n\nsub opp1\n{\n    # opp_punch == 1\n    print \"$Opp_name TAKES A FULL SWING AND \";\n    if ($Your_worst == 1 || int(60*rand(1)+1) < 30)\n    {\n        print \" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\\n\";\n        if ($Your_damage > 35)\n        {\n            done(\"$Your_name IS KNOCKED COLD AND $Opp_name IS THE WINNER AND CHAMP!\");\n        }\n        $Your_damage += 15;\n    }\n    else\n    {\n        print \" IT'S BLOCKED!\\n\";\n    }\n}\n\nsub opp2\n{\n    # opp_punch == 2\n    print \"$Opp_name GETS $Your_name IN THE JAW (OUCH!)\\n\";\n    $Your_damage += 7;\n    print \"....AND AGAIN!\\n\";\n    $Your_damage += 5;\n    if ($Your_damage > 35)\n    {\n        done(\"$Your_name IS KNOCKED COLD AND $Opp_name IS THE WINNER AND CHAMP!\");\n    }\n    print \"\\n\";\n    # 2 continues into opp_punch == 3\n    opp3();\n}\n\nsub opp3()\n{\n    # opp_punch == 3\n    print \"$Your_name IS ATTACKED BY AN UPPERCUT (OH,OH)...\\n\";\n    if ($Your_worst != 3 && int(200*rand(1)+1) > 75)\n    {\n        print \" BLOCKS AND HITS $Opp_name WITH A HOOK.\\n\";\n        $Opp_damage += 5;\n    }\n    else\n    {\n        print \"AND $Opp_name CONNECTS...\\n\";\n        $Your_damage += 8;\n    }\n}\n\nsub opp4\n{\n    # opp_punch == 4\n    print \"$Opp_name JABS AND \";\n    if ($Your_worst == 4)\n    {\n        $Your_damage += 5;\n    }\n    elsif (int(7*rand(1)+1) > 4)\n    {\n        print \" BLOOD SPILLS !!!\\n\";\n        $Your_damage += 5;\n    }\n    else\n    {\n        print \"IT'S BLOCKED!\\n\";\n    }\n}\n"
  },
  {
    "path": "15_Boxing/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "15_Boxing/python/boxing.py",
    "content": "#!/usr/bin/env python3\nimport json\nimport random\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom typing import Dict, Literal, NamedTuple, Tuple, cast\n\n\nclass PunchProfile(NamedTuple):\n    choices: int\n    threshold: int\n    hit_damage: int\n    block_damage: int\n\n    pre_msg: str\n    hit_msg: str\n    blocked_msg: str\n\n    knockout_possible: bool = False\n\n    def is_hit(self) -> bool:\n        return random.randint(1, self.choices) <= self.threshold\n\n\n@dataclass\nclass Player:\n    name: str\n    best: int  # this hit guarantees 2 damage on opponent\n    weakness: int  # you're always hit when your opponent uses this punch\n    is_computer: bool\n\n    # for each of the 4 punch types, we have a probability of hitting\n    punch_profiles: Dict[Literal[1, 2, 3, 4], PunchProfile]\n\n    damage: int = 0\n    score: int = 0\n    knockedout: bool = False\n\n    def get_punch_choice(self) -> Literal[1, 2, 3, 4]:\n        if self.is_computer:\n            return random.randint(1, 4)  # type: ignore\n        punch = -1\n        while punch not in [1, 2, 3, 4]:\n            print(f\"{self.name}'S PUNCH\", end=\"? \")\n            punch = int(input())\n        return punch  # type: ignore\n\n\nKNOCKOUT_THRESHOLD = 35\n\nQUESTION_PROMPT = \"? \"\nKNOCKED_COLD = \"{loser} IS KNOCKED COLD AND {winner} IS THE WINNER AND CHAMP\"\n\n\ndef get_vulnerability() -> int:\n    print(\"WHAT IS HIS VULNERABILITY\", end=QUESTION_PROMPT)\n    return int(input())\n\n\ndef get_opponent_stats() -> Tuple[int, int]:\n    opponent_best = 0\n    opponent_weakness = 0\n    while opponent_best == opponent_weakness:\n        opponent_best = random.randint(1, 4)\n        opponent_weakness = random.randint(1, 4)\n    return opponent_best, opponent_weakness\n\n\ndef read_punch_profiles(filepath: Path) -> Dict[Literal[1, 2, 3, 4], PunchProfile]:\n    with open(filepath) as f:\n        punch_profile_dict = json.load(f)\n    return {\n        cast(Literal[1, 2, 3, 4], int(key)): PunchProfile(**value)\n        for key, value in punch_profile_dict.items()\n    }\n\n\ndef main() -> None:\n    print(\"BOXING\")\n    print(\"CREATIVE COMPUTING   MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n    print(\"BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\")\n\n    print(\"WHAT IS YOUR OPPONENT'S NAME\", end=QUESTION_PROMPT)\n    opponent_name = input()\n    print(\"WHAT IS YOUR MAN'S NAME\", end=QUESTION_PROMPT)\n    player_name = input()\n\n    print(\"DIFFERENT PUNCHES ARE 1 FULL SWING 2 HOOK 3 UPPERCUT 4 JAB\")\n    print(\"WHAT IS YOUR MAN'S BEST\", end=QUESTION_PROMPT)\n    player_best = int(input())  # noqa: TODO - this likely is a bug!\n    player_weakness = get_vulnerability()\n    player = Player(\n        name=player_name,\n        best=player_best,\n        weakness=player_weakness,\n        is_computer=False,\n        punch_profiles=read_punch_profiles(\n            Path(__file__).parent / \"player-profile.json\"\n        ),\n    )\n\n    opponent_best, opponent_weakness = get_opponent_stats()\n    opponent = Player(\n        name=opponent_name,\n        best=opponent_best,\n        weakness=opponent_weakness,\n        is_computer=True,\n        punch_profiles=read_punch_profiles(\n            Path(__file__).parent / \"opponent-profile.json\"\n        ),\n    )\n\n    print(\n        f\"{opponent.name}'S ADVANTAGE is {opponent.weakness} AND VULNERABILITY IS SECRET.\"\n    )\n\n    for round_number in (1, 2, 3):\n        play_round(round_number, player, opponent)\n\n    if player.knockedout:\n        print(KNOCKED_COLD.format(loser=player.name, winner=opponent.name))\n    elif opponent.knockedout:\n        print(KNOCKED_COLD.format(loser=opponent.name, winner=player.name))\n    elif opponent.score > player.score:\n        print(f\"{opponent.name} WINS (NICE GOING), {player.name}\")\n    else:\n        print(f\"{player.name} AMAZINGLY WINS\")\n\n    print(\"\\n\\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\")\n\n\ndef is_opponents_turn() -> bool:\n    return random.randint(1, 10) > 5\n\n\ndef play_round(round_number: int, player: Player, opponent: Player) -> None:\n    print(f\"ROUND {round_number} BEGINS...\\n\")\n    if opponent.score >= 2 or player.score >= 2:\n        return\n\n    for _action in range(7):\n        if is_opponents_turn():\n            punch = opponent.get_punch_choice()\n            active = opponent\n            passive = player\n        else:\n            punch = player.get_punch_choice()\n            active = player\n            passive = opponent\n\n        # Load the hit characteristics of the current player's punch\n        punch_profile = active.punch_profiles[punch]\n\n        if punch == active.best:\n            passive.damage += 2\n\n        print(punch_profile.pre_msg.format(active=active, passive=passive), end=\" \")\n        if passive.weakness == punch or punch_profile.is_hit():\n            print(punch_profile.hit_msg.format(active=active, passive=passive))\n            if punch_profile.knockout_possible and passive.damage > KNOCKOUT_THRESHOLD:\n                passive.knockedout = True\n                break\n            passive.damage += punch_profile.hit_damage\n        else:\n            print(punch_profile.blocked_msg.format(active=active, passive=passive))\n            active.damage += punch_profile.block_damage\n\n    if player.knockedout or opponent.knockedout:\n        return\n    elif player.damage > opponent.damage:\n        print(f\"{opponent.name} WINS ROUND {round_number}\")\n        opponent.score += 1\n    else:\n        print(f\"{player.name} WINS ROUND {round_number}\")\n        player.score += 1\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "15_Boxing/python/opponent-profile.json",
    "content": "{\n    \"1\": {\n        \"choices\": 60,\n        \"threshold\": 29,\n        \"hit_damage\": 15,\n        \"block_damage\": 0,\n        \"knockout_possible\": true,\n        \"pre_msg\": \"{active.name} TAKES A FULL SWING\",\n        \"hit_msg\": \"AND POW!!!! HE HITS HIM RIGHT IN THE FACE!\",\n        \"blocked_msg\": \"BUT IT'S BLOCKED!\"\n    },\n    \"2\": {\n        \"choices\": 1,\n        \"threshold\": 1,\n        \"hit_damage\": 12,\n        \"block_damage\": 0,\n        \"knockout_possible\": true,\n        \"pre_msg\": \"{active.name} GETS {passive.name} IN THE JAW (OUCH!)....AND AGAIN\",\n        \"hit_msg\": \"CONNECTS...\",\n        \"blocked_msg\": \"BUT IT'S BLOCKED!!!!!!!!!!!!!\"\n    },\n    \"3\": {\n        \"choices\": 200,\n        \"threshold\": 125,\n        \"hit_damage\": 8,\n        \"block_damage\": 5,\n        \"pre_msg\": \"{passive.name} IS ATTACKED BY AN UPPERCUT (OH,OH)\",\n        \"hit_msg\": \"AND {active.name} CONNECTS...\",\n        \"blocked_msg\": \"{passive.name} BLOCKS AND HITS {active.name} WITH A HOOK\"\n    },\n    \"4\": {\n        \"choices\": 7,\n        \"threshold\": 3,\n        \"hit_damage\": 3,\n        \"block_damage\": 0,\n        \"pre_msg\": \"{active.name} JABS AND\",\n        \"hit_msg\": \"BLOOD SPILLS !!!\",\n        \"blocked_msg\": \"AND IT'S BLOCKED (LUCKY BLOCK!)\"\n    }\n}\n"
  },
  {
    "path": "15_Boxing/python/player-profile.json",
    "content": "{\n    \"1\": {\n        \"choices\": 30,\n        \"threshold\": 10,\n        \"hit_damage\": 15,\n        \"block_damage\": 0,\n        \"pre_msg\": \"{active.name} SWINGS AND\",\n        \"hit_msg\": \"HE CONNECTS!\",\n        \"blocked_msg\": \"HE MISSES\"\n    },\n    \"2\": {\n        \"choices\": 2,\n        \"threshold\": 1,\n        \"hit_damage\": 7,\n        \"block_damage\": 0,\n        \"pre_msg\": \"{active.name} GIVES THE HOOK...\",\n        \"hit_msg\": \"CONNECTS...\",\n        \"blocked_msg\": \"BUT IT'S BLOCKED!!!!!!!!!!!!!\"\n    },\n    \"3\": {\n        \"choices\": 100,\n        \"threshold\": 50,\n        \"hit_damage\": 4,\n        \"block_damage\": 0,\n        \"pre_msg\": \"{player_name} TRIES AN UPPERCUT\",\n        \"hit_msg\": \"AND HE CONNECTS!\",\n        \"blocked_msg\": \"AND IT'S BLOCKED (LUCKY BLOCK!)\"\n    },\n    \"4\": {\n        \"choices\": 8,\n        \"threshold\": 3,\n        \"hit_damage\": 3,\n        \"block_damage\": 0,\n        \"pre_msg\": \"{active.name} JABS AT {passive.name}'S HEAD\",\n        \"hit_msg\": \"AND HE CONNECTS!\",\n        \"blocked_msg\": \"AND IT'S BLOCKED (LUCKY BLOCK!)\"\n    }\n}\n"
  },
  {
    "path": "15_Boxing/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "15_Boxing/vbnet/Boxing.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Boxing\", \"Boxing.vbproj\", \"{8BCEDE01-59A7-4AA3-AE09-8B7FD69A5867}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8BCEDE01-59A7-4AA3-AE09-8B7FD69A5867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8BCEDE01-59A7-4AA3-AE09-8B7FD69A5867}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8BCEDE01-59A7-4AA3-AE09-8B7FD69A5867}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8BCEDE01-59A7-4AA3-AE09-8B7FD69A5867}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "15_Boxing/vbnet/Boxing.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Boxing</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "15_Boxing/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "16_Bug/README.md",
    "content": "### Bug\n\nThe object of this game is to finish your drawing of a bug before the computer finishes.\n\nYou and the computer roll a die alternately with each number standing for a part of the bug. You must add the parts in the right order; in other words, you cannot have a neck until you have a body, you cannot have a head until you have a neck, and so on. After each new part has been added, you have the option of seeing pictures of the two bugs.\n\nIf you elect to see all the pictures, this program has the ability of consuming well over six feet of terminal paper per run. We can only suggest recycling the paper by using the other side.\n\nBrian Leibowitz wrote this program while in the 7th grade at Harrison Jr-Se High School in Harrison, New York.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=30)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=45)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "16_Bug/bug.bas",
    "content": "10 PRINT TAB(34);\"BUG\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 REM\n50 A=0: B=0: H=0: L=0: N=0: P=0: Q=0: R=0: S=0: T=0: U=0: V=0: Y=0\n60 PRINT \"THE GAME BUG\"\n70 PRINT \"I HOPE YOU ENJOY THIS GAME.\"\n80 PRINT\n90 PRINT \"DO YOU WANT INSTRUCTIONS\";\n100 INPUT Z$\n110 IF Z$=\"NO\" THEN 300\n120 PRINT \"THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH\"\n130 PRINT \"MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.\"\n140 PRINT \"I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU\"\n150 PRINT \"WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.\"\n160 PRINT \"IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.\"\n170 PRINT \"THE SAME WILL HAPPEN ON MY TURN.\"\n180 PRINT \"IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE\"\n190 PRINT \"OPTION OF SEEING THE PICTURES OF THE BUGS.\"\n200 PRINT \"THE NUMBERS STAND FOR PARTS AS FOLLOWS:\"\n210 PRINT \"NUMBER\",\"PART\",\"NUMBER OF PART NEEDED\"\n220 PRINT \"1\",\"BODY\",\"1\"\n230 PRINT \"2\",\"NECK\",\"1\"\n240 PRINT \"3\",\"HEAD\",\"1\"\n250 PRINT \"4\",\"FEELERS\",\"2\"\n260 PRINT \"5\",\"TAIL\",\"1\"\n270 PRINT \"6\",\"LEGS\",\"6\"\n280 PRINT\n290 PRINT\n300 IF Y>0 THEN 2480\n310 Z=INT(6*RND(1)+1)\n320 C=1\n330 PRINT \"YOU ROLLED A\";Z\n340 ON Z GOTO 350,430,540,650,760,870\n350 PRINT \"1=BODY\"\n360 IF B=1 THEN 410\n370 PRINT \"YOU NOW HAVE A BODY.\"\n380 B=1\n390 C=0\n400 GOTO 970\n410 PRINT \"YOU DO NOT NEED A BODY.\"\n420 GOTO 970\n430 PRINT \"2=NECK\"\n440 IF N=1 THEN 500\n450 IF B=0 THEN 520\n460 PRINT \"YOU NOW HAVE A NECK.\"\n470 N=1\n480 C=0\n490 GOTO 970\n500 PRINT \"YOU DO NOT NEED A NECK.\"\n510 GOTO 970\n520 PRINT \"YOU DO NOT HAVE A BODY.\"\n530 GOTO 970\n540 PRINT \"3=HEAD\"\n550 IF N=0 THEN 610\n560 IF H=1 THEN 630\n570 PRINT \"YOU NEEDED A HEAD.\"\n580 H=1\n590 C=0\n600 GOTO 970\n610 PRINT \"YOU DO NOT HAVE A NECK.\"\n620 GOTO 970\n630 PRINT \"YOU HAVE A HEAD.\"\n640 GOTO 970\n650 PRINT \"4=FEELERS\"\n660 IF H=0 THEN 740\n670 IF A=2 THEN 720\n680 PRINT \"I NOW GIVE YOU A FEELER.\"\n690 A=A+1\n700 C=0\n710 GOTO 970\n720 PRINT \"YOU HAVE TWO FEELERS ALREADY.\"\n730 GOTO 970\n740 PRINT \"YOU DO NOT HAVE A HEAD.\"\n750 GOTO 970\n760 PRINT \"5=TAIL\"\n770 IF B=0 THEN 830\n780 IF T=1 THEN 850\n790 PRINT \"I NOW GIVE YOU A TAIL.\"\n800 T=T+1\n810 C=0\n820 GOTO 970\n830 PRINT \"YOU DO NOT HAVE A BODY.\"\n840 GOTO 970\n850 PRINT \"YOU ALREADY HAVE A TAIL.\"\n860 GOTO 970\n870 PRINT \"6=LEG\"\n880 IF L=6 THEN 940\n890 IF B=0 THEN 960\n900 L=L+1\n910 C=0\n920 PRINT \"YOU NOW HAVE\";L;\"LEGS.\"\n930 GOTO 970\n940 PRINT \"YOU HAVE 6 FEET ALREADY.\"\n950 GOTO 970\n960 PRINT \"YOU DO NOT HAVE A BODY.\"\n970 X=INT(6*RND(1)+1)\n971 PRINT\n975 FOR DELAY=1 TO 2000:NEXT DELAY\n980 PRINT \"I ROLLED A\";X\n990 ON X GOTO 1000,1080,1190,1300,1410,1520\n1000 PRINT \"1=BODY\"\n1010 IF P=1 THEN 1060\n1020 PRINT \"I NOW HAVE A BODY.\"\n1030 C=0\n1040 P=1\n1050 GOTO 1630\n1060 PRINT \"I DO NOT NEED A BODY.\"\n1070 GOTO 1630\n1080 PRINT \"2=NECK\"\n1090 IF Q=1 THEN 1150\n1100 IF P=0 THEN 1170\n1110 PRINT \"I NOW HAVE A NECK.\"\n1120 Q=1\n1130 C=0\n1140 GOTO 1630\n1150 PRINT \"I DO NOT NEED A NECK.\"\n1160 GOTO 1630\n1170 PRINT \"I DO NOT HAVE A BODY.\"\n1180 GOTO 1630\n1190 PRINT \"3=HEAD\"\n1200 IF Q=0 THEN 1260\n1210 IF R=1 THEN 1280\n1220 PRINT \"I NEEDED A HEAD.\"\n1230 R=1\n1240 C=0\n1250 GOTO 1630\n1260 PRINT \"I DO NOT HAVE A NECK.\"\n1270 GOTO 1630\n1280 PRINT \"I DO NOT NEED A HEAD.\"\n1290 GOTO 1630\n1300 PRINT \"4=FEELERS\"\n1310 IF R=0 THEN 1390\n1320 IF S=2 THEN 1370\n1330 PRINT \"I GET A FEELER.\"\n1340 S=S+1\n1350 C=0\n1360 GOTO 1630\n1370 PRINT \"I HAVE 2 FEELERS ALREADY.\"\n1380 GOTO 1630\n1390 PRINT \"I DO NOT HAVE A HEAD.\"\n1400 GOTO 1630\n1410 PRINT \"5=TAIL\"\n1420 IF P=0 THEN 1480\n1430 IF U=1 THEN 1500\n1440 PRINT \"I NOW HAVE A TAIL.\"\n1450 U=1\n1460 C=0\n1470 GOTO 1630\n1480 PRINT \"I DO NOT HAVE A BODY.\"\n1490 GOTO 1630\n1500 PRINT \"I DO NOT NEED A TAIL.\"\n1510 GOTO 1630\n1520 PRINT \"6=LEGS\"\n1530 IF V=6 THEN 1590\n1540 IF P=0 THEN 1610\n1550 V=V+1\n1560 C=0\n1570 PRINT \"I NOW HAVE\";V;\"LEGS.\"\n1580 GOTO 1630\n1590 PRINT,\"I HAVE 6 FEET.\"\n1600 GOTO 1630\n1610 PRINT \"I DO NOT HAVE A BODY.\"\n1620 GOTO 1630\n1630 IF A=2 AND T=1 AND L=6 THEN 1650\n1640 GOTO 1670\n1650 PRINT \"YOUR BUG IS FINISHED.\"\n1660 Y=Y+1\n1670 IF S=2 AND P=1 AND V=6 THEN 1690\n1680 GOTO 1710\n1690 PRINT \"MY BUG IS FINISHED.\"\n1700 Y=Y+2\n1710 IF C=1 THEN 300\n1720 PRINT \"DO YOU WANT THE PICTURES\";\n1730 INPUT Z$\n1740 IF Z$=\"NO\" THEN 300\n1750 PRINT \"*****YOUR BUG*****\"\n1760 PRINT\n1770 PRINT\n1780 IF A=0 THEN 1860\n1790 FOR Z=1 TO 4\n1800 FOR X=1 TO A\n1810 PRINT TAB(10);\n1820 PRINT \"A \";\n1830 NEXT X\n1840 PRINT\n1850 NEXT Z\n1860 IF H=0 THEN 1880\n1870 GOSUB 2470\n1880 IF N=0 THEN 1920\n1890 FOR Z=1 TO 2\n1900 PRINT \"          N N\"\n1910 NEXT Z\n1920 IF B=0 THEN 2000\n1930 PRINT \"     BBBBBBBBBBBB\"\n1940 FOR Z=1 TO 2\n1950 PRINT \"     B          B\"\n1960 NEXT Z\n1970 IF T<>1 THEN 1990\n1980 PRINT \"TTTTTB          B\"\n1990 PRINT \"     BBBBBBBBBBBB\"\n2000 IF L=0 THEN 2080\n2010 FOR Z=1 TO 2\n2020 PRINT TAB(5);\n2030 FOR X=1 TO L\n2040 PRINT \" L\";\n2050 NEXT X\n2060 PRINT\n2070 NEXT Z\n2080 FOR Z=1 TO 4\n2090 PRINT\n2100 NEXT Z\n2110 PRINT \"*****MY BUG*****\"\n2120 PRINT\n2130 PRINT\n2140 PRINT\n2150 IF S=0 THEN 2230\n2160 FOR Z=1 TO 4\n2170 PRINT TAB(10);\n2180 FOR X=1 TO S\n2190 PRINT \"F \";\n2200 NEXT X\n2210 PRINT\n2220 NEXT Z\n2230 IF R<>1 THEN 2250\n2240 GOSUB 2470\n2250 IF Q=0 THEN 2280\n2260 PRINT \"          N N\"\n2270 PRINT \"          N N\"\n2280 IF P=0 THEN 2360\n2290 PRINT \"     BBBBBBBBBBBB\"\n2300 FOR Z=1 TO 2\n2310 PRINT \"     B          B\"\n2320 NEXT Z\n2330 IF U<>1 THEN 2350\n2340 PRINT \"TTTTTB          B\"\n2350 PRINT \"     BBBBBBBBBBBB\"\n2360 IF V=0 THEN 2450\n2370 FOR Z=1 TO 2\n2380 PRINT TAB(5);\n2390 FOR X=1 TO V\n2400 PRINT \" L\";\n2410 NEXT X\n2420 PRINT\n2430 NEXT Z\n2450 IF Y<>0 THEN 2540\n2460 GOTO 300\n2470 PRINT \"        HHHHHHH\"\n2480 PRINT \"        H     H\"\n2490 PRINT \"        H O O H\"\n2500 PRINT \"        H     H\"\n2510 PRINT \"        H  V  H\"\n2520 PRINT \"        HHHHHHH\"\n2530 RETURN\n2540 PRINT \"I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!\"\n2550 END\n"
  },
  {
    "path": "16_Bug/csharp/Bug.cs",
    "content": "using System.Text;\nusing BugGame.Parts;\nusing BugGame.Resources;\n\nnamespace BugGame;\n\ninternal class Bug\n{\n    private readonly Body _body = new();\n\n    public bool IsComplete => _body.IsComplete;\n\n    public bool TryAdd(IPart part, out Message message) => _body.TryAdd(part, out message);\n\n    public string ToString(string pronoun, char feelerCharacter)\n    {\n        var builder = new StringBuilder($\"*****{pronoun} Bug*****\").AppendLine().AppendLine().AppendLine();\n        _body.AppendTo(builder, feelerCharacter);\n        return builder.ToString();\n    }\n}"
  },
  {
    "path": "16_Bug/csharp/Bug.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "16_Bug/csharp/Bug.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bug\", \"Bug.csproj\", \"{C1929CC1-C366-43E4-9476-AE107231A302}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C1929CC1-C366-43E4-9476-AE107231A302}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C1929CC1-C366-43E4-9476-AE107231A302}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C1929CC1-C366-43E4-9476-AE107231A302}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C1929CC1-C366-43E4-9476-AE107231A302}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "16_Bug/csharp/Game.cs",
    "content": "using BugGame.Parts;\nusing BugGame.Resources;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing static System.StringComparison;\nnamespace BugGame;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    public void Play()\n    {\n        _io.Write(Resource.Streams.Introduction);\n        if (!_io.ReadString(\"Do you want instructions\").Equals(\"no\", InvariantCultureIgnoreCase))\n        {\n            _io.Write(Resource.Streams.Instructions);\n        }\n\n        BuildBugs();\n\n        _io.Write(Resource.Streams.PlayAgain);\n    }\n\n    private void BuildBugs()\n    {\n        var yourBug = new Bug();\n        var myBug = new Bug();\n\n        while (true)\n        {\n            var partAdded = TryBuild(yourBug, m => m.You);\n            Thread.Sleep(500);\n            _io.WriteLine();\n            partAdded |= TryBuild(myBug, m => m.I);\n\n            if (partAdded)\n            {\n                if (yourBug.IsComplete) { _io.WriteLine(\"Your bug is finished.\"); }\n                if (myBug.IsComplete) { _io.WriteLine(\"My bug is finished.\"); }\n\n                if (!_io.ReadString(\"Do you want the picture\").Equals(\"no\", InvariantCultureIgnoreCase))\n                {\n                    _io.Write(yourBug.ToString(\"Your\", 'A'));\n                    _io.WriteLine();\n                    _io.WriteLine();\n                    _io.WriteLine();\n                    _io.WriteLine();\n                    _io.Write(myBug.ToString(\"My\", 'F'));\n                }\n            }\n\n            if (yourBug.IsComplete || myBug.IsComplete) { break; }\n        }\n    }\n\n    private bool TryBuild(Bug bug, Func<Message, string> messageTransform)\n    {\n        var roll = _random.Next(6) + 1;\n        _io.WriteLine(messageTransform(Message.Rolled.ForValue(roll)));\n\n        IPart part = roll switch\n        {\n            1 => new Body(),\n            2 => new Neck(),\n            3 => new Head(),\n            4 => new Feeler(),\n            5 => new Tail(),\n            6 => new Leg(),\n            _ => throw new Exception(\"Unexpected roll value\")\n        };\n        _io.WriteLine($\"{roll}={part.GetType().Name}\");\n\n        var partAdded = bug.TryAdd(part, out var message);\n        _io.WriteLine(messageTransform.Invoke(message));\n\n        return partAdded;\n    }\n}"
  },
  {
    "path": "16_Bug/csharp/Parts/Body.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Body : ParentPart\n{\n    private readonly Neck _neck = new();\n    private readonly Tail _tail = new();\n    private readonly Legs _legs = new();\n\n    public Body()\n        : base(Message.BodyAdded, Message.BodyNotNeeded)\n    {\n    }\n\n    public override bool IsComplete => _neck.IsComplete && _tail.IsComplete && _legs.IsComplete;\n\n    protected override bool TryAddCore(IPart part, out Message message)\n        => part switch\n        {\n            Neck => _neck.TryAdd(out message),\n            Head or Feeler => _neck.TryAdd(part, out message),\n            Tail => _tail.TryAdd(out message),\n            Leg => _legs.TryAddOne(out message),\n            _ => throw new NotSupportedException($\"Can't add a {part.Name} to a {Name}.\")\n        };\n\n    public void AppendTo(StringBuilder builder, char feelerCharacter)\n    {\n        if (IsPresent)\n        {\n            _neck.AppendTo(builder, feelerCharacter);\n            builder\n                .AppendLine(\"     BBBBBBBBBBBB\")\n                .AppendLine(\"     B          B\")\n                .AppendLine(\"     B          B\");\n            _tail.AppendTo(builder);\n            builder\n                .AppendLine(\"     BBBBBBBBBBBB\");\n            _legs.AppendTo(builder);\n        }\n    }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Feeler.cs",
    "content": "namespace BugGame.Parts;\n\ninternal class Feeler : IPart\n{\n    public string Name => nameof(Feeler);\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Feelers.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Feelers : PartCollection\n{\n    public Feelers()\n        : base(2, Message.FeelerAdded, Message.FeelersFull)\n    {\n    }\n\n    public void AppendTo(StringBuilder builder, char character) => AppendTo(builder, 10, 4, character);\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Head.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Head : ParentPart\n{\n    private Feelers _feelers = new();\n\n    public Head()\n        : base(Message.HeadAdded, Message.HeadNotNeeded)\n    {\n    }\n\n    public override bool IsComplete => _feelers.IsComplete;\n\n    protected override bool TryAddCore(IPart part, out Message message)\n        => part switch\n        {\n            Feeler => _feelers.TryAddOne(out message),\n            _ => throw new NotSupportedException($\"Can't add a {part.Name} to a {Name}.\")\n        };\n\n    public void AppendTo(StringBuilder builder, char feelerCharacter)\n    {\n        if (IsPresent)\n        {\n            _feelers.AppendTo(builder, feelerCharacter);\n            builder\n                .AppendLine(\"        HHHHHHH\")\n                .AppendLine(\"        H     H\")\n                .AppendLine(\"        H O O H\")\n                .AppendLine(\"        H     H\")\n                .AppendLine(\"        H  V  H\")\n                .AppendLine(\"        HHHHHHH\");\n        }\n    }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/IPart.cs",
    "content": "namespace BugGame.Parts;\n\ninternal interface IPart\n{\n    string Name { get; }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Leg.cs",
    "content": "namespace BugGame.Parts;\n\ninternal class Leg : IPart\n{\n    public string Name => nameof(Leg);\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Legs.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Legs : PartCollection\n{\n    public Legs()\n        : base(6, Message.LegAdded, Message.LegsFull)\n    {\n    }\n\n    public void AppendTo(StringBuilder builder) => AppendTo(builder, 6, 2, 'L');\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Neck.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Neck : ParentPart\n{\n    private Head _head = new();\n\n    public Neck()\n        : base(Message.NeckAdded, Message.NeckNotNeeded)\n    {\n    }\n\n    public override bool IsComplete => _head.IsComplete;\n\n    protected override bool TryAddCore(IPart part, out Message message)\n        => part switch\n        {\n            Head => _head.TryAdd(out message),\n            Feeler => _head.TryAdd(part, out message),\n            _ => throw new NotSupportedException($\"Can't add a {part.Name} to a {Name}.\")\n        };\n\n    public void AppendTo(StringBuilder builder, char feelerCharacter)\n    {\n        if (IsPresent)\n        {\n            _head.AppendTo(builder, feelerCharacter);\n            builder.AppendLine(\"          N N\").AppendLine(\"          N N\");\n        }\n    }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/ParentPart.cs",
    "content": "using BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal abstract class ParentPart : Part\n{\n    public ParentPart(Message addedMessage, Message duplicateMessage)\n        : base(addedMessage, duplicateMessage)\n    {\n    }\n\n    public bool TryAdd(IPart part, out Message message)\n        => (part.GetType() == GetType(), IsPresent) switch\n        {\n            (true, _) => TryAdd(out message),\n            (false, false) => ReportDoNotHave(out message),\n            _ => TryAddCore(part, out message)\n        };\n\n    protected abstract bool TryAddCore(IPart part, out Message message);\n\n    private bool ReportDoNotHave(out Message message)\n    {\n        message = Message.DoNotHaveA(this);\n        return false;\n    }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Part.cs",
    "content": "using BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Part : IPart\n{\n    private readonly Message _addedMessage;\n    private readonly Message _duplicateMessage;\n\n    public Part(Message addedMessage, Message duplicateMessage)\n    {\n        _addedMessage = addedMessage;\n        _duplicateMessage = duplicateMessage;\n    }\n\n    public virtual bool IsComplete => IsPresent;\n\n    protected bool IsPresent { get; private set; }\n\n    public string Name => GetType().Name;\n\n    public bool TryAdd(out Message message)\n    {\n        if (IsPresent)\n        {\n            message = _duplicateMessage;\n            return false;\n        }\n\n        message = _addedMessage;\n        IsPresent = true;\n        return true;\n    }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/PartCollection.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class PartCollection\n{\n    private readonly int _maxCount;\n    private readonly Message _addedMessage;\n    private readonly Message _fullMessage;\n    private int _count;\n\n    public PartCollection(int maxCount, Message addedMessage, Message fullMessage)\n    {\n        _maxCount = maxCount;\n        _addedMessage = addedMessage;\n        _fullMessage = fullMessage;\n    }\n\n    public bool IsComplete => _count == _maxCount;\n\n    public bool TryAddOne(out Message message)\n    {\n        if (_count < _maxCount)\n        {\n            _count++;\n            message = _addedMessage.ForValue(_count);\n            return true;\n        }\n\n        message = _fullMessage;\n        return false;\n    }\n\n    protected void AppendTo(StringBuilder builder, int offset, int length, char character)\n    {\n        if (_count == 0) { return; }\n\n        for (var i = 0; i < length; i++)\n        {\n            builder.Append(' ', offset);\n\n            for (var j = 0; j < _count; j++)\n            {\n                builder.Append(character).Append(' ');\n            }\n            builder.AppendLine();\n        }\n    }\n}\n"
  },
  {
    "path": "16_Bug/csharp/Parts/Tail.cs",
    "content": "using System.Text;\nusing BugGame.Resources;\n\nnamespace BugGame.Parts;\n\ninternal class Tail : Part\n{\n    public Tail()\n        : base(Message.TailAdded, Message.TailNotNeeded)\n    {\n    }\n\n    public void AppendTo(StringBuilder builder)\n    {\n        if (IsPresent)\n        {\n            builder.AppendLine(\"TTTTTB          B\");\n        }\n    }\n}"
  },
  {
    "path": "16_Bug/csharp/Program.cs",
    "content": "using BugGame;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\n\nnew Game(new ConsoleIO(), new RandomNumberGenerator()).Play();\n"
  },
  {
    "path": "16_Bug/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "16_Bug/csharp/Resources/Instructions.txt",
    "content": "The object of Bug is to finish your bug before I finish\nmine. Each number stands for a part of the bug body.\nI will roll the die for you, tell you what I rolled for you\nwhat the number stands for, and if you can get the part.\nIf you can get the part I will give it to you.\nThe same will happen on my turn.\nIf there is a change in either bug I will give you the\noption of seeing the pictures of the bugs.\nThe numbers stand for parts as follows:\nNumber        Part          Number of part needed\n 1            Body           1\n 2            Neck           1\n 3            Head           1\n 4            Feelers        2\n 5            Tail           1\n 6            Legs           6\n\n\n"
  },
  {
    "path": "16_Bug/csharp/Resources/Introduction.txt",
    "content": "                                Bug\n               Creative Computing  Morristown, New Jersey\n\n\n\nThe Game Bug\nI hope you enjoy this game.\n\n"
  },
  {
    "path": "16_Bug/csharp/Resources/Message.cs",
    "content": "using BugGame.Parts;\n\nnamespace BugGame.Resources;\n\ninternal class Message\n{\n    public static Message Rolled = new(\"rolled a {0}\");\n\n    public static Message BodyAdded = new(\"now have a body.\");\n    public static Message BodyNotNeeded = new(\"do not need a body.\");\n\n    public static Message NeckAdded = new(\"now have a neck.\");\n    public static Message NeckNotNeeded = new(\"do not need a neck.\");\n\n    public static Message HeadAdded = new(\"needed a head.\");\n    public static Message HeadNotNeeded = new(\"I do not need a head.\", \"You have a head.\");\n\n    public static Message TailAdded = new(\"I now have a tail.\", \"I now give you a tail.\");\n    public static Message TailNotNeeded = new(\"I do not need a tail.\", \"You already have a tail.\");\n\n    public static Message FeelerAdded = new(\"I get a feeler.\", \"I now give you a feeler\");\n    public static Message FeelersFull = new(\"I have 2 feelers already.\", \"You have two feelers already\");\n\n    public static Message LegAdded = new(\"now have {0} legs\");\n    public static Message LegsFull = new(\"I have 6 feet.\", \"You have 6 feet already\");\n\n    public static Message Complete = new(\"bug is finished.\");\n\n    private Message(string common)\n        : this(\"I \" + common, \"You \" + common)\n    {\n    }\n\n    private Message(string i, string you)\n    {\n        I = i;\n        You = you;\n    }\n\n    public string I { get; }\n    public string You { get; }\n\n    public static Message DoNotHaveA(Part part) => new($\"do not have a {part.Name}\");\n\n    public Message ForValue(int quantity) => new(string.Format(I, quantity), string.Format(You, quantity));\n}"
  },
  {
    "path": "16_Bug/csharp/Resources/PlayAgain.txt",
    "content": "I hope you enjoyed the game, play it again soon!!\n"
  },
  {
    "path": "16_Bug/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace BugGame.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n        public static Stream Instructions => GetStream();\n        public static Stream PlayAgain => GetStream();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly()\n            .GetManifestResourceStream($\"Bug.Resources.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "16_Bug/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "16_Bug/java/src/Bug.java",
    "content": "import java.util.ArrayList;\nimport java.util.Scanner;\n\n/**\n * Game of Bug\n * <p>\n * Based on the Basic game of Bug here\n * https://github.com/coding-horror/basic-computer-games/blob/main/16%20Bug/bug.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Bug {\n\n    // Dice roll\n    public static final int SIX = 6;\n\n    private enum GAME_STATE {\n        START,\n        PLAYER_TURN,\n        COMPUTER_TURN,\n        CHECK_FOR_WINNER,\n        GAME_OVER\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n\n    private final Insect playersBug;\n\n    private final Insect computersBug;\n\n    // Used to show the result of dice roll.\n    private final String[] ROLLS = new String[]{\"BODY\", \"NECK\", \"HEAD\", \"FEELERS\", \"TAIL\", \"LEGS\"};\n\n    public Bug() {\n\n        playersBug = new PlayerBug();\n        computersBug = new ComputerBug();\n\n        gameState = GAME_STATE.START;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                // And optionally instructions.\n                case START:\n                    intro();\n                    if (!noEntered(displayTextAndGetInput(\"DO YOU WANT INSTRUCTIONS? \"))) {\n                        instructions();\n                    }\n\n                    gameState = GAME_STATE.PLAYER_TURN;\n                    break;\n\n                case PLAYER_TURN:\n                    int playersRoll = randomNumber();\n                    System.out.println(\"YOU ROLLED A \" + playersRoll + \"=\" + ROLLS[playersRoll - 1]);\n                    switch (playersRoll) {\n                        case 1:\n                            System.out.println(playersBug.addBody());\n                            break;\n                        case 2:\n                            System.out.println(playersBug.addNeck());\n                            break;\n                        case 3:\n                            System.out.println(playersBug.addHead());\n                            break;\n                        case 4:\n                            System.out.println(playersBug.addFeelers());\n                            break;\n                        case 5:\n                            System.out.println(playersBug.addTail());\n                            break;\n                        case 6:\n                            System.out.println(playersBug.addLeg());\n                            break;\n                    }\n\n                    gameState = GAME_STATE.COMPUTER_TURN;\n                    break;\n\n                case COMPUTER_TURN:\n                    int computersRoll = randomNumber();\n                    System.out.println(\"I ROLLED A \" + computersRoll + \"=\" + ROLLS[computersRoll - 1]);\n                    switch (computersRoll) {\n                        case 1:\n                            System.out.println(computersBug.addBody());\n                            break;\n                        case 2:\n                            System.out.println(computersBug.addNeck());\n                            break;\n                        case 3:\n                            System.out.println(computersBug.addHead());\n                            break;\n                        case 4:\n                            System.out.println(computersBug.addFeelers());\n                            break;\n                        case 5:\n                            System.out.println(computersBug.addTail());\n                            break;\n                        case 6:\n                            System.out.println(computersBug.addLeg());\n                            break;\n                    }\n\n                    gameState = GAME_STATE.CHECK_FOR_WINNER;\n                    break;\n\n                case CHECK_FOR_WINNER:\n                    boolean gameOver = false;\n\n                    if (playersBug.complete()) {\n                        System.out.println(\"YOUR BUG IS FINISHED.\");\n                        gameOver = true;\n                    } else if (computersBug.complete()) {\n                        System.out.println(\"MY BUG IS FINISHED.\");\n                        gameOver = true;\n                    }\n\n                    if (noEntered(displayTextAndGetInput(\"DO YOU WANT THE PICTURES? \"))) {\n                        gameState = GAME_STATE.PLAYER_TURN;\n                    } else {\n                        System.out.println(\"*****YOUR BUG*****\");\n                        System.out.println();\n                        draw(playersBug);\n\n                        System.out.println();\n                        System.out.println(\"*****MY BUG*****\");\n                        System.out.println();\n                        draw(computersBug);\n                        gameState = GAME_STATE.PLAYER_TURN;\n                    }\n                    if (gameOver) {\n                        System.out.println(\"I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!\");\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Draw the bug (player or computer) based on what has\n     * already been added to it.\n     *\n     * @param bug The bug to be drawn.\n     */\n    private void draw(Insect bug) {\n        ArrayList<String> insectOutput = bug.draw();\n        for (String s : insectOutput) {\n            System.out.println(s);\n        }\n    }\n\n    /**\n     * Display an intro\n     */\n    private void intro() {\n        System.out.println(\"BUG\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THE GAME BUG\");\n        System.out.println(\"I HOPE YOU ENJOY THIS GAME.\");\n    }\n\n    private void instructions() {\n        System.out.println(\"THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH\");\n        System.out.println(\"MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.\");\n        System.out.println(\"I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU\");\n        System.out.println(\"WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.\");\n        System.out.println(\"IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.\");\n        System.out.println(\"THE SAME WILL HAPPEN ON MY TURN.\");\n        System.out.println(\"IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE\");\n        System.out.println(\"OPTION OF SEEING THE PICTURES OF THE BUGS.\");\n        System.out.println(\"THE NUMBERS STAND FOR PARTS AS FOLLOWS:\");\n        System.out.println(\"NUMBER\\tPART\\tNUMBER OF PART NEEDED\");\n        System.out.println(\"1\\tBODY\\t1\");\n        System.out.println(\"2\\tNECK\\t1\");\n        System.out.println(\"3\\tHEAD\\t1\");\n        System.out.println(\"4\\tFEELERS\\t2\");\n        System.out.println(\"5\\tTAIL\\t1\");\n        System.out.println(\"6\\tLEGS\\t6\");\n        System.out.println();\n\n    }\n\n    /**\n     * Checks whether player entered N or NO to a question.\n     *\n     * @param text player string from kb\n     * @return true if N or NO was entered, otherwise false\n     */\n    private boolean noEntered(String text) {\n        return stringIsAnyValue(text, \"N\", \"NO\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        // Cycle through the variable number of values and test each\n        for (String val : values) {\n            if (text.equalsIgnoreCase(val)) {\n                return true;\n            }\n        }\n\n        // no matches\n        return false;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Generate random number\n     *\n     * @return random number\n     */\n    private int randomNumber() {\n        return (int) (Math.random()\n                * (SIX) + 1);\n    }\n}\n"
  },
  {
    "path": "16_Bug/java/src/BugGame.java",
    "content": "\n\npublic class BugGame {\n\n    public static void main(String[] args) {\n\n        Bug bug = new Bug();\n        bug.play();\n    }\n}\n"
  },
  {
    "path": "16_Bug/java/src/ComputerBug.java",
    "content": "public class ComputerBug extends Insect {\n\n    // Create messages specific to the computer player.\n\n    public ComputerBug() {\n        // Call superclass constructor for initialization.\n        super();\n        addMessages(new String[]{\"I GET A FEELER.\", \"I HAVE \" + MAX_FEELERS + \" FEELERS ALREADY.\", \"I DO NOT HAVE A HEAD.\"}, PARTS.FEELERS);\n        addMessages(new String[]{\"I NEEDED A HEAD.\", \"I DO NOT NEED A HEAD.\", \"I DO NOT HAVE A NECK.\"}, PARTS.HEAD);\n        addMessages(new String[]{\"I NOW HAVE A NECK.\", \"I DO NOT NEED A NECK.\", \"I DO NOT HAVE A BODY.\"}, PARTS.NECK);\n        addMessages(new String[]{\"I NOW HAVE A BODY.\", \"I DO NOT NEED A BODY.\"}, PARTS.BODY);\n        addMessages(new String[]{\"I NOW HAVE A TAIL.\", \"I DO NOT NEED A TAIL.\", \"I DO NOT HAVE A BODY.\"}, PARTS.TAIL);\n        addMessages(new String[]{\"I NOW HAVE ^^^\" + \" LEG\", \"I HAVE \" + MAX_LEGS + \" FEET.\", \"I DO NOT HAVE A BODY.\"}, PARTS.LEGS);\n    }\n}\n"
  },
  {
    "path": "16_Bug/java/src/Insect.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\n\n/**\n * This tracks the insect (bug) and has methods to\n * add body parts, create an array of output so it\n * can be drawn and to determine if a bug is complete.\n * N.B. This is a super class for ComputerBug and PlayerBug\n */\npublic class Insect {\n\n    public static final int MAX_FEELERS = 2;\n    public static final int MAX_LEGS = 6;\n\n    public static final int ADDED = 0;\n    public static final int NOT_ADDED = 1;\n    public static final int MISSING = 2;\n\n    // Various parts of the bug\n    public enum PARTS {\n        FEELERS,\n        HEAD,\n        NECK,\n        BODY,\n        TAIL,\n        LEGS\n    }\n\n    // Tracks what parts of the bug have been added\n    private boolean body;\n    private boolean neck;\n    private boolean head;\n    private int feelers;\n    private boolean tail;\n    private int legs;\n\n    // Messages about for various body parts\n    // These are set in the subclass ComputerBug or PlayerBug\n    private String[] bodyMessages;\n    private String[] neckMessages;\n    private String[] headMessages;\n    private String[] feelerMessages;\n    private String[] tailMessages;\n    private String[] legMessages;\n\n    public Insect() {\n        init();\n    }\n\n    /**\n     * Add a body to the bug if there is not one already added.\n     *\n     * @return return an appropriate message about the status of the operation.\n     */\n    public String addBody() {\n\n        boolean currentState = false;\n\n        if (!body) {\n            body = true;\n            currentState = true;\n        }\n\n        return addBodyMessage(currentState);\n    }\n\n    /**\n     * Create output based on adding the body or it being already added previously\n     *\n     * @return contains the output message\n     */\n\n    private String addBodyMessage(boolean wasAdded) {\n\n        // Return the appropriate message depending on whether the\n        // body was added or not.\n        if (wasAdded) {\n            return bodyMessages[ADDED];\n        } else {\n            return bodyMessages[NOT_ADDED];\n        }\n    }\n\n    /**\n     * Add a neck if a) a body has previously been added and\n     * b) a neck has not previously been added.\n     *\n     * @return text containing the status of the operation\n     */\n    public String addNeck() {\n\n        int status = NOT_ADDED;  // Default is not added\n\n        if (!body) {\n            // No body, cannot add a neck\n            status = MISSING;\n        } else if (!neck) {\n            neck = true;\n            status = ADDED;\n        }\n\n        return neckMessages[status];\n    }\n\n    /**\n     * Add a head to the bug if a) there already exists a neck and\n     * b) a head has not previously been added\n     *\n     * @return text outlining the success of the operation\n     */\n    public String addHead() {\n\n        int status = NOT_ADDED;  // Default is not added\n\n        if (!neck) {\n            // No neck, cannot add a head\n            status = MISSING;\n        } else if (!head) {\n            head = true;\n            status = ADDED;\n        }\n\n        return headMessages[status];\n    }\n\n    /**\n     * Add a feeler to the head if a) there has been a head added to\n     * the bug previously, and b) there are not already 2 (MAX_FEELERS)\n     * feelers previously added to the bug.\n     *\n     * @return text outlining the status of the operation\n     */\n    public String addFeelers() {\n\n        int status = NOT_ADDED;  // Default is not added\n\n        if (!head) {\n            // No head, cannot add a feeler\n            status = MISSING;\n        } else if (feelers < MAX_FEELERS) {\n            feelers++;\n            status = ADDED;\n        }\n\n        return feelerMessages[status];\n    }\n\n    /**\n     * Add a tail to the bug if a) there is already a body previously added\n     * to the bug and b) there is not already a tail added.\n     *\n     * @return text outlining the status of the operation.\n     */\n    public String addTail() {\n\n        int status = NOT_ADDED;  // Default is not added\n\n        if (!body) {\n            // No body, cannot add a tail\n            status = MISSING;\n        } else if (!tail) {\n            tail = true;\n            status = ADDED;\n        }\n\n        return tailMessages[status];\n    }\n\n    /**\n     * Add a leg to the bug if a) there is already a body previously added\n     * b) there are less than 6 (MAX_LEGS) previously added.\n     *\n     * @return text outlining status of the operation.\n     */\n    public String addLeg() {\n\n        int status = NOT_ADDED;  // Default is not added\n\n        if (!body) {\n            // No body, cannot add a leg\n            status = MISSING;\n        } else if (legs < MAX_LEGS) {\n            legs++;\n            status = ADDED;\n        }\n\n        String message = \"\";\n\n        // Create a string showing the result of the operation\n\n        switch(status) {\n            case ADDED:\n                // Replace # with number of legs\n                message = legMessages[status].replace(\"^^^\", String.valueOf(legs));\n                // Add text S. if >1 leg, or just . if one leg.\n                if (legs > 1) {\n                    message += \"S.\";\n                } else {\n                    message += \".\";\n                }\n                break;\n\n            case NOT_ADDED:\n\n                // Deliberate fall through to next case as its the\n                // same code to be executed\n            case MISSING:\n                message = legMessages[status];\n                break;\n        }\n\n        return message;\n    }\n\n    /**\n     * Initialise\n     */\n    public void init() {\n        body = false;\n        neck = false;\n        head = false;\n        feelers = 0;\n        tail = false;\n        legs = 0;\n    }\n\n    /**\n     * Add unique messages depending on type of player\n     * A subclass of this class calls this method\n     * e.g. See ComputerBug or PlayerBug classes\n     *\n     * @param messages an array of messages\n     * @param bodyPart the bodypart the messages relate to.\n     */\n    public void addMessages(String[] messages, PARTS bodyPart) {\n\n        switch (bodyPart) {\n            case FEELERS:\n                feelerMessages = messages;\n                break;\n\n            case HEAD:\n                headMessages = messages;\n                break;\n\n            case NECK:\n                neckMessages = messages;\n                break;\n\n            case BODY:\n                bodyMessages = messages;\n                break;\n\n            case TAIL:\n                tailMessages = messages;\n                break;\n\n            case LEGS:\n                legMessages = messages;\n                break;\n        }\n    }\n\n    /**\n     * Returns a string array containing\n     * the \"bug\" that can be output to console\n     *\n     * @return the bug ready to draw\n     */\n    public ArrayList<String> draw() {\n        ArrayList<String> bug = new ArrayList<>();\n        StringBuilder lineOutput;\n\n        // Feelers\n        if (feelers > 0) {\n            for (int i = 0; i < 4; i++) {\n                lineOutput = new StringBuilder(addSpaces(10));\n                for (int j = 0; j < feelers; j++) {\n                    lineOutput.append(\"A \");\n                }\n                bug.add(lineOutput.toString());\n            }\n        }\n\n        if (head) {\n            lineOutput = new StringBuilder(addSpaces(8) + \"HHHHHHH\");\n            bug.add(lineOutput.toString());\n            lineOutput = new StringBuilder(addSpaces(8) + \"H\" + addSpaces(5) + \"H\");\n            bug.add(lineOutput.toString());\n            lineOutput = new StringBuilder(addSpaces(8) + \"H O O H\");\n            bug.add(lineOutput.toString());\n            lineOutput = new StringBuilder(addSpaces(8) + \"H\" + addSpaces(5) + \"H\");\n            bug.add(lineOutput.toString());\n            lineOutput = new StringBuilder(addSpaces(8) + \"H\" + addSpaces(2) + \"V\" + addSpaces(2) + \"H\");\n            bug.add(lineOutput.toString());\n            lineOutput = new StringBuilder(addSpaces(8) + \"HHHHHHH\");\n            bug.add(lineOutput.toString());\n        }\n\n        if (neck) {\n            for (int i = 0; i < 2; i++) {\n                lineOutput = new StringBuilder(addSpaces(10) + \"N N\");\n                bug.add(lineOutput.toString());\n            }\n        }\n\n        if (body) {\n            lineOutput = new StringBuilder(addSpaces(5) + \"BBBBBBBBBBBB\");\n            bug.add(lineOutput.toString());\n            for (int i = 0; i < 2; i++) {\n                lineOutput = new StringBuilder(addSpaces(5) + \"B\" + addSpaces(10) + \"B\");\n                bug.add(lineOutput.toString());\n            }\n            if (tail) {\n                lineOutput = new StringBuilder(\"TTTTTB\" + addSpaces(10) + \"B\");\n                bug.add(lineOutput.toString());\n            }\n            lineOutput = new StringBuilder(addSpaces(5) + \"BBBBBBBBBBBB\");\n            bug.add(lineOutput.toString());\n        }\n\n        if (legs > 0) {\n            for (int i = 0; i < 2; i++) {\n                lineOutput = new StringBuilder(addSpaces(5));\n                for (int j = 0; j < legs; j++) {\n                    lineOutput.append(\" L\");\n                }\n                bug.add(lineOutput.toString());\n            }\n        }\n\n        return bug;\n    }\n\n    /**\n     * Check if the bug is complete i.e. it has\n     * 2 (MAX_FEELERS) feelers, a head, a neck, a body\n     * a tail and 6 (MAX_FEET) feet.\n     *\n     * @return true if complete.\n     */\n    public boolean complete() {\n        return (feelers == MAX_FEELERS)\n                && head\n                && neck\n                && body\n                && tail\n                && (legs == MAX_LEGS);\n    }\n\n    /**\n     * Simulate tabs be creating a string of X spaces.\n     *\n     * @param number contains number of spaces needed.\n     * @return a String containing the spaces\n     */\n    private String addSpaces(int number) {\n        char[] spaces = new char[number];\n        Arrays.fill(spaces, ' ');\n        return new String(spaces);\n\n    }\n}\n"
  },
  {
    "path": "16_Bug/java/src/PlayerBug.java",
    "content": "public class PlayerBug extends Insect {\n\n    // Create messages specific to the player.\n\n    public PlayerBug() {\n        // Call superclass constructor for initialization.\n        super();\n        addMessages(new String[]{\"I NOW GIVE YOU A FEELER.\", \"YOU HAVE \" + MAX_FEELERS + \" FEELERS ALREADY.\", \"YOU DO NOT HAVE A HEAD.\"}, PARTS.FEELERS);\n        addMessages(new String[]{\"YOU NEEDED A HEAD.\", \"YOU HAVE A HEAD.\", \"YOU DO NOT HAVE A NECK.\"}, PARTS.HEAD);\n        addMessages(new String[]{\"YOU NOW HAVE A NECK.\", \"YOU DO NOT NEED A NECK.\", \"YOU DO NOT HAVE A BODY.\"}, PARTS.NECK);\n        addMessages(new String[]{\"YOU NOW HAVE A BODY.\", \"YOU DO NOT NEED A BODY.\"}, PARTS.BODY);\n        addMessages(new String[]{\"I NOW GIVE YOU A TAIL.\", \"YOU ALREADY HAVE A TAIL.\", \"YOU DO NOT HAVE A BODY.\"}, PARTS.TAIL);\n        addMessages(new String[]{\"YOU NOW HAVE ^^^ LEG\", \"YOU HAVE \" + MAX_LEGS + \" FEET ALREADY.\", \"YOU DO NOT HAVE A BODY.\"}, PARTS.LEGS);\n    }\n\n\n}\n"
  },
  {
    "path": "16_Bug/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "16_Bug/javascript/bug.html",
    "content": "<html>\n<head>\n<title>BUG</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bug.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "16_Bug/javascript/bug.js",
    "content": "// BUG\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    return new Promise(function (resolve) {\n                       const input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_element.addEventListener(\"keydown\",\n                           function (event) {\n                                      if (event.keyCode === 13) {\n                                          const input_str = input_element.value;\n                                          document.getElementById(\"output\").removeChild(input_element);\n                                          print(input_str);\n                                          print(\"\\n\");\n                                          resolve(input_str);\n                                      }\n                                  });\n                       });\n}\n\nfunction tab(space)\n{\n    let str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nfunction waitNSeconds(n) {\n    return new Promise(resolve => setTimeout(resolve, n*1000));\n}\n\nfunction scrollToBottom() {\n    window.scrollTo(0, document.body.scrollHeight);\n}\n\nfunction draw_head()\n{\n    print(\"        HHHHHHH\\n\");\n    print(\"        H     H\\n\");\n    print(\"        H O O H\\n\");\n    print(\"        H     H\\n\");\n    print(\"        H  V  H\\n\");\n    print(\"        HHHHHHH\\n\");\n}\n\nfunction drawFeelers(feelerCount, character) {\n    for (let z = 1; z <= 4; z++) {\n        print(tab(10));\n        for (let x = 1; x <= feelerCount; x++) {\n            print(character + \" \");\n        }\n        print(\"\\n\");\n    }\n}\n\nfunction drawNeck() {\n    for (let z = 1; z <= 2; z++)\n        print(\"          N N\\n\");\n}\n\nfunction drawBody(computerTailCount) {\n    print(\"     BBBBBBBBBBBB\\n\");\n    for (let z = 1; z <= 2; z++)\n        print(\"     B          B\\n\");\n    if (computerTailCount === 1)\n        print(\"TTTTTB          B\\n\");\n    print(\"     BBBBBBBBBBBB\\n\");\n}\n\nfunction drawFeet(computerFeetCount) {\n    for (let z = 1; z <= 2; z++) {\n        print(tab(5));\n        for (let x = 1; x <= computerFeetCount; x++)\n            print(\" L\");\n        print(\"\\n\");\n    }\n}\n\nfunction drawBug(playerFeelerCount, playerHeadCount, playerNeckCount, playerBodyCount, playerTailCount, playerFeetCount, feelerCharacter) {\n    if (playerFeelerCount !== 0) {\n        drawFeelers(playerFeelerCount, feelerCharacter);\n    }\n    if (playerHeadCount !== 0)\n        draw_head();\n    if (playerNeckCount !== 0) {\n        drawNeck();\n    }\n    if (playerBodyCount !== 0) {\n        drawBody(playerTailCount)\n    }\n    if (playerFeetCount !== 0) {\n        drawFeet(playerFeetCount);\n    }\n    for (let z = 1; z <= 4; z++)\n        print(\"\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"BUG\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    let playerFeelerCount = 0;\n    let playerHeadCount = 0;\n    let playerNeckCount = 0;\n    let playerBodyCount = 0;\n    let playerFeetCount = 0;\n    let playerTailCount = 0;\n\n    let computerFeelerCount = 0;\n    let computerHeadCount = 0;\n    let computerNeckCount = 0;\n    let computerBodyCount = 0;\n    let computerTailCount = 0;\n    let computerFeetCount = 0;\n\n    print(\"THE GAME BUG\\n\");\n    print(\"I HOPE YOU ENJOY THIS GAME.\\n\");\n    print(\"\\n\");\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    const instructionsRequired = await input();\n    if (instructionsRequired.toUpperCase() !== \"NO\") {\n        print(\"THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH\\n\");\n        print(\"MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.\\n\");\n        print(\"I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU\\n\");\n        print(\"WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.\\n\");\n        print(\"IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.\\n\");\n        print(\"THE SAME WILL HAPPEN ON MY TURN.\\n\");\n        print(\"IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE\\n\");\n        print(\"OPTION OF SEEING THE PICTURES OF THE BUGS.\\n\");\n        print(\"THE NUMBERS STAND FOR PARTS AS FOLLOWS:\\n\");\n        print(\"NUMBER\\tPART\\tNUMBER OF PART NEEDED\\n\");\n        print(\"1\\tBODY\\t1\\n\");\n        print(\"2\\tNECK\\t1\\n\");\n        print(\"3\\tHEAD\\t1\\n\");\n        print(\"4\\tFEELERS\\t2\\n\");\n        print(\"5\\tTAIL\\t1\\n\");\n        print(\"6\\tLEGS\\t6\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n\n    let gameInProgress = true;\n    while (gameInProgress) {\n        let dieRoll = Math.floor(6 * Math.random() + 1);\n        let partFound = false;\n        print(\"YOU ROLLED A \" + dieRoll + \"\\n\");\n        switch (dieRoll) {\n            case 1:\n                print(\"1=BODY\\n\");\n                if (playerBodyCount === 0) {\n                    print(\"YOU NOW HAVE A BODY.\\n\");\n                    playerBodyCount = 1;\n                    partFound = true;\n                } else {\n                    print(\"YOU DO NOT NEED A BODY.\\n\");\n                }\n                break;\n            case 2:\n                print(\"2=NECK\\n\");\n                if (playerNeckCount === 0) {\n                    if (playerBodyCount === 0) {\n                        print(\"YOU DO NOT HAVE A BODY.\\n\");\n                    } else {\n                        print(\"YOU NOW HAVE A NECK.\\n\");\n                        playerNeckCount = 1;\n                        partFound = true;\n                    }\n                } else {\n                    print(\"YOU DO NOT NEED A NECK.\\n\");\n                }\n                break;\n            case 3:\n                print(\"3=HEAD\\n\");\n                if (playerNeckCount === 0) {\n                    print(\"YOU DO NOT HAVE A NECK.\\n\");\n                } else if (playerHeadCount === 0) {\n                    print(\"YOU NEEDED A HEAD.\\n\");\n                    playerHeadCount = 1;\n                    partFound = true;\n                } else {\n                    print(\"YOU HAVE A HEAD.\\n\");\n                }\n                break;\n            case 4:\n                print(\"4=FEELERS\\n\");\n                if (playerHeadCount === 0) {\n                    print(\"YOU DO NOT HAVE A HEAD.\\n\");\n                } else if (playerFeelerCount === 2) {\n                    print(\"YOU HAVE TWO FEELERS ALREADY.\\n\");\n                } else {\n                    print(\"I NOW GIVE YOU A FEELER.\\n\");\n                    playerFeelerCount ++;\n                    partFound = true;\n                }\n                break;\n            case 5:\n                print(\"5=TAIL\\n\");\n                if (playerBodyCount === 0) {\n                    print(\"YOU DO NOT HAVE A BODY.\\n\");\n                } else if (playerTailCount === 1) {\n                    print(\"YOU ALREADY HAVE A TAIL.\\n\");\n                } else {\n                    print(\"I NOW GIVE YOU A TAIL.\\n\");\n                    playerTailCount++;\n                    partFound = true;\n                }\n                break;\n            case 6:\n                print(\"6=LEG\\n\");\n                if (playerFeetCount === 6) {\n                    print(\"YOU HAVE 6 FEET ALREADY.\\n\");\n                } else if (playerBodyCount === 0) {\n                    print(\"YOU DO NOT HAVE A BODY.\\n\");\n                } else {\n                    playerFeetCount++;\n                    partFound = true;\n                    print(\"YOU NOW HAVE \" + playerFeetCount + \" LEGS.\\n\");\n                }\n                break;\n        }\n        dieRoll = Math.floor(6 * Math.random() + 1) ;\n        print(\"\\n\");\n        scrollToBottom();\n        await waitNSeconds(1);\n\n        print(\"I ROLLED A \" + dieRoll + \"\\n\");\n        switch (dieRoll) {\n            case 1:\n                print(\"1=BODY\\n\");\n                if (computerBodyCount === 1) {\n                    print(\"I DO NOT NEED A BODY.\\n\");\n                } else {\n                    print(\"I NOW HAVE A BODY.\\n\");\n                    partFound = true;\n                    computerBodyCount = 1;\n                }\n                break;\n            case 2:\n                print(\"2=NECK\\n\");\n                if (computerNeckCount === 1) {\n                    print(\"I DO NOT NEED A NECK.\\n\");\n                } else if (computerBodyCount === 0) {\n                    print(\"I DO NOT HAVE A BODY.\\n\");\n                } else {\n                    print(\"I NOW HAVE A NECK.\\n\");\n                    computerNeckCount = 1;\n                    partFound = true;\n                }\n                break;\n            case 3:\n                print(\"3=HEAD\\n\");\n                if (computerNeckCount === 0) {\n                    print(\"I DO NOT HAVE A NECK.\\n\");\n                } else if (computerHeadCount === 1) {\n                    print(\"I DO NOT NEED A HEAD.\\n\");\n                } else {\n                    print(\"I NEEDED A HEAD.\\n\");\n                    computerHeadCount = 1;\n                    partFound = true;\n                }\n                break;\n            case 4:\n                print(\"4=FEELERS\\n\");\n                if (computerHeadCount === 0) {\n                    print(\"I DO NOT HAVE A HEAD.\\n\");\n                } else if (computerFeelerCount === 2) {\n                    print(\"I HAVE 2 FEELERS ALREADY.\\n\");\n                } else {\n                    print(\"I GET A FEELER.\\n\");\n                    computerFeelerCount++;\n                    partFound = true;\n                }\n                break;\n            case 5:\n                print(\"5=TAIL\\n\");\n                if (computerBodyCount === 0) {\n                    print(\"I DO NOT HAVE A BODY.\\n\");\n                } else if (computerTailCount === 1) {\n                    print(\"I DO NOT NEED A TAIL.\\n\");\n                } else {\n                    print(\"I NOW HAVE A TAIL.\\n\");\n                    computerTailCount = 1;\n                    partFound = true;\n                }\n                break;\n            case 6:\n                print(\"6=LEGS\\n\");\n                if (computerFeetCount === 6) {\n                    print(\"I HAVE 6 FEET.\\n\");\n                } else if (computerBodyCount === 0) {\n                    print(\"I DO NOT HAVE A BODY.\\n\");\n                } else {\n                    computerFeetCount++;\n                    partFound = true;\n                    print(\"I NOW HAVE \" + computerFeetCount + \" LEGS.\\n\");\n                }\n                break;\n        }\n        if (playerFeelerCount === 2 && playerTailCount === 1 && playerFeetCount === 6) {\n            print(\"YOUR BUG IS FINISHED.\\n\");\n            gameInProgress = false;\n        }\n        if (computerFeelerCount === 2 && computerBodyCount === 1 && computerFeetCount === 6) {\n            print(\"MY BUG IS FINISHED.\\n\");\n            gameInProgress = false;\n        }\n        if (!partFound)\n            continue;\n        print(\"DO YOU WANT THE PICTURES\");\n        const showPictures = await input();\n        if (showPictures.toUpperCase() === \"NO\")\n            continue;\n        print(\"*****YOUR BUG*****\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        drawBug(playerFeelerCount, playerHeadCount, playerNeckCount, playerBodyCount, playerTailCount, playerFeetCount, \"A\");\n        print(\"*****MY BUG*****\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        drawBug(computerFeelerCount, computerHeadCount, computerNeckCount, computerBodyCount, computerTailCount, computerFeetCount, \"F\");\n        for (let z = 1; z <= 4; z++)\n            print(\"\\n\");\n    }\n    print(\"I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!\\n\");\n    scrollToBottom();\n}\n\nmain();\n"
  },
  {
    "path": "16_Bug/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "16_Bug/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "16_Bug/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "16_Bug/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "16_Bug/python/bug.py",
    "content": "import random\nimport time\nfrom dataclasses import dataclass\nfrom typing import Literal\n\n\n@dataclass\nclass State:\n    is_player: bool\n    body: int = 0\n    neck: int = 0\n    head: int = 0\n    feelers: int = 0\n    tail: int = 0\n    legs: int = 0\n\n    def is_finished(self) -> bool:\n        return (\n            self.feelers == 2\n            and self.tail == 1\n            and self.legs == 6\n            and self.head == 1\n            and self.neck == 1\n        )\n\n    def display(self) -> None:\n        if self.feelers != 0:\n            print_feelers(self.feelers, is_player=self.is_player)\n        if self.head != 0:\n            print_head()\n        if self.neck != 0:\n            print_neck()\n        if self.body != 0:\n            print_body(True) if self.tail == 1 else print_body(False)\n        if self.legs != 0:\n            print_legs(self.legs)\n\n\ndef print_n_newlines(n: int) -> None:\n    for _ in range(n):\n        print()\n\n\ndef print_feelers(n_feelers: int, is_player: bool = True) -> None:\n    for _ in range(4):\n        print(\" \" * 10, end=\"\")\n        for _ in range(n_feelers):\n            print(\"A \" if is_player else \"F \", end=\"\")\n        print()\n\n\ndef print_head() -> None:\n    print(\"        HHHHHHH\")\n    print(\"        H     H\")\n    print(\"        H O O H\")\n    print(\"        H     H\")\n    print(\"        H  V  H\")\n    print(\"        HHHHHHH\")\n\n\ndef print_neck() -> None:\n    print(\"          N N\")\n    print(\"          N N\")\n\n\ndef print_body(has_tail: bool = False) -> None:\n    print(\"     BBBBBBBBBBBB\")\n    print(\"     B          B\")\n    print(\"     B          B\")\n    print(\"TTTTTB          B\") if has_tail else \"\"\n    print(\"     BBBBBBBBBBBB\")\n\n\ndef print_legs(n_legs: int) -> None:\n    for _ in range(2):\n        print(\" \" * 5, end=\"\")\n        for _ in range(n_legs):\n            print(\" L\", end=\"\")\n        print()\n\n\ndef handle_roll(diceroll: Literal[1, 2, 3, 4, 5, 6], state: State) -> bool:\n    who = \"YOU\" if state.is_player else \"I\"\n    changed = False\n\n    print(f\"{who} ROLLED A\", diceroll)\n    if diceroll == 1:\n        print(\"1=BODY\")\n        if state.body:\n            print(f\"{who} DO NOT NEED A BODY.\")\n        else:\n            print(f\"{who} NOW HAVE A BODY.\")\n            state.body = 1\n            changed = True\n    elif diceroll == 2:\n        print(\"2=NECK\")\n        if state.neck:\n            print(f\"{who} DO NOT NEED A NECK.\")\n        elif state.body == 0:\n            print(f\"{who} DO NOT HAVE A BODY.\")\n        else:\n            print(f\"{who} NOW HAVE A NECK.\")\n            state.neck = 1\n            changed = True\n    elif diceroll == 3:\n        print(\"3=HEAD\")\n        if state.neck == 0:\n            print(f\"{who} DO NOT HAVE A NECK.\")\n        elif state.head:\n            print(f\"{who} HAVE A HEAD.\")\n        else:\n            print(f\"{who} NEEDED A HEAD.\")\n            state.head = 1\n            changed = True\n    elif diceroll == 4:\n        print(\"4=FEELERS\")\n        if state.head == 0:\n            print(f\"{who} DO NOT HAVE A HEAD.\")\n        elif state.feelers == 2:\n            print(f\"{who} HAVE TWO FEELERS ALREADY.\")\n        else:\n            if state.is_player:\n                print(\"I NOW GIVE YOU A FEELER.\")\n            else:\n                print(f\"{who} GET A FEELER.\")\n            state.feelers += 1\n            changed = True\n    elif diceroll == 5:\n        print(\"5=TAIL\")\n        if state.body == 0:\n            print(f\"{who} DO NOT HAVE A BODY.\")\n        elif state.tail:\n            print(f\"{who} ALREADY HAVE A TAIL.\")\n        else:\n            if state.is_player:\n                print(\"I NOW GIVE YOU A TAIL.\")\n            else:\n                print(f\"{who} NOW HAVE A TAIL.\")\n            state.tail = 1\n            changed = True\n    elif diceroll == 6:\n        print(\"6=LEG\")\n        if state.legs == 6:\n            print(f\"{who} HAVE 6 FEET ALREADY.\")\n        elif state.body == 0:\n            print(f\"{who} DO NOT HAVE A BODY.\")\n        else:\n            state.legs += 1\n            changed = True\n            print(f\"{who} NOW HAVE {state.legs} LEGS\")\n    return changed\n\n\ndef main() -> None:\n    print(\" \" * 34 + \"BUG\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print_n_newlines(3)\n\n    print(\"THE GAME BUG\")\n    print(\"I HOPE YOU ENJOY THIS GAME.\")\n    print()\n    want_instructions = input(\"DO YOU WANT INSTRUCTIONS? \")\n    if want_instructions != \"NO\":\n        print(\"THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH\")\n        print(\"MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.\")\n        print(\"I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU\")\n        print(\"WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.\")\n        print(\"IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.\")\n        print(\"THE SAME WILL HAPPEN ON MY TURN.\")\n        print(\"IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE\")\n        print(\"OPTION OF SEEING THE PICTURES OF THE BUGS.\")\n        print(\"THE NUMBERS STAND FOR PARTS AS FOLLOWS:\")\n        table = [\n            [\"NUMBER\", \"PART\", \"NUMBER OF PART NEEDED\"],\n            [\"1\", \"BODY\", \"1\"],\n            [\"2\", \"NECK\", \"1\"],\n            [\"3\", \"HEAD\", \"1\"],\n            [\"4\", \"FEELERS\", \"2\"],\n            [\"5\", \"TAIL\", \"1\"],\n            [\"6\", \"LEGS\", \"6\"],\n        ]\n        for row in table:\n            print(f\"{row[0]:<16}{row[1]:<16}{row[2]:<20}\")\n        print_n_newlines(2)\n\n    player = State(is_player=True)\n    opponent = State(is_player=False)\n    bugs_finished = 0\n\n    while bugs_finished <= 0:\n        diceroll = random.randint(1, 6)\n        print()\n        changed = handle_roll(diceroll, player)  # type: ignore\n\n        diceroll = random.randint(1, 6)\n        print()\n        time.sleep(2)\n\n        changed_op = handle_roll(diceroll, opponent)  # type: ignore\n\n        changed = changed or changed_op\n\n        if player.is_finished():\n            print(\"YOUR BUG IS FINISHED.\")\n            bugs_finished += 1\n        if opponent.is_finished():\n            print(\"MY BUG IS FINISHED.\")\n            bugs_finished += 1\n        if not changed:\n            continue\n        want_pictures = input(\"DO YOU WANT THE PICTURES? \")\n        if want_pictures != \"NO\":\n            print(\"*****YOUR BUG*****\")\n            print_n_newlines(2)\n            player.display()\n            print_n_newlines(4)\n            print(\"*****MY BUG*****\")\n            print_n_newlines(3)\n            opponent.display()\n\n            if bugs_finished != 0:\n                break\n\n    print(\"I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "16_Bug/ruby/Bug.rb",
    "content": "class BugGame\n  YES = [\"Y\", \"y\", \"Yes\", \"YES\"]\n  NO  = [\"N\", \"n\", \"No\", \"NO\"]\n\n  YOU = { body: 0, neck: 0, head: 0, antennaes: 0, legs: 0, arms: 0, name: \"YOU\" }\n  I   = { body: 0, neck: 0, head: 0, antennaes: 0, legs: 0, arms: 0, name: \"I\" }\n  def initialize\n    puts \"The Game Bug\"\n    puts \"I HOPE YOU ENJOY THIS GAME.\"\n    instructions\n  end\n\n  def run\n    loop do\n      # YOU FIRST\n      play YOU\n      if is_completed? YOU\n        puts \"\\n\\n\\n\\nYOU WON\"\n        break\n      end\n      puts \"\\n\"\n\n      # I SECOND\n      play I\n      if is_completed? I\n        puts \"\\n\\n\\n\\nI WON\"\n        break\n      end\n\n      loop do\n        puts \"Do you want the pictures? [Y,y,Yes,YES] [N,n,No,NO]\"\n        answer = gets.chomp!\n        if YES.include?(answer) || NO.include?(answer)\n          if YES.include?(answer)\n            puts \"--- YOUR BUG ---\"\n            print_bug YOU\n            puts \"\\n\\n--- MY BUG ---\"\n            print_bug I\n          end\n          break\n        end\n      end\n    end\n  end\n\n  private\n    def play player\n      number = Random.rand(1..6)\n      case number\n      when 1\n        if player[:body].eql? 0\n          player[:body] = 1\n          puts \"#{player[:name]} have acquired a body\"\n        else\n          puts \"#{player[:name]} already have a body\"\n        end\n      when 2\n        one_part player, :neck, :body\n      when 3\n        one_part player, :head, :neck\n      when 4\n        two_parts player, :antennaes, :head\n      when 5\n        two_parts player, :legs, :body\n      when 6\n        two_parts player, :arms, :body\n      end\n    end\n\n    def one_part player, part, part_needed\n      if player[part].eql? 0\n        if player[part_needed].eql? 0\n          puts \"#{player[:name]} need to have a #{part_needed.to_s} first\"\n        else\n          player[part] = 1\n          puts \"#{player[:name]} have acquired a #{part.to_s}\"\n        end\n      else\n        puts \"#{player[:name]} already have a #{part.to_s}\"\n      end\n    end\n\n    def two_parts player, part, part_needed\n      if player[part].eql? 0\n        if player[part_needed].eql? 0\n          puts \"#{player[:name]} need to have a #{part_needed.to_s} first\"\n        else\n          player[part] = 1\n          puts \"#{player[:name]} have acquired first #{part.to_s.chop}\"\n        end\n      else\n        if player[part].eql? 2\n          puts \"#{player[:name]} already have 2 #{part.to_s}\"\n        else\n          player[part] = 2\n          puts \"#{player[:name]} have acquired second #{part.to_s.chop}\"\n        end\n      end\n    end\n\n    def is_completed? player\n      player[:body].eql?(1) && player[:neck].eql?(1) && player[:head].eql?(1) && player[:antennaes].eql?(2) && player[:legs].eql?(2) && player[:arms].eql?(2)\n    end\n\n    def print_bug player\n      antennae_and_leg player, :antennaes\n      head player\n      neck player\n      body player\n      antennae_and_leg player, :legs\n    end\n\n    def instructions\n      loop do\n        puts \"Do you want an instruction? [Y,y,Yes,YES] [N,n,No,NO]\"\n        answer = gets.chomp!\n\n        if YES.include?(answer) || NO.include?(answer)\n          if YES.include?(answer)\n            puts \"THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH\"\n            puts \"MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.\"\n            puts \"I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU\"\n            puts \"WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.\"\n            puts \"IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.\"\n            puts \"THE SAME WILL HAPPEN ON MY TURN.\"\n            puts \"IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE\"\n            puts \"OPTION OF SEEING THE PICTURES OF THE BUGS.\"\n            puts \"THE NUMBERS STAND FOR PARTS AS FOLLOWS:\\n\\n\\n\"\n            puts \"Number    Part          Required Part #\"\n            puts \"1         Body          1\"\n            puts \"2         Neck          1\"\n            puts \"3         Head          2\"\n            puts \"4      (2)antennaes     3\"\n            puts \"5      (2)arms          1\"\n            puts \"6      (2)Legs          1\"\n          end\n          break\n        end\n      end\n    end\n\n    def antennae_and_leg player, part\n      if !player[part].eql? 0\n        for i in (1...5) do\n          if player[part].eql? 1\n            puts \"     N\"\n          else\n            puts \"     N    N\"\n          end\n        end\n      end\n    end\n\n    def head player\n      if !player[:head].eql? 0\n        puts \"     NNNNNNN\"\n        puts \"     N     N\"\n        puts \"     N O O N\"\n        puts \"     N     N\"\n        puts \"     N  V  N\"\n        puts \"     NNNNNNN\"\n      end\n    end\n\n    def neck player\n      if !player[:neck].eql? 0\n        puts \"     N  N\"\n      end\n    end\n\n    def body player\n      if !player[:body].eql? 0\n        puts \"     NNNNNNNNN\"\n        for i in (1...5) do\n          if i.eql? 2\n            if player[:arms].eql? 1\n              puts \"NNNNNN       N\"\n            elsif player[:arms].eql? 2\n              \n              puts \"NNNNNN       NNNNNN\"\n            end\n          else\n            puts \"     N       N\"\n          end\n        end\n        puts \"     NNNNNNNNN\"\n      end\n    end\nend\n\n\nif __FILE__ == $0\n  bug = BugGame.new\n  puts \"\\n\\nNOW WE START THE GAME\\n\\n\"\n  bug.run\nend"
  },
  {
    "path": "16_Bug/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "16_Bug/vbnet/Bug.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bug\", \"Bug.vbproj\", \"{4F4EA8E5-55A8-4191-BE57-B28638C33609}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4F4EA8E5-55A8-4191-BE57-B28638C33609}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4F4EA8E5-55A8-4191-BE57-B28638C33609}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4F4EA8E5-55A8-4191-BE57-B28638C33609}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4F4EA8E5-55A8-4191-BE57-B28638C33609}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "16_Bug/vbnet/Bug.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bug</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "16_Bug/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "17_Bullfight/README.md",
    "content": "### Bullfight\n\nIn this simulated bullfight, you are the matador — i.e., the one with the principle role and the one who must kill the bull or be killed (or run from the ring).\n\nOn each pass of the bull, you may try:\n- 0: Veronica (dangerous inside move of the cape)\n- 1: Less dangerous outside move of the cape\n- 2: Ordinary swirl of the cape\n\nOr you may try to kill the bull:\n- 4: Over the horns\n- 5: In the chest\n\nThe crowd will determine what award you deserve, posthumously if necessary. The braver you are, the better the reward you receive. It’s nice to stay alive too. The better the job the picadores and toreadores do, the better your chances.\n\nDavid Sweet of Dartmouth wrote the original version of this program. It was then modified by students at Lexington High School and finally by Steve North of Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=32)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=47)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- There is a fundamental assumption in the pre-fight subroutine at line 1610, that the Picadores and Toreadores are more likely to do a bad job (and possibly get killed) with a low-quality bull. This appears to be a mistake in the original code, but should be retained.\n\n- Lines 1800-1820 (part of the pre-fight subroutine) can never be reached.\n"
  },
  {
    "path": "17_Bullfight/bullfight.bas",
    "content": "10 PRINT TAB(34);\"BULL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 DEF FNA(K)=INT(RND(1)*2+1)\n200 PRINT:PRINT:PRINT\n202 L=1\n205 PRINT \"DO YOU WANT INSTRUCTIONS\";\n206 INPUT Z$\n207 IF Z$=\"NO\" THEN 400\n210 PRINT \"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\"\n220 PRINT \"HERE IS YOUR BIG CHANCE TO KILL A BULL.\"\n230 PRINT\n240 PRINT \"ON EACH PASS OF THE BULL, YOU MAY TRY\"\n250 PRINT \"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\"\n260 PRINT \"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\"\n270 PRINT \"2 - ORDINARY SWIRL OF THE CAPE.\"\n280 PRINT\n290 PRINT \"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\"\n300 PRINT \"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\"\n310 PRINT \"BUT IF I WERE YOU,\"\n320 PRINT \"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\"\n330 PRINT\n340 PRINT \"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\"\n350 PRINT \"(POSTHUMOUSLY IF NECESSARY).\"\n360 PRINT \"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\"\n370 PRINT\n380 PRINT \"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\"\n390 PRINT \"THE BETTER YOUR CHANCES ARE.\"\n400 PRINT\n410 PRINT\n420 D(5)=1\n430 D(4)=1\n450 DIM L$(5)\n455 A=INT(RND(1)*5+1)\n460 FOR I=1 TO 5\n463 READ L$(I)\n467 NEXT I\n470 DATA \"SUPERB\",\"GOOD\",\"FAIR\",\"POOR\",\"AWFUL\"\n490 PRINT \"YOU HAVE DRAWN A \";L$(A);\" BULL.\"\n500 IF A>4 THEN 530\n510 IF A<2 THEN 550\n520 GOTO 570\n530 PRINT \"YOU'RE LUCKY.\"\n540 GOTO 570\n550 PRINT \"GOOD LUCK.  YOU'LL NEED IT.\"\n560 PRINT\n570 PRINT\n590 A$=\"PICADO\"\n595 B$=\"RES\"\n600 GOSUB 1610\n610 D(1)=C\n630 A$=\"TOREAD\"\n635 B$=\"ORES\"\n640 GOSUB 1610\n650 D(2)=C\n660 PRINT\n670 PRINT\n680 IF Z=1 THEN 1310\n690 D(3)=D(3)+1\n700 PRINT \"PASS NUMBER\";D(3)\n710 IF D(3)<3 THEN 760\n720 PRINT \"HERE COMES THE BULL.  TRY FOR A KILL\";\n730 GOSUB 1930\n735 IF Z1=1 THEN 1130\n740 PRINT \"CAPE MOVE\";\n750 GOTO 800\n760 PRINT \"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\"\n770 PRINT \"DO YOU WANT TO KILL THE BULL\";\n780 GOSUB 1930\n785 IF Z1=1 THEN 1130\n790 PRINT \"WHAT MOVE DO YOU MAKE WITH THE CAPE\";\n800 INPUT E\n810 IF E<>INT(ABS(E)) THEN 830\n820 IF E<3 THEN 850\n830 PRINT \"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\"\n840 GOTO 800\n850 REM\n860 IF E=0 THEN 920\n870 IF E=1 THEN 900\n880 M=.5\n890 GOTO 930\n900 M=2\n910 GOTO 930\n920 M=3\n930 L=L+M\n940 F=(6-A+M/10)*RND(1)/((D(1)+D(2)+D(3)/10)*5)\n950 IF F<.51 THEN 660\n960 PRINT \"THE BULL HAS GORED YOU!\"\n970 ON FNA(0) GOTO 980,1010\n980 PRINT \"YOU ARE DEAD.\"\n990 D(4)=1.5\n1000 GOTO 1310\n1010 PRINT \"YOU ARE STILL ALIVE.\":PRINT\n1020 PRINT \"DO YOU RUN FROM THE RING\";\n1030 GOSUB 1930\n1035 IF Z1=2 THEN 1070\n1040 PRINT \"COWARD\"\n1050 D(4)=0\n1060 GOTO 1310\n1070 PRINT \"YOU ARE BRAVE.  STUPID, BUT BRAVE.\"\n1080 ON FNA(0) GOTO 1090,1110\n1090 D(4)=2\n1100 GOTO 660\n1110 PRINT \"YOU ARE GORED AGAIN!\"\n1120 GOTO 970\n1130 REM\n1140 Z=1\n1150 PRINT:PRINT \"IT IS THE MOMENT OF TRUTH.\":PRINT\n1155 PRINT \"HOW DO YOU TRY TO KILL THE BULL\";\n1160 INPUT H\n1170 IF H=4 THEN 1230\n1180 IF H=5 THEN 1230\n1190 PRINT \"YOU PANICKED.  THE BULL GORED YOU.\"\n1220 GOTO 970\n1230 K=(6-A)*10*RND(1)/((D(1)+D(2))*5*D(3))\n1240 IF H=4 THEN 1290\n1250 IF K>.2 THEN 960\n1260 PRINT \"YOU KILLED THE BULL!\"\n1270 D(5)=2\n1280 GOTO 1320\n1290 IF K>.8 THEN 960\n1300 GOTO 1260\n1310 PRINT\n1320 PRINT\n1330 PRINT\n1340 IF D(4)<>0 THEN 1390\n1350 PRINT \"THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\"\n1360 PRINT \"YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\"\n1370 PRINT \"UNLESS THE BULL DOES FIRST.\"\n1380 GOTO 1580\n1390 DEF FNC(Q)=FND(Q)*RND(1)\n1395 DEF FND(Q)=(4.5+L/6-(D(1)+D(2))*2.5+4*D(4)+2*D(5)-D(3)^2/120-A)\n1400 IF D(4)<>2 THEN 1430\n1410 PRINT \"THE CROWD CHEERS WILDLY!\"\n1420 GOTO 1450\n1430 IF D(5)<>2 THEN 1450\n1440 PRINT \"THE CROWD CHEERS!\":PRINT\n1450 PRINT \"THE CROWD AWARDS YOU\"\n1460 IF FNC(Q)<2.4 THEN 1570\n1470 IF FNC(Q)<4.9 THEN 1550\n1480 IF FNC(Q)<7.4 THEN 1520\n1500 PRINT \"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\"\n1510 GOTO 1580\n1520 PRINT \"BOTH EARS OF THE BULL!\"\n1530 PRINT \"OLE!\"\n1540 GOTO 1580\n1550 PRINT \"ONE EAR OF THE BULL.\"\n1560 GOTO 1580\n1570 PRINT \"NOTHING AT ALL.\"\n1580 PRINT\n1590 PRINT \"ADIOS\":PRINT:PRINT:PRINT\n1600 GOTO 2030\n1610 B=3/A*RND(1)\n1620 IF B<.37 THEN 1740\n1630 IF B<.5 THEN 1720\n1640 IF B<.63 THEN 1700\n1650 IF B<.87 THEN 1680\n1660 C=.1\n1670 GOTO 1750\n1680 C=.2\n1690 GOTO 1750\n1700 C=.3\n1710 GOTO 1750\n1720 C=.4\n1730 GOTO 1750\n1740 C=.5\n1750 T=INT(10*C+.2)\n1760 PRINT \"THE \";A$;B$;\" DID A \";L$(T);\" JOB.\"\n1770 IF 4>T THEN 1900\n1780 IF 5=T THEN 1870\n1790 ON FNA(K) GOTO 1830,1850\n1800 IF A$=\"TOREAD\" THEN 1820\n1810 PRINT \"ONE OF THE HORSES OF THE \";A$;B$;\" WAS KILLED.\"\n1820 ON FNA(K) GOTO 1830,1850\n1830 PRINT \"ONE OF THE \";A$;B$;\" WAS KILLED.\"\n1840 GOTO 1900\n1850 PRINT \"NO \";A$;B$;\" WERE KILLED.\"\n1860 GOTO 1900\n1870 IF A$=\"TOREAD\" THEN 1890\n1880 PRINT FNA(K);\"OF THE HORSES OF THE \";A$;B$;\" KILLED.\"\n1890 PRINT FNA(K);\"OF THE \";A$;B$;\" KILLED.\"\n1900 PRINT\n1910 RETURN\n1920 REM\n1930 INPUT A$\n1940 IF A$=\"YES\" THEN 1990\n1950 IF A$=\"NO\" THEN 2010\n1970 PRINT \"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\"\n1980 GOTO 1930\n1990 Z1=1\n2000 GOTO 2020\n2010 Z1=2\n2020 RETURN\n2030 END\n"
  },
  {
    "path": "17_Bullfight/csharp/Action.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different actions that the player can take on each round\n    /// of the fight.\n    /// </summary>\n    public enum Action\n    {\n        /// <summary>\n        /// Dodge the bull.\n        /// </summary>\n        Dodge,\n\n        /// <summary>\n        /// Kill the bull.\n        /// </summary>\n        Kill,\n\n        /// <summary>\n        /// Freeze in place and don't do anything.\n        /// </summary>\n        Panic\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/ActionResult.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Game\n{\n    /// <summary>\n    /// Enumerates the different possible outcomes of the player's action.\n    /// </summary>\n    public enum ActionResult\n    {\n        /// <summary>\n        /// The fight continues.\n        /// </summary>\n        FightContinues,\n\n        /// <summary>\n        /// The player fled from the ring.\n        /// </summary>\n        PlayerFlees,\n\n        /// <summary>\n        /// The bull has gored the player.\n        /// </summary>\n        BullGoresPlayer,\n\n        /// <summary>\n        /// The bull killed the player.\n        /// </summary>\n        BullKillsPlayer,\n\n        /// <summary>\n        /// The player killed the bull.\n        /// </summary>\n        PlayerKillsBull,\n\n        /// <summary>\n        /// The player attempted to kill the bull and both survived.\n        /// </summary>\n        Draw\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/BullFight.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Game\n{\n    /// <summary>\n    /// Provides a method for simulating a bull fight.\n    /// </summary>\n    public static class BullFight\n    {\n        /// <summary>\n        /// Begins a new fight.\n        /// </summary>\n        /// <param name=\"mediator\">\n        /// Object used to communicate with the player.\n        /// </param>\n        /// <returns>\n        /// The sequence of events that take place during the fight.\n        /// </returns>\n        /// <remarks>\n        /// After receiving each event, the caller must invoke the appropriate\n        /// mediator method to inform this coroutine what to do next.  Failure\n        /// to do so will result in an exception.\n        /// </remarks>\n        public static IEnumerable<Events.Event> Begin(Mediator mediator)\n        {\n            var random = new Random();\n            var result = ActionResult.FightContinues;\n\n            var bullQuality          = GetBullQuality();\n            var toreadorePerformance = GetHelpQuality(bullQuality);\n            var picadorePerformance  = GetHelpQuality(bullQuality);\n\n            var bullStrength    = 6 - (int)bullQuality;\n            var assistanceLevel = (12 - (int)toreadorePerformance - (int)picadorePerformance) * 0.1;\n            var bravery         = 1.0;\n            var style           = 1.0;\n            var passNumber      = 0;\n\n            yield return new Events.MatchStarted(\n                bullQuality,\n                toreadorePerformance,\n                picadorePerformance,\n                GetHumanCasualties(toreadorePerformance),\n                GetHumanCasualties(picadorePerformance),\n                GetHorseCasualties(picadorePerformance));\n\n            while (result == ActionResult.FightContinues)\n            {\n                yield return new Events.BullCharging(++passNumber);\n\n                var (action, riskLevel) = mediator.GetInput<(Action, RiskLevel)>();\n                result = action switch\n                {\n                    Action.Dodge => TryDodge(riskLevel),\n                    Action.Kill  => TryKill(riskLevel),\n                    _            => Panic()\n                };\n\n                var first = true;\n                while (result == ActionResult.BullGoresPlayer)\n                {\n                    yield return new Events.PlayerGored(action == Action.Panic, first);\n                    first = false;\n\n                    result = TrySurvive();\n                    if (result == ActionResult.FightContinues)\n                    {\n                        yield return new Events.PlayerSurvived();\n\n                        var runFromRing = mediator.GetInput<bool>();\n                        if (runFromRing)\n                            result = Flee();\n                        else\n                            result = IgnoreInjury(action);\n                    }\n                }\n            }\n\n            yield return new Events.MatchCompleted(\n                result,\n                bravery == 2,\n                GetReward());\n\n            Quality GetBullQuality() =>\n                (Quality)random.Next(1, 6);\n\n            Quality GetHelpQuality(Quality bullQuality) =>\n                ((3.0 / (int)bullQuality) * random.NextDouble()) switch\n                {\n                    < 0.37 => Quality.Superb,\n                    < 0.50 => Quality.Good,\n                    < 0.63 => Quality.Fair,\n                    < 0.87 => Quality.Poor,\n                    _      => Quality.Awful\n                };\n\n            int GetHumanCasualties(Quality performance) =>\n                performance switch\n                {\n                    Quality.Poor  => random.Next(0, 2),\n                    Quality.Awful => random.Next(1, 3),\n                    _             => 0\n                };\n\n            int GetHorseCasualties(Quality performance) =>\n                performance switch\n                {\n                    // NOTE: The code for displaying a single horse casuality\n                    //  following a poor picadore peformance was unreachable\n                    //  in the original BASIC version.  I've assumed this was\n                    //  a bug.\n                    Quality.Poor  => 1,\n                    Quality.Awful => random.Next(1, 3),\n                    _             => 0\n                };\n\n            ActionResult TryDodge(RiskLevel riskLevel)\n            {\n                var difficultyModifier = riskLevel switch\n                {\n                    RiskLevel.High   => 3.0,\n                    RiskLevel.Medium => 2.0,\n                    _                => 0.5\n                };\n\n                var outcome = (bullStrength + (difficultyModifier / 10)) * random.NextDouble() /\n                    ((assistanceLevel + (passNumber / 10.0)) * 5);\n\n                if (outcome < 0.51)\n                {\n                    style += difficultyModifier;\n                    return ActionResult.FightContinues;\n                }\n                else\n                    return ActionResult.BullGoresPlayer;\n            }\n\n            ActionResult TryKill(RiskLevel riskLevel)\n            {\n                var luck = bullStrength * 10 * random.NextDouble() / (assistanceLevel * 5 * passNumber);\n\n                return ((riskLevel == RiskLevel.High && luck > 0.2) || luck > 0.8) ?\n                    ActionResult.BullGoresPlayer : ActionResult.PlayerKillsBull;\n            }\n\n            ActionResult Panic() =>\n                ActionResult.BullGoresPlayer;\n\n            ActionResult TrySurvive()\n            {\n                if (random.Next(2) == 0)\n                {\n                    bravery = 1.5;\n                    return ActionResult.BullKillsPlayer;\n                }\n                else\n                    return ActionResult.FightContinues;\n            }\n\n            ActionResult Flee()\n            {\n                bravery = 0.0;\n                return ActionResult.PlayerFlees;\n            }\n\n            ActionResult IgnoreInjury(Action action)\n            {\n                if (random.Next(2) == 0)\n                {\n                    bravery = 2.0;\n                    return action == Action.Dodge ? ActionResult.FightContinues : ActionResult.Draw;\n                }\n                else\n                    return ActionResult.BullGoresPlayer;\n            }\n\n            Reward GetReward()\n            {\n                var score = CalculateScore();\n\n                if (score * random.NextDouble() < 2.4)\n                    return Reward.Nothing;\n                else\n                if (score * random.NextDouble() < 4.9)\n                    return Reward.OneEar;\n                else\n                if (score * random.NextDouble() < 7.4)\n                    return Reward.TwoEars;\n                else\n                    return Reward.CarriedFromRing;\n            }\n\n            double CalculateScore()\n            {\n                var score = 4.5;\n\n                // Style\n                score += style / 6;\n\n                // Assisstance\n                score -= assistanceLevel * 2.5;\n\n                // Courage\n                score += 4 * bravery;\n\n                // Kill bonus\n                score += (result == ActionResult.PlayerKillsBull) ? 4 : 2;\n\n                // Match length\n                score -= Math.Pow(passNumber, 2) / 120;\n\n                // Difficulty\n                score -= (int)bullQuality;\n\n                return score;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Bullfight.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "17_Bullfight/csharp/Bullfight.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31321.278\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Bullfight\", \"Bullfight.csproj\", \"{502A672C-F7D7-4A85-973A-B5EA8761008A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{502A672C-F7D7-4A85-973A-B5EA8761008A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{502A672C-F7D7-4A85-973A-B5EA8761008A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{502A672C-F7D7-4A85-973A-B5EA8761008A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{502A672C-F7D7-4A85-973A-B5EA8761008A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {C5BFC749-C7D8-4981-A7D4-1D401901A890}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "17_Bullfight/csharp/Controller.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for getting input from the user.\n    /// </summary>\n    public static class Controller\n    {\n        /// <summary>\n        /// Handles the initial interaction with the player.\n        /// </summary>\n        public static void StartGame()\n        {\n            View.ShowBanner();\n            View.PromptShowInstructions();\n\n            var input = Console.ReadLine();\n            if (input is null)\n                Environment.Exit(0);\n\n            if (input.ToUpperInvariant() != \"NO\")\n                View.ShowInstructions();\n\n            View.ShowSeparator();\n        }\n\n        /// <summary>\n        /// Gets the player's action for the current round.\n        /// </summary>\n        /// <param name=\"passNumber\">\n        /// The current pass number.\n        /// </param>\n        public static (Action action, RiskLevel riskLevel) GetPlayerIntention(int passNumber)\n        {\n            if (passNumber < 3)\n                View.PromptKillBull();\n            else\n                View.PromptKillBullBrief();\n\n            var attemptToKill = GetYesOrNo();\n\n            if (attemptToKill)\n            {\n                View.PromptKillMethod();\n\n                var input = Console.ReadLine();\n                if (input is null)\n                    Environment.Exit(0);\n\n                return input switch\n                {\n                    \"4\" => (Action.Kill,  RiskLevel.High),\n                    \"5\" => (Action.Kill,  RiskLevel.Low),\n                    _   => (Action.Panic, default(RiskLevel))\n                };\n            }\n            else\n            {\n                if (passNumber < 2)\n                    View.PromptCapeMove();\n                else\n                    View.PromptCapeMoveBrief();\n\n                var action = Action.Panic;\n                var riskLevel = default(RiskLevel);\n\n                while (action == Action.Panic)\n                {\n                    var input = Console.ReadLine();\n                    if (input is null)\n                        Environment.Exit(0);\n\n                    (action, riskLevel) = input switch\n                    {\n                        \"0\" => (Action.Dodge, RiskLevel.High),\n                        \"1\" => (Action.Dodge, RiskLevel.Medium),\n                        \"2\" => (Action.Dodge, RiskLevel.Low),\n                        _   => (Action.Panic, default(RiskLevel))\n                    };\n\n                    if (action == Action.Panic)\n                        View.PromptDontPanic();\n                }\n\n                return (action, riskLevel);\n            }\n        }\n\n        /// <summary>\n        /// Gets the player's intention to flee (or not).\n        /// </summary>\n        /// <returns>\n        /// True if the player flees; otherwise, false.\n        /// </returns>\n        public static bool GetPlayerRunsFromRing()\n        {\n            View.PromptRunFromRing();\n\n            var playerFlees = GetYesOrNo();\n            if (!playerFlees)\n                View.ShowPlayerFoolhardy();\n\n            return playerFlees;\n        }\n\n        /// <summary>\n        /// Gets a yes or no response from the player.\n        /// </summary>\n        /// <returns>\n        /// True if the user answered yes; otherwise, false.\n        /// </returns>\n        public static bool GetYesOrNo()\n        {\n            while (true)\n            {\n                var input = Console.ReadLine();\n                if (input is null)\n                    Environment.Exit(0);\n\n                switch (input.ToUpperInvariant())\n                {\n                    case \"YES\":\n                        return true;\n                    case \"NO\":\n                        return false;\n                    default:\n                        Console.WriteLine(\"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\");\n                        break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Events/BullCharging.cs",
    "content": "﻿namespace Game.Events\n{\n    /// <summary>\n    /// Indicates that the bull is charing the player.\n    /// </summary>\n    public sealed record BullCharging(int PassNumber) : Event;\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Events/Event.cs",
    "content": "﻿namespace Game.Events\n{\n    /// <summary>\n    /// Common base class for all events in the game.\n    /// </summary>\n    public abstract record Event();\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Events/MatchCompleted.cs",
    "content": "﻿namespace Game.Events\n{\n    /// <summary>\n    /// Indicates that the fight has completed.\n    /// </summary>\n    public sealed record MatchCompleted(ActionResult Result, bool ExtremeBravery, Reward Reward) : Event;\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Events/MatchStarted.cs",
    "content": "﻿namespace Game.Events\n{\n    /// <summary>\n    /// Indicates that a new match has started.\n    /// </summary>\n    public sealed record MatchStarted(\n        Quality BullQuality,\n        Quality ToreadorePerformance,\n        Quality PicadorePerformance,\n        int ToreadoresKilled,\n        int PicadoresKilled,\n        int HorsesKilled) : Event;\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Events/PlayerGored.cs",
    "content": "﻿namespace Game.Events\n{\n    /// <summary>\n    /// Indicates that the player has been gored by the bull.\n    /// </summary>\n    public sealed record PlayerGored(bool Panicked, bool FirstGoring) : Event;\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Events/PlayerSurvived.cs",
    "content": "﻿namespace Game.Events\n{\n    /// <summary>\n    /// Indicates that the player has survived being gored by the bull.\n    /// </summary>\n    public sealed record PlayerSurvived() : Event;\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Mediator.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace Game\n{\n    /// <summary>\n    /// Facilitates sending messages between the two game loops.\n    /// </summary>\n    /// <remarks>\n    /// This class serves as a little piece of glue in between the main program\n    /// loop and the bull fight coroutine.  When the main program calls one of\n    /// its methods, the mediator creates the appropriate input data that the\n    /// bull fight coroutine later retrieves with <see cref=\"GetInput{T}\"/>.\n    /// </remarks>\n    public class Mediator\n    {\n        private object? m_input;\n\n        public void Dodge(RiskLevel riskLevel) =>\n            m_input = (Action.Dodge, riskLevel);\n\n        public void Kill(RiskLevel riskLevel) =>\n            m_input = (Action.Kill, riskLevel);\n\n        public void Panic() =>\n            m_input = (Action.Panic, default(RiskLevel));\n\n        public void RunFromRing() =>\n            m_input = true;\n\n        public void ContinueFighting() =>\n            m_input = false;\n\n        /// <summary>\n        /// Gets the next input from the user.\n        /// </summary>\n        /// <typeparam name=\"T\">\n        /// The type of input to receive.\n        /// </typeparam>\n        public T GetInput<T>()\n        {\n            Debug.Assert(m_input is not null, \"No input received\");\n            Debug.Assert(m_input.GetType() == typeof(T), \"Invalid input received\");\n            var result = (T)m_input;\n            m_input = null;\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Program.cs",
    "content": "﻿namespace Game\n{\n    class Program\n    {\n        static void Main()\n        {\n            Controller.StartGame();\n\n            var mediator = new Mediator();\n            foreach (var evt in BullFight.Begin(mediator))\n            {\n                switch (evt)\n                {\n                    case Events.MatchStarted matchStarted:\n                        View.ShowStartingConditions(matchStarted);\n                        break;\n\n                    case Events.BullCharging bullCharging:\n                        View.ShowStartOfPass(bullCharging.PassNumber);\n                        var (action, riskLevel) = Controller.GetPlayerIntention(bullCharging.PassNumber);\n                        switch (action)\n                        {\n                            case Action.Dodge:\n                                mediator.Dodge(riskLevel);\n                                break;\n                            case Action.Kill:\n                                mediator.Kill(riskLevel);\n                                break;\n                            case Action.Panic:\n                                mediator.Panic();\n                                break;\n                        }\n                        break;\n\n                    case Events.PlayerGored playerGored:\n                        View.ShowPlayerGored(playerGored.Panicked, playerGored.FirstGoring);\n                        break;\n\n                    case Events.PlayerSurvived:\n                        View.ShowPlayerSurvives();\n                        if (Controller.GetPlayerRunsFromRing())\n                            mediator.RunFromRing();\n                        else\n                            mediator.ContinueFighting();\n                        break;\n\n                    case Events.MatchCompleted matchCompleted:\n                        View.ShowFinalResult(matchCompleted.Result, matchCompleted.ExtremeBravery, matchCompleted.Reward);\n                        break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/Quality.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different levels of quality in the game.\n    /// </summary>\n    /// <remarks>\n    /// Quality applies both to the bull and to the help received from the\n    /// toreadores and picadores.  Note that the ordinal values are significant\n    /// (these are used in various calculations).\n    /// </remarks>\n    public enum Quality\n    {\n        Superb  = 1,\n        Good    = 2,\n        Fair    = 3,\n        Poor    = 4,\n        Awful   = 5\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "17_Bullfight/csharp/Reward.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different things the player can be awarded.\n    /// </summary>\n    public enum Reward\n    {\n        Nothing,\n        OneEar,\n        TwoEars,\n        CarriedFromRing\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/RiskLevel.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different levels of risk for manoeuvres in the game.\n    /// </summary>\n    public enum RiskLevel\n    {\n        Low,\n        Medium,\n        High\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/csharp/View.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for displaying information to the user.\n    /// </summary>\n    public static class View\n    {\n        private static readonly string[] QualityString = { \"SUPERB\", \"GOOD\", \"FAIR\", \"POOR\", \"AWFUL\" };\n\n        public static void ShowBanner()\n        {\n            Console.WriteLine(\"                                  BULL\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void ShowInstructions()\n        {\n            Console.WriteLine(\"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\");\n            Console.WriteLine(\"HERE IS YOUR BIG CHANCE TO KILL A BULL.\");\n            Console.WriteLine();\n            Console.WriteLine(\"ON EACH PASS OF THE BULL, YOU MAY TRY\");\n            Console.WriteLine(\"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\");\n            Console.WriteLine(\"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\");\n            Console.WriteLine(\"2 - ORDINARY SWIRL OF THE CAPE.\");\n            Console.WriteLine();\n            Console.WriteLine(\"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\");\n            Console.WriteLine(\"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\");\n            Console.WriteLine(\"BUT IF I WERE YOU,\");\n            Console.WriteLine(\"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\");\n            Console.WriteLine();\n            Console.WriteLine(\"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\");\n            Console.WriteLine(\"(POSTHUMOUSLY IF NECESSARY).\");\n            Console.WriteLine(\"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\");\n            Console.WriteLine();\n            Console.WriteLine(\"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\");\n            Console.WriteLine(\"THE BETTER YOUR CHANCES ARE.\");\n        }\n\n        public static void ShowSeparator()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void ShowStartingConditions(Events.MatchStarted matchStarted)\n        {\n            ShowBullQuality();\n            ShowHelpQuality(\"TOREADORES\", matchStarted.ToreadorePerformance, matchStarted.ToreadoresKilled, 0);\n            ShowHelpQuality(\"PICADORES\", matchStarted.PicadorePerformance, matchStarted.PicadoresKilled, matchStarted.HorsesKilled);\n\n            void ShowBullQuality()\n            {\n                Console.WriteLine($\"YOU HAVE DRAWN A {QualityString[(int)matchStarted.BullQuality - 1]} BULL.\");\n\n                if (matchStarted.BullQuality > Quality.Poor)\n                {\n                    Console.WriteLine(\"YOU'RE LUCKY\");\n                }\n                else\n                if (matchStarted.BullQuality < Quality.Good)\n                {\n                    Console.WriteLine(\"GOOD LUCK.  YOU'LL NEED IT.\");\n                    Console.WriteLine();\n                }\n\n                Console.WriteLine();\n            }\n\n            static void ShowHelpQuality(string helperName, Quality helpQuality, int helpersKilled, int horsesKilled)\n            {\n                Console.WriteLine($\"THE {helperName} DID A {QualityString[(int)helpQuality - 1]} JOB.\");\n\n                // NOTE: The code below makes some *strong* assumptions about\n                //  how the casualty numbers were generated.  It is written\n                //  this way to preserve the behaviour of the original BASIC\n                //  version, but it would make more sense ignore the helpQuality\n                //  parameter and just use the provided numbers to decide what\n                //  to display.\n                switch (helpQuality)\n                {\n                    case Quality.Poor:\n                        if (horsesKilled > 0)\n                            Console.WriteLine($\"ONE OF THE HORSES OF THE {helperName} WAS KILLED.\");\n\n                        if (helpersKilled > 0)\n                            Console.WriteLine($\"ONE OF THE {helperName} WAS KILLED.\");\n                        else\n                            Console.WriteLine($\"NO {helperName} WERE KILLED.\");\n                        break;\n\n                    case Quality.Awful:\n                        if (horsesKilled > 0)\n                            Console.WriteLine($\" {horsesKilled} OF THE HORSES OF THE {helperName} KILLED.\");\n\n                        Console.WriteLine($\" {helpersKilled} OF THE {helperName} KILLED.\");\n                        break;\n                }\n            }\n        }\n\n        public static void ShowStartOfPass(int passNumber)\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine($\"PASS NUMBER {passNumber}\");\n        }\n\n        public static void ShowPlayerGored(bool playerPanicked, bool firstGoring)\n        {\n            Console.WriteLine((playerPanicked, firstGoring) switch\n            {\n                (true,  true) => \"YOU PANICKED.  THE BULL GORED YOU.\",\n                (false, true) => \"THE BULL HAS GORED YOU!\",\n                (_, false)    => \"YOU ARE GORED AGAIN!\"\n            });\n        }\n\n        public static void ShowPlayerSurvives()\n        {\n            Console.WriteLine(\"YOU ARE STILL ALIVE.\");\n            Console.WriteLine();\n        }\n\n        public static void ShowPlayerFoolhardy()\n        {\n            Console.WriteLine(\"YOU ARE BRAVE.  STUPID, BUT BRAVE.\");\n        }\n\n        public static void ShowFinalResult(ActionResult result, bool extremeBravery, Reward reward)\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n\n            switch (result)\n            {\n                case ActionResult.PlayerFlees:\n                    Console.WriteLine(\"COWARD\");\n                    break;\n                case ActionResult.BullKillsPlayer:\n                    Console.WriteLine(\"YOU ARE DEAD.\");\n                    break;\n                case ActionResult.PlayerKillsBull:\n                    Console.WriteLine(\"YOU KILLED THE BULL!\");\n                    break;\n            }\n\n            if (result == ActionResult.PlayerFlees)\n            {\n                Console.WriteLine(\"THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\");\n                Console.WriteLine(\"YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\");\n                Console.WriteLine(\"UNLESS THE BULL DOES FIRST.\");\n            }\n            else\n            {\n                if (extremeBravery)\n                    Console.WriteLine(\"THE CROWD CHEERS WILDLY!\");\n                else\n                if (result == ActionResult.PlayerKillsBull)\n                {\n                    Console.WriteLine(\"THE CROWD CHEERS!\");\n                    Console.WriteLine();\n                }\n\n                Console.WriteLine(\"THE CROWD AWARDS YOU\");\n                switch (reward)\n                {\n                    case Reward.Nothing:\n                        Console.WriteLine(\"NOTHING AT ALL.\");\n                        break;\n                    case Reward.OneEar:\n                        Console.WriteLine(\"ONE EAR OF THE BULL.\");\n                        break;\n                    case Reward.TwoEars:\n                        Console.WriteLine(\"BOTH EARS OF THE BULL!\");\n                        Console.WriteLine(\"OLE!\");\n                        break;\n                    default:\n                        Console.WriteLine(\"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\");\n                        break;\n                }\n            }\n\n            Console.WriteLine();\n            Console.WriteLine(\"ADIOS\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void PromptShowInstructions()\n        {\n            Console.Write(\"DO YOU WANT INSTRUCTIONS? \");\n        }\n\n        public static void PromptKillBull()\n        {\n            Console.WriteLine(\"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\");\n            Console.Write(\"DO YOU WANT TO KILL THE BULL? \");\n        }\n\n        public static void PromptKillBullBrief()\n        {\n            Console.Write(\"HERE COMES THE BULL.  TRY FOR A KILL? \");\n        }\n\n        public static void PromptKillMethod()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"IT IS THE MOMENT OF TRUTH.\");\n            Console.WriteLine();\n\n            Console.Write(\"HOW DO YOU TRY TO KILL THE BULL? \");\n        }\n\n        public static void PromptCapeMove()\n        {\n            Console.Write(\"WHAT MOVE DO YOU MAKE WITH THE CAPE? \");\n        }\n\n        public static void PromptCapeMoveBrief()\n        {\n            Console.Write(\"CAPE MOVE? \");\n        }\n\n        public static void PromptDontPanic()\n        {\n            Console.WriteLine(\"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\");\n            Console.Write(\"? \");\n        }\n\n        public static void PromptRunFromRing()\n        {\n            Console.Write(\"DO YOU RUN FROM THE RING? \");\n        }\n    }\n}\n"
  },
  {
    "path": "17_Bullfight/java/Bullfight.java",
    "content": "import java.util.Random;\nimport java.util.Scanner;\n\n/**\n * BULLFIGHT\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class Bullfight {\n\n    private static final int MAX_PASSES_BEFORE_CHARGE = 3;\n\n    public static void main(String[] args) {\n        printHeader();\n\n        Scanner scanner = new Scanner(System.in);\n        System.out.print(\"\\n\\n\");\n\n        var instructionsChoice = readInstructionsChoice(scanner);\n        if (instructionsChoice) {\n            printInstructions();\n        }\n\n        Random random = new Random();\n\n        //initialize the game with default values\n        GameState gameState = new GameState();\n\n        //Randomly select a bull grade\n        int randomGrade = (int) (random.nextFloat() * BullGrade.values().length + 1);\n        var bullGrade = BullGrade.fromValue(randomGrade);\n\n        printBullGradeInfo(bullGrade);\n\n        System.out.println();\n\n        //D[1] in the original\n        gameState.picadoresDamage = firstStage(\"PICADO\", \"RES\", bullGrade, random);\n\n        //D[2] in the original\n        gameState.toreadoresDamage = firstStage(\"TOREAD\", \"ORES\", bullGrade, random);\n\n        boolean done = false; //controls the main game loop\n\n        while (!done) {\n\n            gameState.passNumber++;\n            System.out.printf(\"\\n\\nPASS NUMBER %d \\n\", gameState.passNumber);\n\n            if (gameState.passNumber < MAX_PASSES_BEFORE_CHARGE) {\n                System.out.println(\"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\");\n                System.out.print(\"DO YOU WANT TO KILL THE BULL? \");\n            } else {\n                System.out.print(\"HERE COMES THE BULL.  TRY FOR A KILL? \");\n            }\n\n            BooleanAnswer yesOrNo = readYesOrNo(scanner);\n            if (yesOrNo.equals(BooleanAnswer.YES)) {\n                gameState = attemptKillBull(bullGrade, random, gameState, scanner);\n                done = true;\n            } else {\n                int capeMove;\n                if (gameState.passNumber < MAX_PASSES_BEFORE_CHARGE) {\n                    capeMove = readCapeMove(\"WHAT MOVE DO YOU MAKE WITH THE CAPE\", scanner);\n                } else {\n                    capeMove = readCapeMove(\"CAPE MOVE\", scanner);\n                }\n\n                //handle cape move\n                gameState = handleCapeMove(capeMove, random, scanner, bullGrade, gameState);\n\n                if (gameState.matadorStatus.equals(MatadorStatus.DEFEATED) || gameState.matadorStatus.equals(MatadorStatus.DEAD)) {\n                    done = true;\n                }\n            }\n\n        }\n\n        crowdReaction(gameState, bullGrade, random);\n\n        System.out.println(\"\\nADIOS\\n\\n\");\n    }\n\n    private static void printBullGradeInfo(BullGrade bullGrade) {\n        System.out.println(\"\\n\\nYOU HAVE DRAWN A \" + bullGrade.name() + \" BULL.\");\n        if (bullGrade.equals(BullGrade.AWFUL)) {\n            System.out.println(\"YOU'RE LUCKY.\");\n        } else if (bullGrade.equals(BullGrade.SUPERB)) {\n            System.out.println(\"GOOD LUCK.  YOU'LL NEED IT.\");\n        }\n    }\n\n    private static void crowdReaction(GameState gameState, BullGrade bullGrade, Random random) {\n        System.out.println(\"\\n\\n\");\n        if (!gameState.matadorStatus.equals(MatadorStatus.DEFEATED)) {\n            if (!gameState.matadorStatus.equals(MatadorStatus.INJURED)) {\n                if (gameState.bullStatus.equals(BullStatus.DEAD)) {\n                    System.out.println(\"THE CROWD CHEERS!\");\n                }\n            } else {\n                System.out.println(\"THE CROWD CHEERS WILDLY!\");\n            }\n\n            System.out.println(\"\\nTHE CROWD AWARDS YOU\");\n            var crowdReactionScore = calculateCrowdReactionScore(gameState, bullGrade, random);\n            if (crowdReactionScore < 2.4) {\n                System.out.println(\"NOTHING AT ALL.\");\n            } else if (crowdReactionScore < 4.9) {\n                System.out.println(\"ONE EAR OF THE BULL.\");\n            } else if (crowdReactionScore < 7.4) {\n                System.out.println(\"BOTH EARS OF THE BULL!\");\n                System.out.println(\"OLE!\");\n            } else {\n                System.out.println(\"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\");\n            }\n\n        } else {\n            System.out.println(\"THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\");\n            System.out.println(\"YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\");\n            System.out.println(\"UNLESS THE BULL DOES FIRST.\");\n        }\n    }\n\n    private static GameState handleCapeMove(int capeMove, Random random, Scanner scanner, BullGrade bullGrade, GameState gameState) {\n        double m;\n        if (capeMove == 0) {\n            m = 3;\n        } else if (capeMove == 1) {\n            m = 2;\n        } else {\n            //capeMove == 2\n            m = 0.5;\n        }\n        gameState.capeMovesCumulative += m;\n\n        double f = (6 - bullGrade.getValue() + m / 10) * random.nextFloat() / ((gameState.picadoresDamage + gameState.toreadoresDamage + gameState.passNumber / 10d) * 5);\n        if (f >= 0.51) {\n            System.out.println(\"THE BULL HAS GORED YOU!\");\n            gameState = stateAfterGoring(random, scanner, gameState, bullGrade);\n        }\n        return gameState;\n    }\n\n    private static GameState stateAfterGoring(Random random, Scanner scanner, GameState gameState, BullGrade bullGrade) {\n        GameState newGameState = gameState.newCopy();\n        if (random.nextBoolean()) {\n            System.out.println(\"YOU ARE DEAD.\");\n            newGameState.matadorStatus = MatadorStatus.DEAD;\n        } else {\n            System.out.println(\"YOU ARE STILL ALIVE.\");\n            newGameState = readAndHandleForfeitDecision(random, scanner, newGameState, bullGrade);\n        }\n        return newGameState;\n    }\n\n    /**\n     * Calculate the crowd's reaction score based on the game state plus some randomness.\n     * (FNC in the original code on line 1390)\n     */\n    private static double calculateCrowdReactionScore(GameState gameState, BullGrade bullGrade, Random random) {\n        return calculateGameScore(gameState, bullGrade) * random.nextFloat();\n    }\n\n    /**\n     * Calculates the ame score based on the current state and the selected bull grade.\n     * (FND in the original code on line 1395)\n     */\n    private static double calculateGameScore(GameState gameState, BullGrade bullGrade) {\n        return (4.5 + gameState.capeMovesCumulative / 6 - (gameState.picadoresDamage + gameState.toreadoresDamage) * 2.5 + 4 * gameState.matadorStatus.getValue() + 2 * gameState.bullStatus.getValue() - Math.pow(gameState.passNumber, 2) / 120f - bullGrade.getValue());\n    }\n\n    private static int readInt(String prompt, Scanner scanner) {\n        System.out.print(prompt);\n        while (true) {\n            System.out.print(\"? \");\n            String input = scanner.nextLine();\n            try {\n                return Integer.parseInt(input);\n            } catch (NumberFormatException e) {\n                System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n            }\n        }\n    }\n\n    private static int readCapeMove(String initialPrompt, Scanner scanner) {\n        String prompt = initialPrompt;\n        while (true) {\n            int capeMove = readInt(prompt, scanner);\n            if (capeMove <= 0 || capeMove > 3) {\n                System.out.println(\"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\");\n                prompt = \"\";\n            } else {\n                return capeMove;\n            }\n        }\n    }\n\n    private static BooleanAnswer readYesOrNo(Scanner scanner) {\n        while (true) {\n            String answer = scanner.nextLine();\n            if (answer.equalsIgnoreCase(\"YES\")) {\n                return BooleanAnswer.YES;\n            } else if (answer.equalsIgnoreCase(\"NO\")) {\n                return BooleanAnswer.NO;\n            } else {\n                System.out.println(\"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\");\n            }\n        }\n    }\n\n    private static void printInstructions() {\n        System.out.print(\"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\\n\");\n        System.out.print(\"HERE IS YOUR BIG CHANCE TO KILL A BULL.\\n\\n\");\n        System.out.print(\"ON EACH PASS OF THE BULL, YOU MAY TRY\\n\");\n        System.out.print(\"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\\n\");\n        System.out.print(\"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\\n\");\n        System.out.print(\"2 - ORDINARY SWIRL OF THE CAPE.\\n\\n\");\n        System.out.print(\"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\\n\");\n        System.out.print(\"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\\n\");\n        System.out.print(\"BUT IF I WERE YOU,\\n\");\n        System.out.print(\"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\\n\\n\");\n        System.out.print(\"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\\n\");\n        System.out.print(\"(POSTHUMOUSLY IF NECESSARY).\\n\");\n        System.out.print(\"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\\n\\n\");\n        System.out.print(\"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\\n\");\n        System.out.print(\"THE BETTER YOUR CHANCES ARE.\\n\\n\");\n    }\n\n    private static void printHeader() {\n        System.out.println(\"                                               BULL\");\n        System.out.println(\"                            CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    }\n\n    /**\n     * Random number 1 or 2\n     * FNA in the original\n     */\n    private static int randomNumber1or2(Random random) {\n        return (int) (random.nextFloat() * 2 + 1);\n    }\n\n    private static double firstStage(String horseType, String suffix, BullGrade bullGrade, Random random) {\n        double b = ((3d / bullGrade.getValue()) * random.nextFloat());\n        double c;\n\n        if (b < 0.37) {\n            c = 0.5;\n        } else if (b < 0.5) {\n            c = 0.4;\n        } else if (b < 0.63) {\n            c = 0.3;\n        } else if (b < 0.87) {\n            c = 0.2;\n        } else {\n            c = 0.1;\n        }\n\n        int t = (int) (10 * c + 0.2);\n\n        System.out.println(\"THE \" + horseType + suffix + \" DID A \" + getPerformanceRating(t) + \" JOB.\");\n\n        if (t >= 4) {\n            if (t == 5) {\n                if (!horseType.equals(\"TOREAD\")) {\n                    System.out.println(\" \" + randomNumber1or2(random) + \" OF THE HORSES OF THE \" + horseType + suffix + \" KILLED.\");\n                }\n                System.out.println(\" \" + randomNumber1or2(random) + \" OF THE \" + horseType + suffix + \" KILLED.\");\n\n            } else {\n                if (random.nextBoolean()) {\n                    System.out.println(\"ONE OF THE \" + horseType + \" \" + suffix + \" WAS KILLED.\");\n                } else {\n                    System.out.println(\"NO \" + horseType + \" \" + suffix + \" WERE KILLED.\");\n                }\n            }\n        }\n\n        System.out.println();\n        return c;\n    }\n\n    public static String getPerformanceRating(int t) {\n        switch (t) {\n            case 1:\n                return \"SUPERB\";\n            case 2:\n                return \"GOOD\";\n            case 3:\n                return \"FAIR\";\n            case 4:\n                return \"POOR\";\n            default:\n                return \"AWFUL\";\n        }\n    }\n\n    private static GameState attemptKillBull(BullGrade bullGrade, Random random, GameState gameState, Scanner scanner) {\n        GameState newGameState = gameState.newCopy();\n        System.out.println(\"\\nIT IS THE MOMENT OF TRUTH.\\n\");\n\n        int h = readInt(\"HOW DO YOU TRY TO KILL THE BULL\", scanner);\n        if (h == 4 || h == 5) {\n            var K = (6 - bullGrade.getValue()) * 10 * random.nextFloat() / ((gameState.picadoresDamage + gameState.toreadoresDamage) * 5 * gameState.passNumber);\n            if (h == 4) {\n                if (K > 0.8) {\n                    System.out.println(\"THE BULL HAS GORED YOU!\");\n                    newGameState = stateAfterGoring(random, scanner, newGameState, bullGrade);\n                } else {\n                    System.out.println(\"YOU KILLED THE BULL!\");\n                    newGameState.bullStatus = BullStatus.DEAD;\n                    return newGameState;//game over\n                }\n            } else {\n                if (K > 0.2) {\n                    System.out.println(\"THE BULL HAS GORED YOU!\");\n                    newGameState = stateAfterGoring(random, scanner, newGameState, bullGrade);\n                } else {\n                    System.out.println(\"YOU KILLED THE BULL!\");\n                    newGameState.bullStatus = BullStatus.DEAD;\n                    return newGameState;//game over\n                }\n            }\n\n        } else {\n            System.out.println(\"YOU PANICKED.  THE BULL GORED YOU.\");\n            if (random.nextBoolean()) {\n                System.out.println(\"YOU ARE DEAD.\");\n                newGameState.matadorStatus = MatadorStatus.DEAD;\n                return newGameState;\n            } else {\n                return readAndHandleForfeitDecision(random, scanner, newGameState, bullGrade);\n            }\n\n        }\n\n        return newGameState;\n    }\n\n    private static GameState readAndHandleForfeitDecision(Random random, Scanner scanner, GameState gameState, BullGrade bullGrade) {\n        GameState newGameState = gameState.newCopy();\n\n        System.out.print(\"\\nDO YOU RUN FROM THE RING? \");\n        BooleanAnswer yesOrNo = readYesOrNo(scanner);\n        if (yesOrNo == BooleanAnswer.NO) {\n            System.out.println(\"\\n\\nYOU ARE BRAVE.  STUPID, BUT BRAVE.\");\n            if (random.nextBoolean()) {\n                newGameState.matadorStatus = MatadorStatus.INJURED;\n                return newGameState;\n            } else {\n                System.out.println(\"YOU ARE GORED AGAIN!\");\n                return stateAfterGoring(random, scanner, newGameState, bullGrade);\n            }\n        } else {\n            System.out.println(\"COWARD\");\n            newGameState.matadorStatus = MatadorStatus.DEFEATED;\n            return newGameState;\n\n        }\n    }\n\n    private static boolean readInstructionsChoice(Scanner scan) {\n        System.out.print(\"DO YOU WANT INSTRUCTIONS? \");\n\n        String choice = scan.nextLine();\n        return !choice.equalsIgnoreCase(\"NO\");\n    }\n\n\n    private enum BooleanAnswer {\n        YES, NO\n    }\n\n    private enum BullGrade {\n        SUPERB(1),\n        GOOD(2),\n        FAIR(3),\n        POOR(4),\n        AWFUL(5);\n\n        private final int value;\n\n        BullGrade(int value) {\n            this.value = value;\n        }\n\n        public int getValue() {\n            return value;\n        }\n\n        public static BullGrade fromValue(int value) {\n            for (BullGrade grade : BullGrade.values()) {\n                if (grade.getValue() == value) {\n                    return grade;\n                }\n            }\n            throw new IllegalArgumentException(\"Invalid value: \" + value);\n        }\n\n    }\n\n    /**\n     * Represents the game state.\n     */\n    private static class GameState {\n        private MatadorStatus matadorStatus; //D[4] in the original\n        private BullStatus bullStatus; //D[5] in the original\n        private double picadoresDamage; //D[1] in the original\n        private double toreadoresDamage; //D[2] in the original\n        private int passNumber; //D[3] in the original\n        private double capeMovesCumulative; //L in the original\n\n        public GameState() {\n            picadoresDamage = 0;\n            toreadoresDamage = 0;\n            passNumber = 0;\n            matadorStatus = MatadorStatus.ALIVE;\n            bullStatus = BullStatus.ALIVE;\n            capeMovesCumulative = 1;\n        }\n\n        public GameState newCopy() {\n            GameState newState = new GameState();\n            newState.matadorStatus = this.matadorStatus;\n            newState.bullStatus = this.bullStatus;\n            newState.picadoresDamage = this.picadoresDamage;\n            newState.toreadoresDamage = this.toreadoresDamage;\n            newState.passNumber = this.passNumber;\n            newState.capeMovesCumulative = this.capeMovesCumulative;\n            return newState;\n        }\n    }\n\n    private enum MatadorStatus {\n        ALIVE(1),\n        INJURED(2),\n        DEAD(1.5),\n        DEFEATED(0);\n\n        private final double value;\n\n        MatadorStatus(double value) {\n            this.value = value;\n        }\n\n        public double getValue() {\n            return value;\n        }\n    }\n\n    private enum BullStatus {\n        ALIVE(1),\n        DEAD(2);\n\n        private final double value;\n\n        BullStatus(double value) {\n            this.value = value;\n        }\n\n        public double getValue() {\n            return value;\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "17_Bullfight/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "17_Bullfight/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "17_Bullfight/javascript/bullfight.html",
    "content": "<html>\n<head>\n<title>BULLFIGHT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bullfight.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "17_Bullfight/javascript/bullfight.js",
    "content": "// BULLFIGHT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a;\nvar b;\nvar c;\nvar l;\nvar t;\nvar as;\nvar bs;\nvar d = [];\nvar ls = [, \"SUPERB\", \"GOOD\", \"FAIR\", \"POOR\", \"AWFUL\"];\n\nfunction af(k)\n{\n    return Math.floor(Math.random() * 2 + 1);\n}\n\nfunction cf(q)\n{\n    return df(q) * Math.random();\n}\n\nfunction df(q)\n{\n    return (4.5 + l / 6 - (d[1] + d[2]) * 2.5 + 4 * d[4] + 2 * d[5] - Math.pow(d[3], 2) / 120 - a);\n}\n\nfunction setup_helpers()\n{\n    b = 3 / a * Math.random();\n    if (b < 0.37)\n        c = 0.5;\n    else if (b < 0.5)\n        c = 0.4;\n    else if (b < 0.63)\n        c = 0.3;\n    else if (b < 0.87)\n        c = 0.2;\n    else\n        c = 0.1;\n    t = Math.floor(10 * c + 0.2);\n    print(\"THE \" + as + bs + \" DID A \" + ls[t] + \" JOB.\\n\");\n    if (4 <= t) {\n        if (5 != t) {\n            // Lines 1800 and 1810 of original program are unreachable\n            switch (af(0)) {\n                case 1:\n                    print(\"ONE OF THE \" + as + bs + \" WAS KILLED.\\n\");\n                    break;\n                case 2:\n                    print(\"NO \" + as + b + \" WERE KILLED.\\n\");\n                    break;\n            }\n        } else {\n            if (as != \"TOREAD\")\n                print(af(0) + \" OF THE HORSES OF THE \" + as + bs + \" KILLED.\\n\");\n            print(af(0) + \" OF THE \" + as + bs + \" KILLED.\\n\");\n        }\n    }\n    print(\"\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"BULL\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    l = 1;\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    str = await input();\n    if (str != \"NO\") {\n        print(\"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\\n\");\n        print(\"HERE IS YOUR BIG CHANCE TO KILL A BULL.\\n\");\n        print(\"\\n\");\n        print(\"ON EACH PASS OF THE BULL, YOU MAY TRY\\n\");\n        print(\"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\\n\");\n        print(\"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\\n\");\n        print(\"2 - ORDINARY SWIRL OF THE CAPE.\\n\");\n        print(\"\\n\");\n        print(\"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\\n\");\n        print(\"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\\n\");\n        print(\"BUT IF I WERE YOU,\\n\");\n        print(\"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\\n\");\n        print(\"\\n\");\n        print(\"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\\n\");\n        print(\"(POSTHUMOUSLY IF NECESSARY).\\n\");\n        print(\"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\\n\");\n        print(\"\\n\");\n        print(\"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\\n\");\n        print(\"THE BETTER YOUR CHANCES ARE.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    d[5] = 1;\n    d[4] = 1;\n    d[3] = 0;\n    a = Math.floor(Math.random() * 5 + 1);\n    print(\"YOU HAVE DRAWN A \" + ls[a] + \" BULL.\\n\");\n    if (a > 4) {\n        print(\"YOU'RE LUCKY.\\n\");\n    } else if (a < 2) {\n        print(\"GOOD LUCK.  YOU'LL NEED IT.\\n\");\n        print(\"\\n\");\n    }\n    print(\"\\n\");\n    as = \"PICADO\";\n    bs = \"RES\";\n    setup_helpers();\n    d[1] = c;\n    as = \"TOREAD\";\n    bs = \"ORES\";\n    setup_helpers();\n    d[2] = c;\n    print(\"\\n\");\n    print(\"\\n\");\n    z = 0;\n    while (z == 0) {\n        d[3]++;\n        print(\"PASS NUMBER \" + d[3] + \"\\n\");\n        if (d[3] >= 3) {\n            print(\"HERE COMES THE BULL.  TRY FOR A KILL\");\n            while (1) {\n                str = await input();\n                if (str != \"YES\" && str != \"NO\")\n                    print(\"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\\n\");\n                else\n                    break;\n            }\n            z1 = (str == \"YES\") ? 1 : 2;\n            if (z1 != 1) {\n                print(\"CAPE MOVE\");\n            }\n        } else {\n            print(\"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\\n\");\n            print(\"DO YOU WANT TO KILL THE BULL\");\n            while (1) {\n                str = await input();\n                if (str != \"YES\" && str != \"NO\")\n                    print(\"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\\n\");\n                else\n                    break;\n            }\n            z1 = (str == \"YES\") ? 1 : 2;\n            if (z1 != 1) {\n                print(\"WHAT MOVE DO YOU MAKE WITH THE CAPE\");\n            }\n        }\n        gore = 0;\n        if (z1 != 1) {\n            while (1) {\n                e = parseInt(await input());\n                if (e >= 3) {\n                    print(\"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\\n\");\n                } else {\n                    break;\n                }\n            }\n            if (e == 0)\n                m = 3;\n            else if (e == 1)\n                m = 2;\n            else\n                m = 0.5;\n            l += m;\n            f = (6 - a + m / 10) * Math.random() / ((d[1] + d[2] + d[3] / 10) * 5);\n            if (f < 0.51)\n                continue;\n            gore = 1;\n        } else {\n            z = 1;\n            print(\"\\n\");\n            print(\"IT IS THE MOMENT OF THE TRUTH.\\n\");\n            print(\"\\n\");\n            print(\"HOW DO YOU TRY TO KILL THE BULL\");\n            h = parseInt(await input());\n            if (h != 4 && h != 5) {\n                print(\"YOU PANICKED.  THE BULL GORED YOU.\\n\");\n                gore = 2;\n            } else {\n                k = (6 - a) * 10 * Math.random() / ((d[1] + d[2]) * 5 * d[3]);\n                if (h != 4) {   // Bug in original game, it says J instead of H\n                    if (k > 0.2)\n                        gore = 1;\n                } else {\n                    if (k > 0.8)\n                        gore = 1;\n                }\n                if (gore == 0) {\n                    print(\"YOU KILLED THE BULL!\\n\");\n                    d[5] = 2;\n                    break;\n                }\n            }\n        }\n        if (gore) {\n            if (gore == 1)\n                print(\"THE BULL HAS GORED YOU!\\n\");\n            kill = false;\n            while (1) {\n                if (af(0) == 1) {\n                    print(\"YOU ARE DEAD.\\n\");\n                    d[4] = 1.5;\n                    kill = true;\n                    break;\n                }\n                print(\"YOU ARE STILL ALIVE.\\n\");\n                print(\"\\n\");\n                print(\"DO YOU RUN FROM THE RING\");\n                while (1) {\n                    str = await input();\n                    if (str != \"YES\" && str != \"NO\")\n                        print(\"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\\n\");\n                    else\n                        break;\n                }\n                z1 = (str == \"YES\") ? 1 : 2;\n                if (z1 != 2) {\n                    print(\"COWARD\\n\");\n                    d[4] = 0;\n                    kill = true;\n                    break;\n                }\n                print(\"YOU ARE BRAVE.  STUPID, BUT BRAVE.\\n\");\n                if (af(0) == 1) {\n                    d[4] = 2;\n                    kill = false;\n                    break;\n                }\n                print(\"YOU ARE GORED AGAIN!\\n\");\n            }\n            if (kill)\n                break;\n            continue;\n        }\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    if (d[4] == 0) {\n        print(\"THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\\n\");\n        print(\"YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\\n\");\n        print(\"UNLESS THE BULL DOES FIRST.\\n\");\n    } else {\n        if (d[4] == 2) {\n            print(\"THE CROWD CHEERS WILDLY!\\n\");\n        } else if (d[5] == 2) {\n            print(\"THE CROWD CHEERS!\\n\");\n            print(\"\\n\");\n        }\n        print(\"THE CROWD AWARDS YOU\\n\");\n        if (cf(0) < 2.4) {\n            print(\"NOTHING AT ALL.\\n\");\n        } else if (cf(0) < 4.9) {\n            print(\"ONE EAR OF THE BULL.\\n\");\n        } else if (cf(0) < 7.4) {\n            print(\"BOTH EARS OF THE BULL!\\n\");\n            print(\"OLE!\\n\");\n        } else {\n            print(\"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\\n\");\n        }\n        print(\"\\n\");\n        print(\"ADIOS\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n}\n\n\nmain();\n"
  },
  {
    "path": "17_Bullfight/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "17_Bullfight/kotlin/src/bullfight/Main.kt",
    "content": "package bullfight\n\nimport bullfight.Yorn.*\nimport kotlin.random.Random\nimport kotlin.system.exitProcess\n\nprivate val Boolean.asInteger get() = if (this) 1 else 2\nprivate val Float.squared: Float\n    get() = this * this\nval fna: Boolean get() = RandomNumbers.nextBoolean()\n\nenum class Quality(private val typeName: String) {\n    Superb(\"SUPERB\"),\n    Good(\"GOOD\"),\n    Fair(\"FAIR\"),\n    Poor(\"POOR\"),\n    Awful(\"AWFUL\");\n    override fun toString() = typeName\n\n    val level get() = (ordinal + 1).toFloat()\n}\n\nenum class BullDeath(val factor: Float) {\n    Alive(1f), Dead(2f);\n}\n\nvar l = 1f\nlateinit var bullQuality: Quality\nvar momentOfTruth = false\nvar picadoresSuccess = 0f\nvar toreadoresSuccess = 0f\nvar passNumber = 0f\nvar honor = 0f\nvar bullDeath = BullDeath.Alive\n\n\ninterface RandomNumberSource {\n    fun nextBoolean(): Boolean\n    fun nextInt(from: Int, until: Int): Int\n    fun nextFloat(): Float\n}\n\nobject RandomNumbers : RandomNumberSource {\n    override fun nextBoolean() = Random.nextBoolean()\n    override fun nextInt(from: Int, until: Int) = Random.nextInt(from, until)\n    override fun nextFloat() = Random.nextFloat()\n}\n\n\nfun main() {\n    intro()\n    instructions()\n    bullDeath = BullDeath.Alive\n    honor = 1f\n\n    bullQuality = Quality.values()[RandomNumbers.nextInt(1, 6)]\n    println(\"YOU HAVE DRAWN A $bullQuality BULL.\")\n    when (bullQuality) {\n        Quality.Superb -> println(\"GOOD LUCK.  YOU'LL NEED IT.\")\n        Quality.Awful -> println(\"YOU'RE LUCKY.\")\n        else -> Unit\n    }\n\n    picadoresSuccess = fight(FirstAct.picadores)\n    toreadoresSuccess = fight(FirstAct.toreadores)\n    println()\n    println()\n\n    var gored: Boolean\n\n    gameLoop@ do {\n        passNumber++\n        println(\"PASS NUMBER ${passNumber.toInt()}\")\n        gored = if (passNumber >= 3) {\n            print(\"HERE COMES THE BULL.  TRY FOR A KILL\")\n            killAttempt(\"CAPE MOVE\")\n        } else {\n            println(\"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\")\n            print(\"DO YOU WANT TO KILL THE BULL\")\n            killAttempt(\"WHAT MOVE DO YOU MAKE WITH THE CAPE\")\n        }\n\n        if (!gored) {\n            val move = restrictedInput(\n                values = Cape.values(),\n                errorMessage = \"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\"\n            )\n            val m = when (move) {\n                Cape.Veronica -> 3f\n                Cape.Outside -> 2f\n                Cape.Swirl -> 0.5f\n            }\n\n            l += m\n            val f =\n                (6 - bullQuality.level + m / 10f) * RandomNumbers.nextFloat() / ((picadoresSuccess + toreadoresSuccess + passNumber / 10f) * 5f)\n            if (f < 0.51)\n                continue\n        }\n\n        println(\"THE BULL HAS GORED YOU!\")\n        goreLoop@ do {\n            when (fna) {\n                false -> {\n                    println(\"YOU ARE DEAD.\")\n                    honor = 1.5f\n                    gameResult()\n                }\n\n                true -> {\n                    println(\"YOU ARE STILL ALIVE.\")\n                    println()\n                    print(\"DO YOU RUN FROM THE RING\")\n                    when (Yorn.input()) {\n\n                        YES -> {\n                            println(\"COWARD\")\n                            honor = 0f\n                        }\n\n                        NO -> {\n                            println(\"YOU ARE BRAVE.  STUPID, BUT BRAVE.\")\n                            when (fna) {\n                                true -> {\n                                    honor = 2f\n                                    continue@gameLoop\n                                }\n\n                                false -> {\n                                    println(\"YOU ARE GORED AGAIN!\")\n                                    continue@goreLoop\n                                }\n                            }\n                        }\n                    }\n\n                }\n            }\n        } while (true)\n\n    } while (true)\n\n}\n\nfun fnd() = 4.5 +\n        l / 6 -\n        (picadoresSuccess + toreadoresSuccess) * 2.5 +\n        4 * honor +\n        2 * bullDeath.factor -\n        passNumber.squared / 120f -\n        bullQuality.level\n\nfun fnc() = fnd() * RandomNumbers.nextFloat()\n\nprivate fun killAttempt(capeMessage: String): Boolean {\n    when (Yorn.input()) {\n\n        YES ->\n            when (momentOfTruth()) {\n                KillResult.Success -> gameResult()\n                KillResult.Fail -> return true\n            }\n\n        NO ->\n            print(capeMessage)\n\n    }\n    return false\n}\n\nprivate fun gameResult() {\n    println()\n    println()\n    if (honor == 0f) {\n        println(\n            \"\"\"\n                            THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\n                            YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\n                            UNLESS THE BULL DOES FIRST.\n                            \"\"\".trimIndent()\n        )\n    } else {\n        if (honor == 2f)\n            println(\"THE CROWD CHEERS WILDLY!\")\n        else\n            if (bullDeath == BullDeath.Dead) {\n                println(\"THE CROWD CHEERS!\")\n                println()\n            }\n        println(\"THE CROWD AWARDS YOU\")\n        if (fnc() < 2.4)\n            println(\"NOTHING AT ALL.\")\n        else if (fnc() < 4.9)\n            println(\"ONE EAR OF THE BULL.\")\n        else\n            if (fnc() < 7.4)\n                println(\"BOTH EARS OF THE BULL!\")\n            else\n                println(\"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\")\n        println()\n    }\n    println()\n    println(\"ADIOS\")\n    println()\n    println()\n    println()\n    exitProcess(0)\n}\n\nenum class KillResult { Success, Fail }\n\nfun momentOfTruth(): KillResult {\n    momentOfTruth = true\n    print(\n        \"\"\"\n        \n        IT IS THE MOMENT OF TRUTH.\n        \n        HOW DO YOU WANT TO KILL THE BULL\n    \"\"\".trimIndent()\n    )\n\n    val k =\n        (6 - bullQuality.level) * 10 * RandomNumbers.nextFloat() / ((picadoresSuccess + toreadoresSuccess) * 5 * passNumber)\n\n    val chance = when (stdInput(KillMethod.values())) {\n        KillMethod.OverHorns -> .8\n        KillMethod.Chest -> .2\n        null -> {\n            println(\"YOU PANICKED.  THE BULL GORED YOU.\")\n            return KillResult.Fail\n        }\n    }\n    return if (k <= chance) {\n        println(\"YOU KILLED THE BULL!\")\n        bullDeath = BullDeath.Dead\n        KillResult.Success\n    } else {\n        println(\"THE BULL HAS GORED YOU!\")\n        KillResult.Fail\n    }\n}\n\ninterface InputOption {\n    val input: String\n}\n\nenum class Cape(override val input: String) : InputOption {\n    Veronica(\"0\"),\n    Outside(\"1\"),\n    Swirl(\"2\"),\n}\n\nenum class KillMethod(override val input: String) : InputOption {\n    OverHorns(\"4\"),\n    Chest(\"5\"),\n}\n\nprivate fun <T : InputOption> restrictedInput(values: Array<T>, errorMessage: String): T {\n    do {\n        stdInput(values)?.let { return it }\n        println(errorMessage)\n    } while (true)\n}\n\nprivate fun <T : InputOption> stdInput(values: Array<T>): T? {\n    print(\"? \")\n    val z1 = readln()\n    return values.firstOrNull { z1 == it.input }\n}\n\nenum class Yorn(override val input: String) : InputOption {\n    YES(\"YES\"), NO(\"NO\");\n\n    companion object {\n        fun input(): Yorn {\n            return restrictedInput(values(), \"YES OR NO\")\n        }\n    }\n}\n\nenum class FirstAct(val str: String) {\n    picadores(\"PICADORES\"), toreadores(\"TOREADORES\");\n\n    override fun toString() = str\n}\n\nfun fight(firstAct: FirstAct): Float {\n\n    val b = 3.0 / bullQuality.level * RandomNumbers.nextFloat()\n    val firstActQuality = when {\n        b < .37 -> Quality.Awful\n        b < .5 -> Quality.Poor\n        b < .63 -> Quality.Fair\n        b < .87 -> Quality.Good\n        else -> Quality.Superb\n    }\n    val c = firstActQuality.level / 10f\n    val t = firstActQuality.level\n    println(\"THE $firstAct DID A $firstActQuality JOB.\")\n\n    if (t >= 4f) {\n        if (t == 5f) {\n            if (firstAct != FirstAct.toreadores) {\n                println(\"${fna.asInteger} OF THE HORSES OF THE $firstAct KILLED.\")\n            }\n            println(\"${fna.asInteger} OF THE $firstAct KILLED.\")\n        } else {\n            println(\n                when (fna) {\n                    true -> \"ONE OF THE $firstAct WAS KILLED.\"\n                    false -> \"NO $firstAct WERE KILLED.\"\n                }\n            )\n        }\n    }\n    println()\n\n    return c\n}\n\nprivate fun instructions() {\n    print(\"DO YOU WANT INSTRUCTIONS? \")\n    if (readln().trim() != \"NO\") {\n        println(\"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\")\n        println(\"HERE IS YOUR BIG CHANCE TO KILL A BULL.\")\n        println()\n        println(\"ON EACH PASS OF THE BULL, YOU MAY TRY\")\n        println(\"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\")\n        println(\"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\")\n        println(\"2 - ORDINARY SWIRL OF THE CAPE.\")\n        println()\n        println(\"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\")\n        println(\"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\")\n        println(\"BUT IF I WERE YOU,\")\n        println(\"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\")\n        println()\n        println(\"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\")\n        println(\"(POSTHUMOUSLY IF NECESSARY).\")\n        println(\"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\")\n        println()\n        println(\"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\")\n        println(\"THE BETTER YOUR CHANCES ARE.\")\n    }\n    repeat(2) {\n        println()\n    }\n}\n\nfun intro() {\n    println(\" \".repeat(34) + \"BULL\")\n    println(\" \".repeat(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    println()\n    println()\n    println()\n}\n"
  },
  {
    "path": "17_Bullfight/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "17_Bullfight/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "17_Bullfight/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "17_Bullfight/python/bullfight.py",
    "content": "import math\nimport random\nfrom typing import Dict, List, Literal, Tuple, Union\n\n\ndef print_n_newlines(n: int) -> None:\n    for _ in range(n):\n        print()\n\n\ndef determine_player_kills(\n    bull_quality: int,\n    player_type: Literal[\"TOREAD\", \"PICADO\"],\n    plural_form: Literal[\"ORES\", \"RES\"],\n    job_qualities: List[str],\n) -> float:\n    bull_performance = 3 / bull_quality * random.random()\n    if bull_performance < 0.37:\n        job_quality_factor = 0.5\n    elif bull_performance < 0.5:\n        job_quality_factor = 0.4\n    elif bull_performance < 0.63:\n        job_quality_factor = 0.3\n    elif bull_performance < 0.87:\n        job_quality_factor = 0.2\n    else:\n        job_quality_factor = 0.1\n    job_quality = math.floor(10 * job_quality_factor + 0.2)  # higher is better\n    print(f\"THE {player_type}{plural_form} DID A {job_qualities[job_quality]} JOB.\")\n    if job_quality >= 4:\n        if job_quality == 5:\n            if random.choice([True, False]):\n                print(f\"ONE OF THE {player_type}{plural_form} WAS KILLED.\")\n        else:\n            if player_type != \"TOREAD\":\n                killed_horses = random.randint(1, 2)\n                print(\n                    f\"{killed_horses} OF THE HORSES OF THE {player_type}{plural_form} KILLED.\"\n                )\n            killed_players = random.randint(1, 2)\n            print(f\"{killed_players} OF THE {player_type}{plural_form} KILLED.\")\n    print()\n    return job_quality_factor\n\n\ndef calculate_final_score(\n    move_risk_sum: float, job_quality_by_round: Dict[int, float], bull_quality: int\n) -> float:\n    quality = (\n        4.5\n        + move_risk_sum / 6\n        - (job_quality_by_round[1] + job_quality_by_round[2]) * 2.5\n        + 4 * job_quality_by_round[4]\n        + 2 * job_quality_by_round[5]\n        - (job_quality_by_round[3] ** 2) / 120\n        - bull_quality\n    ) * random.random()\n    if quality < 2.4:\n        return 0\n    elif quality < 4.9:\n        return 1\n    elif quality < 7.4:\n        return 2\n    else:\n        return 3\n\n\ndef print_header() -> None:\n    print(\" \" * 34 + \"BULL\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print_n_newlines(2)\n\n\ndef print_instructions() -> None:\n    print(\"HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\")\n    print(\"HERE IS YOUR BIG CHANCE TO KILL A BULL.\")\n    print()\n    print(\"ON EACH PASS OF THE BULL, YOU MAY TRY\")\n    print(\"0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\")\n    print(\"1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\")\n    print(\"2 - ORDINARY SWIRL OF THE CAPE.\")\n    print()\n    print(\"INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\")\n    print(\"ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\")\n    print(\"BUT IF I WERE YOU,\")\n    print(\"I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\")\n    print()\n    print(\"THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\")\n    print(\"(POSTHUMOUSLY IF NECESSARY).\")\n    print(\"THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\")\n    print()\n    print(\"THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\")\n    print(\"THE BETTER YOUR CHANCES ARE.\")\n\n\ndef print_intro() -> None:\n    print_header()\n    want_instructions = input(\"DO YOU WANT INSTRUCTIONS? \")\n    if want_instructions != \"NO\":\n        print_instructions()\n    print_n_newlines(2)\n\n\ndef ask_bool(prompt: str) -> bool:\n    while True:\n        answer = input(prompt).lower()\n        if answer == \"yes\":\n            return True\n        elif answer == \"no\":\n            return False\n        else:\n            print(\"INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.\")\n\n\ndef ask_int() -> int:\n    while True:\n        foo = float(input())\n        if foo != float(int(abs(foo))):  # we actually want an integer\n            print(\"DON'T PANIC, YOU IDIOT!  PUT DOWN A CORRECT NUMBER\")\n        elif foo < 3:\n            break\n    return int(foo)\n\n\ndef did_bull_hit(\n    bull_quality: int,\n    cape_move: int,\n    job_quality_by_round: Dict[int, float],\n    move_risk_sum: float,\n) -> Tuple[bool, float]:\n    # The bull quality is a grade: The lower the grade, the better the bull\n    if cape_move == 0:\n        move_risk: Union[int, float] = 3\n    elif cape_move == 1:\n        move_risk = 2\n    else:\n        move_risk = 0.5\n    move_risk_sum += move_risk\n    bull_strength = 6 - bull_quality\n    bull_hit_factor = (  # the higher the factor, the more \"likely\" it hits\n        (bull_strength + move_risk / 10)\n        * random.random()\n        / (\n            (\n                job_quality_by_round[1]\n                + job_quality_by_round[2]\n                + job_quality_by_round[3] / 10\n            )\n            * 5\n        )\n    )\n    bull_hit = bull_hit_factor >= 0.51\n    return bull_hit, move_risk_sum\n\n\ndef handle_bullkill_attempt(\n    kill_method: int,\n    job_quality_by_round: Dict[int, float],\n    bull_quality: int,\n    gore: int,\n) -> int:\n    if kill_method not in [4, 5]:\n        print(\"YOU PANICKED.  THE BULL GORED YOU.\")\n        gore = 2\n    else:\n        bull_strength = 6 - bull_quality\n        kill_probability = (\n            bull_strength\n            * 10\n            * random.random()\n            / (\n                (job_quality_by_round[1] + job_quality_by_round[2])\n                * 5\n                * job_quality_by_round[3]\n            )\n        )\n        if (\n            kill_method == 4\n            and kill_probability > 0.8\n            or kill_method != 4\n            and kill_probability > 0.2\n        ):\n            gore = 1\n        if gore == 0:\n            print(\"YOU KILLED THE BULL!\")\n            job_quality_by_round[5] = 2\n            return gore\n    return gore\n\n\ndef final_message(\n    job_quality_by_round: Dict[int, float], bull_quality: int, move_risk_sum: float\n) -> None:\n    print_n_newlines(3)\n    if job_quality_by_round[4] == 0:\n        print(\"THE CROWD BOOS FOR TEN MINUTES.  IF YOU EVER DARE TO SHOW\")\n        print(\"YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--\")\n        print(\"UNLESS THE BULL DOES FIRST.\")\n    else:\n        if job_quality_by_round[4] == 2:\n            print(\"THE CROWD CHEERS WILDLY!\")\n        elif job_quality_by_round[5] == 2:\n            print(\"THE CROWD CHEERS!\")\n            print()\n        print(\"THE CROWD AWARDS YOU\")\n        score = calculate_final_score(move_risk_sum, job_quality_by_round, bull_quality)\n        if score == 0:\n            print(\"NOTHING AT ALL.\")\n        elif score == 1:\n            print(\"ONE EAR OF THE BULL.\")\n        elif score == 2:\n            print(\"BOTH EARS OF THE BULL!\")\n            print(\"OLE!\")\n        else:\n            print(\"OLE!  YOU ARE 'MUY HOMBRE'!! OLE!  OLE!\")\n        print()\n        print(\"ADIOS\")\n        print_n_newlines(3)\n\n\ndef main() -> None:\n    print_intro()\n    move_risk_sum: float = 1\n    job_quality_by_round: Dict[int, float] = {4: 1, 5: 1}\n    job_quality = [\"\", \"SUPERB\", \"GOOD\", \"FAIR\", \"POOR\", \"AWFUL\"]\n    bull_quality = random.randint(\n        1, 5\n    )  # the lower the number, the more powerful the bull\n    print(f\"YOU HAVE DRAWN A {job_quality[bull_quality]} BULL.\")\n    if bull_quality > 4:\n        print(\"YOU'RE LUCKY.\")\n    elif bull_quality < 2:\n        print(\"GOOD LUCK.  YOU'LL NEED IT.\")\n        print()\n    print()\n\n    # Round 1: Run Picadores\n    player_type: Literal[\"TOREAD\", \"PICADO\"] = \"PICADO\"\n    plural_form: Literal[\"ORES\", \"RES\"] = \"RES\"\n    job_quality_factor = determine_player_kills(\n        bull_quality, player_type, plural_form, job_quality\n    )\n    job_quality_by_round[1] = job_quality_factor\n\n    # Round 2: Run Toreadores\n    player_type = \"TOREAD\"\n    plural_form = \"ORES\"\n    determine_player_kills(bull_quality, player_type, plural_form, job_quality)\n    job_quality_by_round[2] = job_quality_factor\n    print_n_newlines(2)\n\n    # Round 3\n    job_quality_by_round[3] = 0\n    while True:\n        job_quality_by_round[3] += 1\n        print(f\"PASS NUMBER {job_quality_by_round[3]}\")\n        if job_quality_by_round[3] >= 3:\n            run_from_ring = ask_bool(\"HERE COMES THE BULL.  TRY FOR A KILL? \")\n            if not run_from_ring:\n                print(\"CAPE MOVE? \", end=\"\")\n        else:\n            print(\"THE BULL IS CHARGING AT YOU!  YOU ARE THE MATADOR--\")\n            run_from_ring = ask_bool(\"DO YOU WANT TO KILL THE BULL? \")\n            if not run_from_ring:\n                print(\"WHAT MOVE DO YOU MAKE WITH THE CAPE? \", end=\"\")\n        gore = 0\n        if not run_from_ring:\n            cape_move = ask_int()\n            bull_hit, move_risk_sum = did_bull_hit(\n                bull_quality, cape_move, job_quality_by_round, move_risk_sum\n            )\n            if bull_hit:\n                gore = 1\n            else:\n                continue\n        else:\n            print()\n            print(\"IT IS THE MOMENT OF TRUTH.\")\n            print()\n            kill_method = int(input(\"HOW DO YOU TRY TO KILL THE BULL? \"))\n            gore = handle_bullkill_attempt(\n                kill_method, job_quality_by_round, bull_quality, gore\n            )\n            if gore == 0:\n                break\n        if gore > 0:\n            if gore == 1:\n                print(\"THE BULL HAS GORED YOU!\")\n            death = False\n            while True:\n                if random.randint(1, 2) == 1:\n                    print(\"YOU ARE DEAD.\")\n                    job_quality_by_round[4] = 1.5\n                    death = True\n                    break\n                else:\n                    print(\"YOU ARE STILL ALIVE.\")\n                    print()\n                    print(\"DO YOU RUN FROM THE RING? \", end=\"\")\n                    if run_from_ring := ask_bool(\"DO YOU RUN FROM THE RING? \"):\n                        print(\"COWARD\")\n                        job_quality_by_round[4] = 0\n                        death = True\n                        break\n\n                    else:\n                        print(\"YOU ARE BRAVE.  STUPID, BUT BRAVE.\")\n                        if random.randint(1, 2) == 1:\n                            job_quality_by_round[4] = 2\n                            death = True\n                            break\n                        else:\n                            print(\"YOU ARE GORED AGAIN!\")\n            if death:\n                break\n\n    final_message(job_quality_by_round, bull_quality, move_risk_sum)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "17_Bullfight/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "17_Bullfight/vbnet/Bullfight.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bullfight\", \"Bullfight.vbproj\", \"{38805A6B-C251-4C45-9832-B8E2F3F6436F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{38805A6B-C251-4C45-9832-B8E2F3F6436F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{38805A6B-C251-4C45-9832-B8E2F3F6436F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{38805A6B-C251-4C45-9832-B8E2F3F6436F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{38805A6B-C251-4C45-9832-B8E2F3F6436F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "17_Bullfight/vbnet/Bullfight.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bullfight</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "17_Bullfight/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "18_Bullseye/README.md",
    "content": "### Bullseye\n\nIn this game, up to 20 players throw darts at a target with 10-, 20-, 30-, and 40-point zones. The objective is to get 200 points.\n\nYou have a choice of three methods of throwing:\n\n| Throw | Description        | Probable Score            |\n|-------|--------------------|---------------------------|\n| 1     | Fast overarm       | Bullseye or complete miss |\n| 2     | Controlled overarm | 10, 20, or 30 points      |\n| 3     | Underarm           | Anything                  |\n\nYou will find after playing a while that different players will swear by different strategies. However, considering the expected score per throw by always using throw 3:\n\n| Score (S) | Probability (P) | S x P |\n|-----------|-----------------|-------|\n|     40    |  1.00-.95 = .05 |   2   |\n|     30    |  .95-.75 = .20  |   6   |\n|     30    |  .75-.45 = .30  |   6   |\n|     10    |  .45-.05 = .40  |   4   |\n|     0     |  .05-.00 = .05  |   0   |\n\nExpected score per throw = 18\n\nCalculate the expected score for the other throws and you may be surprised!\n\nThe program was written by David Ahl of Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=34)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=49)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n"
  },
  {
    "path": "18_Bullseye/bullseye.bas",
    "content": "5 PRINT TAB(32);\"BULLSEYE\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n20 PRINT:PRINT:PRINT\n30 PRINT \"IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\"\n40 PRINT \"WITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\"\n50 PRINT \"TO GET 200 POINTS.\": PRINT\n60 PRINT \"THROW\",TAB(20);\"DESCRIPTION\";TAB(45);\"PROBABLE SCORE\"\n70 PRINT\" 1\";TAB(20);\"FAST OVERARM\";TAB(45);\"BULLSEYE OR COMPLETE MISS\"\n80 PRINT\" 2\";TAB(20);\"CONTROLLED OVERARM\";TAB(45);\"10, 20 OR 30 POINTS\"\n90 PRINT\" 3\";TAB(20);\"UNDERARM\";TAB(45);\"ANYTHING\":PRINT\n100 DIM A$(20),S(20),W(10): M=0: R=0: FOR I=1 TO 20: S(I)=0: NEXT I\n110 INPUT \"HOW MANY PLAYERS\";N: PRINT\n120 FOR I=1 TO N\n130 PRINT \"NAME OF PLAYER #\";I;:INPUT A$(I)\n140 NEXT I\n150 R=R+1: PRINT: PRINT \"ROUND\";R:PRINT \"---------\"\n160 FOR I=1 TO N\n170 PRINT: PRINT A$(I)\"'S THROW\";: INPUT T\n180 IF T<1 OR T>3 THEN PRINT \"INPUT 1, 2, OR 3!\": GOTO 170\n190 ON T GOTO 200, 210, 200\n200 P1=.65: P2=.55: P3=.5: P4=.5: GOTO 230\n210 P1=.99: P2=.77: P3=.43: P4=.01: GOTO 230\n220 P1=.95: P2=.75: P3=.45: P4=.05\n230 U=RND(1)\n240 IF U>=P1 THEN PRINT \"BULLSEYE!!  40 POINTS!\":B=40: GOTO 290\n250 IF U>=P2 THEN PRINT \"30-POINT ZONE!\":B=30: GOTO 290\n260 IF U>=P3 THEN PRINT \"20-POINT ZONE\":B=20: GOTO 290\n270 IF U>=P4 THEN PRINT \"WHEW!  10 POINTS.\":B=10: GOTO 290\n280 PRINT \"MISSED THE TARGET!  TOO BAD.\": B=0\n290 S(I)=S(I)+B: PRINT \"TOTAL SCORE =\";S(I): NEXT I\n300 FOR I=1 TO N\n310 IF S(I)>=200 THEN M=M+1: W(M)=I\n320 NEXT I\n330 IF M=0 THEN 150\n340 PRINT: PRINT \"WE HAVE A WINNER!!\": PRINT\n350 FOR I=1 TO M: PRINT A$(W(I));\" SCORED\";S(W(I));\"POINTS.\": NEXT I\n360 PRINT: PRINT \"THANKS FOR THE GAME.\": END\n"
  },
  {
    "path": "18_Bullseye/csharp/Bullseye.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "18_Bullseye/csharp/Bullseye.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bullseye\", \"Bullseye.csproj\", \"{04C164DB-594F-41C4-BC0E-0A203A5536C7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "18_Bullseye/csharp/BullseyeGame.cs",
    "content": "namespace Bullseye\n{\n    /// <summary>\n    /// Class encompassing the game\n    /// </summary>\n    public class BullseyeGame\n    {\n        private readonly List<Player> _players;\n\n        // define a constant for the winning score so that it is\n        // easy to change again in the future\n        private const int WinningScore = 200;\n\n        public BullseyeGame()\n        {\n            // create the initial list of players; list is empty, but\n            // the setup of the game will add items to this list\n            _players = new List<Player>();\n        }\n\n        public void Run()\n        {\n            PrintIntroduction();\n\n            SetupGame();\n\n            PlayGame();\n\n            PrintResults();\n        }\n\n        private void SetupGame()\n        {\n            // First, allow the user to enter how many players are going\n            // to play. This could be weird if the user enters negative\n            // numbers, words, or too many players, so there are some\n            // extra checks on the input to make sure the user didn't do\n            // anything too crazy. Loop until the user enters valid input.\n            bool validPlayerCount;\n            int playerCount;\n            do\n            {\n                Console.WriteLine();\n                Console.Write(\"HOW MANY PLAYERS? \");\n                string? input = Console.ReadLine();\n\n                // assume the user has entered something incorrect - the\n                // next steps will validate the input\n                validPlayerCount = false;\n\n                if (Int32.TryParse(input, out playerCount))\n                {\n                    if (playerCount > 0 && playerCount <= 20)\n                    {\n                        validPlayerCount = true;\n                    }\n                    else\n                    {\n                        Console.WriteLine(\"YOU MUST ENTER A NUMBER BETWEEN 1 AND 20!\");\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(\"YOU MUST ENTER A NUMBER\");\n                }\n\n            }\n            while (!validPlayerCount);\n\n            // Next, allow the user to enter names for the players; as each\n            // name is entered, create a Player object to track the name\n            // and their score, and save the object to the list in this class\n            // so the rest of the game has access to the set of players\n            for (int i = 0; i < playerCount; i++)\n            {\n                string? playerName = String.Empty;\n                do\n                {\n                    Console.Write($\"NAME OF PLAYER #{i+1}? \");\n                    playerName = Console.ReadLine();\n\n                    // names can be any sort of text, so allow whatever the user\n                    // enters as long as it isn't a blank space\n                }\n                while (String.IsNullOrWhiteSpace(playerName));\n\n                _players.Add(new Player(playerName));\n            }\n        }\n\n        private void PlayGame()\n        {\n            Random random = new Random(DateTime.Now.Millisecond);\n\n            int round = 0;\n            bool isOver = false;\n            do\n            {\n                // starting a new round, increment the counter\n                round++;\n                Console.WriteLine($\"ROUND {round}\");\n                Console.WriteLine(\"--------------\");\n\n                foreach (Player player in _players)\n                {\n                    // ask the user how they want to throw\n                    Console.Write($\"{player.Name.ToUpper()}'S THROW: \");\n                    string? input = Console.ReadLine();\n\n                    // based on the input, figure out the probabilities\n                    int[] probabilities;\n                    switch (input)\n                    {\n                        case \"1\":\n                        {\n                            probabilities = new int[] { 65, 55, 50, 50 };\n                            break;\n                        }\n                        case \"2\":\n                        {\n                            probabilities = new int[] { 99, 77, 43, 1 };\n                            break;\n                        }\n                        case \"3\":\n                        {\n                            probabilities = new int[] { 95, 75, 45, 5 };\n                            break;\n                        }\n                        default:\n                        {\n                            // in case the user types something bad, pretend it's\n                            // as if they tripped over themselves while throwing\n                            // the dart - they'll either hit a bullseye or completely\n                            // miss\n                            probabilities = new int[] { 95, 95, 95, 95 };\n                            Console.Write(\"TRIP! \");\n                            break;\n                        }\n                    }\n\n\n                    // Next() returns a number in the range: min <= num < max, so specify 101\n                    // as the maximum so that 100 is a number that could be returned\n                    int chance = random.Next(0, 101);\n\n                    if (chance > probabilities[0])\n                    {\n                        player.Score += 40;\n                        Console.WriteLine(\"BULLSEYE!!  40 POINTS!\");\n                    }\n                    else if (chance > probabilities[1])\n                    {\n                        player.Score += 30;\n                        Console.WriteLine(\"30-POINT ZONE!\");\n                    }\n                    else if (chance > probabilities[2])\n                    {\n                        player.Score += 20;\n                        Console.WriteLine(\"20-POINT ZONE\");\n                    }\n                    else if (chance > probabilities[3])\n                    {\n                        player.Score += 10;\n                        Console.WriteLine(\"WHEW!  10 POINTS.\");\n                    }\n                    else\n                    {\n                        // missed it\n                        Console.WriteLine(\"MISSED THE TARGET!  TOO BAD.\");\n                    }\n\n                    // check to see if the player has won - if they have, then\n                    // break out of the loops\n                    if (player.Score > WinningScore)\n                    {\n                        Console.WriteLine();\n                        Console.WriteLine(\"WE HAVE A WINNER!!\");\n                        Console.WriteLine($\"{player.Name.ToUpper()} SCORED {player.Score} POINTS.\");\n                        Console.WriteLine();\n\n                        isOver = true; // out of the do/while round loop\n                        break; // out of the foreach (player) loop\n                    }\n\n                    Console.WriteLine();\n                }\n            }\n            while (!isOver);\n        }\n\n        private void PrintResults()\n        {\n            // For bragging rights, print out all the scores, but sort them\n            // by who had the highest score\n            var sorted = _players.OrderByDescending(p => p.Score);\n\n            // padding is used to get things to line up nicely - the results\n            // should look something like:\n            //      PLAYER       SCORE\n            //      Bravo          210\n            //      Charlie         15\n            //      Alpha            1\n            Console.WriteLine(\"PLAYER       SCORE\");\n            foreach (var player in sorted)\n            {\n                Console.WriteLine($\"{player.Name.PadRight(12)} {player.Score.ToString().PadLeft(5)}\");\n            }\n\n            Console.WriteLine();\n            Console.WriteLine(\"THANKS FOR THE GAME.\");\n        }\n\n        private void PrintIntroduction()\n        {\n            Console.WriteLine(Title);\n            Console.WriteLine();\n            Console.WriteLine(Introduction);\n            Console.WriteLine();\n            Console.WriteLine(Operations);\n        }\n\n        private const string Title = @\"\n                    BULLSEYE\n    CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\";\n\n        private const string Introduction = @\"\nIN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\nWITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\nTO GET 200 POINTS.\";\n\n        private const string Operations = @\"\nTHROW   DESCRIPTION         PROBABLE SCORE\n  1     FAST OVERARM        BULLSEYE OR COMPLETE MISS\n  2     CONTROLLED OVERARM  10, 20, OR 30 POINTS\n  3     UNDERARM            ANYTHING\";\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/csharp/Player.cs",
    "content": "namespace Bullseye\n{\n    /// <summary>\n    /// Object to track the name and score of a player\n    /// </summary>\n    public class Player\n    {\n        /// <summary>\n        /// Creates a play with the given name\n        /// </summary>\n        /// <param name=\"name\">Name of the player</param>\n        public Player(string name)\n        {\n            Name = name;\n            Score = 0;\n        }\n\n        /// <summary>\n        /// Name of the player\n        /// </summary>\n        public string Name { get; private set; }\n\n        /// <summary>\n        /// Current score of the player\n        /// </summary>\n        public int Score { get; set; }\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Bullseye\n{\n    public static class Program\n    {\n        // Entry point to the application; create an instance of the\n        // game class and call Run()\n        public static void Main(string[] args)\n        {\n            new BullseyeGame().Run();\n        }\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "18_Bullseye/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "18_Bullseye/java/src/Bullseye.java",
    "content": "import java.util.ArrayList;\nimport java.util.Scanner;\n\n/**\n * Game of Bullseye\n * <p>\n * Based on the Basic game of Bullseye here\n * https://github.com/coding-horror/basic-computer-games/blob/main/18%20Bullseye/bullseye.bas\n * <p>\n * Note:  The idea was to create a version of 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Bullseye {\n\n    // Used for formatting output\n    public static final int FIRST_IDENT = 10;\n    public static final int SECOND_IDENT = 30;\n    public static final int THIRD_INDENT = 30;\n\n    // Used to decide throw result\n    public static final double[] SHOT_ONE = new double[]{.65, .55, .5, .5};\n    public static final double[] SHOT_TWO = new double[]{.99, .77, .43, .01};\n    public static final double[] SHOT_THREE = new double[]{.95, .75, .45, .05};\n\n    private enum GAME_STATE {\n        STARTING,\n        START_GAME,\n        PLAYING,\n        GAME_OVER\n    }\n\n    private GAME_STATE gameState;\n\n    private final ArrayList<Player> players;\n\n    private final Shot[] shots;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private int round;\n\n    public Bullseye() {\n\n        gameState = GAME_STATE.STARTING;\n        players = new ArrayList<>();\n\n        // Save the random chances of points based on shot type\n\n        shots = new Shot[3];\n        shots[0] = new Shot(SHOT_ONE);\n        shots[1] = new Shot(SHOT_TWO);\n        shots[2] = new Shot(SHOT_THREE);\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    intro();\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Start the game, set the number of players, names and round\n                case START_GAME:\n\n                    int numberOfPlayers = chooseNumberOfPlayers();\n\n                    for (int i = 0; i < numberOfPlayers; i++) {\n                        String name = displayTextAndGetInput(\"NAME OF PLAYER #\" + (i + 1) + \"? \");\n                        Player player = new Player(name);\n                        this.players.add(player);\n                    }\n\n                    this.round = 1;\n\n                    gameState = GAME_STATE.PLAYING;\n                    break;\n\n                // Playing round by round until we have a winner\n                case PLAYING:\n                    System.out.println();\n                    System.out.println(\"ROUND \" + this.round);\n                    System.out.println(\"=======\");\n\n                    // Each player takes their turn\n                    for (Player player : players) {\n                        int playerThrow = getPlayersThrow(player);\n                        int points = calculatePlayerPoints(playerThrow);\n                        player.addScore(points);\n                        System.out.println(\"TOTAL SCORE = \" + player.getScore());\n                    }\n\n                    boolean foundWinner = false;\n\n                    // Check if any player won\n                    for (Player thePlayer : players) {\n                        int score = thePlayer.getScore();\n                        if (score >= 200) {\n                            if (!foundWinner) {\n                                System.out.println(\"WE HAVE A WINNER!!\");\n                                System.out.println();\n                                foundWinner = true;\n                            }\n                            System.out.println(thePlayer.getName() + \" SCORED \"\n                                    + thePlayer.getScore() + \" POINTS\");\n                        }\n                    }\n\n                    if (foundWinner) {\n                        System.out.println(\"THANKS FOR THE GAME.\");\n                        gameState = GAME_STATE.GAME_OVER;\n                    } else {\n                        // No winner found, continue on with the next round\n                        this.round++;\n                    }\n\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Display info about the game\n     */\n    private void intro() {\n        System.out.println(\"BULLSEYE\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\");\n        System.out.println(\"WITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\");\n        System.out.println(\"TO GET 200 POINTS.\");\n        System.out.println();\n        System.out.println(paddedString(\"THROW\", \"DESCRIPTION\", \"PROBABLE SCORE\"));\n        System.out.println(paddedString(\"1\", \"FAST OVERARM\", \"BULLSEYE OR COMPLETE MISS\"));\n        System.out.println(paddedString(\"2\", \"CONTROLLED OVERARM\", \"10, 20 OR 30 POINTS\"));\n        System.out.println(paddedString(\"3\", \"UNDERARM\", \"ANYTHING\"));\n    }\n\n    /**\n     * Calculate the players score\n     * Score is based on the type of shot plus a random factor\n     *\n     * @param playerThrow 1,2, or 3 indicating the type of shot\n     * @return player score\n     */\n    private int calculatePlayerPoints(int playerThrow) {\n\n        // -1 is because of 0 base Java array\n        double p1 = this.shots[playerThrow - 1].getShot(0);\n        double p2 = this.shots[playerThrow - 1].getShot(1);\n        double p3 = this.shots[playerThrow - 1].getShot(2);\n        double p4 = this.shots[playerThrow - 1].getShot(3);\n\n        double random = Math.random();\n\n        int points;\n\n        if (random >= p1) {\n            System.out.println(\"BULLSEYE!!  40 POINTS!\");\n            points = 40;\n            // If the throw was 1 (bullseye or missed, then make it missed\n            // N.B. This is a fix for the basic code which for shot type 1\n            // allowed a bullseye but did not make the score zero if a bullseye\n            // was not made (which it should have done).\n        } else if (playerThrow == 1) {\n            System.out.println(\"MISSED THE TARGET!  TOO BAD.\");\n            points = 0;\n        } else if (random >= p2) {\n            System.out.println(\"30-POINT ZONE!\");\n            points = 30;\n        } else if (random >= p3) {\n            System.out.println(\"20-POINT ZONE\");\n            points = 20;\n        } else if (random >= p4) {\n            System.out.println(\"WHEW!  10 POINTS.\");\n            points = 10;\n        } else {\n            System.out.println(\"MISSED THE TARGET!  TOO BAD.\");\n            points = 0;\n        }\n\n        return points;\n    }\n\n    /**\n     * Get players shot 1,2, or 3 - ask again if invalid input\n     *\n     * @param player the player we are calculating the throw on\n     * @return 1, 2, or 3 indicating the players shot\n     */\n    private int getPlayersThrow(Player player) {\n        boolean inputCorrect = false;\n        String theThrow;\n        do {\n            theThrow = displayTextAndGetInput(player.getName() + \"'S THROW \");\n            if (theThrow.equals(\"1\") || theThrow.equals(\"2\") || theThrow.equals(\"3\")) {\n                inputCorrect = true;\n            } else {\n                System.out.println(\"INPUT 1, 2, OR 3!\");\n            }\n\n        } while (!inputCorrect);\n\n        return Integer.parseInt(theThrow);\n    }\n\n\n    /**\n     * Get players guess from kb\n     *\n     * @return players guess as an int\n     */\n    private int chooseNumberOfPlayers() {\n\n        return Integer.parseInt((displayTextAndGetInput(\"HOW MANY PLAYERS? \")));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Format three strings to a given number of spaces\n     * Replacing the original basic code which used tabs\n     *\n     * @param first  String to print in pos 1\n     * @param second String to print in pos 2\n     * @param third  String to print in pos 3\n     * @return formatted string\n     */\n    private String paddedString(String first, String second, String third) {\n        String output = String.format(\"%1$\" + FIRST_IDENT + \"s\", first);\n        output += String.format(\"%1$\" + SECOND_IDENT + \"s\", second);\n        output += String.format(\"%1$\" + THIRD_INDENT + \"s\", third);\n        return output;\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/java/src/BullseyeGame.java",
    "content": "public class BullseyeGame {\n\n    public static void main(String[] args) {\n\n        Bullseye bullseye = new Bullseye();\n        bullseye.play();\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/java/src/Player.java",
    "content": "/**\n * A Player in the game - consists of name and score\n *\n */\npublic class Player {\n\n    private final String name;\n\n    private int score;\n\n    Player(String name) {\n        this.name = name;\n        this.score = 0;\n    }\n\n    public void addScore(int score) {\n        this.score += score;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public int getScore() {\n        return score;\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/java/src/Shot.java",
    "content": "/**\n * This class records the percentage chance of a given type of shot\n * scoring specific points\n * see Bullseye class points calculation method where its used\n */\npublic class Shot {\n\n    double[] chances;\n\n    // Array of doubles are passed for a specific type of shot\n    Shot(double[] shots) {\n        chances = new double[shots.length];\n        System.arraycopy(shots, 0, chances, 0, shots.length);\n    }\n\n    public double getShot(int index) {\n        return chances[index];\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "18_Bullseye/javascript/bullseye.html",
    "content": "<html>\n<head>\n<title>BULLSEYE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"bullseye.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "18_Bullseye/javascript/bullseye.js",
    "content": "// BULLSEYE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar as = [];\nvar s = [];\nvar w = [];\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"BULLSEYE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\\n\");\n    print(\"WITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\\n\");\n    print(\"TO GET 200 POINTS.\\n\");\n    print(\"\\n\");\n    print(\"THROW\\t\\tDESCRIPTION\\t\\tPROBABLE SCORE\\n\");\n    print(\"1\\t\\tFAST OVERARM\\t\\tBULLSEYE OR COMPLETE MISS\\n\");\n    print(\"2\\t\\tCONTROLLED OVERARM\\t10, 20 OR 30 POINTS\\n\");\n    print(\"3\\t\\tUNDERARM\\t\\tANYTHING\\n\");\n    print(\"\\n\");\n    m = 0;\n    r = 0;\n    for (i = 1; i <= 20; i++)\n        s[i] = 0;\n    print(\"HOW MANY PLAYERS\");\n    n = parseInt(await input());\n    print(\"\\n\");\n    for (i = 1; i <= n; i++) {\n        print(\"NAME OF PLAYER #\" + i);\n        as[i] = await input();\n    }\n    do {\n        r++;\n        print(\"\\n\");\n        print(\"ROUND \" + r + \"\\n\");\n        print(\"---------\\n\");\n        for (i = 1; i <= n; i++) {\n            do {\n                print(\"\\n\");\n                print(as[i] + \"'S THROW\");\n                t = parseInt(await input());\n                if (t < 1 || t > 3)\n                    print(\"INPUT 1, 2, OR 3!\\n\");\n            } while (t < 1 || t > 3) ;\n            if (t == 1) {\n                p1 = 0.65;\n                p2 = 0.55;\n                p3 = 0.5;\n                p4 = 0.5;\n            } else if (t == 2) {\n                p1 = 0.99;\n                p2 = 0.77;\n                p3 = 0.43;\n                p4 = 0.01;\n            } else {\n                p1 = 0.95;\n                p2 = 0.75;\n                p3 = 0.45;\n                p4 = 0.05;\n            }\n            u = Math.random();\n            if (u >= p1) {\n                print(\"BULLSEYE!!  40 POINTS!\\n\");\n                b = 40;\n            } else if (u >= p2) {\n                print(\"30-POINT ZONE!\\n\");\n                b = 30;\n            } else if (u >= p3) {\n                print(\"20-POINT ZONE\\n\");\n                b = 20;\n            } else if (u >= p4) {\n                print(\"WHEW!  10 POINT.\\n\");\n                b = 10;\n            } else {\n                print(\"MISSED THE TARGET!  TOO BAD.\\n\");\n                b = 0;\n            }\n            s[i] += b;\n            print(\"TOTAL SCORE = \" + s[i] + \"\\n\");\n        }\n        for (i = 1; i <= n; i++) {\n            if (s[i] >= 200) {\n                m++;\n                w[m] = i;\n            }\n        }\n    } while (m == 0) ;\n    print(\"\\n\");\n    print(\"WE HAVE A WINNER!!\\n\");\n    print(\"\\n\");\n    for (i = 1; i <= m; i++)\n        print(as[w[i]] + \" SCORED \" + s[w[i]] + \" POINTS.\\n\");\n    print(\"\\n\");\n    print(\"THANKS FOR THE GAME.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "18_Bullseye/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "18_Bullseye/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "18_Bullseye/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "18_Bullseye/perl/bullseye.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 32 . \"BULLSEYE\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\\n\";\nprint \"WITH 10, 20, 30, AND 40 POINT ZONES. THE OBJECTIVE IS\\n\";\nprint \"TO GET 200 POINTS.\\n\\n\";\n\nprint \"THROW\\t\\tDESCRIPTION\\t\\tPROBABLE SCORE\\n\";\nprint\" 1\\t\\tFAST OVERARM\\t\\tBULLSEYE OR COMPLETE MISS\\n\";\nprint\" 2\\t\\tCONTROLLED OVERARM\\t10, 20 OR 30 POINTS\\n\";\nprint\" 3\\t\\tUNDERARM\\t\\tANYTHING\\n\\n\";\n\nmy @A; my $M=0; my $R=0; my @S; my @W; for (my $I=1; $I<=20; $I++) { $S[$I]= 0; }\nprint \"HOW MANY PLAYERS? \"; chomp(my $N = <STDIN>); print \"\\n\";\nfor (my $I=1; $I<=$N; $I++) {\n\tprint \"NAME OF PLAYER #$I? \"; chomp($A[$I] = <STDIN>);\n\t}\n\ndo {\n\t$R= $R+1; print \"\\n\"; print \"ROUND $R---------\\n\";\n\tfor (my $I=1; $I<=$N; $I++) {\n\t\tmy $Flag=0;\n\t\tmy $T;\n\t\tdo {\n\t\t\tprint \"\\n\"; print \"$A[$I]'S THROW? \"; chomp($T = <STDIN>);\n\t\t\tif ($T<1 || $T>3) { print \"INPUT 1, 2, OR 3!\\n\"; $Flag=0; }\n\t\t\t\telse { $Flag=1; }\n\t\t\t} until ($Flag==1);\n\n\t\tmy $P1; my $P2; my $P3; my $P4;\n\t\tif ($T==1) { $P1=.65; $P2=.55; $P3=.5; $P4=.5; }\n\t\tif ($T==2) { $P1=.99; $P2=.77; $P3=.43; $P4=.01; }\n\t\tif ($T==3) { $P1=.95; $P2=.75; $P3=.45; $P4=.05; }\n\n\t\tmy $B=0;\n\t\tmy $U= rand(1);\n\t\tif ($U>= $P1) { print \"BULLSEYE!! 40 POINTS!\\n\"; $B=40; }\n\t\t\telsif ($U>= $P2) { print \"30-POINT ZONE!\\n\"; $B=30; }\n\t\t\telsif ($U>= $P3) { print \"20-POINT ZONE\\n\"; $B=20; }\n\t\t\telsif ($U>= $P4) { print \"WHEW! 10 POINTS.\\n\"; $B=10; }\n\t\t\telse { print \"MISSED THE TARGET! TOO BAD.\\n\"; $B=0; }\n\t\t$S[$I]= $S[$I]+$B; print \"TOTAL SCORE =$S[$I]\";\n\t\t}\n\n\tfor (my $I=1; $I<=$N; $I++) {\n\t\tif ($S[$I]>=200) { $M= $M+1; $W[$M]= $I; }\n\t\t}\n\t} until ($M!=0);\n\nprint \"\\n\"; print \"WE HAVE A WINNER!!\\n\\n\";\nfor (my $I=1; $I<=$M; $I++) { print $A[$W[$I]].\" SCORED \".$S[$W[$I]].\" POINTS.\\n\"; }\nprint \"\\n\"; print \"THANKS FOR THE GAME.\\n\"; exit;\n"
  },
  {
    "path": "18_Bullseye/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "18_Bullseye/python/bullseye.py",
    "content": "import random\nfrom dataclasses import dataclass\nfrom typing import List\n\n\n@dataclass\nclass Player:\n    name: str\n    score: int = 0\n\n\ndef print_intro() -> None:\n    print(\" \" * 32 + \"BULLSEYE\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\" * 3, end=\"\")\n    print(\"IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\")\n    print(\"WITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\")\n    print(\"TO GET 200 POINTS.\")\n    print()\n    print(\"THROW\", end=\"\")\n    print(\" \" * 20 + \"DESCRIPTION\", end=\"\")\n    print(\" \" * 45 + \"PROBABLE SCORE\")\n    print(\" 1\", end=\"\")\n    print(\" \" * 20 + \"FAST OVERARM\", end=\"\")\n    print(\" \" * 45 + \"BULLSEYE OR COMPLETE MISS\")\n    print(\" 2\", end=\"\")\n    print(\" \" * 20 + \"CONTROLLED OVERARM\", end=\"\")\n    print(\" \" * 45 + \"10, 20 OR 30 POINTS\")\n    print(\" 3\", end=\"\")\n    print(\" \" * 20 + \"UNDERARM\", end=\"\")\n    print(\" \" * 45 + \"ANYTHING\")\n    print()\n\n\ndef print_outro(players: List[Player], winners: List[int]) -> None:\n    print()\n    print(\"WE HAVE A WINNER!!\")\n    print()\n    for winner in winners:\n        print(f\"{players[winner].name} SCORED {players[winner].score} POINTS.\")\n    print()\n    print(\"THANKS FOR THE GAME.\")\n\n\ndef main() -> None:\n    print_intro()\n    players: List[Player] = []\n\n    winners: List[int] = []  # will point to indices of player_names\n\n    nb_players = int(input(\"HOW MANY PLAYERS? \"))\n    for _ in range(nb_players):\n        player_name = input(\"NAME OF PLAYER #\")\n        players.append(Player(player_name))\n\n    round_number = 0\n    while not winners:\n        round_number += 1\n        print()\n        print(f\"ROUND {round_number}---------\")\n        for player in players:\n            print()\n            while True:\n                throw = int(input(f\"{player.name}'S THROW? \"))\n                if throw in {1, 2, 3}:\n                    break\n                else:\n                    print(\"INPUT 1, 2, OR 3!\")\n            if throw == 1:\n                probability_1 = 0.65\n                probability_2 = 0.55\n                probability_3 = 0.5\n                probability_4 = 0.5\n            elif throw == 2:\n                probability_1 = 0.99\n                probability_2 = 0.77\n                probability_3 = 0.43\n                probability_4 = 0.01\n            elif throw == 3:\n                probability_1 = 0.95\n                probability_2 = 0.75\n                probability_3 = 0.45\n                probability_4 = 0.05\n            throwing_luck = random.random()\n            if throwing_luck >= probability_1:\n                print(\"BULLSEYE!!  40 POINTS!\")\n                points = 40\n            elif throwing_luck >= probability_2:\n                print(\"30-POINT ZONE!\")\n                points = 30\n            elif throwing_luck >= probability_3:\n                print(\"20-POINT ZONE\")\n                points = 20\n            elif throwing_luck >= probability_4:\n                print(\"WHEW!  10 POINTS.\")\n                points = 10\n            else:\n                print(\"MISSED THE TARGET!  TOO BAD.\")\n                points = 0\n            player.score += points\n            print(f\"TOTAL SCORE = {player.score}\")\n        winners.extend(\n            player_index\n            for player_index, player in enumerate(players)\n            if player.score > 200\n        )\n    print_outro(players, winners)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "18_Bullseye/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "18_Bullseye/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\""
  },
  {
    "path": "18_Bullseye/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)"
  },
  {
    "path": "18_Bullseye/rust/src/lib.rs",
    "content": "/*\n lib.rs contains all the logic of the program\n*/\n\nuse std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}};\n\nuse rand::Rng;\n\n/// handles setup for the game\npub struct Config {\n    players: Vec<Player>,\n}\nimpl Config {\n    /// creates and returns a new Config from user input\n    pub fn new() -> Result<Config, Box<dyn Error>> {\n        //DATA\n        let mut config: Config = Config { players: Vec::new() };\n        let num_players: usize;\n\n        //get data from user input\n\n        //get num players\n        //input looop\n        num_players = loop {\n            match get_number_from_input(\"HOW MANY PLAYERS? \", 1, 0) {\n                Ok(num) => break num,\n                Err(e) => {\n                    println!(\"{}\",e);\n                    continue;\n                },\n            }\n        };\n\n        //get names of all players\n        for id in 1..=num_players {\n            let name = get_string_from_user_input( format!(\"NAME OF PLAYER#{}: \", id).as_str())?;\n            config.players.push(Player::from(&name));\n        }\n\n        //return new config\n        return Ok(config);\n    }\n}\npub struct Player {\n    name: String,\n    score: usize,\n}\nimpl Player {\n    fn from(name: &str) -> Player {\n        return Player { name: String::from(name), score: 0 };\n    }\n}\n\n/// run the program\npub fn run(config: &mut Config) -> Result<(), Box<dyn Error>> {\n    //DATA\n    let mut round = 1;\n    let mut rng = rand::thread_rng();\n\n    //gameloop\n    loop {\n        //print round\n        println!(\"\");\n        println!(\"\");\n        println!(\"ROUND {}\", round);\n        println!(\"---------\");\n\n        //each players play\n        for player in config.players.iter_mut() {\n            //prompt user for players move\n            //input loop\n            let throw = loop {\n                match get_number_from_input( format!(\"{}'S THROW (input 1, 2, or 3): \", player.name).as_str(), 1, 3) {\n                    Ok(t) => break t,\n                    Err(err) => {\n                        println!(\"{}\", err);\n                        continue;\n                    },\n                };\n            };\n\n            //get probabilities of the various outcomes based on the throw\n            let p_bullseye;\n            let p_30_point_zone;\n            let p_20_point_zone;\n            let p_10_point_zone;\n            match throw {\n                1 => {\n                    p_bullseye = 0.65;\n                    p_30_point_zone = 0.55;\n                    p_20_point_zone = 0.5;\n                    p_10_point_zone = 0.5;\n                },\n                2 => {\n                    p_bullseye = 0.99;\n                    p_30_point_zone = 0.77;\n                    p_20_point_zone = 0.43;\n                    p_10_point_zone = 0.01;\n                },\n                _ => {\n                    p_bullseye = 0.95;\n                    p_30_point_zone = 0.75;\n                    p_20_point_zone = 0.45;\n                    p_10_point_zone = 0.05;\n                },\n            }\n\n            //determine results\n            let roll = rng.gen::<f64>();\n            if roll >= p_bullseye{\n                println!(\"BULLSEYE!!  40 POINTS!\");\n                player.score += 40;\n            } else if roll >= p_30_point_zone {\n                println!(\"30-POINT ZONE!\");\n                player.score += 30;\n            } else if roll >= p_20_point_zone {\n                println!(\"20-POINT ZONE\");\n                player.score += 20;\n            } else if roll >= p_10_point_zone {\n                println!(\"WHEW!  10 POINTS.\");\n                player.score += 10;\n            } else {\n                println!(\"MISSED THE TARGET!  TOO BAD.\");\n            }\n\n            //print their score\n            println!(\"TOTAL SCORE = {}\", player.score);\n        }\n\n        //stuff to do before next round\n        if config.players.iter().any(|player| player.score >= 200) {\n            //print congradulations and scores\n            println!(\"\\nWE HAVE A WINNER!!\\n\");\n            for player in config.players.iter() {\n                println!(\"{} SCORED {} POINTS\", player.name, player.score);\n            }\n            //exit loop\n            break;\n        } else {\n            //otherwise do another round\n            round += 1;\n        }\n    }\n\n    \n    \n\n    //return to main\n    Ok(())\n}\n\n/// gets a string from user input\nfn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\", prompt);\n    //make sure it's printed before getting input\n    io::stdout().flush().unwrap();\n\n    //read user input from standard input, and store it to raw_input, then return it or an error as needed\n    raw_input.clear(); //clear input\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),\n        Err(err) => return Err(format!(\"ERROR: CANNOT READ INPUT!: {}\", err).into()),\n    }\n}\n\n/// generic function to get a number from the passed string (user input)\n/// pass a min lower  than the max to have minimun and maximun bounds\n/// pass a min higher than the max to only have a minumum bound\n/// pass a min equal   to  the max to only have a maximun bound\n/// \n/// Errors:\n/// no number on user input\nfn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {\n    //DATA\n    let raw_input: String;\n    let processed_input: String;\n\n    \n    //input looop\n    raw_input = loop {\n        match get_string_from_user_input(prompt) {\n            Ok(input) => break input,\n            Err(e) => {\n                eprintln!(\"{}\",e);\n                continue;\n            },\n        }\n    };\n\n    //filter out num-numeric characters from user input\n    processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();\n\n    //from input, try to read a number\n    match processed_input.trim().parse() {\n        Ok(i) => {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    return Ok(i); //exit the loop with the value i, returning it\n                } else { //print error message specific to this case\n                    return Err(format!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max).into());\n                } \n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO LESS THAN {}, PLEASE!\", min).into());\n                }\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO MORE THAN {}, PLEASE!\", max).into());\n                }\n            }\n        },\n        Err(_e) => return Err(format!(\"Error: couldn't find a valid number in {}\",raw_input).into()),\n    }\n}\n"
  },
  {
    "path": "18_Bullseye/rust/src/main.rs",
    "content": "/*\n    The responsibilities that remain in the main function after separating concerns\n    should be limited to the following:\n - Setting up any configuration\n - Calling a run function in lib.rs\n - Handling the error if run returns an error\n*/\n\nuse std::process;       //allows for some better error handling\n\nmod lib;\nuse lib::Config;\n\n/// main function\nfn main() {\n    //greet user\n    welcome();\n\n    // set up other configuration\n    let mut config = Config::new().unwrap_or_else(|err| {\n        eprintln!(\"Problem configuring program: {}\", err);\n        process::exit(1);\n    });\n\n    // run the program\n    if let Err(e) = lib::run(&mut config) {\n        eprintln!(\"Application Error: {}\", e); //use the eprintln! macro to output to standard error\n        process::exit(1); //exit the program with an error code\n    }\n\n    //end of program\n    println!(\"THANKS FOR PLAYING!\");\n}\n\n/// prints the welcome/start message\nfn welcome() {\n    println!(\"\n                               BULLSEYE\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n    IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET\n    WITH 10, 20, 30, AND 40 POINT ZONES.  THE OBJECTIVE IS\n    TO GET 200 POINTS.\n    \n    | Throw | Description        | Probable Score            |\n    |-------|--------------------|---------------------------|\n    | 1     | Fast overarm       | Bullseye or complete miss |\n    | 2     | Controlled overarm | 10, 20, or 30 points      |\n    | 3     | Underarm           | Anything                  |\n\n    \");\n}\n"
  },
  {
    "path": "18_Bullseye/rust/src/note on separation of converns for rust projects.md",
    "content": " # Separation of concerns for Binary Projects\n\nThe organizational problem of allocating responsibility for multiple tasks to the main function is common to many projects. As a result, the Rust community has developed a process to use as a guideline for splitting the separate concerns of a binary program when main starts getting large. \n\n ## The process has the following steps:\n - Split your program into a main.rs and a lib.rs and move your program’s logic to lib.rs.\n - As long as your command line logic is small, it can remain in main.rs.\n - When the command line logic starts getting complicated, extract it from main.rs and move it to lib.rs.\n\n ## The responsibilities that remain in the main function after this process should be limited to the following:\n - Calling the command line or input parsing logic with the argument values\n - Setting up any other configuration\n - Calling a run function in lib.rs\n - Handling the error if run returns an error\n\nThis pattern is about separating concerns: main.rs handles running the program, and lib.rs handles all the logic of the task at hand. Because you can’t test the main function directly, this structure lets you test all of your program’s logic by moving it into functions in lib.rs. The only code that remains in main.rs will be small enough to verify its correctness by reading it."
  },
  {
    "path": "18_Bullseye/vbnet/Bullseye.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bullseye\", \"Bullseye.vbproj\", \"{0CFD308F-EB9C-4A05-B742-5EE7C912A5E4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{0CFD308F-EB9C-4A05-B742-5EE7C912A5E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0CFD308F-EB9C-4A05-B742-5EE7C912A5E4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0CFD308F-EB9C-4A05-B742-5EE7C912A5E4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0CFD308F-EB9C-4A05-B742-5EE7C912A5E4}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "18_Bullseye/vbnet/Bullseye.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bullseye</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "18_Bullseye/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "19_Bunny/README.md",
    "content": "### Bunny\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=35)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=50)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "19_Bunny/bunny.bas",
    "content": "10 PRINT TAB(33);\"BUNNY\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 REM  \"BUNNY\" FROM AHL'S 'BASIC COMPUTER GAMES'\n110 REM\n120 FOR I=0 TO 4: READ B(I): NEXT I\n130 GOSUB 260\n140 L=64: REM  ASCII LETTER CODE...\n150 REM\n160 PRINT\n170 READ X: IF X<0 THEN 160\n175 IF X>128 THEN 240\n180 PRINT TAB(X);: READ Y\n190 FOR I=X TO Y: J=I-5*INT(I/5)\n200 PRINT CHR$(L+B(J));\n210 NEXT I\n220 GOTO 170\n230 REM\n240 GOSUB 260: GOTO 450\n250 REM\n260 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n270 RETURN\n280 REM\n290 DATA 2,21,14,14,25\n300 DATA 1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1\n310 DATA 1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1\n320 DATA 5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1\n330 DATA 9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1\n340 DATA 13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1\n350 DATA 19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1\n360 DATA 8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1\n370 DATA 4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1\n380 DATA 2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1\n390 DATA 14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1\n400 DATA 14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1\n410 DATA 12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1\n420 DATA 10,11,17,18,22,22,24,24,29,29,-1\n430 DATA 22,23,26,29,-1,27,29,-1,28,29,-1,4096\n440 REM\n450 END\n"
  },
  {
    "path": "19_Bunny/csharp/BasicData.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bunny\n{\n    internal class BasicData\n    {\n        private readonly int[] data;\n\n        private int index;\n\n        public BasicData(int[] data)\n        {\n            this.data = data;\n            index = 0;\n        }\n        public int Read()\n        {\n            return data[index++];\n        }\n    }\n}\n"
  },
  {
    "path": "19_Bunny/csharp/Bunny.cs",
    "content": "﻿namespace Bunny\n{\n    internal class Bunny\n    {\n        private const int asciiBase = 64;\n        private readonly int[] bunnyData = {\n            2,21,14,14,25,\n            1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1,\n            1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1,\n            5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1,\n            9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1,\n            13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1,\n            19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1,\n            8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1,\n            4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1,\n            2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1,\n            14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1,\n            14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1,\n            12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1,\n            10,11,17,18,22,22,24,24,29,29,-1,\n            22,23,26,29,-1,27,29,-1,28,29,-1,4096\n        };\n\n        public void Run()\n        {\n            PrintString(33, \"BUNNY\");\n            PrintString(15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            PrintLines(3);\n\n            // Set up a BASIC-ish data object\n            BasicData data = new (bunnyData);\n\n            // Get the first five data values into an array.\n            // These are the characters we are going to print.\n            // Unlike the original program, we are only converting\n            // them to ASCII once.\n            var a = new char[5];\n            for (var i = 0; i < 5; ++i)\n            {\n                a[i] = (char)(asciiBase + data.Read());\n            }\n            PrintLines(6);\n\n            PrintLines(1);\n            var col = 0;\n            while (true)\n            {\n                var x = data.Read();\n                if (x < 0) // Start a new line\n                {\n                    PrintLines(1);\n                    col = 0;\n                    continue;\n                }\n                if (x > 128) break; // End processing\n                col += PrintSpaces(x - col); // Move to TAB position x (sort of)\n                var y = data.Read(); // Read the next value\n                for (var i = x; i <= y; ++i)\n                {\n                    // var j = i - 5 * (i / 5); // BASIC didn't have a modulus operator\n                    Console.Write(a[i % 5]);\n                    // Console.Write(a[col % 5]); // This works, too\n                    ++col;\n                }\n            }\n            PrintLines(6);\n        }\n        private static void PrintLines(int count)\n        {\n            for (var i = 0; i < count; ++i)\n                Console.WriteLine();\n        }\n        private static int PrintSpaces(int count)\n        {\n            for (var i = 0; i < count; ++i)\n                Console.Write(' ');\n            return count;\n        }\n        public static void PrintString(int tab, string value, bool newLine = true)\n        {\n            PrintSpaces(tab);\n            Console.Write(value);\n            if (newLine) Console.WriteLine();\n        }\n\n    }\n}\n"
  },
  {
    "path": "19_Bunny/csharp/Bunny.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "19_Bunny/csharp/Bunny.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Bunny\", \"Bunny.csproj\", \"{6685F5CF-20F2-4682-B187-50105BD44906}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6685F5CF-20F2-4682-B187-50105BD44906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6685F5CF-20F2-4682-B187-50105BD44906}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6685F5CF-20F2-4682-B187-50105BD44906}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6685F5CF-20F2-4682-B187-50105BD44906}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "19_Bunny/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Bunny\n{\n    public static class Program\n    {\n        public static void Main()\n        {\n            new Bunny().Run();\n        }\n    }\n}\n"
  },
  {
    "path": "19_Bunny/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "19_Bunny/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "19_Bunny/java/src/Bunny.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\n\n/**\n * Bunny\n * <p>\n * Based on the Basic program Bunny\n * https://github.com/coding-horror/basic-computer-games/blob/main/19%20Bunny/bunny.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\npublic class Bunny {\n\n    // First 4 elements are the text BUNNY, so skip those\n    public static final int REAL_DATA_START_POS = 5;\n\n    // Data for characters is not representative of three ASCII character, so we have\n    // to add 64 to it as per original program design.\n    public static final int CONVERT_TO_ASCII = 64;\n\n    public static final int EOF = 4096; //End of file\n    public static final int EOL = -1;  // End of line\n\n    // Contains the data to draw the picture\n    private final ArrayList<Integer> data;\n\n    public Bunny() {\n        data = loadData();\n    }\n\n    /**\n     * Show an intro, then draw the picture.\n     */\n    public void process() {\n\n        intro();\n\n        // First 5 characters of data spells out BUNNY, so add this to a string\n        StringBuilder bunnyBuilder = new StringBuilder();\n        for (int i = 0; i < REAL_DATA_START_POS; i++) {\n            // Convert the data to the character representation for output\n            // Ascii A=65, B=66 - see loadData method\n            bunnyBuilder.append(Character.toChars(data.get(i) + CONVERT_TO_ASCII));\n        }\n\n        // We now have the string to be used in the output\n        String bunny = bunnyBuilder.toString();\n\n        int pos = REAL_DATA_START_POS;  // Point to the start of the actual data\n        int previousPos = 0;\n\n        // Loop until we reach a number indicating EOF\n        while (true) {\n            // This is where we want to start drawing\n            int first = data.get(pos);\n            if (first == EOF) {\n                break;\n            }\n            if (first == EOL) {\n                System.out.println();\n                previousPos = 0;\n                // Move to the next element in the ArrayList\n                pos++;\n                continue;\n            }\n\n            // Because we are not using screen positioning, we just add an appropriate\n            // numbers of spaces from where we want to be, and where we last outputted something\n            System.out.print(addSpaces(first - previousPos));\n\n            // We use this next time around the loop\n            previousPos = first;\n\n            // Move to next element\n            pos++;\n            // This is where we want to stop drawing/\n            int second = data.get(pos);\n\n            // Now we loop through the number of characters to draw using\n            // the starting and ending point.\n            for (int i = first; i <= second; i++) {\n                // Cycle through the actual number of characters but use the\n                // remainder operator to ensure we only use characters from the\n                // bunny string\n                System.out.print(bunny.charAt(i % bunny.length()));\n                // Advance where we were at.\n                previousPos += 1;\n            }\n            // Point to next data element\n            pos++;\n        }\n\n        System.out.println();\n\n    }\n\n    private void intro() {\n        System.out.println(addSpaces(33) + \"BUNNY\");\n        System.out.println(addSpaces(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n    }\n\n    /**\n     * Return a string of x spaces\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String addSpaces(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /**\n     * Original Basic program had the data in DATA format.\n     * We're importing all the data into an array for ease of processing.\n     * Format of data is\n     * characters 0-4 is the letters that will be used in the output. 64 + the value represents the ASCII character\n     * ASCII code 65 = A, 66 = B, etc.  so 2+64=66 (B), 21+64=85 (U) and so on.\n     * Then we next have pairs of numbers.\n     * Looking at the this data\n     * 1,2,-1,0,2,45,50,-1\n     * That reads as\n     * 1,2 = draw characters - in this case BU\n     * -1 = go to a new line\n     * 0,2 = DRAW BUN\n     * 45,50 = DRAW BUNNYB starting at position 45\n     * and so on.\n     * 4096 is EOF\n     *\n     * @return ArrayList of type Integer containing the data\n     */\n    private ArrayList<Integer> loadData() {\n\n        ArrayList<Integer> theData = new ArrayList<>();\n\n        // This is the data faithfully added from the original basic program.\n        // Notes:\n        // The first 5 ints are ASCII character (well 64 is added to make them ASCII chars we can output).\n        theData.addAll(Arrays.asList(2, 21, 14, 14, 25));\n        theData.addAll(Arrays.asList(1, 2, -1, 0, 2, 45, 50, -1, 0, 5, 43, 52, -1, 0, 7, 41, 52, -1));\n        theData.addAll(Arrays.asList(1, 9, 37, 50, -1, 2, 11, 36, 50, -1, 3, 13, 34, 49, -1, 4, 14, 32, 48, -1));\n        theData.addAll(Arrays.asList(5, 15, 31, 47, -1, 6, 16, 30, 45, -1, 7, 17, 29, 44, -1, 8, 19, 28, 43, -1));\n        theData.addAll(Arrays.asList(9, 20, 27, 41, -1, 10, 21, 26, 40, -1, 11, 22, 25, 38, -1, 12, 22, 24, 36, -1));\n        theData.addAll(Arrays.asList(13, 34, -1, 14, 33, -1, 15, 31, -1, 17, 29, -1, 18, 27, -1));\n        theData.addAll(Arrays.asList(19, 26, -1, 16, 28, -1, 13, 30, -1, 11, 31, -1, 10, 32, -1));\n        theData.addAll(Arrays.asList(8, 33, -1, 7, 34, -1, 6, 13, 16, 34, -1, 5, 12, 16, 35, -1));\n        theData.addAll(Arrays.asList(4, 12, 16, 35, -1, 3, 12, 15, 35, -1, 2, 35, -1, 1, 35, -1));\n        theData.addAll(Arrays.asList(2, 34, -1, 3, 34, -1, 4, 33, -1, 6, 33, -1, 10, 32, 34, 34, -1));\n        theData.addAll(Arrays.asList(14, 17, 19, 25, 28, 31, 35, 35, -1, 15, 19, 23, 30, 36, 36, -1));\n        theData.addAll(Arrays.asList(14, 18, 21, 21, 24, 30, 37, 37, -1, 13, 18, 23, 29, 33, 38, -1));\n        theData.addAll(Arrays.asList(12, 29, 31, 33, -1, 11, 13, 17, 17, 19, 19, 22, 22, 24, 31, -1));\n        theData.addAll(Arrays.asList(10, 11, 17, 18, 22, 22, 24, 24, 29, 29, -1));\n        theData.addAll(Arrays.asList(22, 23, 26, 29, -1, 27, 29, -1, 28, 29, -1, 4096));\n\n        return theData;\n    }\n\n    public static void main(String[] args) {\n\n        Bunny bunny = new Bunny();\n        bunny.process();\n    }\n}\n"
  },
  {
    "path": "19_Bunny/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "19_Bunny/javascript/bunny.html",
    "content": "<html>\n<head>\n<title>BUNNY</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\" style=\"font-size: 8pt;\"></pre>\n<script src=\"bunny.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "19_Bunny/javascript/bunny.js",
    "content": "// BUNNY\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\nfunction print(str)\n{\n\tdocument.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction tab(space)\n{\n\tvar str = \"\";\n\twhile (space-- > 0)\n\t\tstr += \" \";\n\treturn str;\n}\n\nvar bunny_string = [\"B\",\"U\",\"N\",\"N\",\"Y\"];\n\nvar bunny_data = [1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1,\n\t1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1,\n\t5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1,\n\t9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1,\n\t13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1,\n\t19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1,\n\t8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1,\n\t4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1,\n\t2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1,\n\t14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1,\n\t14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1,\n\t12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1,\n\t10,11,17,18,22,22,24,24,29,29,-1,\n\t22,23,26,29,-1,27,29,-1,28,29,-1,4096];\n\nprint(tab(32) + \"BUNNY\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\n\nvar l = 64;\t// ASCII letter code\nvar pos = 0;\n\nprint(\"\\n\");\n\nvar str = \"\";\nfor (var pos = 0; bunny_data[pos] < 128; pos++) {\n\tif (bunny_data[pos] < 0) {\n\t\tprint(str + \"\\n\");\n\t\tstr = \"\";\n\t\tcontinue;\n\t}\n\twhile (str.length < bunny_data[pos])\n\t\tstr += \" \";\n\tfor (var i = bunny_data[pos]; i <= bunny_data[pos + 1]; i++)\n\t\tstr += bunny_string[i % 5];\n\tpos++;\n}\n"
  },
  {
    "path": "19_Bunny/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "19_Bunny/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "19_Bunny/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "19_Bunny/perl/bunny.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x 33 . \"BUNNY\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\n#REM \"BUNNY\" FROM AHL'$S 'BASIC COMPUTER GAMES';\n\n# This data contains the letter Bunny A=1, B=2, C=3...\nmy @A= (2,21,14,14,25);\n\n# This data structure contains the pair of start and finish absolute position to show letters.\n# -1 means next line, whatever more than 128 will stop the data read.\nmy @B= (\n\t1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1,\n\t1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1,\n\t5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1,\n\t9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1,\n\t13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1,\n\t19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1,\n\t8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1,\n\t4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1,\n\t2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1,\n\t14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1,\n\t14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1,\n\t12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1,\n\t10,11,17,18,22,22,24,24,29,29,-1,\n\t22,23,26,29,-1,27,29,-1,28,29,-1,4096\n\t);\n\n\n&ENTERS();\nmy $L= 64; #REM ASCII LETTER CODE...\nprint \"\\n\";\n\nmy $P=0; #Position read iterator\nmy $Line= ' 'x 60;\nwhile (1) {\n\tmy $X= $B[$P]; $P++; #Read start position.\n\tif ($X<0) { print \"$Line\\n\";; $Line= ' 'x 60; next; }\n\tif ($X>128) { last; }\n\tmy $Y= $B[$P]; $P++; #Read end position.\n\n\tfor (my $I=$X; $I<=$Y; $I++) { my $J=$I-5*int($I/5);\n\t\tsubstr($Line, $I, 1, chr($L+$A[$J])); #You can change $I for $X to get a nice bunny shadow.\n\t\t}\n\t}\n\n&ENTERS();\nexit;\n\n\nsub ENTERS { #GOSUB 260\n\tfor (my $I=1; $I<=6; $I++) { print chr(10); }\n\t}\n"
  },
  {
    "path": "19_Bunny/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "19_Bunny/python/bunny.py",
    "content": "#!/usr/bin/env python3\n\n\nimport json\n\n# This data is meant to be read-only, so we are storing it in a tuple\nwith open(\"data.json\") as f:\n    DATA = tuple(json.load(f))\n\n\ndef print_intro() -> None:\n    print(\" \" * 33 + \"BUNNY\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n\n\ndef main() -> None:\n    print_intro()\n\n    # Using an iterator will give us a similar interface to BASIC's READ\n    # command. Instead of READ, we will call 'next(data)' to fetch the next element.\n    data = iter(DATA)\n\n    # Read the first 5 numbers. These correspond to letters of the alphabet.\n    # B=2, U=21, N=14, N=14, Y=25\n\n    # Usually, list comprehensions are good for transforming each element in a sequence.\n    # In this case, we are using range to repeat the call to next(data) 5 times. The underscore (_)\n    # indicates that the values from range are discarded.\n    bunny = [next(data) for _ in range(5)]\n    L = 64\n\n    # Interpretting a stream of data is a very common software task. We've already intepretted\n    # the first 5 numbers as letters of the alphabet (with A being 1). Now, we are going to\n    # combine this with a different interpretation of the following data to draw on the screen.\n    # The drawing data is essentially a series of horizontal line segments given as begin and end\n    # offsets.\n    while True:\n        command = next(data)\n\n        if command < 0:\n            print()\n            continue\n\n        if command > 128:\n            break\n\n        # If we've reached this portion of the code, 'command' indicates the 'start'\n        # position of a line segment.\n        start = command\n        # Position cursor at start\n        print(\" \" * start, end=\"\")\n\n        # The following number, indicates the end of the segment.\n        end = next(data)\n        # Unlike FOR I=X TO Y, the 'stop' argument of 'range' is non-inclusive, so we must add 1\n        for i in range(start, end + 1, 1):\n            # Cycle through the letters in \"BUNNY\" as we draw line\n            j = i - 5 * int(i / 5)\n            print(chr(L + bunny[j]), end=\"\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "19_Bunny/python/data.json",
    "content": "[\n    2,\n    21,\n    14,\n    14,\n    25,\n    1,\n    2,\n    -1,\n    0,\n    2,\n    45,\n    50,\n    -1,\n    0,\n    5,\n    43,\n    52,\n    -1,\n    0,\n    7,\n    41,\n    52,\n    -1,\n    1,\n    9,\n    37,\n    50,\n    -1,\n    2,\n    11,\n    36,\n    50,\n    -1,\n    3,\n    13,\n    34,\n    49,\n    -1,\n    4,\n    14,\n    32,\n    48,\n    -1,\n    5,\n    15,\n    31,\n    47,\n    -1,\n    6,\n    16,\n    30,\n    45,\n    -1,\n    7,\n    17,\n    29,\n    44,\n    -1,\n    8,\n    19,\n    28,\n    43,\n    -1,\n    9,\n    20,\n    27,\n    41,\n    -1,\n    10,\n    21,\n    26,\n    40,\n    -1,\n    11,\n    22,\n    25,\n    38,\n    -1,\n    12,\n    22,\n    24,\n    36,\n    -1,\n    13,\n    34,\n    -1,\n    14,\n    33,\n    -1,\n    15,\n    31,\n    -1,\n    17,\n    29,\n    -1,\n    18,\n    27,\n    -1,\n    19,\n    26,\n    -1,\n    16,\n    28,\n    -1,\n    13,\n    30,\n    -1,\n    11,\n    31,\n    -1,\n    10,\n    32,\n    -1,\n    8,\n    33,\n    -1,\n    7,\n    34,\n    -1,\n    6,\n    13,\n    16,\n    34,\n    -1,\n    5,\n    12,\n    16,\n    35,\n    -1,\n    4,\n    12,\n    16,\n    35,\n    -1,\n    3,\n    12,\n    15,\n    35,\n    -1,\n    2,\n    35,\n    -1,\n    1,\n    35,\n    -1,\n    2,\n    34,\n    -1,\n    3,\n    34,\n    -1,\n    4,\n    33,\n    -1,\n    6,\n    33,\n    -1,\n    10,\n    32,\n    34,\n    34,\n    -1,\n    14,\n    17,\n    19,\n    25,\n    28,\n    31,\n    35,\n    35,\n    -1,\n    15,\n    19,\n    23,\n    30,\n    36,\n    36,\n    -1,\n    14,\n    18,\n    21,\n    21,\n    24,\n    30,\n    37,\n    37,\n    -1,\n    13,\n    18,\n    23,\n    29,\n    33,\n    38,\n    -1,\n    12,\n    29,\n    31,\n    33,\n    -1,\n    11,\n    13,\n    17,\n    17,\n    19,\n    19,\n    22,\n    22,\n    24,\n    31,\n    -1,\n    10,\n    11,\n    17,\n    18,\n    22,\n    22,\n    24,\n    24,\n    29,\n    29,\n    -1,\n    22,\n    23,\n    26,\n    29,\n    -1,\n    27,\n    29,\n    -1,\n    28,\n    29,\n    -1,\n    4096\n]\n"
  },
  {
    "path": "19_Bunny/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n\nThere are two versions of this program here:\n\n* `bunny-faithful.rb` tries to be faithful to the design of the original\n  BASIC program.\n* `bunny-modern.rb` takes more advantage of the features of modern\n  tools and languages.\n"
  },
  {
    "path": "19_Bunny/ruby/bunny-faithful.rb",
    "content": "#!/bin/env ruby\n\n# Bunny - Print a large ASCII-pixel bunny icon made up of the letters\n# of the word BUNNY.\n\n# This is a recreation of bunny.bas in Ruby that attempts to remain\n# relatively faithful to the design of the original program.\n#\n# The BASIC version works by storing the image as a series of pairs of\n# numbers containing ranges of text columns that will need to be\n# filled in with non-blank characters.\n#\n# For example, the first few entries in the block of DATA statements are:\n#\n#       1,2,-1,0,2,45,50,-1 ...\n#\n#           * 1,2 means \"write letters from columns 1 to 2\n#           * -1 starts a new line\n#           * 0,2 draws letters between columns 0 and 2\n#           * 45,50 draws letters between columns 45 and 50\n#           * -1 starts a new line\n#\n# ...and so on.\n#\n# We keep the data statements as they are and redraw the image using\n# them.  (Well, we drop the last one because it's the end-of-data flag\n# and Ruby is perfectly effective at finding the end of the list.)\n#\n# One tricky bit: BASIC has a function called 'tab()' which sets the\n# output column to the given position and which the BASIC version uses\n# to pick the columns to write to.  Ruby doesn't have an equivalent\n# feature (well, not without a *lot* more complexity).  Fortunately,\n# the data always draws from left to right so we just keep track of\n# the last column written to and then add some spaces to advance to\n# where we need to be.\n#\n\n\n# Do the thing.  (We put it in a function to keep from spewing global\n# variables all over the place.  It's not really necessary here but\n# it's good practice.)\ndef main\n\n  # Print the heading.  Note the highly advanced lower-case letters.\n  puts ' '*33 + \"Bunny\"\n  puts ' '*15 + \"Creative Computing  Morristown, New Jersey\"\n\n  # Print blank lines.\n  print \"\\n\\n\\n\"\n\n  # The positions to write; this is ripped from the BASIC program's\n  # DATA statements.\n  positions = [\n    1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1,\n    1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1,\n    5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1,\n    9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1,\n    13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1,\n    19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1,\n    8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1,\n    4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1,\n    2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1,\n    14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1,\n    14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1,\n    12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1,\n    10,11,17,18,22,22,24,24,29,29,-1,\n    22,23,26,29,-1,27,29,-1,28,29,-1,\n  ]\n\n  # The text we're writing.\n  text = \"BUNNY\"\n\n  # Draw the bunny.\n  last_pos = 0\n  while positions.size > 0\n    first = positions.shift\n\n    # If we've found -1, start a new line\n    if first == -1\n      puts\n      last_pos = 0\n      next\n    end\n\n    # Advance to start of the range\n    print ' '*(first - last_pos)\n    last_pos = first\n\n    # Now, draw pixels:\n    second = positions.shift\n    for i in first .. second\n      print text[i % text.size] # choose the letter according to the column\n      last_pos += 1\n    end\n  end\n\n  # Print the final blank line\n  puts\nend\n\nmain\n"
  },
  {
    "path": "19_Bunny/ruby/bunny-modern.rb",
    "content": "#!/bin/env ruby\n\n# Bunny - Print a large ASCII-pixel bunny icon made up of the letters\n# of the word BUNNY.\n\n# This is a recreation of bunny.bas in Ruby that takes advantage of\n# the language's features to make the code easier to understand and\n# modify.\n#\n# Instead of storing the image as a set of ranges, we just store it as\n# ASCII art, then replace the pixes with the appropriate letters when\n# printing.  In addition to being simpler, this also lets you modify\n# the image much more easily.\n\n\n# We assume a screen width of 80.  (With modern consoles, doing this\n# accurately gets complex and it's really not worth the bother for\n# this little program so 80 columns it is.)\nScreenWidth = 80\n\n\n# The bunny image.  Totally not the logo of a magazine that was edgy\n# in the 1970s.\nBunny = <<EOF\n **\n***                                          ******\n******                                     **********\n********                                 ************\n *********                           **************\n  **********                        ***************\n   ***********                    ****************\n    ***********                 *****************\n     ***********               *****************\n      ***********             ****************\n       ***********           ****************\n        ************        ****************\n         ************      ***************\n          ************    ***************\n           ************  **************\n            *********** *************\n             **********************\n              ********************\n               *****************\n                 *************\n                  **********\n                   ********\n                *************\n             ******************\n           *********************\n          ***********************\n        **************************\n       ****************************\n      ********  *******************\n     ********   ********************\n    *********   ********************\n   **********  *********************\n  **********************************\n ***********************************\n  *********************************\n   ********************************\n    ******************************\n      ****************************\n          *********************** *\n              **** *******  ****   *\n               *****   ********     *\n              *****  *  *******      *\n             ******    *******   ******\n            ****************** ***\n           ***   * *  * ********\n          **     **   * *    *\n                      **  ****\n                           ***\n                            **\nEOF\n\n\n# Do the thing.  (We put it in a function to keep from spewing global\n# variables all over the place.  It's not really necessary here but\n# it's good practice.)\ndef main\n\n  puts_centered \"Bunny\"\n  puts_centered \"Creative Computing  Morristown, New Jersey\"\n\n  # Print some blank lines\n  print \"\\n\\n\\n\"\n\n  print_bunny_text(Bunny)\n\n  puts\nend\n\ndef puts_centered(str)\n  print ' ' * ((ScreenWidth - str.size)/2)\n  puts str\nend\n\n# Print an ASCII-pixel image such that each pixel is a letter of the\n# word BUNNY chosen by the column in which it appears.\ndef print_bunny_text(text)\n  bunny = \"BUNNY\"\n\n  # Take the initial string and split it on the newlines (i.e. turn it\n  # into a list of strings, each string making up one line), then loop\n  # over the lines one at a time, converting and then printing each of\n  # them.\n  for line in text.split(/\\n/)\n\n    # Replace the '*' with the correct letter.\n    for n in (0..line.size - 1)\n      line[n] = bunny[n % 5]  if line[n] != ' '\n    end\n\n    # Bonus hackery: we could replace the above with this one-liner,\n    # but it's kind of hard to understand so it may or may not be wise\n    # to use it.\n    #\n    #   line.gsub!(/(\\S)/) {|m| bunny[$~.begin(0) % bunny.size] }\n\n    puts line\n  end\nend\n\nmain()\n"
  },
  {
    "path": "19_Bunny/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n"
  },
  {
    "path": "19_Bunny/rust/src/main.rs",
    "content": "/** BUNNY GAME \n * https://github.com/coding-horror/basic-computer-games/tree/main/19_Bunny\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 17/02/25\n*/\n\n//290 DATA 2,21,14,14,25\n//300 DATA 1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1\n//310 DATA 1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1\n//320 DATA 5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1\n//330 DATA 9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1\n//340 DATA 13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1\n//350 DATA 19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1\n//360 DATA 8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1\n//370 DATA 4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1\n//380 DATA 2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1\n//390 DATA 14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1\n//400 DATA 14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1\n//410 DATA 12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1\n//420 DATA 10,11,17,18,22,22,24,24,29,29,-1\n//430 DATA 22,23,26,29,-1,27,29,-1,28,29,-1,4096\n\n// 4096 is the end of file\n// -1 is the end of line\nconst DATA: [i32;233] = [\n    2,21,14,14,25,\n    1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1,\n    1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1,\n    5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1,\n    9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1,\n    13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1,\n    19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1,\n    8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1,\n    4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1,\n    2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1,\n    14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1,\n    14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1,\n    12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1,\n    10,11,17,18,22,22,24,24,29,29,-1,\n    22,23,26,29,-1,27,29,-1,28,29,-1,4096,\n];\n\nfn main() {\n    let mut col = 0;\n\n    //10 PRINT TAB(33);\"BUNNY\"\n    //20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    //30 PRINT: PRINT: PRINT\n    //100 REM  \"BUNNY\" FROM DAVID AHL'S 'BASIC COMPUTER GAMES'\n    print!(\"{}{}\\n{}{}\\n\",\n        \" \".repeat(33),\n        \"BUNNY\",\n        \" \".repeat(15),\n        \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n\n    //120 FOR I=0 TO 4: READ B(I): NEXT I\n    let mut b = [0;5];\n    for i in 0..=4 {\n        b[i] = DATA[col];\n        col = col + 1;\n    }\n\n    //130 GOSUB 260\n    //260 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n    for _ in 1..=6 {\n        println!();\n    }\n    //270 RETURN\n    \n    //140 L=64: REM  ASCII LETTER CODE...\n    let l = 64;\n    let mut prev = 0;\n    loop {\n        //170 READ X: IF X<0 THEN 160\n        let x = DATA[col];\n        col = col + 1;\n        if x < 0 {\n            //160 PRINT\n            println!();\n            prev = 0;\n            continue;\n        }\n        //175 IF X>128 THEN 240\n        else if x > 128 {\n            //240 GOSUB 260: GOTO 450\n            for _ in 1..=6 {\n                println!();\n            }\n            break;\n        }\n        else {\n            //180 PRINT TAB(X);: READ Y\n            print!(\"{}\", \" \".repeat((x - prev) as usize)); // verificar\n            prev = x;\n            let y = DATA[col];\n            col = col + 1;\n            //190 FOR I=X TO Y: J=I-5*INT(I/5)\n            for i in x..=y {\n                let j = i - 5 * (i / 5);\n                //200 PRINT CHR$(L+B(J));\n                print!(\"{}\", (l + b[j as usize]) as u8 as char);\n                prev = prev + 1;\n                //210 NEXT I\n\n            }\n            //220 GOTO 170\n        }\n    }\n    //450 END\n}\n\n"
  },
  {
    "path": "19_Bunny/vbnet/Bunny.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Bunny\", \"Bunny.vbproj\", \"{E9098ADF-4B31-4082-9102-2A5BB8B40C6C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E9098ADF-4B31-4082-9102-2A5BB8B40C6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E9098ADF-4B31-4082-9102-2A5BB8B40C6C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E9098ADF-4B31-4082-9102-2A5BB8B40C6C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E9098ADF-4B31-4082-9102-2A5BB8B40C6C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "19_Bunny/vbnet/Bunny.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Bunny</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "19_Bunny/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "20_Buzzword/README.md",
    "content": "### Buzzword\n\nThis program is an invaluable aid for preparing speeches and briefings about educational technology. This buzzword generator provides sets of three highly-acceptable words to work into your material. Your audience will never know that the phrases don’t really mean much of anything because they sound so great! Full instructions for running are given in the program.\n\nThis version of Buzzword was written by David Ahl.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=36)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=51)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "20_Buzzword/buzzword.bas",
    "content": "10 PRINT TAB(26);\"BUZZWORD GENERATOR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 PRINT \"THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\"\n50 PRINT \"'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\"\n60 PRINT \"AND SPEECHES.  WHENEVER A QUESTION MARK IS PRINTED,\"\n70 PRINT \"TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT.\"\n80 PRINT:PRINT:PRINT \"HERE'S THE FIRST PHRASE:\"\n90 DIM A$(40)\n100 FOR I=1 TO 39 : READ A$(I) : NEXT I\n110 PRINT A$(INT(13*RND(1)+1));\" \";\n120 PRINT A$(INT(13*RND(1)+14));\" \";\n130 PRINT A$(INT(13*RND(1)+27)) : PRINT\n150 INPUT Y$ : IF Y$=\"Y\" THEN 110\n160 GOTO 999\n200 DATA \"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\"\n210 DATA \"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\"HETEROGENEOUS\"\n220 DATA \"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\"\n230 DATA \"INDIVIDUALIZED\",\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\"\n240 DATA \"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\"\n250 DATA \"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\"\n260 DATA \"MOTIVATIONAL\",\"CREATIVE\",\"GROUPING\",\"MODIFICATION\"\n270 DATA \"ACCOUNTABILITY\",\"PROCESS\",\"CORE CURRICULUM\",\"ALGORITHM\"\n280 DATA \"PERFORMANCE\",\"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\"\n290 DATA \"STRUCTURE\",\"FACILITY\",\"ENVIRONMENT\"\n999 PRINT \"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\":END\n"
  },
  {
    "path": "20_Buzzword/csharp/Buzzword.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>net5.0</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "20_Buzzword/csharp/Buzzword.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.810.15\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Buzzword\", \"Buzzword.csproj\", \"{E342DEB2-F009-47FD-85F6-E84965EAAB56}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {52F15A7F-671A-470D-91CE-F3B629B989B7}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "20_Buzzword/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Buzzword\n{\n    class Program\n    {\n        /// <summary>\n        /// Displays header.\n        /// </summary>\n        static void Header()\n        {\n            Console.WriteLine(\"Buzzword generator\".PadLeft(26));\n            Console.WriteLine(\"Creating Computing Morristown, New Jersey\".PadLeft(15));\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        // Information for the user about possible key input.\n        static string keys = \"type a 'Y' for another phrase or 'N' to quit\";\n\n        /// <summary>\n        /// Displays instructions.\n        /// </summary>\n        static void Instructions()\n        {\n            Console.WriteLine(\"This program prints highly acceptable phrases in\\n\"\n            + \"'educator-speak' that you can work into reports\\n\"\n            + \"and speeches. Whenever a question mark is printed,\\n\"\n            + $\"{keys}.\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.Write(\"Here's the first phrase:\");\n        }\n\n        static string[] Words = new[]\n            { \"ability\", \"basal\", \"behavioral\", \"child-centered\",\n            \"differentiated\", \"discovery\", \"flexible\", \"heterogenous\",\n            \"homogeneous\", \"manipulative\", \"modular\", \"tavistock\",\n            \"individualized\", \"learning\", \"evaluative\", \"objective\",\n            \"cognitive\", \"enrichment\", \"scheduling\", \"humanistic\",\n            \"integrated\", \"non-graded\", \"training\", \"vertical age\",\n            \"motivational\", \"creative\", \"grouping\", \"modification\",\n            \"accountability\", \"process\", \"core curriculum\", \"algorithm\",\n            \"performance\", \"reinforcement\", \"open classroom\", \"resource\",\n            \"structure\", \"facility\", \"environment\" };\n\n        /// <summary>\n        /// Capitalizes first letter of given string.\n        /// </summary>\n        /// <param name=\"input\"></param>\n        /// <returns>string</returns>\n        static string Capitalize(string input)\n        {\n            if (string.IsNullOrWhiteSpace(input))\n                return string.Empty;\n\n            return char.ToUpper(input[0]) + input[1..];\n        }\n\n        // Seed has been calculated to get the same effect as in original,\n        // at least in first phrase\n        static readonly Random rnd = new Random(1486);\n\n        /// <summary>\n        /// Generates random phrase from words available in Words array.\n        /// </summary>\n        /// <returns>String representing random phrase where first letter is capitalized.</returns>\n        static string GeneratePhrase()\n        {\n            // Indexing from 0, so had to decrease generated numbers\n            return $\"{Capitalize(Words[rnd.Next(13)])} \"\n                + $\"{Words[rnd.Next(13, 26)]} \"\n                + $\"{Words[rnd.Next(26, 39)]}\";\n        }\n\n        /// <summary>\n        /// Handles user input. On wrong input it displays information about\n        /// valid keys in infinite loop.\n        /// </summary>\n        /// <returns>True if user pressed 'Y', false if 'N'.</returns>\n        static bool Decision()\n        {\n            while (true)\n            {\n                Console.Write(\"?\");\n                var answer = Console.ReadKey();\n                if (answer.Key == ConsoleKey.Y)\n                    return true;\n                else if (answer.Key == ConsoleKey.N)\n                    return false;\n                else\n                    Console.WriteLine($\"\\n{keys}\");\n            }\n        }\n\n        static void Main(string[] args)\n        {\n            Header();\n            Instructions();\n\n            while (true)\n            {\n                Console.WriteLine();\n                Console.WriteLine(GeneratePhrase());\n                Console.WriteLine();\n\n                if (!Decision())\n                    break;\n            }\n\n            Console.WriteLine(\"\\nCome back when you need help with another report!\");\n        }\n    }\n}\n"
  },
  {
    "path": "20_Buzzword/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "20_Buzzword/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "20_Buzzword/java/src/Buzzword.java",
    "content": "import java.util.Scanner;\r\n\r\npublic class Buzzword {\r\n\r\n\tpublic static void main(final String[] args) {\r\n\t\ttry (\r\n\t\t\t// Scanner is a Closeable so it must be closed\r\n\t\t\t// before the program ends.\r\n\t\t\tfinal Scanner scanner = new Scanner(System.in);\r\n\t\t) {\r\n\t\t\tfinal BuzzwordSupplier buzzwords = new BuzzwordSupplier();\r\n\t\t\tfinal UserInterface userInterface = new UserInterface(\r\n\t\t\t\t\tscanner, System.out, buzzwords);\r\n\t\t\tuserInterface.run();\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "20_Buzzword/java/src/BuzzwordSupplier.java",
    "content": "import java.util.Random;\nimport java.util.function.Supplier;\n\n/**\n * A string supplier that provides an endless stream of random buzzwords.\n */\npublic class BuzzwordSupplier implements Supplier<String> {\n\n\tprivate static final String[] SET_1 = {\n\t\t\t\"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\",\n\t\t\t\"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\"HETEROGENEOUS\",\n\t\t\t\"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\",\n\t\t\t\"INDIVIDUALIZED\" };\n\n\tprivate static final String[] SET_2 = {\n\t\t\t\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\",\n\t\t\t\"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\",\n\t\t\t\"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\",\n\t\t\t\"MOTIVATIONAL\",\"CREATIVE\" };\n\n\tprivate static final String[] SET_3 = {\n\t\t\t\"GROUPING\",\"MODIFICATION\", \"ACCOUNTABILITY\",\"PROCESS\",\n\t\t\t\"CORE CURRICULUM\",\"ALGORITHM\", \"PERFORMANCE\",\n\t\t\t\"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\", \"STRUCTURE\",\n\t\t\t\"FACILITY\",\"ENVIRONMENT\" };\n\n\tprivate final Random random = new Random();\n\n\t/**\n\t * Create a buzzword by concatenating a random word from each of the\n\t * three word sets.\n\t */\n\t@Override\n\tpublic String get() {\n\t\treturn SET_1[random.nextInt(SET_1.length)] + ' ' +\n\t\t\t\tSET_2[random.nextInt(SET_2.length)] + ' ' +\n\t\t\t\tSET_3[random.nextInt(SET_3.length)];\n\t}\n}\n"
  },
  {
    "path": "20_Buzzword/java/src/UserInterface.java",
    "content": "import java.io.PrintStream;\nimport java.util.Scanner;\nimport java.util.function.Supplier;\n\n/**\n * A command line user interface that outputs a buzzword every\n * time the user requests a new one.\n */\npublic class UserInterface implements Runnable {\n\n\t/**\n\t * Input from the user.\n\t */\n\tprivate final Scanner input;\n\n\t/**\n\t * Output to the user.\n\t */\n\tprivate final PrintStream output;\n\n\t/**\n\t * The buzzword generator.\n\t */\n\tprivate final Supplier<String> buzzwords;\n\n\t/**\n\t * Create a new user interface.\n\t *\n\t * @param input The input scanner with which the user gives commands.\n\t * @param output The output to show messages to the user.\n\t * @param buzzwords The buzzword supplier.\n\t */\n\tpublic UserInterface(final Scanner input,\n\t\t\tfinal PrintStream output,\n\t\t\tfinal Supplier<String> buzzwords) {\n\t\tthis.input = input;\n\t\tthis.output = output;\n\t\tthis.buzzwords = buzzwords;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\toutput.println(\"              BUZZWORD GENERATOR\");\n\t\toutput.println(\"   CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\toutput.println();\n\t\toutput.println();\n\t\toutput.println();\n\t\toutput.println(\"THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\");\n\t\toutput.println(\"'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\");\n\t\toutput.println(\"AND SPEECHES.  WHENEVER A QUESTION MARK IS PRINTED,\");\n\t\toutput.println(\"TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT.\");\n\t\toutput.println();\n\t\toutput.println();\n\t\toutput.println(\"HERE'S THE FIRST PHRASE:\");\n\n\t\tdo {\n\t\t\toutput.println(buzzwords.get());\n\t\t\toutput.println();\n\t\t\toutput.print(\"?\");\n\t\t} while (\"Y\".equals(input.nextLine().toUpperCase()));\n\n\t\toutput.println(\"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\");\n\t}\n}\n"
  },
  {
    "path": "20_Buzzword/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "20_Buzzword/javascript/buzzword.html",
    "content": "<html>\n<head>\n<title>BUZZWORD</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"buzzword.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "20_Buzzword/javascript/buzzword.js",
    "content": "// BUZZWORD\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a = [\"\",\n         \"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\",\n         \"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\"HETEROGENEOUS\",\n         \"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\",\n         \"INDIVIDUALIZED\",\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\",\n         \"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\",\n         \"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\",\n         \"MOTIVATIONAL\",\"CREATIVE\",\"GROUPING\",\"MODIFICATION\",\n         \"ACCOUNTABILITY\",\"PROCESS\",\"CORE CURRICULUM\",\"ALGORITHM\",\n         \"PERFORMANCE\",\"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\",\n         \"STRUCTURE\",\"FACILITY\",\"ENVIRONMENT\",\n         ];\n\n// Main program\nasync function main()\n{\n    print(tab(26) + \"BUZZWORD GENERATOR\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\\n\");\n    print(\"'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\\n\");\n    print(\"AND SPEECHES.  WHENEVER A QUESTION MARK IS PRINTED,\\n\");\n    print(\"TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"HERE'S THE FIRST PHRASE:\\n\");\n    do {\n        print(a[Math.floor(Math.random() * 13 + 1)] + \" \");\n        print(a[Math.floor(Math.random() * 13 + 14)] + \" \");\n        print(a[Math.floor(Math.random() * 13 + 27)] + \"\\n\");\n        print(\"\\n\");\n        y = await input();\n    } while (y == \"Y\") ;\n    print(\"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "20_Buzzword/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "20_Buzzword/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "20_Buzzword/lua/buzzword.lua",
    "content": "--- Buzzword\n--- Ported by Brian Wilkins.\n--- Updated for modern buzzwords and corporate-speak\n\nprint [[\n                        BUZZWORD GENERATOR\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n]]\n\nprint [[\n\n\nTHIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\n'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\nAND SPEECHES.  WHENEVER A QUESTION MARK IS PRINTED,\nTYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT.\n]]\n\nlocal phraseList = {\"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\",\n               \"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\"HETEROGENEOUS\",\n               \"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\",\n               \"INDIVIDUALIZED\",\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\",\n               \"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\",\n               \"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\",\n               \"MOTIVATIONAL\",\"CREATIVE\",\"GROUPING\",\"MODIFICATION\",\n               \"ACCOUNTABILITY\",\"PROCESS\",\"CORE CURRICULUM\",\"ALGORITHM\",\n               \"PERFORMANCE\",\"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\",\n               \"STRUCTURE\",\"FACILITY\",\"ENVIRONMENT\"}\n\n--- Credit to https://stackoverflow.com/a/33468353/19232282\n--- for the pickPhrase function\nlocal copyPhraseList = {}\n\nfunction pickPhrase()\n   local i\n   -- make a copy of the original table if we ran out of phrases\n   if #copyPhraseList == 0 then\n      for k,v in pairs(phraseList) do\n         copyPhraseList[k] = v\n      end\n   end\n               \n   -- pick a random element from the copy  \n   i = math.random(#copyPhraseList)\n   phrase = copyPhraseList[i] \n               \n   -- remove phrase from copy\n   table.remove(copyPhraseList, i)\n               \n   return phrase\nend\n\n--- Reused from Bagels.lua\nfunction getInput(prompt)\n    io.write(prompt)\n    io.flush()\n    local input = io.read(\"l\") \n    if not input then  --- test for EOF\n        print(\"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\")\n        os.exit(0)\n    end\n    return input\nend\n\nfor i=1,3,1 do\n    ::phrasepick::\n    io.write (pickPhrase() .. \" \")\n    io.write (pickPhrase() .. \" \")\n    io.write (pickPhrase())\n    print()\n    io.stdin:flush()\n    local response = getInput(\"? \")\n    if response:match(\"[yY].*\") then\n       goto phrasepick\n    else\n       print(\"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\")\n       os.exit(0)\n    end\nend\n\n"
  },
  {
    "path": "20_Buzzword/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "20_Buzzword/perl/buzzword.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x26 . \"BUZZWORD GENERATOR\\n\";\nprint ' 'x15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN\\n\";\nprint \"'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS\\n\";\nprint \"AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED,\\n\";\nprint \"TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT.\\n\";\nprint \"\\n\\n\"; print \"HERE'S THE FIRST PHRASE; \";\n\nmy @A= (\"\",\n\t\"ABILITY\",\"BASAL\",\"BEHAVIORAL\",\"CHILD-CENTERED\",\n\t\"DIFFERENTIATED\",\"DISCOVERY\",\"FLEXIBLE\",\"HETEROGENEOUS\",\n\t\"HOMOGENEOUS\",\"MANIPULATIVE\",\"MODULAR\",\"TAVISTOCK\",\n\t\"INDIVIDUALIZED\",\"LEARNING\",\"EVALUATIVE\",\"OBJECTIVE\",\n\t\"COGNITIVE\",\"ENRICHMENT\",\"SCHEDULING\",\"HUMANISTIC\",\n\t\"INTEGRATED\",\"NON-GRADED\",\"TRAINING\",\"VERTICAL AGE\",\n\t\"MOTIVATIONAL\",\"CREATIVE\",\"GROUPING\",\"MODIFICATION\",\n\t\"ACCOUNTABILITY\",\"PROCESS\",\"CORE CURRICULUM\",\"ALGORITHM\",\n\t\"PERFORMANCE\",\"REINFORCEMENT\",\"OPEN CLASSROOM\",\"RESOURCE\",\n\t\"STRUCTURE\",\"FACILITY\",\"ENVIRONMENT\"\n\t);\n\nmy $Y;\ndo {\n\tprint $A[int(13*rand(1)+1)].\" \";\n\tprint $A[int(13*rand(1)+14)].\" \";\n\tprint $A[int(13*rand(1)+27)]; print \"\\n\";\n\tprint \"? \";\n\tchomp ($Y = <STDIN>);\n\t} until ($Y ne \"Y\");\n\nprint \"COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!\\n\";\nexit;\n"
  },
  {
    "path": "20_Buzzword/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "20_Buzzword/python/buzzword.py",
    "content": "\"\"\"\r\nBuzzword Generator\r\n\r\nFrom: BASIC Computer Games (1978)\r\n      Edited by David H. Ahl\r\n\r\n\"This program is an invaluable aid for preparing speeches and\r\n briefings about education technology.  This buzzword generator\r\n provides sets of three highly-acceptable words to work into your\r\n material.  Your audience will never know that the phrases don't\r\n really mean much of anything because they sound so great!  Full\r\n instructions for running are given in the program.\r\n\r\n\"This version of Buzzword was written by David Ahl.\"\r\n\r\n\r\nPython port by Jeff Jetton, 2019\r\n\"\"\"\r\n\r\n\r\nimport random\r\n\r\n\r\ndef main() -> None:\r\n    words = [\r\n        [\r\n            \"Ability\",\r\n            \"Basal\",\r\n            \"Behavioral\",\r\n            \"Child-centered\",\r\n            \"Differentiated\",\r\n            \"Discovery\",\r\n            \"Flexible\",\r\n            \"Heterogeneous\",\r\n            \"Homogenous\",\r\n            \"Manipulative\",\r\n            \"Modular\",\r\n            \"Tavistock\",\r\n            \"Individualized\",\r\n        ],\r\n        [\r\n            \"learning\",\r\n            \"evaluative\",\r\n            \"objective\",\r\n            \"cognitive\",\r\n            \"enrichment\",\r\n            \"scheduling\",\r\n            \"humanistic\",\r\n            \"integrated\",\r\n            \"non-graded\",\r\n            \"training\",\r\n            \"vertical age\",\r\n            \"motivational\",\r\n            \"creative\",\r\n        ],\r\n        [\r\n            \"grouping\",\r\n            \"modification\",\r\n            \"accountability\",\r\n            \"process\",\r\n            \"core curriculum\",\r\n            \"algorithm\",\r\n            \"performance\",\r\n            \"reinforcement\",\r\n            \"open classroom\",\r\n            \"resource\",\r\n            \"structure\",\r\n            \"facility\",\r\n            \"environment\",\r\n        ],\r\n    ]\r\n\r\n    # Display intro text\r\n    print(\"\\n           Buzzword Generator\")\r\n    print(\"Creative Computing  Morristown, New Jersey\")\r\n    print(\"\\n\\n\")\r\n    print(\"This program prints highly acceptable phrases in\")\r\n    print(\"'educator-speak' that you can work into reports\")\r\n    print(\"and speeches.  Whenever a question mark is printed,\")\r\n    print(\"type a 'Y' for another phrase or 'N' to quit.\")\r\n    print(\"\\n\\nHere's the first phrase:\")\r\n\r\n    still_running = True\r\n    while still_running:\r\n        phrase = \"\"\r\n        for section in words:\r\n            if len(phrase) > 0:\r\n                phrase += \" \"\r\n            phrase += section[random.randint(0, len(section) - 1)]\r\n\r\n        print(phrase)\r\n        print()\r\n\r\n        response = input(\"? \")\r\n        try:\r\n            if response.upper()[0] != \"Y\":\r\n                still_running = False\r\n        except Exception:\r\n            still_running = False\r\n\r\n    print(\"Come back when you need help with another report!\\n\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n\r\n######################################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   The original program stored all 39 words in one array, then\r\n#   built the buzzword phrases by randomly sampling from each of the\r\n#   three regions of the array (1-13, 14-26, and 27-39).\r\n#\r\n#   Here, we're storing the words for each section in separate\r\n#   tuples.  That makes it easy to just loop through the sections\r\n#   to stitch the phrase together, and it easily accomodates adding\r\n#   (or removing) elements from any section.  They don't all need to\r\n#   be the same length.\r\n#\r\n#   The author of this program (and founder of Creative Computing\r\n#   magazine) first started working at DEC--Digital Equipment\r\n#   Corporation--as a consultant helping the company market its\r\n#   computers as educational products.  He later was editor of a DEC\r\n#   newsletter named \"EDU\" that focused on using computers in an\r\n#   educational setting.  No surprise, then, that the buzzwords in\r\n#   this program were targeted towards educators!\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   Try adding more/different words.  Better yet, add a third\r\n#   dimnension to our WORDS tuple to add new sets of words that\r\n#   might pertain to different fields.  What would business buzzwords\r\n#   be? Engineering buzzwords?  Art/music buzzwords?  Let the user\r\n#   choose a field and pick the buzzwords accordingly.\r\n#\r\n######################################################################\r\n"
  },
  {
    "path": "20_Buzzword/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "20_Buzzword/ruby/buzzword.rb",
    "content": "######################################################################\r\n#\r\n# Buzzword Generator\r\n#\r\n# From: BASIC Computer Games (1978)\r\n#       Edited by David H. Ahl\r\n#\r\n# \"This program is an invaluable aid for preparing speeches and\r\n#  briefings about education technology.  This buzzword generator\r\n#  provides sets of three highly-acceptable words to work into your\r\n#  material.  Your audience will never know that the phrases don't\r\n#  really mean much of anything because they sound so great!  Full\r\n#  instructions for running are given in the program.\r\n#\r\n# \"This version of Buzzword was written by David Ahl.\"\r\n#\r\n#\r\n# Ruby port by Leslie Viljoen, 2021\r\n#\r\n######################################################################\r\n\r\nWORDS = [[\"Ability\", \"Basal\", \"Behavioral\", \"Child-centered\",\r\n           \"Differentiated\", \"Discovery\", \"Flexible\", \"Heterogeneous\",\r\n           \"Homogenous\", \"Manipulative\", \"Modular\", \"Tavistock\",\r\n           \"Individualized\"],\r\n\r\n          [\"learning\", \"evaluative\", \"objective\", \"cognitive\",\r\n           \"enrichment\", \"scheduling\", \"humanistic\", \"integrated\",\r\n           \"non-graded\", \"training\", \"vertical age\", \"motivational\",\r\n           \"creative\"] ,\r\n\r\n          [\"grouping\", \"modification\", \"accountability\", \"process\",\r\n           \"core curriculum\", \"algorithm\", \"performance\",\r\n           \"reinforcement\", \"open classroom\", \"resource\", \"structure\",\r\n           \"facility\",\"environment\"]]\r\n\r\n\r\n# Display intro text\r\n\r\nputs \"\\n           Buzzword Generator\"\r\nputs \"Creative Computing  Morristown, New Jersey\"\r\nputs \"\\n\\n\"\r\nputs \"This program prints highly acceptable phrases in\"\r\nputs \"'educator-speak' that you can work into reports\"\r\nputs \"and speeches.  Whenever a question mark is printed,\"\r\nputs \"type a 'Y' for another phrase or 'N' to quit.\"\r\nputs \"\\n\\nHere's the first phrase:\"\r\n\r\nloop do\r\n    phrase = []\r\n\r\n    prefix, body, postfix = WORDS\r\n\r\n    phrase << prefix[rand(prefix.length)]\r\n    phrase << body[rand(body.length)]\r\n    phrase << postfix[rand(postfix.length)]\r\n\r\n    puts phrase.join(' ')\r\n    puts \"\\n\"\r\n\r\n    print \"?\"\r\n    response = gets\r\n\r\n    break unless response.upcase.start_with?('Y')\r\nend\r\n\r\nputs \"Come back when you need help with another report!\\n\"\r\n\r\n\r\n######################################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   The original program stored all 39 words in one array, then\r\n#   built the buzzword phrases by randomly sampling from each of the\r\n#   three regions of the array (1-13, 14-26, and 27-39).\r\n#\r\n#   Instead, we're storing the words for each section in three\r\n#   separate arrays. That makes it easy to loop through the sections\r\n#   to stitch the phrase together, and it easily accomodates adding\r\n#   (or removing) elements from any section.  They don't all need to\r\n#   be the same length.\r\n#\r\n#   The author of this program (and founder of Creative Computing\r\n#   magazine) first started working at DEC--Digital Equipment\r\n#   Corporation--as a consultant helping the company market its\r\n#   computers as educational products.  He later was editor of a DEC\r\n#   newsletter named \"EDU\" that focused on using computers in an\r\n#   educational setting.  No surprise, then, that the buzzwords in\r\n#   this program were targeted towards educators!\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   Try adding more/different words. Better yet, add a third\r\n#   array to the WORDS array to add new sets of words that\r\n#   might pertain to different fields. What would business buzzwords\r\n#   be? Engineering buzzwords?  Art/music buzzwords?  Let the user\r\n#   choose a field and pick the buzzwords accordingly.\r\n#\r\n######################################################################\r\n"
  },
  {
    "path": "20_Buzzword/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "20_Buzzword/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "20_Buzzword/rust/src/main.rs",
    "content": "use rand::seq::SliceRandom;\nuse std::io::{self, Write};\n\nfn main() {\n    let words = vec![\n        vec![\n            \"Ability\",\n            \"Basal\",\n            \"Behavioral\",\n            \"Child-centered\",\n            \"Differentiated\",\n            \"Discovery\",\n            \"Flexible\",\n            \"Heterogeneous\",\n            \"Homogenous\",\n            \"Manipulative\",\n            \"Modular\",\n            \"Tavistock\",\n            \"Individualized\",\n        ],\n        vec![\n            \"learning\",\n            \"evaluative\",\n            \"objective\",\n            \"cognitive\",\n            \"enrichment\",\n            \"scheduling\",\n            \"humanistic\",\n            \"integrated\",\n            \"non-graded\",\n            \"training\",\n            \"vertical age\",\n            \"motivational\",\n            \"creative\",\n        ],\n        vec![\n            \"grouping\",\n            \"modification\",\n            \"accountability\",\n            \"process\",\n            \"core curriculum\",\n            \"algorithm\",\n            \"performance\",\n            \"reinforcement\",\n            \"open classroom\",\n            \"resource\",\n            \"structure\",\n            \"facility\",\n            \"environment\",\n        ],\n    ];\n\n    // intro text\n    println!(\"\\n           Buzzword Generator\");\n    println!(\"Creative Computing  Morristown, New Jersey\");\n    println!(\"\\n\\n\");\n    println!(\"This program prints highly acceptable phrases in\");\n    println!(\"'educator-speak' that you can work into reports\");\n    println!(\"and speeches.  Whenever a question mark is printed,\");\n    println!(\"type a 'Y' for another phrase or 'N' to quit.\");\n    println!(\"\\n\\nHere's the first phrase:\");\n\n    let mut continue_running: bool = true;\n\n    while continue_running {\n        let mut first_word: bool = true;\n        for section in &words {\n            if !first_word {\n                print!(\" \");\n            }\n            first_word = false;\n            print!(\"{}\", section.choose(&mut rand::thread_rng()).unwrap());\n        }\n        print!(\"\\n\\n? \");\n        io::stdout().flush().unwrap();\n\n        let mut cont_question: String = String::new();\n        io::stdin()\n            .read_line(&mut cont_question)\n            .expect(\"Failed to read the line\");\n        if !cont_question.to_uppercase().starts_with(\"Y\") {\n            continue_running = false;\n        }\n    }\n    println!(\"Come back when you need help with another report!\\n\");\n\n}\n\n\n/////////////////////////////////////////////////////////////////////////\n//\n// Porting Notes\n//\n//   The original program stored all 39 words in one array, then\n//   built the buzzword phrases by randomly sampling from each of the\n//   three regions of the array (1-13, 14-26, and 27-39).\n//\n//   Here, we're storing the words for each section in separate\n//   tuples.  That makes it easy to just loop through the sections\n//   to stitch the phrase together, and it easily accommodates adding\n//   (or removing) elements from any section.  They don't all need to\n//   be the same length.\n//\n//   The author of this program (and founder of Creative Computing\n//   magazine) first started working at DEC--Digital Equipment\n//   Corporation--as a consultant helping the company market its\n//   computers as educational products.  He later was editor of a DEC\n//   newsletter named \"EDU\" that focused on using computers in an\n//   educational setting.  No surprise, then, that the buzzwords in\n//   this program were targeted towards educators!\n//\n/////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "20_Buzzword/vbnet/Buzzword.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Buzzword\", \"Buzzword.vbproj\", \"{B2BD53F2-82C3-4729-BA82-DB96E18F8666}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B2BD53F2-82C3-4729-BA82-DB96E18F8666}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B2BD53F2-82C3-4729-BA82-DB96E18F8666}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B2BD53F2-82C3-4729-BA82-DB96E18F8666}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B2BD53F2-82C3-4729-BA82-DB96E18F8666}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "20_Buzzword/vbnet/Buzzword.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Buzzword</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "20_Buzzword/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "21_Calendar/README.md",
    "content": "### Calendar\n\nThis program prints out a calendar for any year. You must specify the starting day of the week of the year:\n- 0: Sunday\n- -1: Monday\n- -2: Tuesday\n- -3: Wednesday\n- -4: Thursday\n- -5: Friday\n- -6: Saturday\n\nYou can determine this by using the program WEEKDAY. You must also make two changes for leap years. The program listing describes the necessary changes. Running the program produces a nice 12-month calendar.\n\nThe program was written by Geoffrey Chase of the Abbey, Portsmouth, Rhode Island.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=37)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=52)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- While many modern environments have time/date functions that would make this program both easier and more automatic, in these ports we are choosing to do without them, as in the original program.\n\n- Some ports choose to ask the user the starting day of week, and whether it's a leap year, rather than force changes to the code to fit the desired year.\n"
  },
  {
    "path": "21_Calendar/calendar.bas",
    "content": "10 PRINT TAB(32);\"CALENDAR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 REM     VALUES FOR 1979 - SEE NOTES\n110 DIM M(12)\n120 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n130 D=-1: REM 1979 STARTS ON MONDAY (0=SUN, -1=MON, -2=TUES...)\n140 S=0\n150 REM     READ DAYS OF EACH MONTH\n160 FOR N=0 TO 12: READ M(N): NEXT N\n170 REM\n180 FOR N=1 TO 12\n190 PRINT: PRINT: S=S+M(N-1)\n200 PRINT \"**\";S;TAB(7);\n210 FOR I=1 TO 18: PRINT \"*\";: NEXT I\n220 ON N GOTO 230,240,250,260,270,280,290,300,310,320,330,340\n230 PRINT \" JANUARY \";: GOTO 350\n240 PRINT \" FEBRUARY\";: GOTO 350\n250 PRINT \"  MARCH  \";: GOTO 350\n260 PRINT \"  APRIL  \";: GOTO 350\n270 PRINT \"   MAY   \";: GOTO 350\n280 PRINT \"   JUNE  \";: GOTO 350\n290 PRINT \"   JULY  \";: GOTO 350\n300 PRINT \"  AUGUST \";: GOTO 350\n310 PRINT \"SEPTEMBER\";: GOTO 350\n320 PRINT \" OCTOBER \";: GOTO 350\n330 PRINT \" NOVEMBER\";: GOTO 350\n340 PRINT \" DECEMBER\";\n350 FOR I=1 TO 18: PRINT \"*\";: NEXT I\n360 PRINT 365-S;\"**\";\n370 REM   366-S;     ON LEAP YEARS\n380 PRINT CHR$(10): PRINT \"     S       M       T       W\";\n390 PRINT \"       T       F       S\"\n400 PRINT\n410 FOR I=1 TO 59: PRINT \"*\";: NEXT I\n420 REM\n430 FOR W=1 TO 6\n440 PRINT CHR$(10)\n450 PRINT TAB(4)\n460 REM\n470 FOR G=1 TO 7\n480 D=D+1\n490 D2=D-S\n500 IF D2>M(N) THEN 580\n510 IF D2>0 THEN PRINT D2;\n520 PRINT TAB(4+8*G);\n530 NEXT G\n540 REM\n550 IF D2=M(N) THEN 590\n560 NEXT W\n570 REM\n580 D=D-G\n590 NEXT N\n600 REM\n610 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I\n620 DATA 0,31,28,31,30,31,30,31,31,30,31,30,31\n630 REM  0,31,29,  ..., ON LEAP YEARS\n640 END\n"
  },
  {
    "path": "21_Calendar/csharp/Calendar.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "21_Calendar/csharp/Calendar.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31613.86\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Calendar\", \"Calendar.csproj\", \"{1EADFB6C-4496-42C2-A80F-84FEC3F061D1}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1EADFB6C-4496-42C2-A80F-84FEC3F061D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1EADFB6C-4496-42C2-A80F-84FEC3F061D1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1EADFB6C-4496-42C2-A80F-84FEC3F061D1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1EADFB6C-4496-42C2-A80F-84FEC3F061D1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1B423C35-492F-4AF8-97FC-BEC69B44EC8D}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "21_Calendar/csharp/Program.cs",
    "content": "﻿using System;\n\n/*\n 21_Calendar in C# for basic-computer-games\n Converted by luminoso-256\n*/\n\nnamespace _21_calendar\n{\n    class Program\n    {\n        //basic has a TAB function. We do not by default, so we make our own!\n        static string Tab(int numspaces)\n        {\n            string space = \"\";\n            //loop as many times as there are spaces specified, and add a space each time\n            while (numspaces > 0)\n            {\n                //add the space\n                space += \" \";\n                //decrement the loop variable so we don't keep going forever!\n                numspaces--;\n            }\n            return space;\n        }\n\n        static void Main(string[] args)\n        {\n            // print the \"title\" of our program\n            // the usage of Write*Line* means we do not have to specify a newline (\\n)\n            Console.WriteLine(Tab(32) + \"CALENDAR\");\n            Console.WriteLine(Tab(15) + \"CREATE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            //give us some space.\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"\");\n\n            //establish some variables needed to print out a calculator\n\n            //the length of each month in days. On a leap year, the start of this would be\n            // 0, 31, 29 to account for Feb. the 0 at the start is for days elapsed to work right in Jan.\n            int[] monthLengths = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // m in original source\n\n            //the starting day of the month. in 1979 this was monday\n            // 0 = sun, -1 = mon, -2 = tue, -3 = wed, etc.\n            int day = -1; // called d in original source\n\n            //how much time in the year has gone by?\n            int elapsed = 0; // called s in original source\n\n            //loop through printing all the months.\n            for (int month = 1; month <= 12; month++) //month is called n in original source\n            {\n                //pad some space\n                Console.WriteLine(\"\");\n                Console.WriteLine(\"\");\n                //increment days elapsed\n                elapsed += monthLengths[month - 1];\n                //build our header for this month of the calendar\n                string header = \"** \" + elapsed;\n                //add padding as needed\n                while (header.Length < 7)\n                {\n                    header += \" \";\n                }\n                for (int i = 1; i <= 18; i++)\n                {\n                    header += \"*\";\n                }\n                //determine what month it is, add text accordingly\n                switch (month) {\n                    case 1: header += \" JANUARY \"; break;\n                    case 2: header += \" FEBRUARY\"; break;\n                    case 3: header += \"  MARCH  \"; break;\n                    case 4: header += \"  APRIL  \"; break;\n                    case 5: header += \"   MAY   \"; break;\n                    case 6: header += \"   JUNE  \"; break;\n                    case 7: header += \"   JULY  \"; break;\n                    case 8: header += \"  AUGUST \"; break;\n                    case 9: header += \"SEPTEMBER\"; break;\n                    case 10: header += \" OCTOBER \"; break;\n                    case 11: header += \" NOVEMBER\"; break;\n                    case 12: header += \" DECEMBER\"; break;\n                }\n                //more padding\n                for (int i = 1; i <= 18; i++)\n                {\n                    header += \"*\";\n                }\n                header += \"  \";\n                // how many days left till the year's over?\n                header += (365 - elapsed) + \" **\"; // on leap years 366\n                Console.WriteLine(header);\n                //dates\n                Console.WriteLine(\"     S       M       T       W       T       F       S\");\n                Console.WriteLine(\" \");\n\n                string weekOutput = \"\";\n                for (int i = 1; i <= 59; i++)\n                {\n                    weekOutput += \"*\";\n                }\n                //init some vars ahead of time\n                int g = 0;\n                int d2 = 0;\n                //go through the weeks and days\n                for (int week = 1; week <= 6; week++)\n                {\n                    Console.WriteLine(weekOutput);\n                    weekOutput = \"    \";\n                    for (g = 1; g <= 7; g++)\n                    {\n                        //add one to the day\n                        day++;\n                        d2 = day - elapsed;\n                        //check if we're done with this month\n                        if (d2 > monthLengths[month])\n                        {\n                            week = 6;\n                            break;\n                        }\n                        //should we print this day?\n                        if (d2 > 0)\n                        {\n                            weekOutput += d2;\n                        }\n                        //padding\n                        while (weekOutput.Length < 4 + 8 * g)\n                        {\n                            weekOutput += \" \";\n                        }\n                    }\n                    if (d2 == monthLengths[month])\n                    {\n                        day += g;\n                        break;\n                    }\n                }\n                day -= g;\n                Console.WriteLine(weekOutput);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "21_Calendar/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "21_Calendar/java/Calendar.java",
    "content": "/**\n * Game of Calendar\n * <p>\n * Based on the BASIC game of Calendar here\n * https://github.com/coding-horror/basic-computer-games/blob/main/21%20Calendar/calendar.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Calendar {\n\n  private static final int NUM_WEEK_ROWS = 6;\n  private static final int NUM_DAYS_PER_WEEK = 7;\n  private static final int NUM_MONTHS_PER_YEAR = 12;\n  private static final int[] daysPerMonth = { 0, 31, 28, 31, 30, 31, 30,\n                                             31, 31, 30, 31, 30, 31 };\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(31) + \"CALENDAR\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    int dayOfMonth = 0;\n    int dayOfWeek = 0;\n    int dayOfYear = 0;\n    int daysTotal = 0;\n    int index = 0;\n    int month = 0;\n    int row = 0;\n\n    String lineContent = \"\";\n\n    for (index = 1; index <= 6; index++) {\n      System.out.println(\"\");\n    }\n\n    daysTotal = -1;\n    dayOfYear = 0;\n\n    System.out.println(\"\");\n\n    // Begin loop through all months\n    for (month = 1; month <= NUM_MONTHS_PER_YEAR; month++) {\n\n      System.out.println(\"\");\n\n      dayOfYear = dayOfYear + daysPerMonth[month - 1];\n\n      lineContent = String.format(\"** %-3d\" + \"*\".repeat(18), dayOfYear);\n\n      switch (month) {\n        case 1:\n          lineContent += \" JANUARY \";\n          break;\n        case 2:\n          lineContent += \" FEBRUARY\";\n          break;\n        case 3:\n          lineContent += \"  MARCH  \";\n          break;\n        case 4:\n          lineContent += \"  APRIL  \";\n          break;\n        case 5:\n          lineContent += \"   MAY   \";\n          break;\n        case 6:\n          lineContent += \"   JUNE  \";\n          break;\n        case 7:\n          lineContent += \"   JULY  \";\n          break;\n        case 8:\n          lineContent += \"  AUGUST \";\n          break;\n        case 9:\n          lineContent += \"SEPTEMBER\";\n          break;\n        case 10:\n          lineContent += \" OCTOBER \";\n          break;\n        case 11:\n          lineContent += \" NOVEMBER\";\n          break;\n        case 12:\n          lineContent += \" DECEMBER\";\n          break;\n        default:\n          break;\n      }\n\n      lineContent += \"*\".repeat(18) + \" \" + (365 - dayOfYear) + \"**\";\n\n      System.out.println(lineContent);\n      System.out.println(\"\");\n\n      System.out.print(\"     S       M       T       W\");\n      System.out.println(\"       T       F       S\");\n      System.out.println(\"\");\n\n      System.out.println(\"*\".repeat(59));\n\n      // Begin loop through each week row\n      for (row = 1; row <= NUM_WEEK_ROWS; row++) {\n\n        System.out.println(\"\");\n\n        lineContent = \"    \";\n\n        // Begin loop through days of the week\n        for (dayOfWeek = 1; dayOfWeek <= NUM_DAYS_PER_WEEK; dayOfWeek++) {\n\n          daysTotal++;\n\n          dayOfMonth = daysTotal - dayOfYear;\n\n          if (dayOfMonth > daysPerMonth[month]) {\n            row = 6;\n            break;\n          }\n\n          if (dayOfMonth > 0) {\n            lineContent += dayOfMonth;\n          }\n\n          while (lineContent.length() < (4 + 8 * dayOfWeek)) {\n            lineContent += \" \";\n          }\n\n        }  // End loop through days of the week\n\n        if (dayOfMonth == daysPerMonth[month]) {\n          row = 6;\n          daysTotal += dayOfWeek;\n          System.out.println(lineContent);\n          break;\n        }\n\n        System.out.println(lineContent);\n\n      }  // End loop through each week row\n\n      daysTotal -= dayOfWeek;\n\n    }  // End loop through all months\n\n    for (index = 1; index <= 6; index++) {\n      System.out.println(\"\");\n    }\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    Calendar game = new Calendar();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class Calendar\n"
  },
  {
    "path": "21_Calendar/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "21_Calendar/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "21_Calendar/javascript/calendar.html",
    "content": "<html>\n<head>\n<title>CALENDAR</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"calendar.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "21_Calendar/javascript/calendar.js",
    "content": "// CALENDAR\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\nfunction print(str)\n{\n\tdocument.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction tab(space)\n{\n\tvar str = \"\";\n\twhile (space-- > 0)\n\t\tstr += \" \";\n\treturn str;\n}\n\nprint(tab(32) + \"CALENDAR\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\n\n//       0, 31, 29  ON LEAP YEARS\nvar m = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n\n// VALUES FOR 1979 - SEE NOTES\nfor (i = 1; i <= 6; i++)\n\tprint(\"\\n\");\n\nd = -1;\t// 1979 starts on Monday (0 = Sun, -1 = Monday, -2 = Tuesday)\ns = 0;\n\nfor (n = 1; n <= 12; n++) {\n\tprint(\"\\n\");\n\tprint(\"\\n\");\n\ts = s + m[n - 1];\n\tstr = \"**\" + s;\n\twhile (str.length < 7)\n\t\tstr += \" \";\n\tfor (i = 1; i <= 18; i++)\n\t\tstr += \"*\";\n\tswitch (n) {\n\t\tcase  1:\tstr += \" JANUARY \"; break;\n\t\tcase  2:\tstr += \" FEBRUARY\"; break;\n\t\tcase  3:\tstr += \"  MARCH  \"; break;\n\t\tcase  4:\tstr += \"  APRIL  \"; break;\n\t\tcase  5:\tstr += \"   MAY   \"; break;\n\t\tcase  6:\tstr += \"   JUNE  \"; break;\n\t\tcase  7:\tstr += \"   JULY  \"; break;\n\t\tcase  8:\tstr += \"  AUGUST \"; break;\n\t\tcase  9:\tstr += \"SEPTEMBER\"; break;\n\t\tcase 10:\tstr += \" OCTOBER \"; break;\n\t\tcase 11:\tstr += \" NOVEMBER\"; break;\n\t\tcase 12:\tstr += \" DECEMBER\"; break;\n\t}\n\tfor (i = 1; i <= 18; i++)\n\t\tstr += \"*\";\n\tstr += (365 - s) + \"**\";\n\t     // 366 - s on leap years\n\tprint(str + \"\\n\");\n\tprint(\"     S       M       T       W       T       F       S\\n\");\n\tprint(\"\\n\");\n\tstr = \"\";\n\tfor (i = 1; i <= 59; i++)\n\t\tstr += \"*\";\n\tfor (week = 1; week <= 6; week++) {\n\t\tprint(str + \"\\n\");\n\t\tstr = \"    \";\n\t\tfor (g = 1; g <= 7; g++) {\n\t\t\td++;\n\t\t\td2 = d - s;\n\t\t\tif (d2 > m[n]) {\n\t\t\t\tweek = 6;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (d2 > 0)\n\t\t\t\tstr += d2;\n\t\t\twhile (str.length < 4 + 8 * g)\n\t\t\t\tstr += \" \";\n\t\t}\n\t\tif (d2 == m[n]) {\n\t\t\td += g;\n\t\t\tbreak;\n\t\t}\n\t}\n\td -= g;\n\tprint(str + \"\\n\");\n}\n"
  },
  {
    "path": "21_Calendar/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "21_Calendar/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "21_Calendar/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nActually, this is not so much a port as a complete rewrite, making use of\nPerl's Posix time functionality. The calendar is for the current year (not\n1979), but you can get another year by specifying it on the command line, e.g.\n\n `perl 21_Calendar/perl/calendar.pl 2001`\n\nIt *may* even produce output in languages other than English. But the\nleftmost column will still be Sunday, even in locales where it is\ntypically Monday.\n"
  },
  {
    "path": "21_Calendar/perl/calendar.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse POSIX qw{ strftime };\nuse Term::ReadLine;     # Prompt and return user input\nuse Time::Local ();\n\nBEGIN {\n    *time_gm =\n        Time::Local->can( 'timegm_modern' ) ||\n        Time::Local->can( 'timegm' );\n}\n\nour $VERSION = '0.000_01';\n\nuse constant COLUMN_WIDTH       => 6;\nuse constant SECONDS_PER_DAY    => 86400;\n\nbinmode STDOUT, ':encoding(utf-8)';\n\nmy $year = @ARGV ? $ARGV[0] : ( localtime )[5] + 1900;\nmy $is_leap_year = is_leap_year( $year );\nmy $year_len = 365 + $is_leap_year;\nprint <<'EOD';\n                                CALENDAR\n               Creative Computing  Morristown, New Jersey\n\n\nEOD\n\nmy @mon_len = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );\n$mon_len[1] += $is_leap_year;\n\nforeach my $month ( 0 .. 11 ) {\n    my $epoch = time_gm( 0, 0, 0, 1, $month, $year );\n    my @start_time = gmtime( $epoch );\n    my ( $week_day, $year_day ) = @start_time[ 6, 7 ];\n    my $label = strftime( '%B %Y', @start_time );\n    $label .= ' ' x ( ( 14 - length $label ) / 2 );\n    printf \"\\n** %3d ****** %14s ****** %3d **\\n\",\n    $year_day, $label, $year_len - $year_day;\n    {\n        my $day = 1 + ( 7 - $week_day ) % 7;\n        foreach my $wd ( 0 .. 6 ) {\n            my $ep = time_gm( 0, 0, 0, $day + $wd, $month, $year );\n            printf '%*s', COLUMN_WIDTH, strftime( '%a', gmtime $ep );\n        }\n        print \"\\n\";\n    }\n    say '*' x ( COLUMN_WIDTH * 7 );\n    print ' ' x ( COLUMN_WIDTH * $week_day );\n    my $month_day = 1;\n    while ( $week_day < 7 ) {\n        printf '%*d', COLUMN_WIDTH, $month_day++;\n        $week_day++;\n    }\n    print \"\\n\";\n    $week_day = 0;\n    while ( $month_day <= $mon_len[$month] ) {\n        printf '%*d', COLUMN_WIDTH, $month_day++;\n        $week_day++;\n        unless ( $week_day % 7 ) {\n            print \"\\n\";\n            $week_day = 0;\n        }\n    }\n    print \"\\n\" if $week_day;\n\n}\n\nsub is_leap_year {\n    my ( $year ) = 1;\n    return 0 if $year % 4;\n    return 1 if $year % 100;\n    return 0 if $year % 400;\n    return 1;\n}\n\n__END__\n\n=head1 TITLE\n\ncalendar - Play the game 'Calendar' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n calendar.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of calendar, which is the 21st\nentry in Basic Computer Games.\n\nActually, it is not so much a port as a complete rewrite, making use of\nPerl's Posix time functionality. The calendar is for the current year\n(not 1979), but you can get another year by specifying it on the command\nline, e.g.\n\n perl 21_Calendar/perl/calendar.pl 2001\n\nIt B<may> even produce output in languages other than English. But the\nleftmost column will still be Sunday, even in locales where it is\ntypically Monday.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "21_Calendar/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "21_Calendar/python/calendar.py",
    "content": "\"\"\"\nCalendar\n\nFrom: BASIC Computer Games (1978)\n      Edited by David Ahl#\n\n   This program prints out a calendar\nfor any year. You must specify the\nstarting day of the week of the year in\nstatement 130. (Sunday(0), Monday\n(-1), Tuesday(-2), etc.) You can determine\nthis by using the program WEEKDAY.\nYou must also make two changes\nfor leap years in statement 360 and 620.\nThe program listing describes the necessary\nchanges. Running the program produces a\nnice 12-month calendar.\n   The program was written by Geofrey\nChase of the Abbey, Portsmouth, Rhode Island.\n\"\"\"\n\nfrom typing import Tuple\n\n\ndef parse_input() -> Tuple[int, bool]:\n    \"\"\"\n    function to parse input for weekday and leap year boolean\n    \"\"\"\n\n    days_mapping = {\n        \"sunday\": 0,\n        \"monday\": -1,\n        \"tuesday\": -2,\n        \"wednesday\": -3,\n        \"thursday\": -4,\n        \"friday\": -5,\n        \"saturday\": -6,\n    }\n\n    day = 0\n    leap_day = False\n\n    correct_day_input = False\n    while not correct_day_input:\n        weekday = input(\"INSERT THE STARTING DAY OF THE WEEK OF THE YEAR:\")\n\n        for day_k in days_mapping:\n            if weekday.lower() in day_k:\n                day = days_mapping[day_k]\n                correct_day_input = True\n                break\n\n    while True:\n        leap = input(\"IS IT A LEAP YEAR?:\")\n\n        if \"y\" in leap.lower():\n            leap_day = True\n            break\n\n        if \"n\" in leap.lower():\n            leap_day = False\n            break\n\n    return day, leap_day\n\n\ndef calendar(weekday: int, leap_year: bool) -> None:\n    \"\"\"\n    function to print a year's calendar.\n\n    input:\n        _weekday_: int - the initial day of the week (0=SUN, -1=MON, -2=TUES...)\n        _leap_year_: bool - indicates if the year is a leap year\n    \"\"\"\n    months_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    days = \"S        M        T        W        T        F        S\\n\"\n    sep = \"*\" * 59\n    years_day = 365\n    d = weekday\n\n    if leap_year:\n        months_days[2] = 29\n        years_day = 366\n\n    months_names = [\n        \" JANUARY \",\n        \" FEBRUARY\",\n        \"  MARCH  \",\n        \"  APRIL  \",\n        \"   MAY   \",\n        \"   JUNE  \",\n        \"   JULY  \",\n        \"  AUGUST \",\n        \"SEPTEMBER\",\n        \" OCTOBER \",\n        \" NOVEMBER\",\n        \" DECEMBER\",\n    ]\n\n    days_count = 0  # S in the original program\n\n    # main loop\n    for n in range(1, 13):\n        days_count += months_days[n - 1]\n        print(\n            f\"** {days_count} ****************** {months_names[n - 1]} \"\n            f\"****************** {years_day - days_count} **\\n\"\n        )\n        print(days)\n        print(sep)\n\n        for _ in range(1, 7):\n            print(\"\\n\")\n            for g in range(1, 8):  # noqa\n                d += 1\n                d2 = d - days_count\n\n                if d2 > months_days[n]:\n                    break\n\n                if d2 <= 0:\n                    print(\"  \", end=\"       \")\n                elif d2 < 10:\n                    print(f\" {d2}\", end=\"       \")\n                else:\n                    print(f\"{d2}\", end=\"       \")\n            print()\n\n            if d2 >= months_days[n]:\n                break\n\n        if d2 > months_days[n]:\n            d -= g\n\n        print(\"\\n\")\n\n    print(\"\\n\")\n\n\ndef main() -> None:\n    print(\" \" * 32 + \"CALENDAR\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\" * 11)\n\n    day, leap_year = parse_input()\n    calendar(day, leap_year)\n\n\nif __name__ == \"__main__\":\n    main()\n\n########################################################\n#\n# Porting notes:\n#\n# It has been added an input at the beginning of the\n# program so the user can specify the first day of the\n# week of the year and if the year is leap or not.\n#\n########################################################\n"
  },
  {
    "path": "21_Calendar/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "21_Calendar/ruby/calendar.rb",
    "content": "class Calendar\n  def parse_input\n    days_mapping = {\n      \"sunday\": 0,\n      \"monday\": -1,\n      \"tuesday\": -2,\n      \"wednesday\": -3,\n      \"thursday\": -4,\n      \"friday\": -5,\n      \"saturday\": -6,\n    }\n\n    day = 0\n    leap_day = false\n    correct_day_input = false\n\n    while !correct_day_input \n      print \"INSERT THE STARTING DAY OF THE WEEK OF THE YEAR: \"\n      weekday = gets.chomp!\n\n      days_mapping.each do |k, v|\n        if k.to_s == weekday.downcase.to_s\n          day = v\n          correct_day_input = true\n          break\n        end\n      end\n    end\n\n    while true\n      print \"IS IT A LEAP YEAR?: \"\n      leap = gets.chomp!\n      if \"y\" == leap.downcase.to_s\n        leap_day = true\n        break\n      end\n\n      if \"n\" == leap.downcase.to_s\n        leap_day = false\n        break\n      end\n    end\n\n    return day, leap_day\n  end\n\n  def start(weekday, leap_year)\n    months_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    days = \"S        M        T        W        T        F        S\\n\"\n    sep = \"*\" * 59\n    years_day = 365\n    d = weekday\n\n    if leap_year\n      months_days[2] = 29\n      years_day = 366\n    end\n\n    months_names = [\n      \" JANUARY \",\n      \" FEBRUARY\",\n      \"  MARCH  \",\n      \"  APRIL  \",\n      \"   MAY   \",\n      \"   JUNE  \",\n      \"   JULY  \",\n      \"  AUGUST \",\n      \"SEPTEMBER\",\n      \" OCTOBER \",\n      \" NOVEMBER\",\n      \" DECEMBER\",\n    ]\n\n    days_count = 0\n\n    for n in (1..12) do\n      days_count += months_days[n - 1]\n      print \"** #{days_count} ****************** #{months_names[n - 1]} ****************** #{years_day - days_count} **\\n\"\n      print days\n      print sep\n      for nnn in (1..6) do\n        print \"\\n\"\n        for g in (1..7) do\n          d += 1\n          d2 = d - days_count\n\n          break if d2 > months_days[n]\n\n          if d2 <= 0\n            print \"         \"\n          elsif d2 < 10\n            print \" #{d2}       \"\n          else\n            print \"#{d2}       \"\n          end\n        end\n\n        print \"\\n\\n\"\n\n        break if d2 >= months_days[n]\n      end\n      d -= g if d2 > months_days[n]\n      print \"\\n\"\n    end\n    print \"\\n\"\n  end\nend\n\nif __FILE__ == $0\n  calendar = Calendar.new\n  input = calendar.parse_input\n  calendar.start(input[0], input[1])\nend"
  },
  {
    "path": "21_Calendar/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "21_Calendar/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by [Uğur Küpeli](https://github.com/ugurkupeli)"
  },
  {
    "path": "21_Calendar/rust/src/main.rs",
    "content": "use std::io::stdin;\n\nconst WIDTH: usize = 64;\nconst DAYS_WIDTH: usize = WIDTH / 8;\nconst MONTH_WIDTH: usize = WIDTH - (DAYS_WIDTH * 2);\nconst DAY_NUMS_WIDTH: usize = WIDTH / 7;\n\nconst DAYS: [&str; 7] = [\n    \"SUNDAY\",\n    \"MONDAY\",\n    \"TUESDAY\",\n    \"WEDNESDAY\",\n    \"THURSDAY\",\n    \"FRIDAY\",\n    \"SATURDAY\",\n];\n\nfn main() {\n    println!(\"\\n\\t\\t CALENDAR\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n\n    let (starting_day, leap_year) = prompt();\n    let (months, total_days) = get_months_and_days(leap_year);\n\n    let mut days_passed = 0;\n    let mut current_day_index = DAYS.iter().position(|d| *d == starting_day).unwrap();\n\n    for (month, days) in months {\n        print_header(month, days_passed, total_days - days_passed);\n        print_days(&mut current_day_index, days);\n        days_passed += days as u16;\n        println!(\"\\n\");\n    }\n}\n\nfn prompt() -> (String, bool) {\n    let mut day = String::new();\n\n    loop {\n        println!(\"\\nFirst day of the year?\");\n        if let Ok(_) = stdin().read_line(&mut day) {\n            day = day.trim().to_uppercase();\n            if DAYS.contains(&day.as_str()) {\n                break;\n            } else {\n                day.clear();\n            }\n        }\n    }\n\n    let mut leap = false;\n\n    loop {\n        println!(\"Is this a leap year?\");\n        let mut input = String::new();\n        if let Ok(_) = stdin().read_line(&mut input) {\n            match input.to_uppercase().trim() {\n                \"Y\" | \"YES\" => {\n                    leap = true;\n                    break;\n                }\n                \"N\" | \"NO\" => break,\n                _ => (),\n            }\n        }\n    }\n\n    println!();\n    (day, leap)\n}\n\nfn get_months_and_days(leap_year: bool) -> (Vec<(String, u8)>, u16) {\n    let months = [\n        \"JANUARY\",\n        \"FEBUARY\",\n        \"MARCH\",\n        \"APRIL\",\n        \"MAY\",\n        \"JUNE\",\n        \"JULY\",\n        \"AUGUST\",\n        \"SEPTEMBER\",\n        \"OCTOBER\",\n        \"NOVEMBER\",\n        \"DECEMBER\",\n    ];\n\n    let mut months_with_days = Vec::new();\n    let mut total_days: u16 = 0;\n\n    for (i, month) in months.iter().enumerate() {\n        let days = if i == 1 {\n            if leap_year {\n                29u8\n            } else {\n                28\n            }\n        } else if if i < 7 { (i % 2) == 0 } else { (i % 2) != 0 } {\n            31\n        } else {\n            30\n        };\n\n        total_days += days as u16;\n        months_with_days.push((month.to_string(), days));\n    }\n\n    (months_with_days, total_days)\n}\n\nfn print_between(s: String, w: usize, star: bool) {\n    let s = format!(\" {s} \");\n    if star {\n        print!(\"{:*^w$}\", s);\n        return;\n    }\n    print!(\"{:^w$}\", s);\n}\n\nfn print_header(month: String, days_passed: u16, days_left: u16) {\n    print_between(days_passed.to_string(), DAYS_WIDTH, true);\n    print_between(month.to_string(), MONTH_WIDTH, true);\n    print_between(days_left.to_string(), DAYS_WIDTH, true);\n    println!();\n\n    for d in DAYS {\n        let d = d.chars().nth(0).unwrap();\n        print_between(d.to_string(), DAY_NUMS_WIDTH, false);\n    }\n    println!();\n\n    println!(\"{:*>WIDTH$}\", \"\");\n}\n\nfn print_days(current_day_index: &mut usize, days: u8) {\n    let mut current_date = 1u8;\n\n    print!(\"{:>w$}\", \" \", w = DAY_NUMS_WIDTH * *current_day_index);\n\n    for _ in 1..=days {\n        print_between(current_date.to_string(), DAY_NUMS_WIDTH, false);\n\n        if ((*current_day_index + 1) % 7) == 0 {\n            *current_day_index = 0;\n            println!();\n        } else {\n            *current_day_index += 1;\n        }\n\n        current_date += 1;\n    }\n}\n"
  },
  {
    "path": "21_Calendar/vbnet/Calendar.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Calendar\", \"Calendar.vbproj\", \"{00B21257-3E25-4150-AA6D-266350688663}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{00B21257-3E25-4150-AA6D-266350688663}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00B21257-3E25-4150-AA6D-266350688663}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{00B21257-3E25-4150-AA6D-266350688663}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{00B21257-3E25-4150-AA6D-266350688663}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "21_Calendar/vbnet/Calendar.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Calendar</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "21_Calendar/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "22_Change/README.md",
    "content": "### Change\n\nIn this program, the computer pretends it is the cashier at your friendly neighborhood candy store. You tell it the cost of the item(s) you are buying, the amount of your payment, and it will automatically (!) determine your correct change. Aren’t machines wonderful? Dennis Lunder of People’s Computer Company wrote this program.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=39)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=54)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "22_Change/change.bas",
    "content": "2 PRINT TAB(33);\"CHANGE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n5 PRINT:PRINT:PRINT\n6 PRINT \"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\"\n8 PRINT \"THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\"\n9 PRINT:PRINT\n10 PRINT \"COST OF ITEM\";:INPUT A:PRINT \"AMOUNT OF PAYMENT\";:INPUT P\n20 C=P-A:M=C:IF C<>0 THEN 90\n25 PRINT \"CORRECT AMOUNT, THANK YOU.\"\n30 GOTO 400\n90 IF C>0 THEN 120\n95 PRINT \"SORRY, YOU HAVE SHORT-CHANGED ME $\";A-P\n100 GOTO 10\n120 PRINT \"YOUR CHANGE, $\";C\n130 D=INT(C/10)\n140 IF D=0 THEN 155\n150 PRINT D;\"TEN DOLLAR BILL(S)\"\n155 C=M-(D*10)\n160 E=INT(C/5)\n170 IF E=0 THEN 185\n180 PRINT E;\"FIVE DOLLARS BILL(S)\"\n185 C=M-(D*10+E*5)\n190 F=INT(C)\n200 IF F=0 THEN 215\n210 PRINT F;\"ONE DOLLAR BILL(S)\"\n215 C=M-(D*10+E*5+F)\n220 C=C*100\n225 N=C\n230 G=INT(C/50)\n240 IF G=0 THEN 255\n250 PRINT G;\"ONE HALF DOLLAR(S)\"\n255 C=N-(G*50)\n260 H=INT(C/25)\n270 IF H=0 THEN 285\n280 PRINT H;\"QUARTER(S)\"\n285 C=N-(G*50+H*25)\n290 I=INT(C/10)\n300 IF I=0 THEN 315\n310 PRINT I;\"DIME(S)\"\n315 C=N-(G*50+H*25+I*10)\n320 J=INT(C/5)\n330 IF J=0 THEN 345\n340 PRINT J;\"NICKEL(S)\"\n345 C=N-(G*50+H*25+I*10+J*5)\n350 K=INT(C+.5)\n360 IF K=0 THEN 380\n370 PRINT K;\"PENNY(S)\"\n380 PRINT \"THANK YOU, COME AGAIN.\"\n390 PRINT:PRINT\n400 GOTO 10\n410 END\n"
  },
  {
    "path": "22_Change/csharp/Change.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>net5.0</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "22_Change/csharp/Change.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.810.16\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Change\", \"Change.csproj\", \"{AE094667-8496-4ECF-8B42-B1648EE26073}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{AE094667-8496-4ECF-8B42-B1648EE26073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{AE094667-8496-4ECF-8B42-B1648EE26073}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{AE094667-8496-4ECF-8B42-B1648EE26073}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{AE094667-8496-4ECF-8B42-B1648EE26073}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {65684CBD-CD74-46AF-8E9E-0F69DCF72697}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "22_Change/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Change\n{\n    class Program\n    {\n        /// <summary>\n        /// Prints header.\n        /// </summary>\n        static void Header()\n        {\n            Console.WriteLine(\"Change\".PadLeft(33));\n            Console.WriteLine(\"Creative Computing Morristown, New Jersey\".PadLeft(15));\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"I, your friendly microcomputer, will determine\\n\"\n            + \"the correct change for items costing up to $100.\");\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        /// <summary>\n        /// Gets user input for price and payment.\n        /// </summary>\n        /// <returns>\n        /// False if any input can't be parsed to double. Price and payment returned would be 0.\n        /// True if it was possible to parse inputs into doubles. Price and payment returned\n\t    /// would be as provided by the user.\n\t    /// </returns>\n        static (bool status, double price, double payment) GetInput()\n        {\n            Console.Write(\"Cost of item? \");\n            var priceString = Console.ReadLine();\n            if (!double.TryParse(priceString, out double price))\n            {\n                Console.WriteLine($\"{priceString} isn't a number!\");\n                return (false, 0, 0);\n            }\n\n            Console.Write(\"Amount of payment? \");\n            var paymentString = Console.ReadLine();\n            if (!double.TryParse(paymentString, out double payment))\n            {\n                Console.WriteLine($\"{paymentString} isn't a number!\");\n                return (false, 0, 0);\n            }\n\n            return (true, price, payment);\n        }\n\n        /// <summary>\n        /// Prints bills and coins for given change.\n        /// </summary>\n        /// <param name=\"change\"></param>\n        static void PrintChange(double change)\n        {\n            var tens = (int)(change / 10);\n            if (tens > 0)\n                Console.WriteLine($\"{tens} ten dollar bill(s)\");\n\n            var temp = change - (tens * 10);\n            var fives = (int)(temp / 5);\n            if (fives > 0)\n                Console.WriteLine($\"{fives} five dollar bill(s)\");\n\n            temp -= fives * 5;\n            var ones = (int)temp;\n            if (ones > 0)\n                Console.WriteLine($\"{ones} one dollar bill(s)\");\n\n            temp -= ones;\n            var cents = temp * 100;\n            var half = (int)(cents / 50);\n            if (half > 0)\n                Console.WriteLine($\"{half} one half dollar(s)\");\n\n            temp = cents - (half * 50);\n            var quarters = (int)(temp / 25);\n            if (quarters > 0)\n                Console.WriteLine($\"{quarters} quarter(s)\");\n\n            temp -= quarters * 25;\n            var dimes = (int)(temp / 10);\n            if (dimes > 0)\n                Console.WriteLine($\"{dimes} dime(s)\");\n\n            temp -= dimes * 10;\n            var nickels = (int)(temp / 5);\n            if (nickels > 0)\n                Console.WriteLine($\"{nickels} nickel(s)\");\n\n            temp -= nickels * 5;\n            var pennies = (int)(temp + 0.5);\n            if (pennies > 0)\n                Console.WriteLine($\"{pennies} penny(s)\");\n        }\n\n        static void Main(string[] args)\n        {\n            Header();\n\n            while (true)\n            {\n                (bool result, double price, double payment) = GetInput();\n                if (!result)\n                    continue;\n\n                var change = payment - price;\n                if (change == 0)\n                {\n                    Console.WriteLine(\"Correct amount, thank you!\");\n                    continue;\n                }\n\n                if (change < 0)\n                {\n                    Console.WriteLine($\"Sorry, you have short-changed me ${price - payment:N2}!\");\n                    continue;\n                }\n\n                Console.WriteLine($\"Your change ${change:N2}\");\n                PrintChange(change);\n                Console.WriteLine(\"Thank you, come again!\");\n                Console.WriteLine();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "22_Change/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "22_Change/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "22_Change/java/src/Change.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Change\n * <p>\n * Based on the Basic game of Change here\n * https://github.com/coding-horror/basic-computer-games/blob/main/22%20Change/change.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Change {\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        START_GAME,\n        INPUT,\n        CALCULATE,\n        END_GAME,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // Amount of change needed to be given\n    private double change;\n\n    public Change() {\n        kbScanner = new Scanner(System.in);\n\n        gameState = GAME_STATE.START_GAME;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n                case START_GAME:\n                    intro();\n                    gameState = GAME_STATE.INPUT;\n                    break;\n\n                case INPUT:\n\n                    double costOfItem = displayTextAndGetNumber(\"COST OF ITEM \");\n                    double amountPaid = displayTextAndGetNumber(\"AMOUNT OF PAYMENT \");\n                    change = amountPaid - costOfItem;\n                    if (change == 0) {\n                        // No change needed\n                        System.out.println(\"CORRECT AMOUNT, THANK YOU.\");\n                        gameState = GAME_STATE.END_GAME;\n                    } else if (change < 0) {\n                        System.out.println(\"YOU HAVE SHORT-CHANGES ME $\" + (costOfItem - amountPaid));\n                        // Don't change game state so it will loop back and try again\n                    } else {\n                        // Change needed.\n                        gameState = GAME_STATE.CALCULATE;\n                    }\n                    break;\n\n                case CALCULATE:\n                    System.out.println(\"YOUR CHANGE, $\" + change);\n                    calculateChange();\n                    gameState = GAME_STATE.END_GAME;\n                    break;\n\n                case END_GAME:\n                    System.out.println(\"THANK YOU, COME AGAIN\");\n                    System.out.println();\n                    gameState = GAME_STATE.INPUT;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Calculate and output the change required for the purchase based on\n     * what money was paid.\n     */\n    private void calculateChange() {\n\n        double originalChange = change;\n\n        int tenDollarBills = (int) change / 10;\n        if (tenDollarBills > 0) {\n            System.out.println(tenDollarBills + \" TEN DOLLAR BILL(S)\");\n        }\n        change = originalChange - (tenDollarBills * 10);\n\n        int fiveDollarBills = (int) change / 5;\n        if (fiveDollarBills > 0) {\n            System.out.println(fiveDollarBills + \" FIVE DOLLAR BILL(S)\");\n        }\n        change = originalChange - (tenDollarBills * 10 + fiveDollarBills * 5);\n\n        int oneDollarBills = (int) change;\n        if (oneDollarBills > 0) {\n            System.out.println(oneDollarBills + \" ONE DOLLAR BILL(S)\");\n        }\n        change = originalChange - (tenDollarBills * 10 + fiveDollarBills * 5 + oneDollarBills);\n\n        change = change * 100;\n        double cents = change;\n\n        int halfDollars = (int) change / 50;\n        if (halfDollars > 0) {\n            System.out.println(halfDollars + \" ONE HALF DOLLAR(S)\");\n        }\n        change = cents - (halfDollars * 50);\n\n        int quarters = (int) change / 25;\n        if (quarters > 0) {\n            System.out.println(quarters + \" QUARTER(S)\");\n        }\n\n        change = cents - (halfDollars * 50 + quarters * 25);\n\n        int dimes = (int) change / 10;\n        if (dimes > 0) {\n            System.out.println(dimes + \" DIME(S)\");\n        }\n\n        change = cents - (halfDollars * 50 + quarters * 25 + dimes * 10);\n\n        int nickels = (int) change / 5;\n        if (nickels > 0) {\n            System.out.println(nickels + \" NICKEL(S)\");\n        }\n\n        change = cents - (halfDollars * 50 + quarters * 25 + dimes * 10 + nickels * 5);\n\n        int pennies = (int) (change + .5);\n        if (pennies > 0) {\n            System.out.println(pennies + \" PENNY(S)\");\n        }\n\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(33) + \"CHANGE\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\");\n        System.out.println(\"THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\");\n        System.out.println();\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to a Double\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private double displayTextAndGetNumber(String text) {\n        return Double.parseDouble(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n}\n"
  },
  {
    "path": "22_Change/java/src/ChangeGame.java",
    "content": "public class ChangeGame {\n    public static void main(String[] args) {\n        Change change = new Change();\n        change.play();\n    }\n}\n"
  },
  {
    "path": "22_Change/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "22_Change/javascript/change.html",
    "content": "<html>\n<head>\n<title>CHANGE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"change.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "22_Change/javascript/change.js",
    "content": "// CHANGE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"CHANGE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\\n\");\n    print(\"THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"COST OF ITEM\");\n        a = parseFloat(await input());\n        print(\"AMOUNT OF PAYMENT\");\n        p = parseFloat(await input());\n        c = p - a;\n        m = c;\n        if (c == 0) {\n            print(\"CORRECT AMOUNT, THANK YOU.\\n\");\n        } else {\n            print(\"YOUR CHANGE, $\" + c + \"\\n\");\n            d = Math.floor(c / 10);\n            if (d)\n                print(d + \" TEN DOLLAR BILL(S)\\n\");\n            c -= d * 10;\n            e = Math.floor(c / 5);\n            if (e)\n                print(e + \" FIVE DOLLAR BILL(S)\\n\");\n            c -= e * 5;\n            f = Math.floor(c);\n            if (f)\n                print(f + \" ONE DOLLAR BILL(S)\\n\");\n            c -= f;\n            c *= 100;\n            g = Math.floor(c / 50);\n            if (g)\n                print(g + \" ONE HALF DOLLAR(S)\\n\");\n            c -= g * 50;\n            h = Math.floor(c / 25);\n            if (h)\n                print(h + \" QUARTER(S)\\n\");\n            c -= h * 25;\n            i = Math.floor(c / 10);\n            if (i)\n                print(i + \" DIME(S)\\n\");\n            c -= i * 10;\n            j = Math.floor(c / 5);\n            if (j)\n                print(j + \" NICKEL(S)\\n\");\n            c -= j * 5;\n            k = Math.floor(c + 0.5);\n            if (k)\n                print(k + \" PENNY(S)\\n\");\n            print(\"THANK YOU, COME AGAIN.\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "22_Change/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "22_Change/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "22_Change/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "22_Change/perl/change.pl",
    "content": "#!/usr/bin/perl\n\nuse v5.24; # for say and use strict\nuse warnings;\n\nsub get_pennies {\n  my $query = shift;\n\n  print \"$query? \";\n  my $in = <>;\n  chomp $in;\n  $in =~ /([\\d.]+)/; # the first match of digits and decimal points\n  return int( $1 * 100 );\n}\n\nsub make_change {\n  my $change = shift;\n\n  state %change_options = (\n    'Penny' => { value => 1, plural => 'Pennies' },\n    'Nickel' => { value => 5 },\n    'Dime' => { value => 10 },\n    'Quarter' => { value => 25 },\n    'One Half Dollar' => { value => 50 },\n    'One Dollar Bill' => { value => 100 * 1 },\n    'Five Dollar Bill' => { value => 100 * 5 },\n    '10 Dollar Bill' => { value => 100 * 10 },\n  );\n\n  foreach my $unit ( sort { $change_options{$b}->{value} <=> $change_options{$a}->{value} } keys %change_options ) {\n    my $value = $change_options{$unit}->{value};\n    next if $value > $change;\n    my $number = int( $change / $value );\n    if ( $number > 1 ) {\n      $unit = exists $change_options{$unit}->{plural} ? $change_options{$unit}->{plural} : \"${unit}s\";\n    }\n    say \"$number $unit\";\n    $change -= $number * $value;\n  }\n}\n\nprint <<'__END_OF_INTRO';\n                              Change\n               Creative Computing  Morristown, New Jersey\n\n\nI, Your friendly microcomputer, will determine\nthe correct change for items costing up to $100.\n\n\n__END_OF_INTRO\n\nwhile ( 1 ) {\n  my $cost = get_pennies( 'Cost of item' );\n  my $payment = get_pennies( 'Amount of payment');\n\n  my $change = $payment - $cost;\n  my $change_formatted = sprintf( \"%.2f\", $change / 100 );\n  if ( $change == 0 ) {\n    say 'Correct amount, thank you.';\n  } elsif ( $change < 0 ) {\n    say 'Sorry, you have short-changed me $', abs($change_formatted);\n  } else {\n    say 'Your change, $', $change_formatted;\n    make_change( $change );\n    say \"Thank you, come again\\n\\n\";\n  }\n}\n"
  },
  {
    "path": "22_Change/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "22_Change/python/change.py",
    "content": "\"\"\"\nCHANGE\n\nChange calculator\n\nPort by Dave LeCompte\n\"\"\"\n\nPAGE_WIDTH = 64\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef print_introduction() -> None:\n    print(\"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\")\n    print(\"THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\\n\\n\")\n\n\ndef pennies_to_dollar_string(p: float) -> str:\n    d = p / 100\n    return f\"${d:0.2f}\"\n\n\ndef compute_change() -> None:\n    print(\"COST OF ITEM?\")\n    cost = float(input())\n    print(\"AMOUNT OF PAYMENT?\")\n    payment = float(input())\n\n    change_in_pennies = round((payment - cost) * 100)\n    if change_in_pennies == 0:\n        print(\"CORRECT AMOUNT, THANK YOU.\")\n        return\n\n    if change_in_pennies < 0:\n        short = -change_in_pennies / 100\n\n        print(f\"SORRY, YOU HAVE SHORT-CHANGED ME ${short:0.2f}\")\n        print()\n        return\n\n    print(f\"YOUR CHANGE, {pennies_to_dollar_string(change_in_pennies)}\")\n\n    d = change_in_pennies // 1000\n    if d > 0:\n        print(f\"{d} TEN DOLLAR BILL(S)\")\n    change_in_pennies -= d * 1000\n\n    e = change_in_pennies // 500\n    if e > 0:\n        print(f\"{e} FIVE DOLLAR BILL(S)\")\n    change_in_pennies -= e * 500\n\n    f = change_in_pennies // 100\n    if f > 0:\n        print(f\"{f} ONE DOLLAR BILL(S)\")\n    change_in_pennies -= f * 100\n\n    g = change_in_pennies // 50\n    if g > 0:\n        print(\"ONE HALF DOLLAR\")\n    change_in_pennies -= g * 50\n\n    h = change_in_pennies // 25\n    if h > 0:\n        print(f\"{h} QUARTER(S)\")\n    change_in_pennies -= h * 25\n\n    i = change_in_pennies // 10\n    if i > 0:\n        print(f\"{i} DIME(S)\")\n    change_in_pennies -= i * 10\n\n    j = change_in_pennies // 5\n    if j > 0:\n        print(f\"{j} NICKEL(S)\")\n    change_in_pennies -= j * 5\n\n    if change_in_pennies > 0:\n        print(f\"{change_in_pennies} PENNY(S)\")\n\n\ndef main() -> None:\n    print_header(\"CHANGE\")\n    print_introduction()\n\n    while True:\n        compute_change()\n        print(\"THANK YOU, COME AGAIN.\\n\\n\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "22_Change/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "22_Change/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "22_Change/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "22_Change/rust/src/main.rs",
    "content": "use std::io::{self, stdout, Write};\n\nfn main() {\n    //DATA\n    let mut cost_in_cents:i16;\n    let mut payment_in_cents:i16;\n    let mut amount_owed_in_cents:i16;\n\n    let mut hundred:i16;\n    let mut fifty:i16;\n    let mut twenty:i16;\n    let mut ten:i16;\n    let mut five:i16;\n    let mut one:i16;\n    let mut quarters:i16;\n    let mut dimes:i16;\n    let mut nickles:i16;\n    let mut pennies:i16;\n\n    //print welcome message\n    welcome();\n\n    //print prompt\n    println!(\"I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE\");\n    println!(\"THE CORRECT CHANGE FOR ITEMS COSTING UP TO ${}.00.\",i16::MAX/100);\n\n    //game loop \n    loop {\n        //get cost of items\n        cost_in_cents = get_dollar_value_in_cents_from_user(\"COST OF ITEM:\\t\\t$\");\n        //get amount they already paid\n        payment_in_cents = get_dollar_value_in_cents_from_user(\"AMOUNT OF PAYMENT:\\t$\");\n\n        //calculate amount they owe\n        amount_owed_in_cents = payment_in_cents - cost_in_cents;\n\n        //check whether the payment is equal to, less than, or greater than, the cost\n        if cost_in_cents == payment_in_cents {\n            println!(\"CORRECT AMOUNT, THANK YOU.\");\n            continue;\n        }\n        else if payment_in_cents < cost_in_cents{ //amount_owed_in_cents is less than 0\n            println!(\n                \"SORRY, YOU HAVE SHORT-CHANGED ME ${}.{}\",\n                -amount_owed_in_cents/100,//leading digits\n                -amount_owed_in_cents%100,//trailing digits\n            );\n            continue;\n        }\n        else {\n            println!(\"YOUR CHANGE, ${}.{}\", amount_owed_in_cents/100, amount_owed_in_cents%100);\n        }\n\n        //calculate change due\n        //hundred dollar bills owed\n        hundred = amount_owed_in_cents / (100*100);\n        if hundred > 0 {println!(\"HUNDRED DOLLAR BILL(S): {}\", hundred);}\n        amount_owed_in_cents = amount_owed_in_cents % (100*100);\n\n        //fifty dollar bills owed\n        fifty = amount_owed_in_cents / (50*100);\n        if fifty > 0 {println!(\"FIFTY DOLLAR BILL(S): {}\", fifty);}\n        amount_owed_in_cents = amount_owed_in_cents % (50*100);\n\n        //twenty dollar bills owed\n        twenty = amount_owed_in_cents / (20*100);\n        if twenty > 0 {println!(\"TWENTY DOLLAR BILL(S): {}\", twenty);}\n        amount_owed_in_cents = amount_owed_in_cents % (20*100);\n\n        //ten dollar bills owed\n        ten = amount_owed_in_cents / (10*100);\n        if ten > 0 {println!(\"TEN DOLLAR BILL(S): {}\", ten);}\n        amount_owed_in_cents = amount_owed_in_cents % (10*100);\n\n        //five dollar bills owed\n        five = amount_owed_in_cents / (5*100);\n        if five > 0 {println!(\"FIVE DOLLAR BILL(S): {}\", five);}\n        amount_owed_in_cents = amount_owed_in_cents % (5*100);\n\n        //one dollar bills owed\n        one = amount_owed_in_cents / (1*100);\n        if one > 0 {println!(\"ONE DOLLAR BILL(S): {}\", one);}\n        amount_owed_in_cents = amount_owed_in_cents % (1*100);\n\n        //quarters owed\n        quarters = amount_owed_in_cents / 25;\n        if quarters > 0 {println!(\"QUARTER(S): {}\", quarters);}\n        amount_owed_in_cents = amount_owed_in_cents % 25;\n\n        //dimes owed\n        dimes = amount_owed_in_cents / 10;\n        if dimes > 0 {println!(\"DIME(S): {}\", dimes);}\n        amount_owed_in_cents = amount_owed_in_cents % 10;\n\n        //nickles owed\n        nickles = amount_owed_in_cents / 5;\n        if nickles > 0 {println!(\"NICKEL(S): {}\", nickles);}\n        amount_owed_in_cents = amount_owed_in_cents % 5;\n\n        //pennies owed\n        pennies = amount_owed_in_cents / 1;\n        if pennies > 0 {println!(\"PENNY(S): {}\", pennies);}\n\n        //print ending message\n        println!(\"THANK YOU, COME AGAIN.\\n\\n\");\n    }\n}\n\n/**\n * print welcome message\n */\nfn welcome() {\n    println!(\"\\t\\t\\t\\tCHANGE\\n\\t      CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\");\n}\n\n/**\n * get number of money from user input\n */\nfn get_dollar_value_in_cents_from_user(prompt:&str) -> i16 {\n    let mut value:i16;\n    //input loop\n    loop {\n        //data\n        let mut raw_input = String::new();\n\n        //print prompt\n        print!(\"{}\",prompt);\n        //flush std out // allows prompt to be on same line as input\n        stdout().flush().expect(\"failed to flush\");\n\n        //get input\n        io::stdin().read_line(&mut raw_input).expect(\"failed to read input\");\n        //filter out characters that aren't numbers or '.'\n        let mut no_prior_periods = true;\n        raw_input = raw_input.chars().filter(|c| {\n            if c.eq_ignore_ascii_case(&'.') && no_prior_periods {\n                no_prior_periods = false;\n                true\n            } else {\n                c.is_ascii_digit()\n            }\n        }).collect();\n\n        //should only be (at most) 1 .\n        if !raw_input.contains(\".\") { raw_input += \".00\";} //if there are none, add one\n\n        //ensure there are at least 2 trailing digits\n        if raw_input[raw_input.find('.').unwrap_or(raw_input.len())..].len() <= 2 { //if a slice of the string from the . onwards is less than or equal to 2, add two 0's to the end\n            raw_input += \"00\"\n        }\n        //truncate the trailing digits to 2 digits\n        raw_input = raw_input[..=raw_input.find('.').unwrap_or(raw_input.len()-2)+2].to_string(); //raw_input = a slice of raw_input from the start to 2 past the . \n        \n        //remove the '.' and convert the string to an integer\n        raw_input = raw_input.chars().filter(|c| c.is_ascii_digit()).collect();\n        match raw_input.parse::<i16>().ok() {\n            Some(v) => {value = v;}\n            None => {\n                println!(\"INPUT OUTSIDE OF ACCEPTABLE RANGE, TRY AGAIN\");\n                continue;\n            },\n        }\n\n        //println!(\"{}\",value);\n\n        if value <= 0 {continue;}\n        else {return value;}\n    }\n}\n"
  },
  {
    "path": "22_Change/vbnet/Change.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Change\", \"Change.vbproj\", \"{77FC724B-EA88-4419-824B-32366FFE9608}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{77FC724B-EA88-4419-824B-32366FFE9608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{77FC724B-EA88-4419-824B-32366FFE9608}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{77FC724B-EA88-4419-824B-32366FFE9608}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{77FC724B-EA88-4419-824B-32366FFE9608}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "22_Change/vbnet/Change.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Change</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "22_Change/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "23_Checkers/README.md",
    "content": "### Checkers\n\nThis program plays checkers. The pieces played by the computer are marked with an “X”, yours are marked “O”. A move is made by specifying the coordinates of the piece to be moved (X, Y). Home (0,0) is in the bottom left and X specifies distance to the right of home (i.e., column) and Y specifies distance above home (i.e. row). You then specify where you wish to move to.\n\nThe original version of the program by Alan Segal was not able to recognize (or permit) a double or triple jump. If you tried one, it was likely that your piece would disappear altogether!\n\nSteve North of Creative Computing rectified this problem and Lawrence Neal contributed modifications to allow the program to tell which player has won the game. The computer does not play a particularly good game but we leave it to _you_ to improve that.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=40)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=55)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\nThe file `checkers.annotated.bas` contains an indented and annotated\nversion of the source code.  This is no longer valid BASIC code but\nshould be more readable.\n\n#### Porting Notes\n\n - If the computer moves a checker to the bottom row, it promotes, but\n   leaves the original checker in place. (See line 1240)\n - Human players may move non-kings as if they were kings. (See lines 1590 to 1810)\n - Human players are not required to jump if it is possible, and may make a number\n   other illegal moves (jumping their own pieces, jumping empty squares, etc.).\n - Curious writing to \"I\" variable without ever reading it. (See lines 1700 and 1806)\n"
  },
  {
    "path": "23_Checkers/checkers.annotated.bas",
    "content": "     # Annotated version of CHECKERS.BAS, modified to improve readability.\n     #\n     # I've made the following changes:\n     #\n     #  1. Added many comments and blank lines.\n     #  2. Separated each statement into its own line.\n     #  3. Indented loops, conditionals and subroutines.\n     #  4. Turned *SOME* conditionals and loops into\n     #     structured-BASIC-style if/endif and loop/endloop blocks.\n     #  5. Switched to using '#' to delimit comments.\n     #  6. Subroutines now begin with \"Sub_Start\"\n     #  7. All non-string text has been converted to lower-case\n     #  8. All line numbers that are not jump destinations have been removed.\n     #\n     # This has helped me make sense of the code.  I hope it will also help you.\n     #\n\n     # Print the banner\n     print tab(32);\"CHECKERS\"\n     print tab(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n     print\n     print\n     print\n     print \"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\"\n     print \"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\"\n     print \"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\"\n     print \"(0,0) IS THE LOWER LEFT CORNER\"\n     print \"(0,7) IS THE UPPER LEFT CORNER\"\n     print \"(7,0) IS THE LOWER RIGHT CORNER\"\n     print \"(7,7) IS THE UPPER RIGHT CORNER\"\n     print \"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\"\n     print \"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\"\n     print\n     print\n     print\n\n     # Declare the \"globals\":\n\n     # The current move: (rating, current x, current y, new x, new y)\n     # 'rating' represents how good the move is; higher is better.\n     dim r(4)\n     r(0)=-99       # Start with minimum score\n\n     # The board.  Pieces are represented by numeric values:\n     #\n     #      - 0     = empty square\n     #      - -1,-2 = X (-1 for regular piece, -2 for king)\n     #      - 1,2   = O (1 for regular piece, 2 for king)\n     #\n     # This program's player (\"me\") plays X.\n     dim s(7,7)\n\n     g=-1           # constant holding -1\n\n     # Initialize the board.  Data is 2 length-wise strips repeated.\n     data 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15\n     for x=0 to 7\n       for y=0 to 7\n         read j\n         if j=15 then 180\n         s(x,y)=j\n         goto 200\n180      restore\n         read s(x,y)\n200  next y,x\n\n230  # Start of game loop.  First, my turn.\n\n     # For each square on the board, search for one of my pieces\n     # and if it can make the best move so far, store that move in 'r'\n     for x=0 to 7\n       for y=0 to 7\n\n         # Skip if this is empty or an opponent's piece\n         if s(x,y) > -1 then 350\n\n         # If this is one of my ordinary pieces, analyze possible\n         # forward moves.\n         if s(x,y) = -1 then\n           for a=-1 to 1 step 2\n             b=g\n             gosub 650\n           next a\n         endif\n\n         # If this is one of my kings, analyze possible forward\n         # and backward moves.\n         if s(x,y) = -2 then\n           for a=-1 to 1 step 2\n             for b=-1 to 1 step 2\n               gosub 650\n           next b,a\n         endif\n\n350  next y,x\n     goto 1140  # Skip the subs\n\n\n     # Analyze a move from (x,y) to (x+a, y+b) and schedule it if it's\n     # the best candidate so far.\n650  Sub_Start\n       u=x+a\n       v=y+b\n\n       # Done if it's off the board\n       if u<0 or u>7 or v<0 or v>7 then 870\n\n       # Consider the destination if it's empty\n       if s(u,v) = 0 then\n         gosub 910\n         goto 870\n       endif\n\n       # If it's got an opponent's piece, jump it instead\n       if s(u,v) > 0\n\n           # Restore u and v, then return if it's off the board\n           u=u+a\n           v=v+b\n           if u<0 or v<0 or u>7 or v>7 then 870\n\n           # Otherwise, consider u,v\n           if s(u,v)=0 then gosub 910\n       endif\n870  return\n\n     # Evaluate jumping (x,y) to (u,v).\n     #\n     # Computes a score for the proposed move and if it's higher\n     # than the best-so-far move, uses that instead by storing it\n     # and its score in array 'r'.\n910  Sub_Start\n\n       # q is the score; it starts at 0\n\n       # +2 if it promotes this piece\n       if v=0 and s(x,y)=-1 then q=q+2\n\n       # +5 if it takes an opponent's piece\n       if abs(y-v)=2 then q=q+5\n\n       # -2 if the piece is moving away from the top boundary\n       if y=7 then q=q-2\n\n       # +1 for putting the piece against a vertical boundary\n       if u=0 or u=7 then q=q+1\n\n       for c=-1 to 1 step 2\n         if u+c < 0 or u+c > 7 or v+g < 0 then 1080\n\n         # +1 for each adjacent friendly piece\n         if s(u+c, v+g) < 0 then\n           q=q+1\n           goto 1080\n         endif\n\n         # Prevent out-of-bounds testing\n         if u-c < 0 or u-c > 7 or v-g > 7 then 1080\n\n         # -2 for each opponent piece that can now take this piece here\n         if s(u+c,v+g) > 0 and(s(u-c,v-g)=0 or(u-c=x and v-g=y))then q=q-2\n1080   next c\n\n       # Use this move if it's better than the previous best\n       if q>r(0) then\n         r(0)=q\n         r(1)=x\n         r(2)=y\n         r(3)=u\n         r(4)=v\n       endif\n\n       q=0  # reset the score\n     return\n\n1140 if r(0)=-99 then 1880  # Game is lost if no move could be found.\n\n     # Print the computer's move.  (Note: chr$(30) is an ASCII RS\n     # (record separator) code; probably no longer relevant.)\n     print chr$(30)\"FROM\"r(1);r(2)\"TO\"r(3);r(4);\n     r(0)=-99\n\n     # Make the computer's move.  If the piece finds its way to the\n     # end of the board, crown it.\n1240 if r(4)=0 then\n       s(r(3),r(4))=-2\n       goto 1420\n     endif\n     s(r(3),r(4))=s(r(1),r(2))\n     s(r(1),r(2))=0\n\n     # If the piece has jumped 2 squares, it means the computer has\n     # taken an opponents' piece.\n     if abs(r(1)-r(3)) == 2 then\n       s((r(1)+r(3))/2,(r(2)+r(4))/2)=0     # Delete the opponent's piece\n\n       # See if we can jump again.  Evaluate all possible moves.\n       x=r(3)\n       y=r(4)\n       for a=-2 to 2 step 4\n         if s(x,y)=-1 then\n           b=-2\n           gosub 1370\n         endif\n         if s(x,y)=-2 then\n           for b=-2 to 2 step 4\n             gosub 1370\n           next b\n         endif\n       next a\n\n       # If we've found a move, go back and make that one as well\n       if r(0) <> -99 then\n         print \"TO\" r(3); r(4);\n         r(0)=-99\n         goto 1240\n       endif\n\n       goto 1420   # Skip the sub\n\n       # If (u,v) is in the bounds, evaluate it as a move using\n       # the sub at 910\n1370   Sub_Start\n         u=x+a\n         v=y+b\n         if u<0 or u>7 or v<0 or v>7 then 1400\n         if s(u,v)=0 and s(x+a/2,y+b/2)>0 then gosub 910\n1400   return\n\n1420 endif\n\n     # Now, print the board\n     print\n     print\n     print\n     for y=7 to 0 step-1\n       for x=0 to 7\n         i=5*x\n         print tab(i);\n         if s(x,y)=0 then print\".\";\n         if s(x,y)=1 then print\"O\";\n         if s(x,y)=-1 then print\"X\";\n         if s(x,y)=-2 then print\"X*\";\n         if s(x,y)=2 then print\"O*\";\n       next x\n       print\" \"\n       print\n     next y\n     print\n\n     # Check if either player is out of pieces.  If so, announce the\n     # winner.\n     for l=0 to 7\n       for m=0 to 7\n         if s(l,m)=1 or s(l,m)=2 then z=1\n         if s(l,m)=-1 or s(l,m)=-2 then t=1\n       next m\n     next l\n     if z<>1 then 1885\n     if t<>1 then 1880\n\n     # Prompt the player for their move.\n     z=0\n     t=0\n1590 input \"FROM\";e,h\n     x=e\n     y=h\n     if s(x,y)<=0 then 1590\n1670 input \"TO\";a,b\n     x=a\n     y=b\n     if s(x,y)=0 and abs(a-e)<=2 and abs(a-e)=abs(b-h)then 1700\n     print chr$(7)chr$(11);     # bell, vertical tab; invalid move\n     goto 1670\n\n1700 i=46       # Not used; probably a bug\n1750 loop\n       # Make the move and stop unless it might be a jump.\n       s(a,b) = s(e,h)\n       s(e,h) = 0\n       if abs(e-a) <> 2 then break\n\n       # Remove the piece jumped over\n       s((e+a)/2,(h+b)/2) = 0\n\n       # Prompt for another move; -1 means player can't, so I've won.\n       # Keep prompting until there's a valid move or the player gives\n       # up.\n1802   input \"+TO\";a1,b1\n       if a1 < 0 then break\n       if s(a1,b1) <> 0 or abs(a1-a) <>2  or abs(b1-b) <> 2 then 1802\n\n       # Update the move variables to correspond to the next jump\n       e=a\n       h=b\n       a=a1\n       b=b1\n\n       i=i+15   # Not used; probably a bug\n     endloop\n\n     # If the player has reached the end of the board, crown this piece\n1810 if b=7 then s(a,b)=2\n\n     # And play the next turn.\n     goto 230\n\n     # Endgame:\n1880 print\n     print \"YOU WIN.\"\n     end\n\n1885 print\n     print \"I WIN.\"\n     end\n"
  },
  {
    "path": "23_Checkers/checkers.bas",
    "content": "5 PRINT TAB(32);\"CHECKERS\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n15 PRINT:PRINT:PRINT\n20 PRINT \"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\"\n25 PRINT \"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\"\n30 PRINT \"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\"\n35 PRINT \"(0,0) IS THE LOWER LEFT CORNER\"\n40 PRINT \"(0,7) IS THE UPPER LEFT CORNER\"\n45 PRINT \"(7,0) IS THE LOWER RIGHT CORNER\"\n50 PRINT \"(7,7) IS THE UPPER RIGHT CORNER\"\n55 PRINT \"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\"\n60 PRINT \"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\"\n65 PRINT:PRINT:PRINT\n80 DIM R(4),S(7,7):G=-1:R(0)=-99\n90 DATA 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15\n120 FOR X=0 TO 7:FOR Y=0 TO 7:READ J:IF J=15 THEN 180\n160 S(X,Y)=J:GOTO 200\n180 RESTORE:READ S(X,Y)\n200 NEXT Y,X\n230 FOR X=0 TO 7:FOR Y=0 TO 7:IF S(X,Y)>-1 THEN 350\n310 IF S(X,Y)=-1 THEN FOR A=-1 TO 1 STEP 2:B=G:GOSUB 650:NEXT A\n330 IF S(X,Y)=-2 THEN FOR A=-1 TO 1 STEP 2:FOR B=-1 TO 1 STEP 2:GOSUB 650:NEXT B,A\n350 NEXT Y,X:GOTO 1140\n650 U=X+A:V=Y+B:IF U<0 OR U>7 OR V<0 OR V>7 THEN 870\n740 IF S(U,V)=0 THEN GOSUB 910:GOTO 870\n770 IF S(U,V)<0 THEN 870\n790 U=U+A:V=V+B:IF U<0 OR V<0 OR U>7 OR V>7 THEN 870\n850 IF S(U,V)=0 THEN GOSUB 910\n870 RETURN\n910 IF V=0 AND S(X,Y)=-1 THEN Q=Q+2\n920 IF ABS(Y-V)=2 THEN Q=Q+5\n960 IF Y=7 THEN Q=Q-2\n980 IF U=0 OR U=7 THEN Q=Q+1\n1030 FOR C=-1 TO 1 STEP 2:IF U+C<0 OR U+C>7 OR V+G<0 THEN 1080\n1035 IF S(U+C,V+G)<0 THEN Q=Q+1:GOTO 1080\n1040 IF U-C<0 OR U-C>7 OR V-G>7 THEN 1080\n1045 IF S(U+C,V+G)>0 AND(S(U-C,V-G)=0 OR(U-C=X AND V-G=Y))THEN Q=Q-2\n1080 NEXT C:IF Q>R(0)THEN R(0)=Q:R(1)=X:R(2)=Y:R(3)=U:R(4)=V\n1100 Q=0:RETURN\n1140 IF R(0)=-99 THEN 1880\n1230 PRINT CHR$(30)\"FROM\"R(1);R(2)\"TO\"R(3);R(4);:R(0)=-99\n1240 IF R(4)=0 THEN S(R(3),R(4))=-2:GOTO 1420\n1250 S(R(3),R(4))=S(R(1),R(2))\n1310 S(R(1),R(2))=0:IF ABS(R(1)-R(3))<>2 THEN 1420\n1330 S((R(1)+R(3))/2,(R(2)+R(4))/2)=0\n1340 X=R(3):Y=R(4):IF S(X,Y)=-1 THEN B=-2:FOR A=-2 TO 2 STEP 4:GOSUB 1370\n1350 IF S(X,Y)=-2 THEN FOR A=-2 TO 2 STEP 4:FOR B=-2 TO 2 STEP 4:GOSUB 1370:NEXT B\n1360 NEXT A:IF R(0)<>-99 THEN PRINT\"TO\"R(3);R(4);:R(0)=-99:GOTO 1240\n1365 GOTO 1420\n1370 U=X+A:V=Y+B:IF U<0 OR U>7 OR V<0 OR V>7 THEN 1400\n1380 IF S(U,V)=0 AND S(X+A/2,Y+B/2)>0 THEN GOSUB 910\n1400 RETURN\n1420 PRINT:PRINT:PRINT:FOR Y=7 TO 0 STEP-1:FOR X=0 TO 7:I=5*X:PRINT TAB(I);\n1430 IF S(X,Y)=0 THEN PRINT\".\";\n1470 IF S(X,Y)=1 THEN PRINT\"O\";\n1490 IF S(X,Y)=-1 THEN PRINT\"X\";\n1510 IF S(X,Y)=-2 THEN PRINT\"X*\";\n1530 IF S(X,Y)=2 THEN PRINT\"O*\";\n1550 NEXT X:PRINT\" \":PRINT:NEXT Y:PRINT\n1552 FOR L=0 TO 7\n1554 FOR M=0 TO 7\n1556 IF S(L,M)=1 OR S(L,M)=2 THEN Z=1\n1558 IF S(L,M)=-1 OR S(L,M)=-2 THEN T=1\n1560 NEXT M\n1562 NEXT L\n1564 IF Z<>1 THEN 1885\n1566 IF T<>1 THEN 1880\n1570 Z=0: T=0\n1590 INPUT \"FROM\";E,H:X=E:Y=H:IF S(X,Y)<=0 THEN 1590\n1670 INPUT \"TO\";A,B:X=A:Y=B\n1680 IF S(X,Y)=0 AND ABS(A-E)<=2 AND ABS(A-E)=ABS(B-H)THEN 1700\n1690 PRINT CHR$(7)CHR$(11);:GOTO 1670\n1700 I=46\n1750 S(A,B)=S(E,H):S(E,H)=0:IF ABS(E-A)<>2 THEN 1810\n1800 S((E+A)/2,(H+B)/2)=0\n1802 INPUT \"+TO\";A1,B1:IF A1<0 THEN 1810\n1804 IF S(A1,B1)<>0 OR ABS(A1-A)<>2 OR ABS(B1-B)<>2 THEN 1802\n1806 E=A:H=B:A=A1:B=B1:I=I+15:GOTO 1750\n1810 IF B=7 THEN S(A,B)=2\n1830 GOTO 230\n1880 PRINT: PRINT \"YOU WIN.\": END\n1885 PRINT: PRINT \"I WIN.\": END\n"
  },
  {
    "path": "23_Checkers/csharp/Checkers.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "23_Checkers/csharp/Checkers.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Checkers\", \"Checkers.csproj\", \"{52D0DDFC-1A0D-4E57-A4FC-428EC717313C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{52D0DDFC-1A0D-4E57-A4FC-428EC717313C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{52D0DDFC-1A0D-4E57-A4FC-428EC717313C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{52D0DDFC-1A0D-4E57-A4FC-428EC717313C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{52D0DDFC-1A0D-4E57-A4FC-428EC717313C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "23_Checkers/csharp/Program.cs",
    "content": "﻿/*********************************************************************************\n * CHECKERS\n * ported from BASIC https://www.atariarchives.org/basicgames/showpage.php?page=41\n *\n * Porting philosophy\n * 1) Adhere to the original as much as possible\n * 2) Attempt to be understandable by Novice progammers\n *\n * There are no classes or Object Oriented design patterns used in this implementation.\n * Everything is written procedurally, using only top-level functions. Hopefully, this\n * will be approachable for someone who wants to learn C# syntax without experience with\n * Object Oriented concepts. Similarly, basic data structures have been chosen over more\n * powerful collection types.  Linq/lambda syntax is also excluded.\n *\n * C# Concepts contained in this example:\n *    Loops (for, foreach, while, and do)\n *    Multidimensional arrays\n *    Tuples\n *    Nullables\n *    IEnumerable (yield return / yield break)\n *\n * The original had multiple implementations of logic, like determining valid jump locations.\n * This has been refactored to reduce unnecessary code duplication.\n *********************************************************************************/\n#region Display functions\nvoid SkipLines(int count)\n{\n    for (int i = 0; i < count; i++)\n    {\n        Console.WriteLine();\n    }\n}\n\nvoid PrintBoard(int[,] state)\n{\n    SkipLines(3);\n    for (int y = 7; y >= 0; y--)\n    {\n        for (int x = 0; x < 8; x++)\n        {\n            switch(state[x,y])\n            {\n                case -2:\n                    Console.Write(\"X*\");\n                    break;\n                case -1:\n                    Console.Write(\"X \");\n                    break;\n                case 0:\n                    Console.Write(\". \");\n                    break;\n                case 1:\n                    Console.Write(\"O \");\n                    break;\n                case 2:\n                    Console.Write(\"O*\");\n                    break;\n            }\n            Console.Write(\"   \");\n        }\n        Console.WriteLine();\n    }\n}\n\nvoid WriteCenter(string text)\n{\n    const int LineLength = 80;\n    var spaces = (LineLength - text.Length) / 2;\n    Console.WriteLine($\"{\"\".PadLeft(spaces)}{text}\");\n}\n\nvoid ComputerWins()\n{\n    Console.WriteLine(\"I WIN.\");\n}\nvoid PlayerWins()\n{\n    Console.WriteLine(\"YOU WIN.\");\n}\n\nvoid WriteIntroduction()\n{\n    WriteCenter(\"CHECKERS\");\n    WriteCenter(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    SkipLines(3);\n    Console.WriteLine(\"THIS IS THE GAME OF CHECKERS. THE COMPUTER IS X,\");\n    Console.WriteLine(\"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\");\n    Console.WriteLine(\"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\");\n    Console.WriteLine(\"(0,0) IS THE LOWER LEFT CORNER\");\n    Console.WriteLine(\"(0,7) IS THE UPPER LEFT CORNER\");\n    Console.WriteLine(\"(7,0) IS THE LOWER RIGHT CORNER\");\n    Console.WriteLine(\"(7,7) IS THE UPPER RIGHT CORNER\");\n    Console.WriteLine(\"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\");\n    Console.WriteLine(\"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\");\n    SkipLines(3);\n}\n#endregion\n\n#region State validation functions\nbool IsPointOutOfBounds(int x)\n{\n    return x < 0 || x > 7;\n}\n\nbool IsOutOfBounds((int x, int y) position)\n{\n    return IsPointOutOfBounds(position.x) || IsPointOutOfBounds(position.y);\n}\n\nbool IsJumpMove((int x, int y) from, (int x, int y) to)\n{\n    return Math.Abs(from.y - to.y) == 2;\n}\n\nbool IsValidPlayerMove(int[,] state, (int x, int y) from, (int x, int y) to)\n{\n    if (state[to.x, to.y] != 0)\n    {\n        return false;\n    }\n    var deltaX = Math.Abs(to.x - from.x);\n    var deltaY = Math.Abs(to.y - from.y);\n    if (deltaX != 1 && deltaX != 2)\n    {\n        return false;\n    }\n    if (deltaX != deltaY)\n    {\n        return false;\n    }\n    if (state[from.x, from.y] == 1 && Math.Sign(to.y - from.y) <= 0)\n    {\n        // only kings can move downwards\n        return false;\n    }\n    if (deltaX == 2)\n    {\n        var jump = GetJumpedPiece(from, to);\n        if (state[jump.x, jump.y] >= 0)\n        {\n            // no valid piece to jump\n            return false;\n        }\n    }\n    return true;\n}\n\nbool CheckForComputerWin(int[,] state)\n{\n    bool playerAlive = false;\n    foreach (var piece in state)\n    {\n        if (piece > 0)\n        {\n            playerAlive = true;\n            break;\n        }\n    }\n    return !playerAlive;\n}\n\nbool CheckForPlayerWin(int[,] state)\n{\n    bool computerAlive = false;\n    foreach (var piece in state)\n    {\n        if (piece < 0)\n        {\n            computerAlive = true;\n            break;\n        }\n    }\n    return !computerAlive;\n}\n#endregion\n\n#region Board \"arithmetic\"\n/// <summary>\n/// Get the Coordinates of a jumped piece\n/// </summary>\n(int x, int y) GetJumpedPiece((int x, int y) from, (int x, int y) to)\n{\n    var midX = (to.x + from.x) / 2;\n    var midY = (to.y + from.y) / 2;\n    return (midX, midY);\n}\n/// <summary>\n/// Apply a directional vector \"direction\" to location \"from\"\n/// return resulting location\n/// direction will contain: (-1,-1), (-1, 1), ( 1,-1), ( 1, 1)\n/// /// </summary>\n(int x, int y) GetLocation((int x , int y) from, (int x, int y) direction)\n{\n    return (x: from.x + direction.x, y: from.y + direction.y);\n}\n#endregion\n\n#region State change functions\n/// <summary>\n/// Alter current \"state\" by moving a piece from \"from\" to \"to\"\n/// This method does not verify that the move being made is valid\n/// This method works for both player moves and computer moves\n/// </summary>\nint[,] ApplyMove(int[,] state, (int x, int y) from, (int x, int y) to)\n{\n    state[to.x, to.y] = state[from.x, from.y];\n    state[from.x, from.y] = 0;\n\n    if (IsJumpMove(from, to))\n    {\n        // a jump was made\n        // remove the jumped piece from the board\n        var jump = GetJumpedPiece(from, to);\n        state[jump.x, jump.y] = 0;\n    }\n    return state;\n}\n/// <summary>\n/// At the end of a turn (either player or computer) check to see if any pieces\n/// reached the final row.  If so, change them to kings (crown)\n/// </summary>\nint[,] CrownKingPieces(int[,] state)\n{\n    for (int x = 0; x < 8; x++)\n    {\n        // check the bottom row if computer has a piece in it\n        if (state[x, 0] == -1)\n        {\n            state[x, 0] = -2;\n        }\n        // check the top row if the player has a piece in it\n        if (state[x, 7] == 1)\n        {\n            state[x, 7] = 2;\n        }\n    }\n    return state;\n}\n#endregion\n\n#region Computer Logic\n/// <summary>\n/// Given a current location \"from\", determine if a move exists in a given vector, \"direction\"\n/// direction will contain: (-1,-1), (-1, 1), ( 1,-1), ( 1, 1)\n/// return \"null\" if no move is possible in this direction\n/// </summary>\n(int x, int y)? GetCandidateMove(int[,] state, (int x, int y) from, (int x, int y) direction)\n{\n    var to = GetLocation(from, direction);\n    if (IsOutOfBounds(to))\n        return null;\n    if (state[to.x, to.y] > 0)\n    {\n        // potential jump\n        to = GetLocation(to, direction);\n        if (IsOutOfBounds(to))\n            return null;\n    }\n    if (state[to.x, to.y] != 0)\n        // space already occupied by another piece\n        return null;\n\n    return to;\n}\n/// <summary>\n/// Calculate a rank for a given potential move\n/// The higher the rank value, the better the move is considered to be\n/// </summary>\nint RankMove(int[,] state, (int x, int y) from, (int x, int y) to)\n{\n    int rank = 0;\n\n    if (to.y == 0 && state[from.x, from.y] == -1)\n    {\n        // getting a king\n        rank += 2;\n    }\n    if (IsJumpMove(from, to))\n    {\n        // making a jump\n        rank += 5;\n    }\n    if (from.y == 7)\n    {\n        // leaving home row\n        rank -= 2;\n    }\n    if (to.x == 0 || to.x == 7)\n    {\n        // move to edge of board\n        rank += 1;\n    }\n    // look to the row in front of the potential destination for\n    for (int c = -1; c <=1; c+=2)\n    {\n        var inFront = GetLocation(to, (c, -1));\n        if (IsOutOfBounds(inFront))\n            continue;\n        if (state[inFront.x, inFront.y] < 0)\n        {\n            // protected by our piece in front\n            rank++;\n            continue;\n        }\n        var inBack = GetLocation(to, (-c, 1));\n        if (IsOutOfBounds(inBack))\n        {\n            continue;\n        }\n        if ((state[inFront.x, inFront.y] > 0) &&\n            (state[inBack.x, inBack.y] == 0) || (inBack == from))\n        {\n            // the player can jump us\n            rank -= 2;\n        }\n    }\n    return rank;\n};\n\n/// <summary>\n/// Returns an enumeration of possible moves that can be made by the given piece \"from\"\n/// If no moves, can be made, the enumeration will be empty\n/// </summary>\nIEnumerable<(int x, int y)> GetPossibleMoves(int[,] state, (int x, int y) from)\n{\n    int maxB;\n    switch (state[from.x, from.y])\n    {\n        case -2:\n            // kings can go backwards too\n            maxB = 1;\n            break;\n        case -1:\n            maxB = -1;\n            break;\n        default:\n            // not one of our pieces\n            yield break;\n    }\n\n    for (int a = -1; a <= 1; a += 2)\n    {\n        // a\n        // -1 = left\n        // +1 = right\n        for (int b = -1; b <= maxB; b += 2)\n        {\n            // b\n            // -1 = forwards\n            // +1 = backwards (only kings allowed to make this move)\n            var to = GetCandidateMove(state, from, (a, b));\n            if (to == null)\n            {\n                // no valid move in this direction\n                continue;\n            }\n            yield return to.Value;\n        }\n    }\n}\n/// <summary>\n/// Determine the best move from a list of candidate moves \"possibleMoves\"\n/// Returns \"null\" if no move can be made\n/// </summary>\n((int x, int y) from, (int x, int y) to)? GetBestMove(int[,] state, IEnumerable<((int x, int y) from, (int x, int y) to)> possibleMoves)\n{\n    int? bestRank = null;\n    ((int x, int y) from, (int x, int y) to)? bestMove = null;\n\n    foreach (var move in possibleMoves)\n    {\n        int rank = RankMove(state, move.from, move.to);\n\n        if (bestRank == null || rank > bestRank)\n        {\n            bestRank = rank;\n            bestMove = move;\n        }\n    }\n\n    return bestMove;\n}\n\n/// <summary>\n/// Examine the entire board and record all possible moves\n/// Return the best move found, if one exists\n/// Returns \"null\" if no move found\n/// </summary>\n((int x, int y) from, (int x, int y) to)? CalculateMove(int[,] state)\n{\n    var possibleMoves = new List<((int x, int y) from, (int x, int y) to)>();\n    for (int x = 0; x < 8; x++)\n    {\n        for (int y = 0; y < 8; y++)\n        {\n            var from = (x, y);\n            foreach (var to in GetPossibleMoves(state, from))\n            {\n                possibleMoves.Add((from, to));\n            }\n        }\n    }\n    var bestMove = GetBestMove(state, possibleMoves);\n    return bestMove;\n}\n\n/// <summary>\n/// The logic behind the Computer's turn\n/// Look for valid moves and possible subsequent moves\n/// </summary>\n(bool moveMade, int[,] state) ComputerTurn(int[,] state)\n{\n    // Get best move available\n    var move = CalculateMove(state);\n    if (move == null)\n    {\n        // No move can be made\n        return (false, state);\n    }\n    var from = move.Value.from;\n    Console.Write($\"FROM {from.x} {from.y} \");\n    // Continue to make moves until no more valid moves can be made\n    while (move != null)\n    {\n        var to = move.Value.to;\n        Console.WriteLine($\"TO {to.x} {to.y}\");\n        state = ApplyMove(state, from, to);\n        if (!IsJumpMove(from, to))\n            break;\n\n        // check for double / triple / etc. jump\n        var possibleMoves = new List<((int x, int y) from, (int x, int y) to)>();\n        from = to;\n        foreach (var candidate in GetPossibleMoves(state, from))\n        {\n            if (IsJumpMove(from, candidate))\n            {\n                possibleMoves.Add((from, candidate));\n            }\n        }\n        // Get best jump move\n        move = GetBestMove(state, possibleMoves);\n    }\n    // apply crowns to any new Kings\n    state = CrownKingPieces(state);\n    return (true, state);\n}\n#endregion\n\n#region Player Logic\n/// <summary>\n/// Get input from the player in the form \"x,y\" where x and y are integers\n/// If invalid input is received, return null\n/// If input is valid, return the coordinate of the location\n/// </summary>\n(int x, int y)? GetCoordinate(string prompt)\n{\n    Console.Write(prompt + \"? \");\n    var input = Console.ReadLine();\n    // split the string into multiple parts\n    var parts = input?.Split(\",\");\n    if (parts?.Length != 2)\n        // must be exactly 2 parts\n        return null;\n    int x;\n    if (!int.TryParse(parts[0], out x))\n        // first part is not a number\n        return null;\n    int y;\n    if (!int.TryParse(parts[1], out y))\n        //second part is not a number\n        return null;\n\n    return (x, y);\n}\n\n/// <summary>\n/// Get the move from the player.\n/// return a tuple of \"from\" and \"to\" representing a valid move\n///\n/// </summary>\n((int x, int y) from, (int x,int y) to) GetPlayerMove(int[,] state)\n{\n    // The original program has some issues regarding user input\n    // 1)  There are minimal data sanity checks in the original:\n    //     a)  FROM piece must be owned by player\n    //     b)  TO location must be empty\n    //     c)  the FROM and TO x's must be less than 2 squares away\n    //     d)  the FROM and TO y's must be same distance as x's\n    //     No checks are made for direction, if a jump is valid, or\n    //     if the piece even moves.\n    // 2)  Once a valid FROM is selected, a TO must be selected.\n    //     If there are no valid TO locations, you are soft-locked\n    // This approach is intentionally different from the original\n    // but maintains the original intent as much as possible\n    // 1)  Select a FROM location\n    // 2)  If FROM is invalid, return to step 1\n    // 3)  Select a TO location\n    // 4)  If TO is invalid or the implied move is invalid,\n    //     return to step 1\n\n\n    // There is still currently no way for the player to indicate that no move can be made\n    // This matches the original logic, but is a candidate for a refactor\n\n    do\n    {\n        var from = GetCoordinate(\"FROM\");\n        if ((from != null)\n            && !IsOutOfBounds(from.Value)\n            && (state[from.Value.x, from.Value.y] > 0))\n        {\n            // we have a valid \"from\" location\n            var to = GetCoordinate(\"TO\");\n            if ((to != null)\n                && !IsOutOfBounds(to.Value)\n                && IsValidPlayerMove(state, from.Value, to.Value))\n            {\n                // we have a valid \"to\" location\n                return (from.Value, to.Value);\n            }\n        }\n    } while (true);\n}\n\n/// <summary>\n/// Get a subsequent jump from the player if they can / want to\n/// returns a move (\"from\", \"to\") if a player jumps\n/// returns null if a player does not make another move\n/// The player must input negative numbers for the coordinates to indicate\n/// that no more moves are to be made.  This matches the original implementation\n/// </summary>\n((int x, int y) from, (int x, int y) to)? GetPlayerSubsequentJump(int[,] state, (int x, int y) from)\n{\n    do\n    {\n        var to = GetCoordinate(\"+TO\");\n        if ((to != null)\n            && !IsOutOfBounds(to.Value)\n            && IsValidPlayerMove(state, from, to.Value)\n            && IsJumpMove(from, to.Value))\n        {\n            // we have a valid \"to\" location\n            return (from, to.Value); ;\n        }\n\n        if (to != null && to.Value.x < 0 && to.Value.y < 0)\n        {\n            // player has indicated to not make any more moves\n            return null;\n        }\n    }\n    while (true);\n}\n\n/// <summary>\n/// The logic behind the Player's turn\n/// Get the player input for a move\n/// Get subsequent jumps, if possible\n/// </summary>\nint [,] PlayerTurn(int[,] state)\n{\n    var move = GetPlayerMove(state);\n    do\n    {\n        state = ApplyMove(state, move.from, move.to);\n        if (!IsJumpMove(move.from, move.to))\n        {\n            // If player doesn't make a jump move, no further moves are possible\n            break;\n        }\n        var nextMove = GetPlayerSubsequentJump(state, move.to);\n        if (nextMove == null)\n        {\n            // another jump is not made\n            break;\n        }\n        move = nextMove.Value;\n    }\n    while (true);\n    // check to see if any kings need crowning\n    state = CrownKingPieces(state);\n    return state;\n}\n#endregion\n\n/*****************************************************************************\n *\n * Main program starts here\n *\n ****************************************************************************/\n\nWriteIntroduction();\n\n// initalize state -  empty spots initialize to 0\n// set player pieces to 1, computer pieces to -1\n// turn your head to the right to visualize the board.\n// kings will be represented by -2 (for computer) and 2 (for player)\nint[,] state = new int[8, 8] {\n    { 1, 0, 1, 0, 0, 0,-1, 0 },\n    { 0, 1, 0, 0, 0,-1, 0,-1 },\n    { 1, 0, 1, 0, 0, 0,-1, 0 },\n    { 0, 1, 0, 0, 0,-1, 0,-1 },\n    { 1, 0, 1, 0, 0, 0,-1, 0 },\n    { 0, 1, 0, 0, 0,-1, 0,-1 },\n    { 1, 0, 1, 0, 0, 0,-1, 0 },\n    { 0, 1, 0, 0, 0,-1, 0,-1 },\n};\n\nwhile (true)\n{\n    bool moveMade;\n    (moveMade, state) = ComputerTurn(state);\n    if (!moveMade)\n    {\n        // In the original program the computer wins if it cannot make a move\n        // I believe the player should win in this case, assuming the player can make a move.\n        // if neither player can make a move, the game should be draw.\n        // I have left it as the original logic for now.\n        ComputerWins();\n        break;\n    }\n    PrintBoard(state);\n    if (CheckForComputerWin(state))\n    {\n        ComputerWins();\n        break;\n    }\n    state = PlayerTurn(state);\n    if (CheckForPlayerWin(state))\n    {\n        PlayerWins();\n        break;\n    }\n}\n"
  },
  {
    "path": "23_Checkers/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "23_Checkers/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "23_Checkers/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "23_Checkers/javascript/checkers.html",
    "content": "<html>\n<head>\n<title>CHECKERS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"checkers.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "23_Checkers/javascript/checkers.js",
    "content": "// CHECKERS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// x,y = origin square\n// a,b = movement direction\nfunction try_computer()\n{\n    u = x + a;\n    v = y + b;\n    if (u < 0 || u > 7 || v < 0 || v > 7)\n        return;\n    if (s[u][v] == 0) {\n        eval_move();\n        return;\n    }\n    if (s[u][v] < 0)\t// Cannot jump over own pieces\n        return;\n    u += a;\n    u += b;\n    if (u < 0 || u > 7 || v < 0 || v > 7)\n        return;\n    if (s[u][v] == 0)\n        eval_move();\n}\n\n// x,y = origin square\n// u,v = target square\nfunction eval_move()\n{\n    if (v == 0 && s[x][y] == -1)\n        q += 2;\n    if (Math.abs(y - v) == 2)\n        q += 5;\n    if (y == 7)\n        q -= 2;\n    if (u == 0 || u == 7)\n        q++;\n    for (c = -1; c <= 1; c += 2) {\n        if (u + c < 0 || u + c > 7 || v + g < 0)\n            continue;\n        if (s[u + c][v + g] < 0) {\t// Computer piece\n            q++;\n            continue;\n        }\n        if (u - c < 0 || u - c > 7 || v - g > 7)\n            continue;\n        if (s[u + c][v + g] > 0 && (s[u - c][v - g] == 0 || (u - c == x && v - g == y)))\n            q -= 2;\n    }\n    if (q > r[0]) {\t// Best movement so far?\n        r[0] = q;\t// Take note of score\n        r[1] = x;\t// Origin square\n        r[2] = y;\n        r[3] = u;\t// Target square\n        r[4] = v;\n    }\n    q = 0;\n}\n\nfunction more_captures() {\n    u = x + a;\n    v = y + b;\n    if (u < 0 || u > 7 || v < 0 || v > 7)\n        return;\n    if (s[u][v] == 0 && s[x + a / 2][y + b / 2] > 0)\n        eval_move();\n}\n\nvar r = [-99, 0, 0, 0, 0];\nvar s = [];\n\nfor (x = 0; x <= 7; x++)\n    s[x] = [];\n\nvar g = -1;\nvar data = [1, 0, 1, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, -1, 0, -1, 15];\nvar p = 0;\nvar q = 0;\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"CHECKERS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\\n\");\n    print(\"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\\n\");\n    print(\"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\\n\");\n    print(\"(0,0) IS THE LOWER LEFT CORNER\\n\");\n    print(\"(0,7) IS THE UPPER LEFT CORNER\\n\");\n    print(\"(7,0) IS THE LOWER RIGHT CORNER\\n\");\n    print(\"(7,7) IS THE UPPER RIGHT CORNER\\n\");\n    print(\"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\\n\");\n    print(\"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (x = 0; x <= 7; x++) {\n        for (y = 0; y <= 7; y++) {\n            if (data[p] == 15)\n                p = 0;\n            s[x][y] = data[p];\n            p++;\n        }\n    }\n    while (1) {\n\n        // Search the board for the best movement\n        for (x = 0; x <= 7; x++) {\n            for (y = 0; y <= 7; y++) {\n                if (s[x][y] > -1)\n                    continue;\n                if (s[x][y] == -1) {\t// Piece\n                    for (a = -1; a <= 1; a += 2) {\n                        b = g;\t// Only advances\n                        try_computer();\n                    }\n                } else if (s[x][y] == -2) {\t// King\n                    for (a = -1; a <= 1; a += 2) {\n                        for (b = -1; b <= 1; b += 2) {\n                            try_computer();\n                        }\n                    }\n                }\n            }\n        }\n        if (r[0] == -99) {\n            print(\"\\n\");\n            print(\"YOU WIN.\\n\");\n            break;\n        }\n        print(\"FROM \" + r[1] + \",\" + r[2] + \" TO \" + r[3] + \",\" + r[4]);\n        r[0] = -99;\n        while (1) {\n            if (r[4] == 0) {\t// Computer reaches the bottom\n                s[r[3]][r[4]] = -2;\t// King\n                break;\n            }\n            s[r[3]][r[4]] = s[r[1]][r[2]];\t// Move\n            s[r[1]][r[2]] = 0;\n            if (Math.abs(r[1] - r[3]) == 2) {\n                s[(r[1] + r[3]) / 2][(r[2] + r[4]) / 2] = 0;\t// Capture\n                x = r[3];\n                y = r[4];\n                if (s[x][y] == -1) {\n                    b = -2;\n                    for (a = -2; a <= 2; a += 4) {\n                        more_captures();\n                    }\n                } else if (s[x][y] == -2) {\n                    for (a = -2; a <= 2; a += 4) {\n                        for (b = -2; b <= 2; b += 4) {\n                            more_captures();\n                        }\n                    }\n                }\n                if (r[0] != -99) {\n                    print(\" TO \" + r[3] + \",\" + r[4]);\n                    r[0] = -99;\n                    continue;\n                }\n            }\n            break;\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        for (y = 7; y >= 0; y--) {\n            str = \"\";\n            for (x = 0; x <= 7; x++) {\n                if (s[x][y] == 0)\n                    str += \".\";\n                if (s[x][y] == 1)\n                    str += \"O\";\n                if (s[x][y] == -1)\n                    str += \"X\";\n                if (s[x][y] == -2)\n                    str += \"X*\";\n                if (s[x][y] == 2)\n                    str += \"O*\";\n                while (str.length % 5)\n                    str += \" \";\n            }\n            print(str + \"\\n\");\n            print(\"\\n\");\n        }\n        print(\"\\n\");\n        z = 0;\n        t = 0;\n        for (l = 0; l <= 7; l++) {\n            for (m = 0; m <= 7; m++) {\n                if (s[l][m] == 1 || s[l][m] == 2)\n                    z = 1;\n                if (s[l][m] == -1 || s[l][m] == -2)\n                    t = 1;\n            }\n        }\n        if (z != 1) {\n            print(\"\\n\");\n            print(\"I WIN.\\n\");\n            break;\n        }\n        if (t != 1) {\n            print(\"\\n\");\n            print(\"YOU WIN.\\n\");\n            break;\n        }\n        do {\n            print(\"FROM\");\n            e = await input();\n            h = parseInt(e.substr(e.indexOf(\",\") + 1));\n            e = parseInt(e);\n            x = e;\n            y = h;\n        } while (s[x][y] <= 0) ;\n        do {\n            print(\"TO\");\n            a = await input();\n            b = parseInt(a.substr(a.indexOf(\",\") + 1));\n            a = parseInt(a);\n            x = a;\n            y = b;\n            if (s[x][y] == 0 && Math.abs(a - e) <= 2 && Math.abs(a - e) == Math.abs(b - h))\n                break;\n            print(\"WHAT?\\n\");\n        } while (1) ;\n        i = 46;\n        do {\n            s[a][b] = s[e][h]\n            s[e][h] = 0;\n            if (Math.abs(e - a) != 2)\n                break;\n            s[(e + a) / 2][(h + b) / 2] = 0;\n            while (1) {\n                print(\"+TO\");\n                a1 = await input();\n                b1 = parseInt(a1.substr(a1.indexOf(\",\") + 1));\n                a1 = parseInt(a1);\n                if (a1 < 0)\n                    break;\n                if (s[a1][b1] == 0 && Math.abs(a1 - a) == 2 && Math.abs(b1 - b) == 2)\n                    break;\n            }\n            if (a1 < 0)\n                break;\n            e = a;\n            h = b;\n            a = a1;\n            b = b1;\n            i += 15;\n        } while (1);\n        if (b == 7)\t// Player reaches top\n            s[a][b] = 2;\t// Convert to king\n    }\n}\n\nmain();\n"
  },
  {
    "path": "23_Checkers/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "23_Checkers/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "23_Checkers/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nNote: This version has lines and columns numbers to help you with choosing the cell\nto move from and to, so you don't have to continually count. It also puts a \".\" only for\nblank cells you can move to, which I think makes for a more pleasing look and makes\nit easier to play. If you want the original behavior, start the program with an arg\nof \"-o\" for the original behavior.\n"
  },
  {
    "path": "23_Checkers/perl/checkers.pl",
    "content": "#!/usr/bin/perl\n\n# Checkers program in Perl\n#   Started with checkers.annotated.bas\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\n#\n# The current move: (rating, current x, current y, new x, new y)\n# 'rating' represents how good the move is; higher is better.\nmy @ratings = (-99); # (4); # Start with minimum score\n# The board.  Pieces are represented by numeric values:\n#\n#      - 0     = empty square\n#      - -1,-2 = X (-1 for regular piece, -2 for king)\n#      - 1,2   = O (1 for regular piece, 2 for king)\n#\n# This program's player (\"me\") plays X.\nmy @board; # (7,7)\n# chars to print for the board, add 2 to the board value as an index to the char\nmy @chars = (\"X*\", \"X\", \".\", \"O\", \"O*\");\nmy $neg1 = -1;          # constant holding -1\nmy $winner = \"\";\nmy $upgrade = shift(@ARGV) // \"\";\n$upgrade = $upgrade eq \"-o\" ? 0 : 1;\n\n#####\n\nprint \"\\n\";\nprint \" \" x 32, \"CHECKERS\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\n\nprint \"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\\n\";\nprint \"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\\n\";\nprint \"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\\n\";\nprint \"(0,0) IS THE LOWER LEFT CORNER\\n\";\nprint \"(0,7) IS THE UPPER LEFT CORNER\\n\";\nprint \"(7,0) IS THE LOWER RIGHT CORNER\\n\";\nprint \"(7,7) IS THE UPPER RIGHT CORNER\\n\";\nprint \"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\\n\";\nprint \"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\\n\";\nprint \"ENTER YOUR MOVE POSITION LIKE '0 0' OR '0,0'.\\n\\n\\n\";\n\n# Initialize the board.  Data is 2 length-wise strips repeated.\nmy @data = ();\nfor (1 .. 32) { push(@data, (1,0,1,0,0,0,-1,0, 0,1,0,0,0,-1,0,-1)); }\nfor my $x (0 .. 7)\n{\n    for my $y (0 .. 7)\n    {\n        $board[$x][$y] = shift(@data);\n    }\n}\n\n# Start of game loop.  First, my turn.\nwhile (1)\n{\n\n    # For each square on the board, search for one of my pieces\n    # and if it can make the best move so far, store that move in 'r'\n    for my $x (0 .. 7)\n    {\n        for my $y (0 .. 7)\n        {\n            # Skip if this is empty or an opponent's piece\n            next if ($board[$x][$y] > -1);\n\n            # If this is one of my ordinary pieces, analyze possible\n            # forward moves.\n            if ($board[$x][$y] == -1)\n            {\n                for (my $a = -1 ; $a <= 1 ; $a +=2)\n                {\n                    $b = $neg1;\n                    find_move($x, $y, $a, $b);\n                }\n            }\n\n            # If this is one of my kings, analyze possible forward\n            # and backward moves.\n            if ($board[$x][$y] == -2)\n            {\n                for (my $a = -1 ; $a <= 1 ; $a += 2)\n                {\n                    for (my $b = -1 ; $a <= 1 ; $b += 2) { find_move($x, $y, $a, $b); }\n                }\n            }\n        }\n    }\n\n\n    if ($ratings[0] == -99) # Game is lost if no move could be found.\n    {\n        $winner = \"you\";\n        last;\n    }\n\n    # Print the computer's move.  (Note: chr$(30) is an ASCII RS\n    # (record separator) code; probably no longer relevant.)\n    print \"FROM $ratings[1],$ratings[2] TO $ratings[3],$ratings[4] \";\n    $ratings[0] = -99;\n\n    # Make the computer's move.  If the piece finds its way to the\n    # end of the board, crown it.\n    LOOP1240: {\n        if ($ratings[4] == 0)\n        {\n            $board[$ratings[3]][$ratings[4]] = -2;\n            last LOOP1240;\n        }\n        $board[$ratings[3]][$ratings[4]] = $board[$ratings[1]][$ratings[2]];\n        $board[$ratings[1]][$ratings[2]] = 0;\n\n        # If the piece has jumped 2 squares, it means the computer has\n        # taken an opponents' piece.\n        if (abs($ratings[1] - $ratings[3]) == 2)\n        {\n            $board [($ratings[1]+$ratings[3])/2] [($ratings[2]+$ratings[4])/2] = 0;     # Delete the opponent's piece\n\n            # See if we can jump again.  Evaluate all possible moves.\n            my $x = $ratings[3];\n            my $y = $ratings[4];\n            for (my $a = -2 ; $a <= 2 ; $a += 4)\n            {\n                if ($board[$x][$y] == -1)\n                {\n                    $b = -2;\n                    eval_move($x, $y, $a, $b);\n                }\n                if ($board[$x][$y] == -2)\n                {\n                    for (my $b = -2 ; $b <= 2 ; $b += 4) { eval_move($x, $y, $a, $b); }\n                }\n            }\n\n            # If we've found a move, go back and make that one as well\n            if ($ratings[0] != -99)\n            {\n                print \"TO $ratings[3], $ratings[4] \";\n                $ratings[0] = -99;\n                next LOOP1240;\n            }\n        }\n    } # LOOP1240\n\n    # Now, print the board\n    print \"\\n\\n\\n\";\n    for (my $y = 7 ; $y >= 0 ; $y--)\n    {\n        my $line = \"\";\n        $line = \"$y|\" if ($upgrade);\n        for my $x (0 .. 7)\n        {\n            my $c = $chars[$board[$x][$y] + 2];\n            $c = ' ' if ($upgrade && (($y % 2 == 0 && $x % 2 == 1) || ($y % 2 == 1 && $x % 2 == 0)));\n            $line = tab($line, 5*$x+7, $c);\n        }\n        print $line;\n        print \" \\n\\n\";\n    }\n    print \"       _    _    _    _    _    _    _    _\\n\" if ($upgrade);\n    print \"       0    1    2    3    4    5    6    7\\n\" if ($upgrade);\n    print \"\\n\";\n\n    # Check if either player is out of pieces.  If so, announce the\n    # winner.\n    my ($z, $t) = (0, 0);\n    for my $x (0 .. 7)\n    {\n        for my $y (0 .. 7)\n        {\n            if ($board[$x][$y] == 1  || $board[$x][$y] == 2)  { $z = 1; }\n            if ($board[$x][$y] == -1 || $board[$x][$y] == -2) { $t = 1; }\n        }\n    }\n    if ($z != 1) { $winner = \"comp\"; last; }\n    if ($t != 1) { $winner = \"you\"; last; }\n\n    # Prompt the player for their move.\n    ($z, $t) = (0, 0);\n    my ($x, $y, $e, $h, $a, $b);\n    do {\n        ($e,$h) = get_pos(\"FROM:\");\n        $x = $e;\n        $y = $h;\n    } while ($board[$x][$y] <= 0);\n    do {\n        ($a,$b) = get_pos(\"TO:\");\n        $x = $a;\n        $y = $b;\n    } while (!($board[$x][$y] == 0 && abs($a-$e) <= 2 && abs($a-$e) == abs($b-$h)));\n\n    LOOP1750: {\n        # Make the move and stop unless it might be a jump.\n        $board[$a][$b] = $board[$e][$h];\n        $board[$e][$h] = 0;\n        if (abs($e-$a) != 2) { last LOOP1750; }\n\n        # Remove the piece jumped over\n        $board[($e+$a)/2][($h+$b)/2] = 0;\n\n        # Prompt for another move; -1 means player can't, so I've won.\n        # Keep prompting until there's a valid move or the player gives\n        # up.\n        my ($a1, $b1);\n        do {\n            ($a1,$b1) = get_pos(\"+TO:\");\n            if ($a1 < 0) { last LOOP1750; }\n        } while ($board[$a1][$b1] != 0 || abs($a1-$a) != 2 || abs($b1-$b) != 2);\n\n        # Update the move variables to correspond to the next jump\n        $e = $a;\n        $h = $b;\n        $a = $a1;\n        $b = $b1;\n    }\n\n    # If the player has reached the end of the board, crown this piece\n    if ($b == 7) { $board[$a][$b] = 2; }\n\n    # And play the next turn.\n}\n\n# Endgame:\nprint \"\\n\", ($winner eq \"you\" ? \"YOU\" : \"I\"), \" WIN\\n\";\nexit(0);\n\n###########################################\n\n# make sure we get a 2 value position\nsub get_pos\n{\n    my $prompt = shift;\n    my ($p1, $p2);\n    do {\n        print \"$prompt \";\n        chomp(my $ans = <>);\n        ($p1,$p2) = split(/[, ]/, $ans);\n    } while (!defined($p1) || !defined($p2) || $p1 < -1 || $p2 < -1 || $p1 > 7 || $p2 > 7);\n    return ($p1,$p2);\n}\n\n# deal with basic's tab() for line positioning\n#   line = line string we're starting with\n#   pos = position to start writing\n#   s = string to write\n# returns the resultant string, which might not have been changed\nsub tab\n{\n    my ($line, $pos, $str) = @_;\n    my $len = length($line);\n    # if curser is past position, do nothing\n    if ($len <= $pos) { $line .= \" \" x ($pos - $len) . $str; }\n    return $line;\n}\n\n# Analyze a move from (x,y) to (x+a, y+b) and schedule it if it's\n# the best candidate so far.\nsub find_move\n{\n    my ($x, $y, $a, $b) = @_;\n    my $u = $x+$a;\n    my $v = $y+$b;\n\n    # Done if it's off the board\n    return if ($u < 0 || $u > 7 || $v < 0 || $ v> 7);\n\n    # Consider the destination if it's empty\n    eval_jump($x, $y, $u, $v) if ($board[$u][$v] == 0);\n\n    # If it's got an opponent's piece, jump it instead\n    if ($board[$u][$v] > 0)\n    {\n\n        # Restore u and v, then return if it's off the board\n        $u += $a;\n        $v += $b;\n        return if ($u < 0 || $v < 0 || $u > 7 || $v > 7);\n\n        # Otherwise, consider u,v\n        eval_jump($x, $y, $u, $v) if ($board[$u][$v] == 0);\n    }\n}\n\n# Evaluate jumping (x,y) to (u,v).\n#\n# Computes a score for the proposed move and if it's higher\n# than the best-so-far move, uses that instead by storing it\n# and its score in @ratings.\nsub eval_jump\n{\n    my ($x, $y, $u, $v) = @_;\n\n    # q is the score; it starts at 0\n    my $q = 0;\n\n    # +2 if it promotes this piece\n    $q += 2 if ($v == 0 && $board[$x][$y] == -1);\n\n    # +5 if it takes an opponent's piece\n    $q += 5 if (abs($y-$v) == 2);\n\n    # -2 if the piece is moving away from the top boundary\n    $q -= 2 if ($y == 7);\n\n    # +1 for putting the piece against a vertical boundary\n    $q++ if ($u == 0 || $u == 7);\n\n    for (my $c = -1 ; $c <= 1 ; $c += 2)\n    {\n        next if ($u+$c < 0 || $u+$c > 7 || $v+$neg1 < 0);\n\n        # +1 for each adjacent friendly piece\n        if ($board[$u+$c][$v+$neg1] < 0)\n        {\n            $q++;\n            next;\n        }\n\n        # Prevent out-of-bounds testing\n        next if ($u-$c < 0 || $u-$c > 7 || $v-$neg1 > 7);\n\n        # -2 for each opponent piece that can now take this piece here\n        $q -= 2 if ($board[$u+$c][$v+$neg1] > 0 && ($board[$u-$c][$v-$neg1] == 0 || ($u-$c == $x && $v-$neg1 == $y)));\n    }\n\n    # Use this move if it's better than the previous best\n    if ($q > $ratings[0])\n    {\n        $ratings[0] = $q;\n        $ratings[1] = $x;\n        $ratings[2] = $y;\n        $ratings[3] = $u;\n        $ratings[4] = $v;\n    }\n}\n\n# If (u,v) is in the bounds, evaluate it as a move using\n# the sub at 910, so storing eval in @ratings.\nsub eval_move\n{\n    my ($x, $y, $a, $b) = @_;\n    my $u = $x+$a;\n    my $v = $y+$b;\n    return if ($u < 0 || $u > 7 || $v < 0 || $v > 7);\n    eval_jump($x, $y, $u, $v) if ($board[$u][$v] == 0 && $board[$x+$a/2][$y+$b/2] > 0);\n}\n"
  },
  {
    "path": "23_Checkers/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "23_Checkers/python/checkers.py",
    "content": "\"\"\"\nCHECKERS\n\nHow about a nice game of checkers?\n\nPorted by Dave LeCompte\n\"\"\"\n\nfrom typing import Iterator, NamedTuple, Optional, Tuple\n\nPAGE_WIDTH = 64\n\nHUMAN_PLAYER = 1\nCOMPUTER_PLAYER = -1\nHUMAN_PIECE = 1\nHUMAN_KING = 2\nCOMPUTER_PIECE = -1\nCOMPUTER_KING = -2\nEMPTY_SPACE = 0\n\nTOP_ROW = 7\nBOTTOM_ROW = 0\n\n\nclass MoveRecord(NamedTuple):\n    quality: int\n    start_x: int\n    start_y: int\n    dest_x: int\n    dest_y: int\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef get_coordinates(prompt: str) -> Tuple[int, int]:\n    err_msg = \"ENTER COORDINATES in X,Y FORMAT\"\n    while True:\n        print(prompt)\n        response = input()\n        if \",\" not in response:\n            print(err_msg)\n            continue\n\n        try:\n            x, y = (int(c) for c in response.split(\",\"))\n        except ValueError:\n            print(err_msg)\n            continue\n\n        return x, y\n\n\ndef is_legal_board_coordinate(x: int, y: int) -> bool:\n    return (0 <= x <= 7) and (0 <= y <= 7)\n\n\nclass Board:\n    def __init__(self) -> None:\n        self.spaces = [[0 for _ in range(8)] for _ in range(8)]\n        for x in range(8):\n            if (x % 2) == 0:\n                self.spaces[x][6] = COMPUTER_PIECE\n                self.spaces[x][2] = HUMAN_PIECE\n                self.spaces[x][0] = HUMAN_PIECE\n            else:\n                self.spaces[x][7] = COMPUTER_PIECE\n                self.spaces[x][5] = COMPUTER_PIECE\n                self.spaces[x][1] = HUMAN_PIECE\n\n    def __str__(self) -> str:\n        pieces = {\n            EMPTY_SPACE: \".\",\n            HUMAN_PIECE: \"O\",\n            HUMAN_KING: \"O*\",\n            COMPUTER_PIECE: \"X\",\n            COMPUTER_KING: \"X*\",\n        }\n\n        s = \"\\n\\n\\n\"\n        for y in range(7, -1, -1):\n            for x in range(0, 8):\n                piece_str = pieces[self.spaces[x][y]]\n                piece_str += \" \" * (5 - len(piece_str))\n                s += piece_str\n            s += \"\\n\"\n        s += \"\\n\\n\"\n\n        return s\n\n    def get_spaces(self) -> Iterator[Tuple[int, int]]:\n        for x in range(0, 8):\n            for y in range(0, 8):\n                yield x, y\n\n    def get_spaces_with_computer_pieces(self) -> Iterator[Tuple[int, int]]:\n        for x, y in self.get_spaces():\n            contents = self.spaces[x][y]\n            if contents < 0:\n                yield x, y\n\n    def get_spaces_with_human_pieces(self) -> Iterator[Tuple[int, int]]:\n        for x, y in self.get_spaces():\n            contents = self.spaces[x][y]\n            if contents > 0:\n                yield x, y\n\n    def get_legal_deltas_for_space(self, x: int, y: int) -> Iterator[Tuple[int, int]]:\n        contents = self.spaces[x][y]\n        for delta_x in (-1, 1):\n            if contents == COMPUTER_PIECE:\n                yield (delta_x, -1)\n            else:\n                for delta_y in (-1, 1):\n                    yield (delta_x, delta_y)\n\n    def get_legal_moves(self, x: int, y: int) -> Iterator[MoveRecord]:\n        for delta_x, delta_y in self.get_legal_deltas_for_space(x, y):\n            new_move_record = self.check_move(x, y, delta_x, delta_y)\n\n            if new_move_record is not None:\n                yield new_move_record\n\n    def pick_computer_move(self) -> Optional[MoveRecord]:\n        move_record = None\n\n        for start_x, start_y in self.get_spaces_with_computer_pieces():\n            for delta_x, delta_y in self.get_legal_deltas_for_space(start_x, start_y):\n                new_move_record = self.check_move(start_x, start_y, delta_x, delta_y)\n\n                if new_move_record is None:\n                    continue\n\n                if (move_record is None) or (\n                    new_move_record.quality > move_record.quality\n                ):\n                    move_record = new_move_record\n\n        return move_record\n\n    def check_move(\n        self, start_x: int, start_y: int, delta_x: int, delta_y: int\n    ) -> Optional[MoveRecord]:\n        new_x = start_x + delta_x\n        new_y = start_y + delta_y\n        if not is_legal_board_coordinate(new_x, new_y):\n            return None\n\n        contents = self.spaces[new_x][new_y]\n        if contents == EMPTY_SPACE:\n            return self.evaluate_move(start_x, start_y, new_x, new_y)\n        if contents < 0:\n            return None\n\n        # check jump landing space, which is an additional dx, dy from new_x, newy\n        landing_x = new_x + delta_x\n        landing_y = new_y + delta_y\n\n        if not is_legal_board_coordinate(landing_x, landing_y):\n            return None\n        if self.spaces[landing_x][landing_y] == EMPTY_SPACE:\n            return self.evaluate_move(start_x, start_y, landing_x, landing_y)\n        return None\n\n    def evaluate_move(\n        self, start_x: int, start_y: int, dest_x: int, dest_y: int\n    ) -> MoveRecord:\n        quality = 0\n        if dest_y == 0 and self.spaces[start_x][start_y] == COMPUTER_PIECE:\n            # promoting is good\n            quality += 2\n        if abs(dest_y - start_y) == 2:\n            # jumps are good\n            quality += 5\n        if start_y == 7:\n            # prefer to defend back row\n            quality -= 2\n        if dest_x in {0, 7}:\n            # moving to edge column\n            quality += 1\n        for delta_x in (-1, 1):\n            if not is_legal_board_coordinate(dest_x + delta_x, dest_y - 1):\n                continue\n\n            if self.spaces[dest_x + delta_x][dest_y - 1] < 0:\n                # moving into \"shadow\" of another computer piece\n                quality += 1\n\n            if not is_legal_board_coordinate(dest_x - delta_x, dest_y + 1):\n                continue\n\n            if (\n                (self.spaces[dest_x + delta_x][dest_y - 1] > 0)\n                and (self.spaces[dest_x - delta_x][dest_y + 1] == EMPTY_SPACE)\n                or ((dest_x - delta_x == start_x) and (dest_y + 1 == start_y))\n            ):\n                # we are moving up to a human checker that could jump us\n                quality -= 2\n        return MoveRecord(quality, start_x, start_y, dest_x, dest_y)\n\n    def remove_r_pieces(self, move_record: MoveRecord) -> None:\n        self.remove_pieces(\n            move_record.start_x,\n            move_record.start_y,\n            move_record.dest_x,\n            move_record.dest_y,\n        )\n\n    def remove_pieces(\n        self, start_x: int, start_y: int, dest_x: int, dest_y: int\n    ) -> None:\n        self.spaces[dest_x][dest_y] = self.spaces[start_x][start_y]\n        self.spaces[start_x][start_y] = EMPTY_SPACE\n\n        if abs(dest_x - start_x) == 2:\n            mid_x = (start_x + dest_x) // 2\n            mid_y = (start_y + dest_y) // 2\n            self.spaces[mid_x][mid_y] = EMPTY_SPACE\n\n    def play_computer_move(self, move_record: MoveRecord) -> None:\n        print(\n            f\"FROM {move_record.start_x} {move_record.start_y} TO {move_record.dest_x} {move_record.dest_y}\"\n        )\n\n        while True:\n            if move_record.dest_y == BOTTOM_ROW:\n                # KING ME\n                self.remove_r_pieces(move_record)\n                self.spaces[move_record.dest_x][move_record.dest_y] = COMPUTER_KING\n                return\n            else:\n                self.spaces[move_record.dest_x][move_record.dest_y] = self.spaces[\n                    move_record.start_x\n                ][move_record.start_y]\n                self.remove_r_pieces(move_record)\n\n                if abs(move_record.dest_x - move_record.start_x) != 2:\n                    return\n\n                landing_x = move_record.dest_x\n                landing_y = move_record.dest_y\n\n                best_move = None\n                if self.spaces[landing_x][landing_y] == COMPUTER_PIECE:\n                    for delta_x in (-2, 2):\n                        test_record = self.try_extend(landing_x, landing_y, delta_x, -2)\n                        if (move_record is not None) and (\n                            (best_move is None)\n                            or (move_record.quality > best_move.quality)\n                        ):\n                            best_move = test_record\n                else:\n                    assert self.spaces[landing_x][landing_y] == COMPUTER_KING\n                    for delta_x in (-2, 2):\n                        for delta_y in (-2, 2):\n                            test_record = self.try_extend(\n                                landing_x, landing_y, delta_x, delta_y\n                            )\n                            if (move_record is not None) and (\n                                (best_move is None)\n                                or (move_record.quality > best_move.quality)\n                            ):\n                                best_move = test_record\n\n                if best_move is None:\n                    return\n                print(f\"TO {best_move.dest_x} {best_move.dest_y}\")\n                move_record = best_move\n\n    def try_extend(\n        self, start_x: int, start_y: int, delta_x: int, delta_y: int\n    ) -> Optional[MoveRecord]:\n        new_x = start_x + delta_x\n        new_y = start_y + delta_y\n\n        if not is_legal_board_coordinate(new_x, new_y):\n            return None\n\n        jumped_x = start_x + delta_x // 2\n        jumped_y = start_y + delta_y // 2\n\n        if (self.spaces[new_x][new_y] == EMPTY_SPACE) and (\n            self.spaces[jumped_x][jumped_y] > 0\n        ):\n            return self.evaluate_move(start_x, start_y, new_x, new_y)\n        return None\n\n    def get_human_move(self) -> Tuple[int, int, int, int]:\n        is_king = False\n\n        while True:\n            start_x, start_y = get_coordinates(\"FROM?\")\n\n            legal_moves = list(self.get_legal_moves(start_x, start_y))\n            if not legal_moves:\n                print(f\"({start_x}, {start_y}) has no legal moves. Choose again.\")\n                continue\n            if self.spaces[start_x][start_y] > 0:\n                break\n\n        is_king = self.spaces[start_x][start_y] == HUMAN_KING\n\n        while True:\n            dest_x, dest_y = get_coordinates(\"TO?\")\n\n            if (not is_king) and (dest_y < start_y):\n                # CHEATER! Trying to move non-king backwards\n                continue\n            is_free = self.spaces[dest_x][dest_y] == 0\n            within_reach = abs(dest_x - start_x) <= 2\n            is_diagonal_move = abs(dest_x - start_x) == abs(dest_y - start_y)\n            if is_free and within_reach and is_diagonal_move:\n                break\n        return start_x, start_y, dest_x, dest_y\n\n    def get_human_extension(\n        self, start_x: int, start_y: int\n    ) -> Tuple[bool, Optional[Tuple[int, int, int, int]]]:\n        is_king = self.spaces[start_x][start_y] == HUMAN_KING\n\n        while True:\n            dest_x, dest_y = get_coordinates(\"+TO?\")\n\n            if dest_x < 0:\n                return False, None\n            if (not is_king) and (dest_y < start_y):\n                # CHEATER! Trying to move non-king backwards\n                continue\n            if (\n                (self.spaces[dest_x][dest_y] == EMPTY_SPACE)\n                and (abs(dest_x - start_x) == 2)\n                and (abs(dest_y - start_y) == 2)\n            ):\n                return True, (start_x, start_y, dest_x, dest_y)\n\n    def play_human_move(\n        self, start_x: int, start_y: int, dest_x: int, dest_y: int\n    ) -> None:\n        self.remove_pieces(start_x, start_y, dest_x, dest_y)\n\n        if dest_y == TOP_ROW:\n            # KING ME\n            self.spaces[dest_x][dest_y] = HUMAN_KING\n\n    def check_pieces(self) -> bool:\n        if not list(self.get_spaces_with_computer_pieces()):\n            print_human_won()\n            return False\n        if not list(self.get_spaces_with_computer_pieces()):\n            print_computer_won()\n            return False\n        return True\n\n\ndef print_instructions() -> None:\n    print(\"THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,\")\n    print(\"AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST.\")\n    print(\"SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\")\n    print(\"(0,0) IS THE LOWER LEFT CORNER\")\n    print(\"(0,7) IS THE UPPER LEFT CORNER\")\n    print(\"(7,0) IS THE LOWER RIGHT CORNER\")\n    print(\"(7,7) IS THE UPPER RIGHT CORNER\")\n    print(\"THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\")\n    print(\"JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\\n\\n\\n\")\n\n\ndef print_human_won() -> None:\n    print(\"\\nYOU WIN.\")\n\n\ndef print_computer_won() -> None:\n    print(\"\\nI WIN.\")\n\n\ndef play_game() -> None:\n    board = Board()\n\n    while True:\n        move_record = board.pick_computer_move()\n        if move_record is None:\n            print_human_won()\n            return\n        board.play_computer_move(move_record)\n\n        print(board)\n\n        if not board.check_pieces():\n            return\n\n        start_x, start_y, dest_x, dest_y = board.get_human_move()\n        board.play_human_move(start_x, start_y, dest_x, dest_y)\n        if abs(dest_x - start_x) == 2:\n            while True:\n                extend, move = board.get_human_extension(dest_x, dest_y)\n                assert move is not None\n                if not extend:\n                    break\n                start_x, start_y, dest_x, dest_y = move\n                board.play_human_move(start_x, start_y, dest_x, dest_y)\n\n\ndef main() -> None:\n    print_header(\"CHECKERS\")\n    print_instructions()\n\n    play_game()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "23_Checkers/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n\nThis version preserves the underlying algorithms and functionality of\nthe original while using more modern programming constructs\n(functions, classes, symbols) and providing much more detailed\ncomments.  It also fixes some (but not all) of the bugs.\n"
  },
  {
    "path": "23_Checkers/ruby/checkers.rb",
    "content": "#!/usr/bin/env ruby\n\n# Checkers in Ruby, Version 1\n#\n# This version of the game attempts to preserve the underlying\n# algorithm(s) and feel of the BASIC version while using more modern\n# coding techniques.  Specifically:\n#\n# 1. The major data structures (the board and current move, known as S\n#    and R in the BASIC version) have been turned into classes.  In\n#    addition, I made a class for coordinates so that you don't always\n#    have to deal with pairs of numbers.\n#\n# 2. Much of the functionality associated with this data has been moved\n#    into methods of these classes in line with the philosophy that objects\n#    are smart data.\n#\n# 3. While I've kept the board as a single object (not global, though),\n#    this program will create many Move objects (i.e. copies of the move\n#    under consideration) rather than operating on a single global\n#    instance.\n#\n# 4. The rest of the code has been extracted into Ruby functions with\n#    all variables as local as reasonably possible.\n#\n# 5. Pieces are now represented with Symbols instead of integers; this\n#    made it *much* easier to understand what was going on.\n#\n# 6. There are various internal sanity checks.  They fail by throwing\n#    a string as an exception.  (This is generally frowned upon if\n#    you're going to catch the exception later but we never do that;\n#    an exception here means a bug in the software and the way to fix\n#    that is to fix the program.)\n#\n# And probably other stuff.\n#\n\n\n# Note: I've ordered the various major definitions here from (roughly)\n# general to specific so that if you read the code starting from the\n# beginning, you'll (hopefully) get a big-picture view first and then\n# get into details.  Normally, I'd order things by topic and define\n# things before using them, which is a better ordering.  So in this\n# case, do what I say and not what I do.\n\n\n#\n# Some global constants\n#\n\nBOARD_TEXT_INDENT = 30  # Number of spaces to indent the board when printing\n\n# Various constants related to the game of Checkers.\n#\n# (Yes, they're obvious but if you see BOARD_WIDTH, you know this is\n# related to board dimensions in a way that you wouldn't if you saw\n# '8'.)\nBOARD_WIDTH = 8\nKING_ROW_X = 0\nKING_ROW_Y = BOARD_WIDTH - 1\n\n\n\n# This is the mainline routine of the program.  Ruby doesn't require\n# that you put this in a function but this way, your local variables\n# are contained here.  It's also neater, IMO.\n#\n# The name 'main' isn't special; it's just a function.  The last line\n# of this program is a call to it.\ndef main\n  print <<EOF\n                                Checkers\n         Inspiration: Creative Computing  Morristown, New Jersey\n\n\n          This is the game of checkers.  The computer is X,\n          and you are O.  The computer will move first.\n          Squares are referred to by a coordinate system.\n                    (0,0) is the lower left corner\n                    (0,7) is the upper left corner\n                    (7,0) is the lower right corner\n                    (7,7) is the upper right corner\n          The computer will tell you when you have another\n          jump.\n\n          Enter a blank line if you cannot make a move.  If this\n          not after a jump, it means you have lost the game.\n\n\n\nEOF\n\n  board = Board.new\n  winner = game_loop(board)\n\n  puts board.text\n  puts\n  puts \"#{winner ? 'I' : 'You'} win.\"\nend\n\n\n# This is the main game loop.  Returns true if I win and false if the\n# player wins.  Each of my_turn and players_turn return false if they\n# could not move.  (Recall that the game ends when one player can't\n# move.)\ndef game_loop(board)\n  while true\n    my_turn(board)      or return false\n    players_turn(board) or return true\n  end\nend\n\n\n#\n# My (i.e. computer's) turn\n#\n\n# Play my turn, returning true if it could make at least one move and\n# false otherwise.  This is pretty simple because the heavy lifting is\n# done by the methods of the Board and Move classes.\ndef my_turn(board, jumpStart = nil)\n  # Print the initial board\n  puts board.text\n\n  # Find the candidate move.  If this is a move after a jump, the\n  # starting point will be in jumpStart and we use only that.\n  # Otherwise, we check all available pieces.\n  bestMove = Move.invalid\n  candidates = jumpStart ? [jumpStart] : board.my_pieces\n  for coord in candidates\n    bestMove = bestMove.betterOf( board.bestMoveFrom(coord, !!jumpStart) )\n  end\n\n  # If we can't find a move, we're done\n  if !bestMove.valid?\n    puts \"I can't make another #{jumpStart ? 'jump' : 'move'}.\"\n    return false\n  end\n\n  # Do the move\n  puts \"My move: #{bestMove}\"\n  board.make_move!(bestMove)\n\n  # Repeat (recursively) if we can make another jump\n  my_turn(board, bestMove.to) if bestMove.jump?\n\n  # No loss yet!\n  return true\nend\n\n\n\n\n#\n# Player's turn\n#\n\n\n# Prompt the player for a move and then play it.  If the player can\n# make multiple moves (i.e. jump), repeat. Return true if at least one\n# move was played, false otherwise.\n#\n# Note that this does not enforce all of the rules of the game; it\n# assumes the player knows the rules and will stick to them.  In\n# particular, the player is not required to jump if possible.  This\n# behaviour was inherited from the BASIC version but I've made some\n# improvements so we will catch most illegal moves; in that case, the\n# player is prompted for another move.\ndef players_turn(board)\n  from = nil\n\n  while true\n    move = get_player_move(board, from)\n\n    # If the player declines to enter a move, we're done.  If this is\n    # the first move ('from' will be nil in this case), it's a forfeit\n    # and we return false to indicate the player has lost.  But if\n    # it's a jump, the player was able to move and therefor has not\n    # lost so we return true.  (Note: this requires the player to not\n    # cheat, which is kind of a bug but that's how the original worked\n    # as well.)\n    return false    if !from && !move\n    return true     if from && !move\n\n    board.make_move!(move)\n    return true unless move.jump?\n\n    # If the player can jump again, repeat from the new position.\n    from = move.to\n  end\n\n  # Can't reach here\n\nend\n\n\n# Prompt the player for a move, read it, check if it's legal and\n# return it if it is or try again if it isn't.  If the player declines\n# to move, returns nil.  If this is a jump following a previous jump,\n# the second argument will be the source (i.e. Move.from) and we don't\n# ask for it here..\ndef get_player_move(board, jumpFrom = nil)\n\n  puts \"You can jump again!\" if jumpFrom\n\n  while true\n    puts board.text\n    puts \"Enter your move:\"\n\n    puts \"From? #{jumpFrom}\" if jumpFrom\n    from = jumpFrom || read_coord(\"From? \")\n\n    to = read_coord(\"To? \") unless !from\n\n    # If the player entered a blank line, it's a forfeit\n    if !from || !to\n      return nil if jumpFrom || confirm_quit()\n    end\n\n    move = Move.new(from, to)\n    return move if board.legal_move?(false, move)\n\n    print \"\\nThis move is not legal!\\n\\n\"\n  end\nend\n\n\n# Prompt the player for the x,y coordinates of a piece on the board,\n# repeating until a valid coordinate is provided and return it.  If\n# the player enters a blank line, returns nil; this is interpreted as\n# declining to move.\ndef read_coord(prompt)\n  while true\n    print prompt\n    STDOUT.flush\n\n    line = (STDIN.gets || \"\").strip\n    return nil if line == ''\n\n    coord = parse_coord(line)\n\n    return coord if coord\n    puts \"Invalid input; try again!\"\n  end\nend\n\n# Ask the player if they wish to quit; return true if they do, false\n# otherwise.  Tends to assume false unless given an explicit yes.\ndef confirm_quit\n  print \"Really forfeit (y/n) \"\n  STDOUT.flush\n  line = STDIN.gets.strip\n\n  return !!(line =~ /^y(es)?$/i)     # For extra credit, explain why I use '!!'\nend\n\n# Parse a string containing x,y coordinates to produce and return a\n# new Coord object.  Returns nil if the string is not a valid\n# coordinate.\ndef parse_coord(coord)\n  coord = coord.gsub(/\\s/, '')\n  return nil unless coord =~ /^\\d,\\d$/\n\n  parts = coord.split(/,/)\n  result = Coord.new(parts[0].to_i, parts[1].to_i)\n  return nil unless result.valid?\n  return result\nend\n\n\n\n#\n# Classes\n#\n\n\n# Class to represent the game board and all of the pieces on it.\n#\n# Like the BASIC version, the board is represented using an 8 by 8\n# array.  However, instead of using numbers between -2 and 2, we\n# represent board squares with Ruby symbols:\n#\n#   - :_ (underscore) is an empty square\n#   - :o and :x (lowercase) are ordinary pieces for their respective sides\n#   - :O and :X (uppercase) are kings for their respective sides\n#\n# Most of the smarts of the game are also here as methods of this\n# class.  So my_turn() doesn't (e.g.) go through the board squares\n# looking for the best move; it asks the board for it by calling\n# bestMove().\n#\nclass Board\n\n  # Set up the board to the starting position\n  def initialize\n    @board = []\n\n    col1 = %i{o _ o _ _ _ x _}\n    col2 = %i{_ o _ _ _ x _ x}\n    4.times {\n      @board += [col1.dup, col2.dup]\n    }\n  end\n\n  # We use [] and []= (the array/hash get and set operators) to get\n  # individual board pieces instead of accessing it directly; this\n  # prevents errors where you get the row and column wrong in some\n  # places and not others.  They're private because it turns out that\n  # nothing outside of this class needs them but we could make them\n  # public without a lot of trouble.  The position must be a Coord\n  # object.\n  private\n  def [](coord)\n    return nil unless coord.valid?\n    return @board[coord.x][coord.y]\n  end\n\n  def []=(coord, value)\n    # Sanity checks\n    raise \"Invalid coordinate: #{coord}\" unless coord.valid?\n    raise \"Invalid board value: #{value}\" unless %i{_ x o X O}.include?(value)\n\n    @board[coord.x][coord.y] = value\n  end\n\n  public\n\n  # Return an ASCII picture of the board.  This is what gets printed\n  # between turns.\n  def text(indent = BOARD_TEXT_INDENT)\n    result = \"\"\n\n    glyph = {_: '.'}    # Replace some symbols when printing for readability\n\n    for y in (0 .. 7).to_a.reverse\n      result += ' '*indent + y.to_s + ' '\n      for x in (0 .. 7)\n        result += glyph.fetch(self[ Coord.new(x, y) ]) {|k| k.to_s}\n      end\n      result += \"\\n\"\n    end\n\n    result += ' '*indent + '  ' + (0..7).map{|n| n.to_s}.join\n\n    return result + \"\\n\\n\"\n  end\n\n  # Answer various questions about positions on the board\n  def mine_at?(coord)\n    return %i{x X}.include? self[coord]\n  end\n\n  def king_at?(coord)\n    return %i{X O}.include? self[coord]\n  end\n\n  def opponent_at?(coord)\n    return %i{o O}.include? self[coord]\n  end\n\n  def empty_at?(coord)\n    return self[coord] == :_\n  end\n\n  # Return a list of all valid positions on the board\n  def all_coords\n    coords = []\n    for x in 0 .. BOARD_WIDTH - 1\n      for y in 0 .. BOARD_WIDTH - 1\n        coords.push Coord.new(x, y)\n      end\n    end\n\n    return coords\n  end\n\n  # Return a list of all coords containing my (i.e. X's) pieces.\n  def my_pieces\n    all_coords.select{|coord| mine_at?(coord)}\n  end\n\n  private\n\n  # Return a list of all valid positions on the board.  (To do: skip\n  # all light-coloured squares, since they will never hold a piece.)\n  def all_coords\n    coords = []\n    for x in 0 .. BOARD_WIDTH - 1\n      for y in 0 .. BOARD_WIDTH - 1\n        coords.push Coord.new(x, y)\n      end\n    end\n\n    return coords\n  end\n\n  public\n\n  # Test if the move 'move' is legal; tests for me (i.e. the computer)\n  # if 'is_me' is true and for the human player if 'is_me' is false.\n  def legal_move?(is_me, move)\n    # If the move isn't valid, it's not legal.\n    return false unless move.valid?\n\n    # There's a piece belonging to me at the source\n    return false unless mine_at?(move.from) == is_me\n\n    # The destination is empty\n    return false unless empty_at?(move.to)\n\n    # The source holds one of the players' pieces\n    return false if empty_at?(move.from) || mine_at?(move.from) != is_me\n\n    # moving forward if not a king\n    if !king_at?(move.from)\n      return false if is_me && move.to.y > move.from.y\n      return false if !is_me && move.to.y < move.from.y\n    end\n\n    # If jumping, that there's an opponent's piece between the start\n    # and end.\n    return false if\n      move.jump? &&\n      (empty_at?(move.midpoint) || opponent_at?(move.midpoint) != is_me)\n\n    # Otherwise, it's legal\n    return true\n  end\n\n  # Perform 'move' on the board.  'move' must be legal; the player\n  # performing it is determined by the move's starting ('from')\n  # position.\n  def make_move!(move)\n    piece = self[move.from]\n\n    # Sanity check\n    raise \"Illegal move: #{move}\" unless legal_move?(piece.downcase == :x,move)\n\n    # Promote the piece if it's reached the end row\n    piece = piece.upcase if\n      (piece == :x && move.to.y == KING_ROW_X) ||\n      (piece == :o && move.to.y == KING_ROW_Y)\n\n    # And do the move\n    self[move.to] = piece\n    self[move.from] = :_\n\n    # Remove the piece jumped over if this is a jump\n    self[move.midpoint] = :_ if move.jump?\n  end\n\n\n  # Return the best (i.e. likely to win) move possible for the\n  # piece (mine) at 'coord'.\n  def bestMoveFrom(coord, mustJump)\n    so_far = Move.invalid\n    return so_far unless coord.valid?\n\n    offsets = [ [-1, -1], [1, -1]]\n    offsets += [ [-1, 1], [1, 1]] if king_at?(coord)\n\n    for ofx, ofy in offsets\n      new_coord = coord.by(ofx, ofy)\n\n      if opponent_at?(new_coord)\n        new_coord = new_coord.by(ofx, ofy)\n      elsif mustJump\n        next\n      end\n\n      next unless new_coord.valid?\n\n      so_far = so_far.betterOf( ratedMove(coord, new_coord) )\n    end\n\n    return so_far\n  end\n\n\n  # Create and return a move for *me* from Coords 'from' to 'to' with\n  # its 'rating' set to how good the move looks according to criteria\n  # used by the BASIC version of this program.  If the move is\n  # illegal, returns an invalid Move object.\n  def ratedMove(from, to)\n    return Move.invalid unless legal_move?(true, Move.new(from, to))\n\n    rating = 0\n\n    # +2 if it promotes this piece\n    rating += 2 if to.y == 0\n\n    # +50 if it takes the opponent's piece.  (Captures are mandatory\n    # so we ensure that a capture will always outrank a non-capture.)\n    rating += 4 if (from.y - to.y).abs == 2\n\n    # -2 if we're moving away from the king row\n    rating -= 2 if from.y == BOARD_WIDTH - 1\n\n    # +1 for putting the piece against a vertical boundary\n    rating += 1 if to.x == 0 || to.x == BOARD_WIDTH - 1\n\n    # +1 for each friendly piece behind this one\n    [-1, 1].each {|c|\n      rating += 1 if mine_at?( to.by(c, -1) )\n    }\n\n    # -2 for each opponent's piece that can now capture this one.\n    # (This includes a piece that may be captured when moving here;\n    # this is a bug.)\n    [ -1, 1].each {|c|\n      there = to.by(c, -1)\n      opposite = to.by(-c, 1)\n      rating -= 2 if\n        opponent_at?(there) && (empty_at?(opposite) || opposite == from)\n    }\n\n    return Move.new(from, to, rating)\n  end\nend\n\n\n# Class to hold the X and Y coordinates of a position on the board.\n#\n# Coord objects are immutable--that is, they never change after\n# creation.  Instead, you will always get a modified copy back.\nclass Coord\n\n  # Coordinates are readable\n  attr_reader :x, :y\n\n  # Initialize\n  def initialize(x, y)\n    @x, @y = [x,y]\n  end\n\n  # Test if this move is on the board.\n  def valid?\n    return x >= 0 && y >= 0 && x < BOARD_WIDTH && y < BOARD_WIDTH\n  end\n\n  # Test if this Coord is equal to another Coord.\n  def ==(other)\n    return other.class == self.class && other.x == @x && other.y == y\n  end\n\n  # Return a string that describes this Coord in a human-friendly way.\n  def to_s\n    return \"(#{@x},#{@y})\"\n  end\n\n  # Return a new Coord whose x and y coordinates have been adjusted by\n  # arguments 'x' and 'y'.\n  def by(x, y)\n    return Coord.new(@x + x, @y + y)\n  end\nend\n\n\n# Class to represent a move by a player between two positions,\n# possibly with a rating that can be used to select the best of a\n# collection of moves.\n#\n# An (intentionally) invalid move will have a value of nil for both\n# 'from' and 'to'.  Most methods other than 'valid?' assume the Move\n# is valid.\nclass Move\n  # Readable fields:\n  attr_reader :from, :to, :rating\n\n  # The initializer; -99 is the lowest rating from the BASIC version\n  # so we use that here as well.\n  def initialize(from, to, rating = -99)\n    @from, @to, @rating = [from, to, rating]\n\n    # Sanity check; the only invalid Move tolerated is the official\n    # one (i.e. with nil for each endpoint.)\n    raise \"Malformed Move: #{self}\" if @from && @to && !valid?\n  end\n\n  # Return an invalid Move object.\n  def self.invalid\n    return self.new(nil, nil, -99)\n  end\n\n  # Return true if this is a valid move (i.e. as close to legal as we\n  # can determine without seeing the board.)\n  def valid?\n    # Not valid if @from or @to is nil\n    return false unless @from && @to\n\n    # Not valid unless both endpoints are on the board\n    return false unless @from.valid? && @to.valid?\n\n    # Not valid unless it's a diagonal move by 1 or 2 squares\n    dx, dy = delta\n    return false if dx.abs != dy.abs || (dx.abs != 1 && dx.abs != 2)\n\n    # Otherwise, valid\n    return true\n  end\n\n  # Return true if this move is a jump, false otherwise\n  def jump?\n    return valid? && magnitude() == 2\n  end\n\n  # Return the coordinates of the piece being jumped over by this\n  # move.\n  def midpoint\n    raise \"Called 'midpoint' on a non-jump move!\" unless jump?\n    dx, dy = delta\n    return @from.by(dx / dx.abs, dy / dy.abs)\n  end\n\n  # Return the better-rated of self or otherMove.\n  def betterOf(otherMove)\n    return otherMove if !valid?\n    return rating > otherMove.rating ? self : otherMove\n  end\n\n  # Return a human-friendly string representing this move.\n  def to_s\n    return \"[NOMOVE]\" if !@from && !@to     # Well-known invalid move\n\n    jumpover = jump? ?\n                 \"-> #{midpoint} ->\"\n               : \"->\"\n\n    return \"#{@from} #{jumpover} #{to}#{valid? ? '' : ' [INVALID]'}\"\n  end\n\n  private\n\n  # Return the distance (x, y) between the 'from' and 'to' locations.\n  def delta\n    return [to.x - from.x, to.y - from.y]\n  end\n\n  # Return the number of squares this move will take the piece (either\n  # 1 or 2).\n  def magnitude\n    # Note: we assume that this move is a legal move (and therefore\n    # diagonal); otherwise, this may not be correct.\n    return (to.x - from.x).abs\n  end\nend\n\n\n\n# Start the game\nmain()\n"
  },
  {
    "path": "23_Checkers/vbnet/Checkers.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Checkers\", \"Checkers.vbproj\", \"{92B871EF-4871-40C0-ADDE-406301B937B9}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{92B871EF-4871-40C0-ADDE-406301B937B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{92B871EF-4871-40C0-ADDE-406301B937B9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{92B871EF-4871-40C0-ADDE-406301B937B9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{92B871EF-4871-40C0-ADDE-406301B937B9}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "23_Checkers/vbnet/Checkers.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Checkers</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "23_Checkers/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "24_Chemist/README.md",
    "content": "### Chemist\n\nThe fictitious chemical, kryptocyanic acid, can only be diluted by the ratio of 7 parts water to 3 parts acid. Any other ratio causes an unstable compound which soon explodes. Given an amount of acid, you must determine how much water to add to the dilution. If you’re more than 5% off, you lose one of your nine lives. The program continues to play until you lose all nine lives or until it is interrupted.\n\nIt was originally written by Wayne Teeter of Ridgecrest, California.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=42)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=57)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- There is a typo in the original Basic, \"...DECIDE **WHO** MUCH WATER...\" should be \"DECIDE **HOW** MUCH WATER\"\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n#### External Links\n - C: https://github.com/ericfischer/basic-computer-games/blob/main/24%20Chemist/c/chemist.c\n"
  },
  {
    "path": "24_Chemist/chemist.bas",
    "content": "3 PRINT TAB(33);\"CHEMIST\"\n6 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n8 PRINT:PRINT:PRINT\n10 PRINT \"THE FICTITIOUS CHEMICAL KRYPTOCYANIC ACID CAN ONLY BE\"\n20 PRINT \"DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\"\n30 PRINT \"IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\"\n40 PRINT \"AND SOON EXPLODES.  GIVEN THE AMOUNT OF ACID, YOU MUST\"\n50 PRINT \"DECIDE WHO MUCH WATER TO ADD FOR DILUTION.  IF YOU MISS\"\n60 PRINT \"YOU FACE THE CONSEQUENCES.\"\n100 A=INT(RND(1)*50)\n110 W=7*A/3\n120 PRINT A;\"LITERS OF KRYPTOCYANIC ACID.  HOW MUCH WATER\";\n130 INPUT R\n140 D=ABS(W-R)\n150 IF D>W/20 THEN 200\n160 PRINT \" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\"\n170 PRINT\n180 GOTO 100\n200 PRINT \" SIZZLE!  YOU HAVE JUST BEEN DESALINATED INTO A BLOB\"\n210 PRINT \" OF QUIVERING PROTOPLASM!\"\n220 T=T+1\n230 IF T=9 THEN 260\n240 PRINT \" HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\"\n250 GOTO 100\n260 PRINT \" YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\"\n270 PRINT \" YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\"\n280 END\n"
  },
  {
    "path": "24_Chemist/csharp/Chemist.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "24_Chemist/csharp/Chemist.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31005.135\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Chemist\", \"Chemist.csproj\", \"{C16545E8-E078-4C69-B7CA-9D821C944252}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C16545E8-E078-4C69-B7CA-9D821C944252}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C16545E8-E078-4C69-B7CA-9D821C944252}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C16545E8-E078-4C69-B7CA-9D821C944252}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C16545E8-E078-4C69-B7CA-9D821C944252}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {4AFDA581-82B1-42C7-9C9C-26F6B4288584}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "24_Chemist/csharp/Program.cs",
    "content": "﻿using System;\nconst int maxLives = 9;\n\nWriteCentred(\"Chemist\");\nWriteCentred(\"Creative Computing, Morristown, New Jersey\");\nConsole.WriteLine(@\"\n\n\nThe fictitious chemical kryptocyanic acid can only be\ndiluted by the ratio of 7 parts water to 3 parts acid.\nIf any other ratio is attempted, the acid becomes unstable\nand soon explodes.  Given the amount of acid, you must\ndecide who much water to add for dilution.  If you miss\nyou face the consequences.\n\");\n\nvar random = new Random();\nint livesUsed = 0;\nwhile (livesUsed < maxLives)\n{\n    int krypto = random.Next(1, 50);\n    double water = krypto * 7.0 / 3.0;\n\n    Console.WriteLine($\"{krypto} Liters of kryptocyanic acid.  How much water?\");\n    double answer = double.Parse(Console.ReadLine());\n\n    double diff = Math.Abs(answer - water);\n    if (diff <= water / 20)\n    {\n        Console.WriteLine(\"Good job! You may breathe now, but don't inhale the fumes\"!);\n        Console.WriteLine();\n    }\n    else\n    {\n        Console.WriteLine(\"Sizzle!  You have just been desalinated into a blob\\nof quivering protoplasm!\");\n        Console.WriteLine();\n        livesUsed++;\n\n        if (livesUsed < maxLives)\n            Console.WriteLine(\"However, you may try again with another life.\");\n    }\n}\nConsole.WriteLine($\"Your {maxLives} lives are used, but you will be long remembered for\\nyour contributions to the field of comic book chemistry.\");\n\nstatic void WriteCentred(string text)\n{\n    int indent = (Console.WindowWidth + text.Length) / 2;\n    Console.WriteLine($\"{{0,{indent}}}\", text);\n}\n"
  },
  {
    "path": "24_Chemist/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "24_Chemist/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "24_Chemist/java/src/Chemist.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Chemist\n * <p>\n * Based on the Basic game of Chemist here\n * https://github.com/coding-horror/basic-computer-games/blob/main/24%20Chemist/chemist.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Chemist {\n\n    public static final int MAX_LIVES = 9;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        START_GAME,\n        INPUT,\n        BLOWN_UP,\n        SURVIVED,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private int timesBlownUp;\n\n    public Chemist() {\n        kbScanner = new Scanner(System.in);\n\n        gameState = GAME_STATE.START_GAME;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case START_GAME:\n                    intro();\n                    timesBlownUp = 0;\n                    gameState = GAME_STATE.INPUT;\n                    break;\n\n                case INPUT:\n\n                    int amountOfAcid = (int) (Math.random() * 50);\n                    int correctAmountOfWater = (7 * amountOfAcid) / 3;\n                    int water = displayTextAndGetNumber(amountOfAcid + \" LITERS OF KRYPTOCYANIC ACID.  HOW MUCH WATER? \");\n\n                    // Calculate if the player mixed enough water\n                    int result = Math.abs(correctAmountOfWater - water);\n\n                    // Ratio of water wrong?\n                    if (result > (correctAmountOfWater / 20)) {\n                        gameState = GAME_STATE.BLOWN_UP;\n                    } else {\n                        // Got the ratio correct\n                        gameState = GAME_STATE.SURVIVED;\n                    }\n                    break;\n\n                case BLOWN_UP:\n                    System.out.println(\" SIZZLE!  YOU HAVE JUST BEEN DESALINATED INTO A BLOB\");\n                    System.out.println(\" OF QUIVERING PROTOPLASM!\");\n\n                    timesBlownUp++;\n\n                    if (timesBlownUp < MAX_LIVES) {\n                        System.out.println(\" HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\");\n                        gameState = GAME_STATE.INPUT;\n                    } else {\n                        System.out.println(\" YOUR \" + MAX_LIVES + \" LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\");\n                        System.out.println(\" YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\");\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n\n                    break;\n\n                case SURVIVED:\n                    System.out.println(\" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\");\n                    System.out.println();\n                    gameState = GAME_STATE.INPUT;\n                    break;\n\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(33) + \"CHEMIST\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THE FICTITIOUS CHEMICAL KRYPTOCYANIC ACID CAN ONLY BE\");\n        System.out.println(\"DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\");\n        System.out.println(\"IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\");\n        System.out.println(\"AND SOON EXPLODES.  GIVEN THE AMOUNT OF ACID, YOU MUST\");\n        System.out.println(\"DECIDE WHO MUCH WATER TO ADD FOR DILUTION.  IF YOU MISS\");\n        System.out.println(\"YOU FACE THE CONSEQUENCES.\");\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n}\n"
  },
  {
    "path": "24_Chemist/java/src/ChemistGame.java",
    "content": "public class ChemistGame {\n    public static void main(String[] args) {\n        Chemist chemist = new Chemist();\n        chemist.play();\n    }\n}\n"
  },
  {
    "path": "24_Chemist/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "24_Chemist/javascript/chemist.html",
    "content": "<html>\n<head>\n<title>CHEMIST</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"chemist.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "24_Chemist/javascript/chemist.js",
    "content": "// CHEMIST\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"CHEMIST\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THE FICTITIOUS CHECMICAL KRYPTOCYANIC ACID CAN ONLY BE\\n\");\n    print(\"DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\\n\");\n    print(\"IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\\n\");\n    print(\"AND SOON EXPLODES.  GIVEN THE AMOUNT OF ACID, YOU MUST\\n\");\n    print(\"DECIDE WHO MUCH WATER TO ADD FOR DILUTION.  IF YOU MISS\\n\");\n    print(\"YOU FACE THE CONSEQUENCES.\\n\");\n    t = 0;\n    while (1) {\n        a = Math.floor(Math.random() * 50);\n        w = 7 * a / 3;\n        print(a + \" LITERS OF KRYPTOCYANIC ACID.  HOW MUCH WATER\");\n        r = parseFloat(await input());\n        d = Math.abs(w - r);\n        if (d > w / 20) {\n            print(\" SIZZLE!  YOU HAVE JUST BEEN DESALINATED INTO A BLOB\\n\");\n            print(\" OF QUIVERING PROTOPLASM!\\n\");\n            t++;\n            if (t == 9)\n                break;\n            print(\" HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\\n\");\n        } else {\n            print(\" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\\n\");\n            print(\"\\n\");\n        }\n    }\n    print(\" YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\\n\");\n    print(\" YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "24_Chemist/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "24_Chemist/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "24_Chemist/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "24_Chemist/perl/chemist.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x33 . \"CHEMIST\\n\";\nprint ' 'x15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"THE FICTITIOUS CHECMICAL KRYPTOCYANIC ACID CAN ONLY BE\\n\";\nprint \"DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\\n\";\nprint \"IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\\n\";\nprint \"AND SOON EXPLODES. GIVEN THE AMOUNT OF ACID, YOU MUST\\n\";\nprint \"DECIDE HOW MUCH WATER TO ADD FOR DILUTION. IF YOU MISS\\n\";\nprint \"YOU FACE THE CONSEQUENCES.\\n\";\n\nmy $T=0;\nwhile ($T<9) {\n\tmy $A= int(rand(50) + 1);\n\tmy $W= 7*$A/3;\n\tprint \" $A LITERS OF KRYPTOCYANIC ACID. HOW MUCH WATER? \";\n\tchomp(my $R = <STDIN>);\n\tmy $D= abs($W-$R);\n\tif ($D>$W/20) {\n\t\tprint \"SIZZLE! YOU HAVE JUST BEEN DESALINATED INTO A BLOB\\n\";\n\t\tprint \"OF QUIVERING PROTOPLASM!\\n\";\n\t\tprint \"HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\\n\";\n\t\tprint \"\\n\";\n\t\t$T++;\n\t} else {\n\t\tprint \"GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\\n\";\n\t\tprint \"\\n\";\n\t}\n}\n\nprint \"YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\\n\";\nprint \"YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\\n\";\nexit;\n"
  },
  {
    "path": "24_Chemist/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "24_Chemist/python/chemist.py",
    "content": "\"\"\"\nCHEMIST\n\nA math game posing as a chemistry word problem.\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\n\nMAX_LIVES = 9\n\n\ndef play_scenario() -> bool:\n    acid_amount = random.randint(1, 50)\n\n    water_amount = 7 * acid_amount / 3\n\n    print(f\"{acid_amount} LITERS OF KRYPTOCYANIC ACID.  HOW MUCH WATER?\")\n\n    response = float(input())\n\n    difference = abs(water_amount - response)\n\n    acceptable_difference = water_amount / 20\n\n    if difference > acceptable_difference:\n        show_failure()\n\n        return False\n    else:\n        show_success()\n\n        return True\n\n\ndef show_failure() -> None:\n    print(\" SIZZLE!  YOU HAVE JUST BEEN DESALINATED INTO A BLOB\")\n    print(\" OF QUIVERING PROTOPLASM!\")\n\n\ndef show_success() -> None:\n    print(\" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\\n\")\n\n\ndef show_ending() -> None:\n    print(f\" YOUR {MAX_LIVES} LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\")\n    print(\" YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\")\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"CHEMIST\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    print(\"THE FICTITIOUS CHEMICAL KRYPTOCYANIC ACID CAN ONLY BE\")\n    print(\"DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\")\n    print(\"IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\")\n    print(\"AND SOON EXPLODES.  GIVEN THE AMOUNT OF ACID, YOU MUST\")\n    print(\"DECIDE WHO MUCH WATER TO ADD FOR DILUTION.  IF YOU MISS\")\n    print(\"YOU FACE THE CONSEQUENCES.\")\n\n    lives_used = 0\n\n    while True:\n        success = play_scenario()\n\n        if not success:\n            lives_used += 1\n\n            if lives_used == MAX_LIVES:\n                show_ending()\n                return\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "24_Chemist/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "24_Chemist/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "24_Chemist/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "24_Chemist/rust/src/lib.rs",
    "content": "/*\n lib.rs contains all the logic of the program\n*/\nuse rand::{Rng, prelude::thread_rng}; //rng\nuse std::error::Error; //better errors\nuse std::io::{self, Write}; //io interactions\nuse std::{str::FromStr, fmt::Display}; //traits\n\n//DATA\n\n/// handles setup for the game\npub struct Config {\n}\nimpl Config {\n    /// creates and returns a new Config from user input\n    pub fn new() -> Result<Config, Box<dyn Error>> {\n        //DATA\n        let config: Config = Config {\n        };\n        \n        //return new config\n        return Ok(config);\n    }\n}\n\n/// run the program\npub fn run(_config: &Config) -> Result<(), Box<dyn Error>> {\n    //DATA\n    let mut rng = thread_rng();\n    let mut lives: i8 = 9;\n\n    let mut amount_of_acid:i8;\n\n    let mut guess:f32;\n    let mut answer:f32;\n    \n    let mut error:f32; \n\n    //Game loop\n    loop {\n        //initialize variables\n        amount_of_acid =  rng.gen_range(1..50);\n        answer = 7.0 * (amount_of_acid as f32/3.0);\n\n        //print starting message / conditions\n        println!();\n        //get guess\n        guess = loop {\n            match get_number_from_input(&format!(\"{} Liters of Kryptocyanic acid.  How much water? \", amount_of_acid),0.0,-1.0) {\n                Ok(num) => break num,\n                Err(err) => {\n                    eprintln!(\"{}\",err);\n                    continue;\n                },\n            }\n        };\n\n        //calculate error\n        error = (answer as f32 - guess).abs() / guess;\n        \n        println!(\"answer: {} | error: {}%\", answer,error*100.);\n\n        //check guess against answer\n        if error > 0.05 { //error > 5%\n            println!(\" Sizzle!  You may have just been desalinated into a blob\");\n            println!(\" of quivering protoplasm!\");\n            //update lives\n            lives -= 1;\n\n            if lives <= 0 {\n                println!(\" Your 9 lives are used, but you will be long remembered for\");\n                println!(\" your contributions to the field of comic book chemistry.\");\n                break;\n            }\n            else {\n                println!(\" However, you may try again with another life.\")\n            } \n        } else {\n            println!(\" Good job!  You may breathe now, but don't inhale the fumes!\");\n            println!();\n        }\n    }\n\n    //return to main\n    Ok(())\n}\n\n/// gets a string from user input\nfn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\", prompt);\n    //make sure it's printed before getting input\n    io::stdout().flush().expect(\"couldn't flush stdout\");\n\n    //read user input from standard input, and store it to raw_input, then return it or an error as needed\n    raw_input.clear(); //clear input\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),\n        Err(err) => return Err(format!(\"ERROR: CANNOT READ INPUT!: {}\", err).into()),\n    }\n}\n/// generic function to get a number from the passed string (user input)\n/// pass a min lower  than the max to have minimum and maximum bounds\n/// pass a min higher than the max to only have a minimum bound\n/// pass a min equal   to  the max to only have a maximum bound\n/// \n/// Errors:\n/// no number on user input\nfn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {\n    //DATA\n    let raw_input: String;\n    let processed_input: String;\n\n    \n    //input loop\n    raw_input = loop {\n        match get_string_from_user_input(prompt) {\n            Ok(input) => break input,\n            Err(e) => {\n                eprintln!(\"{}\",e);\n                continue;\n            },\n        }\n    };\n\n    //filter out non-numeric characters from user input\n    processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();\n\n    //from input, try to read a number\n    match processed_input.trim().parse() {\n        Ok(i) => {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    return Ok(i); //exit the loop with the value i, returning it\n                } else { //print error message specific to this case\n                    return Err(format!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max).into());\n                } \n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO LESS THAN {}, PLEASE!\", min).into());\n                }\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO MORE THAN {}, PLEASE!\", max).into());\n                }\n            }\n        },\n        Err(_e) => return Err(format!(\"Error: couldn't find a valid number in {}\",raw_input).into()),\n    }\n}\n"
  },
  {
    "path": "24_Chemist/rust/src/main.rs",
    "content": "use std::process;//allows for some better error handling\n\nmod lib; //allows access to lib.rs\nuse lib::Config;\n\n/// main function\n/// responsibilities:\n/// - Calling the command line logic with the argument values\n/// - Setting up any other configuration\n/// - Calling a run function in lib.rs\n/// - Handling the error if run returns an error\nfn main() {\n    //greet user\n    welcome();\n\n    // set up other configuration\n    let mut config = Config::new().unwrap_or_else(|err| {\n        eprintln!(\"Problem configuring program: {}\", err);\n        process::exit(1);\n    });\n\n    // run the program\n    if let Err(e) = lib::run(&mut config) {\n        eprintln!(\"Application Error: {}\", e); //use the eprintln! macro to output to standard error\n        process::exit(1); //exit the program with an error code\n    }\n\n    //end of program\n    println!(\"THANKS FOR PLAYING!\");\n}\n\n/// print the welcome message\nfn welcome() {\n    println!(\"\n                                Chemist\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\nThe fictitious chemical kryptocyanic acid can only be\ndiluted by the ratio of 7 parts water to 3 parts acid.\nIf any other ratio is attempted, the acid becomes unstable\nand soon explodes.  Given the amount of acid, you must\ndecide how much water to add for dilution.  If you miss\nyou face the consequences.\n    \");\n}\n"
  },
  {
    "path": "24_Chemist/vbnet/Chemist.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Chemist\", \"Chemist.vbproj\", \"{25BEFBB8-58A1-4691-9CE6-D8C770F5189D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{25BEFBB8-58A1-4691-9CE6-D8C770F5189D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{25BEFBB8-58A1-4691-9CE6-D8C770F5189D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{25BEFBB8-58A1-4691-9CE6-D8C770F5189D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{25BEFBB8-58A1-4691-9CE6-D8C770F5189D}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "24_Chemist/vbnet/Chemist.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Chemist</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "24_Chemist/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "25_Chief/README.md",
    "content": "### Chief\n\nIn the words of the program author, John Graham, “CHIEF is designed to give people (mostly kids) practice in the four operations (addition, multiplication, subtraction, and division).\n\nIt does this while giving people some fun. And then, if the people are wrong, it shows them how they should have done it.\n\nCHIEF was written by John Graham of Upper Brookville, New York.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=43)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=58)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "25_Chief/chief.bas",
    "content": "2 PRINT TAB(30) \"CHIEF\"\n4 PRINT TAB(15) \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 PRINT \"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\"\n20 PRINT \"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR\";\n30 INPUT A$\n40 IF A$=\"YES\" THEN 60\n50 PRINT \"SHUT UP, PALE FACE WITH WISE TONGUE.\"\n60 PRINT \" TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\"\n70 PRINT \"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\"\n80 PRINT \"  WHAT DO YOU HAVE\";\n90 INPUT B\n100 LET C = (B+1-5)*5/8*5-3\n110 PRINT \"I BET YOUR NUMBER WAS\" C\". AM I RIGHT\";\n120 INPUT D$\n130 IF D$=\"YES\" THEN 500\n140 PRINT \"WHAT WAS YOUR ORIGINAL NUMBER\";\n150 INPUT K\n155 LET F=K+3\n160 LET G=F/5\n170 LET H=G*8\n180 LET I=H/5+5\n190 LET J=I-1\n200 PRINT \"SO YOU THINK YOU'RE SO SMART, EH?\"\n210 PRINT \"NOW WATCH.\"\n230 PRINT K\"PLUS 3 EQUALS\"F\". THIS DIVIDED BY 5 EQUALS\"G\";\"\n240 PRINT \"THIS TIMES 8 EQUALS\"H\". IF WE DIVIDE BY 5 AND ADD 5,\"\n250 PRINT \"WE GET\"I\", WHICH, MINUS 1, EQUALS\"J\".\"\n260 PRINT \"NOW DO YOU BELIEVE ME\";\n270 INPUT Z$\n290 IF Z$=\"YES\" THEN 500\n295 PRINT \"YOU HAVE MADE ME MAD!!!\"\n300 PRINT \"THERE MUST BE A GREAT LIGHTNING BOLT!\"\n310 PRINT:PRINT\n330 FOR X=30 TO 22 STEP -1\n340 PRINT TAB(X) \"X X\"\n350 NEXT X\n360 PRINT TAB(21) \"X XXX\"\n370 PRINT TAB(20) \"X   X\"\n380 PRINT TAB(19) \"XX X\"\n390 FOR Y=20 TO 13 STEP -1\n400 PRINT TAB(Y) \"X X\"\n410 NEXT Y\n420 PRINT TAB(12) \"XX\"\n430 PRINT TAB(11) \"X\"\n440 PRINT TAB(10) \"*\"\n450 PRINT:PRINT\"#########################\":PRINT\n470 PRINT \"I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\"\n480 GOTO 520\n500 PRINT \"BYE!!!\"\n520 END\n"
  },
  {
    "path": "25_Chief/csharp/Chief.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "25_Chief/csharp/Chief.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Chief\", \"Chief.csproj\", \"{AE650092-EEF2-4747-91F4-C8311AD16A4B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AE650092-EEF2-4747-91F4-C8311AD16A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AE650092-EEF2-4747-91F4-C8311AD16A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AE650092-EEF2-4747-91F4-C8311AD16A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AE650092-EEF2-4747-91F4-C8311AD16A4B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "25_Chief/csharp/Game.cs",
    "content": "using static Chief.Resources.Resource;\n\nnamespace Chief;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n\n    public Game(IReadWrite io)\n    {\n        _io = io;\n    }\n\n    internal void Play()\n    {\n        DoIntroduction();\n\n        var result = _io.ReadNumber(Prompts.Answer);\n\n        if (_io.ReadYes(Formats.Bet, Math.CalculateOriginal(result)))\n        {\n            _io.Write(Streams.Bye);\n            return;\n        }\n\n        var original = _io.ReadNumber(Prompts.Original);\n\n        _io.WriteLine(Math.ShowWorking(original));\n\n        if (_io.ReadYes(Prompts.Believe))\n        {\n            _io.Write(Streams.Bye);\n            return;\n        }\n\n        _io.Write(Streams.Lightning);\n    }\n\n    private void DoIntroduction()\n    {\n        _io.Write(Streams.Title);\n        if (!_io.ReadYes(Prompts.Ready))\n        {\n            _io.Write(Streams.ShutUp);\n        }\n\n        _io.Write(Streams.Instructions);\n    }\n}\n"
  },
  {
    "path": "25_Chief/csharp/IReadWriteExtensions.cs",
    "content": "namespace Chief;\n\ninternal static class IReadWriteExtensions\n{\n    internal static bool ReadYes(this IReadWrite io, string format, Number value) =>\n        io.ReadYes(string.Format(format, value));\n    internal static bool ReadYes(this IReadWrite io, string prompt) =>\n        io.ReadString(prompt).Equals(\"Yes\", StringComparison.InvariantCultureIgnoreCase);\n}"
  },
  {
    "path": "25_Chief/csharp/Math.cs",
    "content": "using static Chief.Resources.Resource;\n\nnamespace Chief;\n\npublic static class Math\n{\n    public static float CalculateOriginal(float result) => (result + 1 - 5) * 5 / 8 * 5 - 3;\n\n    public static string ShowWorking(Number value) =>\n        string.Format(\n            Formats.Working,\n            value,\n            value += 3,\n            value /= 5,\n            value *= 8,\n            value = value / 5 + 5,\n            value - 1);\n}"
  },
  {
    "path": "25_Chief/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Chief;\n\nnew Game(new ConsoleIO()).Play();"
  },
  {
    "path": "25_Chief/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "25_Chief/csharp/Resources/Answer.txt",
    "content": "  What do you have"
  },
  {
    "path": "25_Chief/csharp/Resources/Believe.txt",
    "content": "Now do you believe me"
  },
  {
    "path": "25_Chief/csharp/Resources/Bet.txt",
    "content": "I bet your number was{0}. Am I right"
  },
  {
    "path": "25_Chief/csharp/Resources/Bye.txt",
    "content": "Bye!!!\n"
  },
  {
    "path": "25_Chief/csharp/Resources/Instructions.txt",
    "content": " Take a number and add 3. Divide this number by 5 and\nmultiply by 8. Divide by 5 and add the same. Subtract 1.\n"
  },
  {
    "path": "25_Chief/csharp/Resources/Lightning.txt",
    "content": "You have made me mad!!!\nThere must be a great lightning bolt!!\n\n\n                              X X\n                             X X\n                            X X\n                           X X\n                          X X\n                         X X\n                        X X\n                       X X\n                      X X\n                     X XXX\n                    X   X\n                   XX X\n                    X X\n                   X X\n                  X X\n                 X X\n                X X\n               X X\n              X X\n             X X\n            XX\n           X\n          *\n\n#########################\n\nI hope you believe me now, for your sake!!\n"
  },
  {
    "path": "25_Chief/csharp/Resources/Original.txt",
    "content": "What was your original number"
  },
  {
    "path": "25_Chief/csharp/Resources/Ready.txt",
    "content": "I am Chief Numbers Freek, the great Indian math god.\nAre you ready to take the test you called me out for"
  },
  {
    "path": "25_Chief/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Chief.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Bye => GetStream();\n        public static Stream Instructions => GetStream();\n        public static Stream Lightning => GetStream();\n        public static Stream ShutUp => GetStream();\n        public static Stream Title => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string Bet => GetString();\n        public static string Working => GetString();\n    }\n\n    internal static class Prompts\n    {\n        public static string Answer => GetString();\n        public static string Believe => GetString();\n        public static string Original => GetString();\n        public static string Ready => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null)\n        => Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Chief.Resources.{name}.txt\")\n            ?? throw new ArgumentException($\"Resource stream {name} does not exist\", nameof(name));\n}"
  },
  {
    "path": "25_Chief/csharp/Resources/ShutUp.txt",
    "content": "Shut up, pale face with wise tongue."
  },
  {
    "path": "25_Chief/csharp/Resources/Title.txt",
    "content": "                                  Chief\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "25_Chief/csharp/Resources/Working.txt",
    "content": "So you think you're so smart, eh?\nNow watch.\n{0}plus 3 equals{1}. This divided by 5 equals{2};\nThis times by 8 equals{3}. If we divide by 5 and add 5,\nwe get{4}, which, minus 1, equals{5}.\n"
  },
  {
    "path": "25_Chief/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "25_Chief/java/src/Chief.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Chief\n * <p>\n * Based on the Basic game of Hurkle here\n * https://github.com/coding-horror/basic-computer-games/blob/main/25%20Chief/chief.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Chief {\n\n    private enum GAME_STATE {\n        STARTING,\n        READY_TO_START,\n        ENTER_NUMBER,\n        CALCULATE_AND_SHOW,\n        END_GAME,\n        GAME_OVER\n    }\n\n    private GAME_STATE gameState;\n\n    // The number the computer determines to be the players starting number\n    private double calculatedNumber;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    public Chief() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    intro();\n                    gameState = GAME_STATE.READY_TO_START;\n                    break;\n\n                // show an message to start\n                case READY_TO_START:\n                    if (!yesEntered(displayTextAndGetInput(\"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR? \"))) {\n                        System.out.println(\"SHUT UP, PALE FACE WITH WISE TONGUE.\");\n                    }\n\n                    instructions();\n                    gameState = GAME_STATE.ENTER_NUMBER;\n                    break;\n\n                // Enter the number to be used to calculate\n                case ENTER_NUMBER:\n                    double playerNumber = Double.parseDouble(\n                            displayTextAndGetInput(\" WHAT DO YOU HAVE? \"));\n\n                    // Exact same formula used in the original game to calculate the players original number\n                    calculatedNumber = (playerNumber + 1 - 5) * 5 / 8 * 5 - 3;\n\n                    gameState = GAME_STATE.CALCULATE_AND_SHOW;\n                    break;\n\n                // Enter the number to be used to calculate\n                case CALCULATE_AND_SHOW:\n                    if (yesEntered(\n                            displayTextAndGetInput(\"I BET YOUR NUMBER WAS \" + calculatedNumber\n                                    + \". AM I RIGHT? \"))) {\n                        gameState = GAME_STATE.END_GAME;\n\n                    } else {\n                        // Player did not agree, so show the breakdown\n                        double number = Double.parseDouble(\n                                displayTextAndGetInput(\" WHAT WAS YOUR ORIGINAL NUMBER? \"));\n                        double f = number + 3;\n                        double g = f / 5;\n                        double h = g * 8;\n                        double i = h / 5 + 5;\n                        double j = i - 1;\n                        System.out.println(\"SO YOU THINK YOU'RE SO SMART, EH?\");\n                        System.out.println(\"NOW WATCH.\");\n                        System.out.println(number + \" PLUS 3 EQUALS \" + f + \". DIVIDED BY 5 EQUALS \" + g);\n                        System.out.println(\"TIMES 8 EQUALS \" + h + \". IF WE DIVIDE BY 5 AND ADD 5,\");\n                        System.out.println(\"WE GET \" + i + \", WHICH, MINUS 1, EQUALS \" + j + \".\");\n                        if (yesEntered(displayTextAndGetInput(\"NOW DO YOU BELIEVE ME? \"))) {\n                            gameState = GAME_STATE.END_GAME;\n                        } else {\n                            // Time for a lightning bolt.\n                            System.out.println(\"YOU HAVE MADE ME MAD!!!\");\n                            System.out.println(\"THERE MUST BE A GREAT LIGHTNING BOLT!\");\n                            System.out.println();\n                            for (int x = 30; x >= 22; x--) {\n                                System.out.println(tabbedSpaces(x) + \"X X\");\n                            }\n                            System.out.println(tabbedSpaces(21) + \"X XXX\");\n                            System.out.println(tabbedSpaces(20) + \"X   X\");\n                            System.out.println(tabbedSpaces(19) + \"XX X\");\n                            for (int y = 20; y >= 13; y--) {\n                                System.out.println(tabbedSpaces(y) + \"X X\");\n                            }\n                            System.out.println(tabbedSpaces(12) + \"XX\");\n                            System.out.println(tabbedSpaces(11) + \"X\");\n                            System.out.println(tabbedSpaces(10) + \"*\");\n                            System.out.println();\n                            System.out.println(\"#########################\");\n                            System.out.println();\n                            System.out.println(\"I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\");\n                            gameState = GAME_STATE.GAME_OVER;\n                        }\n\n                    }\n                    break;\n\n                // Sign off message for cases where the Chief is not upset\n                case END_GAME:\n                    System.out.println(\"BYE!!!\");\n                    gameState = GAME_STATE.GAME_OVER;\n                    break;\n\n                // GAME_OVER State does not specifically have a case\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Simulate tabs by building up a string of spaces\n     *\n     * @param spaces how many spaces are there to be\n     * @return a string with the requested number of spaces\n     */\n    private String tabbedSpaces(int spaces) {\n        char[] repeat = new char[spaces];\n        Arrays.fill(repeat, ' ');\n        return new String(repeat);\n    }\n\n    private void instructions() {\n        System.out.println(\" TAKE A NUMBER AND ADD 3. DIVIDE NUMBER BY 5 AND\");\n        System.out.println(\"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\");\n    }\n\n    /**\n     * Basic information about the game\n     */\n    private void intro() {\n        System.out.println(\"CHIEF\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\");\n    }\n\n    /**\n     * Returns true if a given string is equal to at least one of the values specified in the call\n     * to the stringIsAnyValue method\n     *\n     * @param text string to search\n     * @return true if string is equal to one of the varargs\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Returns true if a given string contains at least one of the varargs (2nd parameter).\n     * Note: Case insensitive comparison.\n     *\n     * @param text   string to search\n     * @param values varargs of type string containing values to compare\n     * @return true if one of the varargs arguments was found in text\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        // Cycle through the variable number of values and test each\n        for (String val : values) {\n            if (text.equalsIgnoreCase(val)) {\n                return true;\n            }\n        }\n\n        // no matches\n        return false;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n}\n"
  },
  {
    "path": "25_Chief/java/src/ChiefGame.java",
    "content": "public class ChiefGame {\n\n    public static void main(String[] args) {\n\n        Chief chief = new Chief();\n        chief.play();\n    }\n}\n"
  },
  {
    "path": "25_Chief/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "25_Chief/javascript/chief.html",
    "content": "<html>\n<head>\n<title>CHIEF</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"chief.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "25_Chief/javascript/chief.js",
    "content": "// CHIEF\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"CHIEF\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\\n\");\n    print(\"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR\");\n    a = await input();\n    if (a.substr(0, 1) != \"Y\")\n        print(\"SHUT UP, PALE FACE WITH WIE TONGUE.\\n\");\n    print(\" TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\\n\");\n    print(\"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\\n\");\n    print(\"  WHAT DO YOU HAVE\");\n    b = parseFloat(await input());\n    c = (b + 1 - 5) * 5 / 8 * 5 - 3;\n    print(\"I BET YOUR NUMBER WAS \" + Math.floor(c + 0.5) + \". AM I RIGHT\");\n    d = await input();\n    if (d.substr(0, 1) != \"Y\") {\n        print(\"WHAT WAS YOUR ORIGINAL NUMBER\");\n        k = parseFloat(await input());\n        f = k + 3;\n        g = f / 5;\n        h = g * 8;\n        i = h / 5 + 5;\n        j = i - 1;\n        print(\"SO YOU THINK YOU'RE SO SMART, EH?\\n\");\n        print(\"NOW WATCH.\\n\");\n        print(k + \" PLUS 3 EQUALS \" + f + \". THIS DIVIDED BY 5 EQUALS \" + g + \";\\n\");\n        print(\"THIS TIMES 8 EQUALS \" + h + \". IF WE DIVIDE BY 5 AND ADD 5,\\n\");\n        print(\"WE GET \" + i + \", WHICH, MINUS 1, EQUALS \" + j + \".\\n\");\n        print(\"NOW DO YOU BELIEVE ME\");\n        z = await input();\n        if (z.substr(0, 1) != \"Y\") {\n            print(\"YOU HAVE MADE ME MAD!!!\\n\");\n            print(\"THERE MUST BE A GREAT LIGHTNING BOLT!\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            for (x = 30; x >= 22; x--)\n                print(tab(x) + \"X X\\n\");\n            print(tab(21) + \"X XXX\\n\");\n            print(tab(20) + \"X   X\\n\");\n            print(tab(19) + \"XX X\\n\");\n            for (y = 20; y >= 13; y--)\n                print(tab(y) + \"X X\\n\");\n            print(tab(12) + \"XX\\n\");\n            print(tab(11) + \"X\\n\");\n            print(tab(10) + \"*\\n\");\n            print(\"\\n\");\n            print(\"#########################\\n\");\n            print(\"\\n\");\n            print(\"I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\\n\");\n            return;\n        }\n    }\n    print(\"BYE!!!\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "25_Chief/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "25_Chief/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/) by Alex Conconi\n\n---\n\n### Lua porting notes\n\n- I did not like the old Western movie language style in the game introduction\nand decided to tone it down, even if this deviates from the original BASIC\nversion.\n\n- The `craps_game` function contains the main game logic: it\n  - prints the game credits and presents the intro question;\n  - asks for the end result and computes the original numer;\n  - calls `explain_solution` to print the various steps of the computation;\n  - presents the outro question and prints a `bolt` if necessary.\n\n- Added basic input validation to accept only valid integers for numeric input.\n\n- Minor formatting edits (lowercase, punctuation).\n\n- Any answer to a \"yes or no\" question is regarded as \"yes\" if the input line\nstarts with 'y' or 'Y', else no.\n"
  },
  {
    "path": "25_Chief/lua/chief.lua",
    "content": "--[[\nChief\n\nFrom: BASIC Computer Games (1978)\nEdited by David H. Ahl\n\n    In the words of the program author, John Graham, “CHIEF is designed to\n    give people (mostly kids) practice in the four operations (addition,\n    multiplication, subtraction, and division).\n\n    It does this while giving people some fun. And then, if the people are\n    wrong, it shows them how they should have done it.\n\n    CHIEF was written by John Graham of Upper Brookville, New York.\n\n    \nLua port by Alex Conconi, 2022.\n]]--\n\n\n--- Helper function for tabulating messages.\nlocal function space(n) return string.rep(\" \", n) end\n\n\n--- Generates a multi-line string representing a lightning bolt\nlocal function bolt()\n    local bolt_lines = {}\n    for n = 29, 21, -1 do\n        table.insert(bolt_lines, space(n) .. \"x x\")\n    end\n    table.insert(bolt_lines, space(20) .. \"x xxx\")\n    table.insert(bolt_lines, space(19) .. \"x   x\")\n    table.insert(bolt_lines, space(18) .. \"xx x\")\n    for n = 19, 12, -1 do\n        table.insert(bolt_lines, space(n) .. \"x x\")\n    end\n    table.insert(bolt_lines, space(11) .. \"xx\")\n    table.insert(bolt_lines, space(10) .. \"x\")\n    table.insert(bolt_lines, space(9) .. \"*\\n\")\n    table.insert(bolt_lines, string.rep(\"#\", 25) .. \"\\n\")\n    return table.concat(bolt_lines, \"\\n\")\nend\n\n\n--- Print the prompt and read a yes/no answer from stdin.\nlocal function ask_yes_or_no(prompt)\n    io.stdout:write(prompt .. \" \")\n    local answer = string.lower(io.stdin:read(\"*l\"))\n    -- any line starting with a 'y' or 'Y' is considered a 'yes'\n    return answer:sub(1, 1) == \"y\"\nend\n\n\n--- Print the prompt and read a valid number from stdin.\nlocal function ask_number(prompt)\n    io.stdout:write(prompt .. \" \")\n    while true do\n        local n = tonumber(io.stdin:read(\"*l\"))\n        if n then\n            return n\n        else\n            print(\"Enter a valid number.\")\n        end\n    end\nend\n\n\n--- Explain the solution to persuade the player.\nlocal function explain_solution()\n    local k = ask_number(\"What was your original number?\")\n    -- For clarity we kept the same variable names of the original BASIC version\n    local f = k + 3\n    local g = f / 5\n    local h = g * 8\n    local i = h / 5 + 5\n    local j = i - 1\n    print(\"So you think you're so smart, eh?\")\n    print(\"Now watch.\")\n    print(k .. \" plus 3 equals \" .. f .. \". This divided by 5 equals \" .. g .. \";\")\n    print(\"this times 8 equals \" .. h .. \". If we divide by 5 and add 5,\")\n    print(\"we get \" .. i .. \", which, minus 1, equals \" .. j .. \".\")\nend\n\n\n--- Main game function.\nlocal function chief_game()\n    --- Print game introduction and challenge\n    print(space(29) .. \"Chief\")\n    print(space(14) .. \"Creative Computing  Morristown, New Jersey\\n\\n\")\n    print(\"I am Chief Numbers Freek, the great math god.\")\n    if not ask_yes_or_no(\"Are you ready to take the test you called me out for?\") then\n        print(\"Shut up, wise tongue.\")\n    end\n\n    -- Print how to obtain the end result.\n    print(\" Take a number and add 3. Divide this number by 5 and\")\n    print(\"multiply by 8. Divide by 5 and add the same. Subtract 1.\")\n\n    -- Ask the result end and reverse calculate the original number.\n    local end_result = ask_number(\" What do you have?\")\n    local original_number = (end_result + 1 - 5) * 5 / 8 * 5 - 3\n\n    -- If it is an integer we do not want to print any zero decimals.\n    local int_part, dec_part = math.modf(original_number)\n    if dec_part == 0 then original_number = int_part end\n\n    -- If the player challenges the answer, print the explanation.\n    if not ask_yes_or_no(\"I bet your number was \" .. original_number .. \". Am I right?\") then\n        explain_solution()\n        -- If the player does not accept the explanation, zap them.\n        if not ask_yes_or_no(\"Now do you believe me?\") then\n            print(\"YOU HAVE MADE ME MAD!!!\")\n            print(\"THERE MUST BE A GREAT LIGHTNING BOLT!\\n\\n\")\n            print(bolt())\n            print(\"I hope you believe me now, for your sake!!\")\n        end\n    end\nend\n\n--- Run the game.\nchief_game()\n"
  },
  {
    "path": "25_Chief/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "25_Chief/perl/chief.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\nprint ' ' x 30 . \"CHIEF\\n\";\nprint ' ' x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\\n\";\nprint \"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR?\\n\";\n\nchomp( my $A = uc <STDIN> );\nprint \"SHUT UP, PALE FACE WITH WISE TONGUE.\\n\" unless ( $A eq 'YES' );\n\nprint \" TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\\n\";\nprint \"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\\n\";\nprint \"  WHAT DO YOU HAVE?\\n\";\n\nchomp( my $B = <STDIN> );\nmy $C = ( $B + 1 - 5 ) * 5 / 8 * 5 - 3;\n\nprint \"I BET YOUR NUMBER WAS $C. AM I RIGHT?\\n\";\n\nchomp( my $D = uc <STDIN> );\nif ( $D eq 'YES' ) {\n    print \"BYE!!!\\n\";\n    exit;\n}\n\nprint \"WHAT WAS YOUR ORIGINAL NUMBER?\\n\";\n\nchomp( my $K = <STDIN> );\nmy $F = $K + 3;\nmy $G = $F / 5;\nmy $H = $G * 8;\nmy $I = $H / 5 + 5;\nmy $J = $I - 1;\n\nprint \"SO YOU THINK YOU'RE SO SMART, EH?\\n\";\nprint \"NOW WATCH.\\n\";\nprint \"$K PLUS 3 EQUALS $F. THIS DIVIDED BY 5 EQUALS $G;\\n\";\nprint \"THIS TIMES 8 EQUALS $H. IF WE DIVIDE BY 5 AND ADD 5,\\n\";\nprint \"WE GET $I , WHICH, MINUS 1, EQUALS $J.\\n\";\nprint \"NOW DO YOU BELIEVE ME?\\n\";\n\nchomp( my $Z = uc <STDIN> );\nif ( $Z eq 'YES' ) {\n    print \"BYE!!!\\n\";\n    exit;\n}\n\nprint \"YOU HAVE MADE ME MAD!!!\\n\";\nprint \"THERE MUST BE A GREAT LIGHTNING BOLT!\\n\\n\\n\";\n\nfor my $i ( reverse 22 .. 30 ) {\n    print ' ' x $i . \"X X\\n\";\n}\nprint ' ' x 21 . \"X XXX\\n\";\nprint ' ' x 20 . \"X   X\\n\";\nprint ' ' x 19 . \"XX X\\n\";\nfor my $i ( reverse 13 .. 20 ) {\n    print ' ' x $i . \"X X\\n\";\n}\nprint ' ' x 12 . \"XX\\n\";\nprint ' ' x 11 . \"X\\n\";\nprint ' ' x 10 . \"*\\n\";\nprint \"\\n#########################\\n\\n\";\nprint \"I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\\n\";\n"
  },
  {
    "path": "25_Chief/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "25_Chief/python/chief.py",
    "content": "def print_lightning_bolt() -> None:\n    print(\"*\" * 36)\n    n = 24\n    while n > 16:\n        print(\" \" * n + \"x x\")\n        n -= 1\n    print(\" \" * 16 + \"x xxx\")\n    print(\" \" * 15 + \"x   x\")\n    print(\" \" * 14 + \"xxx x\")\n    n -= 1\n    while n > 8:\n        print(\" \" * n + \"x x\")\n        n -= 1\n    print(\" \" * 8 + \"xx\")\n    print(\" \" * 7 + \"x\")\n    print(\"*\" * 36)\n\n\ndef print_solution(n: float) -> None:\n    print(f\"\\n{n} plus 3 gives {n + 3}. This Divided by 5 equals {(n + 3) / 5}\")\n    print(f\"This times 8 gives {((n + 3) / 5) * 8}. If we divide 5 and add 5.\")\n    print(\n        f\"We get {(((n + 3) / 5) * 8) / 5 + 5}, \"\n        f\"which, minus 1 equals {((((n + 3) / 5) * 8) / 5 + 5) - 1}\"\n    )\n\n\ndef game() -> None:\n    print(\"\\nTake a Number and ADD 3. Now, Divide this number by 5 and\")\n    print(\"multiply by 8. Now, Divide by 5 and add the same. Subtract 1\")\n\n    you_have = float(input(\"\\nWhat do you have? \"))\n    comp_guess = (((you_have - 4) * 5) / 8) * 5 - 3\n    first_guess_right = input(\n        f\"\\nI bet your number was {comp_guess} was I right(Yes or No)? \"\n    )\n\n    if first_guess_right.lower() == \"yes\":\n        print(\"\\nHuh, I Knew I was unbeatable\")\n        print(\"And here is how i did it\")\n        print_solution(comp_guess)\n    else:\n        original_number = float(input(\"\\nHUH!! what was you original number? \"))\n\n        if original_number == comp_guess:\n            print(\"\\nThat was my guess, AHA i was right\")\n            print(\n                \"Shamed to accept defeat i guess, don't worry you can master mathematics too\"\n            )\n            print(\"Here is how i did it\")\n            print_solution(comp_guess)\n        else:\n            print(\"\\nSo you think you're so smart, EH?\")\n            print(\"Now, Watch\")\n            print_solution(original_number)\n\n            believe_me = input(\"\\nNow do you believe me? \")\n\n            if believe_me.lower() == \"yes\":\n                print(\"\\nOk, Lets play again sometime bye!!!!\")\n            else:\n                print(\"\\nYOU HAVE MADE ME VERY MAD!!!!!\")\n                print(\"BY THE WRATH OF THE MATHEMATICS AND THE RAGE OF THE GODS\")\n                print(\"THERE SHALL BE LIGHTNING!!!!!!!\")\n                print_lightning_bolt()\n                print(\"\\nI Hope you believe me now, for your own sake\")\n\n    input()\n\n\nif __name__ == \"__main__\":\n    print(\"I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.\")\n    play = input(\"\\nAre you ready to take the test you called me out for(Yes or No)? \")\n    if play.lower() == \"yes\":\n        game()\n    else:\n        print(\"Ok, Nevermind. Let me go back to my great slumber, Bye\")\n        input()\n"
  },
  {
    "path": "25_Chief/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "25_Chief/ruby/chief.rb",
    "content": "def tab(size)\n  str = ''\n  size.times do\n    str += ' '\n  end\n\n  str\nend\n\ndef input\n  gets.chomp\nend\n\ndef bye\n  print \"BYE!!!\\n\"\nend\n\ndef main\n  print tab(30), \"CHIEF\\n\"\n  print tab(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\"\n  print \"\\n\"\n  print \"\\n\"\n  print \"\\n\"\n  print \"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\\n\"\n  print \"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR\\n\"\n\n  a = input\n  if a != 'YES'\n    print \"SHUT UP, PALE FACE WITH WISE TONGUE.\\n\"\n  end\n\n  print \" TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\\n\"\n  print \"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\\n\"\n  print  \"  WHAT DO YOU HAVE\\n\"\n\n  b = input.to_f\n  c = ((b + 1 - 5) * 5 / 8 * 5 -3).to_f\n  print \"I BET YOUR NUMBER WAS #{c}. AM I RIGHT\\n\"\n\n  d = input\n  if d == 'YES'\n    return bye\n  end\n\n  print \"WHAT WAS YOUR ORIGINAL NUMBER\\n\"\n\n  k = input.to_f\n  f = k + 3\n  g = f / 5\n  h = g * 8\n  i = h / 5 + 5\n  j = i - 1\n\n  print \"SO YOU THINK YOU'RE SO SMART, EH?\\n\"\n  print \"NOW WATCH.\\n\"\n  print k, \" PLUS 3 EQUALS \", f, \". THIS DIVIDED BY 5 EQUALS \", g, \";\\n\"\n  print \"THIS TIMES 8 EQUALS \", h, \". IF WE DIVIDE BY 5 AND ADD 5,\\n\"\n  print \"WE GET \", i, \", WHICH, MINUS 1, EQUALS \", j, \".\\n\"\n  print \"NOW DO YOU BELIEVE ME\\n\"\n\n  z = input\n  if z == 'YES'\n    return bye\n  end\n\n  print \"YOU HAVE MADE ME MAD!!!\\n\"\n  print \"THERE MUST BE A GREAT LIGHTNING BOLT!\\n\"\n  print \"\\n\"\n  print \"\\n\"\n\n  x = 30\n  while x >= 22\n    print tab(x), \"X X\\n\"\n    x -= 1\n  end\n\n  print tab(21), \"X XXX\\n\"\n  print tab(20), \"X   X\\n\"\n  print tab(19), \"XX X\\n\"\n\n  y = 20\n  while y >= 13\n    print tab(y), \"X X\\n\"\n    y -= 1\n  end\n\n  print tab(12), \"XX\\n\"\n  print tab(11), \"X\\n\"\n  print tab(10), \"*\\n\"\n\n  print \"\\n\"\n  print \"#########################\\n\"\n  print \"\\n\"\n  print \"I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\\n\"\n  return bye\nend\n\nmain\n"
  },
  {
    "path": "25_Chief/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "25_Chief/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by [Jadi](https://github.com/jadijadi)"
  },
  {
    "path": "25_Chief/rust/src/main.rs",
    "content": "use std::io;\n\nfn print_center(text: String, width: usize) {\n    let pad_size: usize = if width > text.len() {\n        (width - text.len()) / 2\n    } else {\n        0\n    };\n    println!(\"{}{}\", \" \".repeat(pad_size), text);\n}\n\nfn send_lightening() {\n    println!(\n        \"YOU HAVE MADE ME MAD!!!\nTHERE MUST BE A GREAT LIGHTNING BOLT!\n\n                              X X\n                             X X\n                            X X\n                           X X\n                          X X\n                         X X\n                        X X\n                       X X\n                      X X\n                     X XXX\n                    X   X\n                   XX X\n                    X X\n                   X X\n                  X X\n                 X X\n                X X\n               X X\n              X X\n             X X\n            XX\n           X\n          *\n\n#########################\n\nI HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\"\n    );\n}\n\nfn check_yes_answer() -> bool {\n    // reads from input and return true if it starts with Y or y\n\n    let mut answer: String = String::new();\n    io::stdin()\n        .read_line(&mut answer)\n        .expect(\"Error reading from stdin\");\n\n    answer.to_uppercase().starts_with('Y')\n}\n\nfn main() {\n    const PAGE_WIDTH: usize = 64;\n    print_center(\"CHIEF\".to_string(), PAGE_WIDTH);\n    print_center(\n        \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".to_string(),\n        PAGE_WIDTH,\n    );\n    println!(\"\\n\\n\\n\");\n\n    println!(\"I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\");\n    println!(\"ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR?\");\n\n    if !check_yes_answer() {\n        println!(\"SHUT UP, PALE FACE WITH WISE TONGUE.\");\n    }\n\n    println!(\"TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\");\n    println!(\"MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\");\n    println!(\"  WHAT DO YOU HAVE?\");\n\n    // read a float number\n    let mut answer: String = String::new();\n    io::stdin()\n        .read_line(&mut answer)\n        .expect(\"Error reading from stdin\");\n    let guess: f32 = answer.trim().parse().expect(\"Input not a number\");\n\n    let calculated_answer: f32 = (guess + 1.0 - 5.0) * 5.0 / 8.0 * 5.0 - 3.0;\n\n    println!(\"I BET YOUR NUMBER WAS {calculated_answer}. AM I RIGHT?\");\n\n    if check_yes_answer() {\n        println!(\"BYE!!!\");\n    } else {\n        println!(\"WHAT WAS YOUR ORIGINAL NUMBER?\");\n\n        // read a float number\n        let mut answer: String = String::new();\n        io::stdin()\n            .read_line(&mut answer)\n            .expect(\"Error reading from stdin\");\n        let claimed: f32 = answer.trim().parse().expect(\"Input not a number\");\n\n        println!(\"SO YOU THINK YOU'RE SO SMART, EH?\");\n        println!(\"NOW WATCH.\");\n        println!(\n            \"{claimed} PLUS 3 EQUALS {}. THIS DIVIDED BY 5 EQUALS {};\",\n            claimed + 3.0,\n            (claimed + 3.0) / 5.0\n        );\n        println!(\n            \"THIS TIMES 8 EQUALS {}. IF WE DIVIDE BY 5 AND ADD 5,\",\n            (claimed + 3.0) / 5.0 * 8.0\n        );\n        println!(\n            \"WE GET {} , WHICH, MINUS 1, EQUALS {}.\",\n            ((claimed + 3.0) / 5.0 * 8.0 / 5.0) + 5.0,\n            ((claimed + 3.0) / 5.0 * 8.0 / 5.0) + 4.0\n        );\n        println!(\"NOW DO YOU BELIEVE ME?\");\n\n        if check_yes_answer() {\n            println!(\"BYE!!!\");\n        } else {\n            send_lightening();\n        }\n    }\n}\n\n////////////////////////////////////////////////////////////////////\n// Porting notes:\n// In floating point arithmetics in \"modern\" languages we might see\n// unfamiliar situations such as 6.9999999 instead of 7 and such.\n// resolving this needs using specific mathematical libraries which\n// IMO is out of scope in these basic programs\n///////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "25_Chief/vbnet/Chief.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Chief\", \"Chief.vbproj\", \"{9BAA28D9-1DCF-42DA-934A-CD3EC5E26E7C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9BAA28D9-1DCF-42DA-934A-CD3EC5E26E7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9BAA28D9-1DCF-42DA-934A-CD3EC5E26E7C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9BAA28D9-1DCF-42DA-934A-CD3EC5E26E7C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9BAA28D9-1DCF-42DA-934A-CD3EC5E26E7C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "25_Chief/vbnet/Chief.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Chief</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "25_Chief/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "26_Chomp/README.md",
    "content": "### Chomp\n\nThis program is an adaptation of a mathematical game originally described by Martin Gardner in the January 1973 issue of _Scientific American_. Up to a 9x9 grid is set up by you with the upper left square in a poison square. This grid is the cookie. Players alternately chomp away at the cookie from the lower right. To take a chomp, input a row and column number of one of the squares remaining on the cookie. All of the squares below and to the right of that square, including that square, disappear.\n\nAny number of people can play — the computer is only the moderator; it is not a player. Two-person strategies are interesting to work out but strategies when three or more people are playing are the real challenge.\n\nThe computer version of the game was written by Peter Sessions of People’s Computer Company.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=44)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=59)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "26_Chomp/chomp.bas",
    "content": "10 PRINT TAB(33);\"CHOMP\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 DIM A(10,10)\n100 REM *** THE GAME OF CHOMP *** COPYRIGHT PCC 1973 ***\n110 PRINT\n120 PRINT \"THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\"\n130 PRINT \"DO YOU WANT THE RULES (1=YES, 0=NO!)\";\n140 INPUT R\n150 IF R=0 THEN 340\n160 F=1\n170 R=5\n180 C=7\n190 PRINT \"CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\"\n200 PRINT\n210 PRINT \"HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\"\n220 GOSUB 540\n230 PRINT\n240 PRINT \"THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\"\n250 PRINT \"WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\"\n260 PRINT \"CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\"\n270 PRINT \"CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\"\n280 PRINT \"ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\"\n290 PRINT \"ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\"\n300 PRINT \"(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\"\n310 PRINT \"NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\"\n320 PRINT \"OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\"\n330 PRINT\n340 PRINT \"HERE WE GO...\"\n350 REM\n360 F=0\n370 FOR I=1 TO 10\n372 FOR J=1 TO 10\n375 A(I,J)=0\n377 NEXT J\n379 NEXT I\n380 PRINT\n390 PRINT \"HOW MANY PLAYERS\";\n400 INPUT P\n410 I1=0\n420 PRINT \"HOW MANY ROWS\";\n430 INPUT R\n440 IF R <= 9 THEN 470\n450 PRINT \"TOO MANY ROWS (9 IS MAXIMUM). NOW, \";\n460 GOTO 420\n470 PRINT \"HOW MANY COLUMNS\";\n480 INPUT C\n490 IF C <= 9 THEN 530\n500 PRINT \"TOO MANY COLUMNS (9 IS MAXIMUM). NOW, \";\n510 GOTO 470\n530 PRINT\n540 FOR I=1 TO R\n550 FOR J=1 TO C\n560 A(I,J)=1\n570 NEXT J\n580 NEXT I\n590 A(1,1)=-1\n600 REM PRINT THE BOARD\n610 PRINT\n620 PRINT TAB(7);\"1 2 3 4 5 6 7 8 9\"\n630 FOR I=1 TO R\n640 PRINT I;TAB(7);\n650 FOR J=1 TO C\n660 IF A(I,J)=-1 THEN 700\n670 IF A(I,J)=0 THEN 720\n680 PRINT \"* \";\n690 GOTO 710\n700 PRINT \"P \";\n710 NEXT J\n720 PRINT\n730 NEXT I\n740 PRINT\n750 IF F=0 THEN 770\n760 RETURN\n770 REM GET CHOMPS FOR EACH PLAYER IN TURN\n780 LET I1=I1+1\n790 LET P1=I1-INT(I1/P)*P\n800 IF P1 <> 0 THEN 820\n810 P1=P\n820 PRINT \"PLAYER\";P1\n830 PRINT \"COORDINATES OF CHOMP (ROW,COLUMN)\";\n840 INPUT R1,C1\n850 IF R1<1 THEN 920\n860 IF R1>R THEN 920\n870 IF C1<1 THEN 920\n880 IF C1>C THEN 920\n890 IF A(R1,C1)=0 THEN 920\n900 IF A(R1,C1)=-1 THEN 1010\n910 GOTO 940\n920 PRINT \"NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\"\n930 GOTO 820\n940 FOR I=R1 TO R\n950 FOR J=C1 TO C\n960 A(I,J)=0\n970 NEXT J\n980 NEXT I\n990 GOTO 610\n1000 REM END OF GAME DETECTED IN LINE 900\n1010 PRINT \"YOU LOSE, PLAYER\";P1\n1020 PRINT\n1030 PRINT \"AGAIN (1=YES, 0=NO!)\";\n1040 INPUT R\n1050 IF R=1 THEN 340\n1060 END\n"
  },
  {
    "path": "26_Chomp/csharp/Chomp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "26_Chomp/csharp/Chomp.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Chomp\", \"Chomp.csproj\", \"{35863FB3-002D-4618-B993-51A51A586BCC}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{35863FB3-002D-4618-B993-51A51A586BCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{35863FB3-002D-4618-B993-51A51A586BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{35863FB3-002D-4618-B993-51A51A586BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{35863FB3-002D-4618-B993-51A51A586BCC}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "26_Chomp/csharp/Cookie.cs",
    "content": "using System.Text;\n\nnamespace Chomp;\n\ninternal class Cookie\n{\n    private readonly int _rowCount;\n    private readonly int _columnCount;\n    private readonly char[][] _bits;\n\n    public Cookie(int rowCount, int columnCount)\n    {\n        _rowCount = rowCount;\n        _columnCount = columnCount;\n\n        // The calls to Math.Max here are to duplicate the original behaviour\n        // when negative values are given for the row or column count.\n        _bits = new char[Math.Max(_rowCount, 1)][];\n        for (int row = 0; row < _bits.Length; row++)\n        {\n            _bits[row] = Enumerable.Repeat('*', Math.Max(_columnCount, 1)).ToArray();\n        }\n        _bits[0][0] = 'P';\n    }\n\n    public bool TryChomp(int row, int column, out char chomped)\n    {\n        if (row < 1 || row > _rowCount || column < 1 || column > _columnCount || _bits[row - 1][column - 1] == ' ')\n        {\n            chomped = default;\n            return false;\n        }\n\n        chomped = _bits[row - 1][column - 1];\n\n        for (int r = row; r <= _rowCount; r++)\n        {\n            for (int c = column; c <= _columnCount; c++)\n            {\n                _bits[r - 1][c - 1] = ' ';\n            }\n        }\n\n        return true;\n    }\n\n    public override string ToString()\n    {\n        var builder = new StringBuilder().AppendLine(\"       1 2 3 4 5 6 7 8 9\");\n        for (int row = 1; row <= _bits.Length; row++)\n        {\n            builder.Append(' ').Append(row).Append(\"     \").AppendLine(string.Join(' ', _bits[row - 1]));\n        }\n        return builder.ToString();\n    }\n}"
  },
  {
    "path": "26_Chomp/csharp/Game.cs",
    "content": "namespace Chomp;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n\n    public Game(IReadWrite io)\n    {\n        _io = io;\n    }\n\n    internal void Play()\n    {\n        _io.Write(Resource.Streams.Introduction);\n        if (_io.ReadNumber(\"Do you want the rules (1=Yes, 0=No!)\") != 0)\n        {\n            _io.Write(Resource.Streams.Rules);\n        }\n\n        while (true)\n        {\n            _io.Write(Resource.Streams.HereWeGo);\n\n            var (playerCount, rowCount, columnCount) = _io.ReadParameters();\n\n            var loser = Play(new Cookie(rowCount, columnCount), new PlayerNumber(playerCount));\n\n            _io.WriteLine(string.Format(Resource.Formats.YouLose, loser));\n\n            if (_io.ReadNumber(\"Again (1=Yes, 0=No!)\") != 1) { break; }\n        }\n    }\n\n    private PlayerNumber Play(Cookie cookie, PlayerNumber player)\n    {\n        while (true)\n        {\n            _io.WriteLine(cookie);\n\n            var poisoned = Chomp(cookie, player);\n\n            if (poisoned) { return player; }\n\n            player++;\n        }\n    }\n\n    private bool Chomp(Cookie cookie, PlayerNumber player)\n    {\n        while (true)\n        {\n            _io.WriteLine(string.Format(Resource.Formats.Player, player));\n\n            var (row, column) = _io.Read2Numbers(Resource.Prompts.Coordinates);\n\n            if (cookie.TryChomp((int)row, (int)column, out char chomped))\n            {\n                return chomped == 'P';\n            }\n\n            _io.Write(Resource.Streams.NoFair);\n        }\n    }\n}\n"
  },
  {
    "path": "26_Chomp/csharp/IOExtensions.cs",
    "content": "namespace Chomp;\n\ninternal static class IOExtensions\n{\n    public static (float, int, int) ReadParameters(this IReadWrite io)\n        => (\n            (int)io.ReadNumber(Resource.Prompts.HowManyPlayers),\n            io.ReadNumberWithMax(Resource.Prompts.HowManyRows, 9, Resource.Strings.TooManyRows),\n            io.ReadNumberWithMax(Resource.Prompts.HowManyColumns, 9, Resource.Strings.TooManyColumns)\n        );\n\n    private static int ReadNumberWithMax(this IReadWrite io, string initialPrompt, int max, string reprompt)\n    {\n        var prompt = initialPrompt;\n\n        while (true)\n        {\n            var response = io.ReadNumber(prompt);\n            if (response <= 9) { return (int)response; }\n\n            prompt = $\"{reprompt} {initialPrompt.ToLowerInvariant()}\";\n        }\n    }\n}"
  },
  {
    "path": "26_Chomp/csharp/PlayerNumber.cs",
    "content": "namespace Chomp;\n\ninternal class PlayerNumber\n{\n    private readonly float _playerCount;\n    private int _counter;\n    private float _number;\n\n    // The original code does not constrain playerCount to be an integer\n    public PlayerNumber(float playerCount)\n    {\n        _playerCount = playerCount;\n        _number = 0;\n        Increment();\n    }\n\n    public static PlayerNumber operator ++(PlayerNumber number) => number.Increment();\n\n    private PlayerNumber Increment()\n    {\n\t\tif (_playerCount == 0) { throw new DivideByZeroException(); }\n\n        // The increment logic here is the same as the original program, and exhibits\n        // interesting behaviour when _playerCount is not an integer.\n        _counter++;\n        _number = _counter - (float)Math.Floor(_counter / _playerCount) * _playerCount;\n        if (_number == 0) { _number = _playerCount; }\n        return this;\n    }\n\n    public override string ToString() => (_number >= 0 ? \" \" : \"\") + _number.ToString();\n}"
  },
  {
    "path": "26_Chomp/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Chomp.Resources;\nusing Chomp;\n\nnew Game(new ConsoleIO()).Play();"
  },
  {
    "path": "26_Chomp/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "26_Chomp/csharp/Resources/Coordinates.txt",
    "content": "Coordinates of Chomp (row, column)"
  },
  {
    "path": "26_Chomp/csharp/Resources/HereWeGo.txt",
    "content": "Here we go...\n\n"
  },
  {
    "path": "26_Chomp/csharp/Resources/HowManyColumns.txt",
    "content": "How many columns"
  },
  {
    "path": "26_Chomp/csharp/Resources/HowManyPlayers.txt",
    "content": "How many players"
  },
  {
    "path": "26_Chomp/csharp/Resources/HowManyRows.txt",
    "content": "How many rows"
  },
  {
    "path": "26_Chomp/csharp/Resources/Introduction.txt",
    "content": "                                 Chomp\n               Creative Computing  Morristown, New Jersey\n\n\n\nThis is the game of Chomp (Scientific American, Jan 1973)\n"
  },
  {
    "path": "26_Chomp/csharp/Resources/NoFair.txt",
    "content": "No fair. You're trying to chomp on empty space!\n"
  },
  {
    "path": "26_Chomp/csharp/Resources/Player.txt",
    "content": "Player{0}"
  },
  {
    "path": "26_Chomp/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Chomp.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream HereWeGo => GetStream();\n        public static Stream Introduction => GetStream();\n        public static Stream Rules => GetStream();\n        public static Stream NoFair => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string Player => GetString();\n        public static string YouLose => GetString();\n    }\n\n    internal static class Prompts\n    {\n        public static string Coordinates => GetString();\n        public static string HowManyPlayers => GetString();\n        public static string HowManyRows => GetString();\n        public static string HowManyColumns => GetString();\n        public static string TooManyColumns => GetString();\n    }\n\n    internal static class Strings\n    {\n        public static string TooManyColumns => GetString();\n        public static string TooManyRows => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "26_Chomp/csharp/Resources/Rules.txt",
    "content": "Chomp is for 1 or more players (humans only).\n\nHere's how a board looks (this one is 5 by 7):\n\n       1 2 3 4 5 6 7 8 9\n 1     P * * * * * *\n 2     * * * * * * *\n 3     * * * * * * *\n 4     * * * * * * *\n 5     * * * * * * *\n\n\nThe board is a big cookie - R rows high and C columns\nwide. You input R and C at the start. In the upper left\ncorner of the cookie is a poison square (P). The one who\nchomps the poison square loses. To take a chomp, type the\nrow and column of one of the squares on the cookie.\nAll of the squares below and to the right of that square\n(including that square, too) disappear -- Chomp!!\nNo fair chomping on squares that have already been chomped,\nor that are outside the original dimensions of the cookie.\n\n"
  },
  {
    "path": "26_Chomp/csharp/Resources/TooManyColumns.txt",
    "content": "Too many rows (9 is maximum). Now,"
  },
  {
    "path": "26_Chomp/csharp/Resources/TooManyRows.txt",
    "content": "Too many rows (9 is maximum). Now,"
  },
  {
    "path": "26_Chomp/csharp/Resources/YouLose.txt",
    "content": "You lose, player{0}\n"
  },
  {
    "path": "26_Chomp/java/Chomp.java",
    "content": "import java.util.Scanner;\npublic class Chomp{\n\tint rows;\n\tint cols;\n\tint numberOfPlayers;\n\tint []board;\n\tScanner scanner;\n\tChomp(){\n\t\tSystem.out.println(\"\\t\\t\\t\\tCHOMP\");\n\t\tSystem.out.println(\"\\t\\tCREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n\t\tSystem.out.println(\"THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\");\n\t\tSystem.out.print(\"Do you want the rules (1=Yes, 0=No!)  \");\n\n\t\tscanner = new Scanner(System.in);\n\t\tint choice = scanner.nextInt();\n\t\tif(choice != 0){\n\t\t\tSystem.out.println(\"Chomp is for 1 or more players (Humans only).\\n\");\n\t\t\tSystem.out.println(\"Here's how a board looks (This one is 5 by 7):\");\n\t\t\tSystem.out.println(\"\\t1 2 3 4 5 6 7\");\n\t\t\tSystem.out.println(\" 1     P * * * * * *\\n 2     * * * * * * *\\n 3     * * * * * * *\\n 4     * * * * * * *\\n 5     * * * * * * *\");\n\t\t\tSystem.out.println(\"\\nThe board is a big cookie - R rows high and C columns \\nwide. You input R and C at the start. In the upper left\\ncorner of the cookie is a poison square (P). The one who\\nchomps the poison square loses. To take a chomp, type the\\nrow and column of one of the squares on the cookie.\\nAll of the squares below and to the right of that square\\n(Including that square, too) disappear -- CHOMP!!\\nNo fair chomping squares that have already been chomped,\\nor that are outside the original dimensions of the cookie.\\n\");\n\t\t\tSystem.out.println(\"Here we go...\\n\");\n\t\t}\n\t\tstartGame();\n\t}\n\n\tprivate void startGame(){\n\t\tSystem.out.print(\"How many players \");\n\t\tnumberOfPlayers = scanner.nextInt();\n\t\twhile(numberOfPlayers < 2){\n\t\t\tSystem.out.print(\"How many players \");\n                \tnumberOfPlayers = scanner.nextInt();\n\t\t}\n\t\tSystem.out.print(\"How many rows \");\n\t\trows = scanner.nextInt();\n\t\twhile(rows<=0 || rows >9){\n\t\t\tif(rows <= 0){\n\t\t\t\tSystem.out.println(\"Minimun 1 row is required !!\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.println(\"Too many rows(9 is maximum). \");\n\t\t\t}\n\t\t\tSystem.out.print(\"How many rows \");\n\t\t\trows = scanner.nextInt();\n\t\t}\n\t\tSystem.out.print(\"How many columns \");\n                cols = scanner.nextInt();\n                while(cols<=0 || cols >9){\n                        if(cols <= 0){\n                                System.out.println(\"Minimun 1 column is required !!\");\n                        }\n                        else{\n                                System.out.println(\"Too many columns(9 is maximum). \");\n                        }\n                        System.out.print(\"How many columns \");\n                        cols = scanner.nextInt();\n                }\n\t\tboard = new int[rows];\n\t\tfor(int i=0;i<rows;i++){\n\t\t\tboard[i]=cols;\n\t\t}\n\t\tprintBoard();\n\t\tscanner.nextLine();\n\t\tmove(0);\n\t}\n\n\tprivate void printBoard(){\n\t\tSystem.out.print(\"        \");\n\t\tfor(int i=0;i<cols;i++){\n\t\t\tSystem.out.print(i+1);\n\t\t\tSystem.out.print(\" \");\n\t\t}\n\t\tfor(int i=0;i<rows;i++){\n\t\t\tSystem.out.print(\"\\n \");\n\t\t\tSystem.out.print(i+1);\n\t\t\tSystem.out.print(\"      \");\n\t\t\tfor(int j=0;j<board[i];j++){\n\t\t\t\tif(i == 0 && j == 0){\n\t\t\t\t\tSystem.out.print(\"P \");\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(\"* \");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"\");\n\t}\n\n\tprivate void move(int player){\n\t\tSystem.out.println(String.format(\"Player %d\",(player+1)));\n\n\t\tString input;\n\t\tString [] coordinates;\n\t\tint x=-1,y=-1;\n\t\twhile(true){\n\t\t\ttry{\n\t\t\t\tSystem.out.print(\"Coordinates of chomp (Row, Column) \");\n\t\t\t\tinput = scanner.nextLine();\n\t\t\t\tcoordinates = input.split(\",\");\n\t\t\t\tx = Integer.parseInt(coordinates[0]);\n\t\t\t\ty = Integer.parseInt(coordinates[1]);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcatch(Exception e){\n\t\t\t\tSystem.out.println(\"Please enter valid coordinates.\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\twhile(x>rows || x <1 || y>cols || y<1 || board[x-1]<y){\n\t\t\tSystem.out.println(\"No fair. You're trying to chomp on empty space!\");\n\t                while(true){\n                        \ttry{\n\t\t\t\t\tSystem.out.print(\"Coordinates of chomp (Row, Column) \");\n                \t                input = scanner.nextLine();\n        \t                        coordinates = input.split(\",\");\n\t                                x = Integer.parseInt(coordinates[0]);\n                        \t        y = Integer.parseInt(coordinates[1]);\n                \t                break;\n        \t                }\n\t                        catch(Exception e){\n                        \t        System.out.println(\"Please enter valid coordinates.\");\n                \t                continue;\n        \t                }\n\t                }\n\t\t}\n\n\t\tif(x == 1 && y == 1){\n\t\t\tSystem.out.println(\"You lose player \"+(player+1));\n\t\t\tint choice = -1 ;\n\t\t\twhile(choice != 0 && choice != 1){\n\t\t\t\tSystem.out.print(\"Again (1=Yes, 0=No!) \");\n\t\t\t\tchoice = scanner.nextInt();\n\t\t\t}\n\t\t\tif(choice == 1){\n\t\t\t\tstartGame();\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.exit(0);\n\t\t\t}\n\t\t}\n\t\telse{\n\t\t\tfor(int i=x-1;i<rows;i++){\n\t\t\t\tif(board[i] >= y){\n\t\t\t\t\tboard[i] = y-1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintBoard();\n\t\t\tmove((player+1)%numberOfPlayers);\n\t\t}\n\t}\n\n\n\tpublic static void main(String []args){\n\t\tnew Chomp();\n\t}\n}\n"
  },
  {
    "path": "26_Chomp/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "26_Chomp/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "26_Chomp/javascript/chomp.html",
    "content": "<html>\n<head>\n<title>CHOMP</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"chomp.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "26_Chomp/javascript/chomp.js",
    "content": "// CHOMP\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a = [];\nvar r;\nvar c;\n\nfunction init_board()\n{\n    for (i = 1; i <= r; i++)\n        for (j = 1; j <= c; j++)\n            a[i][j] = 1;\n    a[1][1] = -1;\n}\n\nfunction show_board()\n{\n    print(\"\\n\");\n    print(tab(7) + \"1 2 3 4 5 6 7 8 9\\n\");\n    for (i = 1; i <= r; i++) {\n        str = i + tab(6);\n        for (j = 1; j <= c; j++) {\n            if (a[i][j] == -1)\n                str += \"P \";\n            else if (a[i][j] == 0)\n                break;\n            else\n                str += \"* \";\n        }\n        print(str + \"\\n\");\n    }\n    print(\"\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"CHOMP\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 1; i <= 10; i++)\n        a[i] = [];\n    // *** THE GAME OF CHOMP *** COPYRIGHT PCC 1973 ***\n    print(\"\\n\");\n    print(\"THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\\n\");\n    print(\"DO YOU WANT THE RULES (1=YES, 0=NO!)\");\n    r = parseInt(await input());\n    if (r != 0) {\n        f = 1;\n        r = 5;\n        c = 7;\n        print(\"CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\\n\");\n        print(\"\\n\");\n        print(\"HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\\n\");\n        init_board();\n        show_board();\n        print(\"\\n\");\n        print(\"THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\\n\");\n        print(\"WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\\n\");\n        print(\"CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\\n\");\n        print(\"CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\\n\");\n        print(\"ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\\n\");\n        print(\"ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\\n\");\n        print(\"INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\\n\");\n        print(\"NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\\n\");\n        print(\"OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\\n\");\n        print(\"\\n\");\n    }\n    while (1) {\n        print(\"HERE WE GO...\\n\");\n        f = 0;\n        for (i = 1; i <= 10; i++) {\n            a[i] = [];\n            for (j = 1; j <= 10; j++) {\n                a[i][j] = 0;\n            }\n        }\n        print(\"\\n\");\n        print(\"HOW MANY PLAYERS\");\n        p = parseInt(await input());\n        i1 = 0;\n        while (1) {\n            print(\"HOW MANY ROWS\");\n            r = parseInt(await input());\n            if (r <= 9)\n                break;\n            print(\"TOO MANY ROWS (9 IS MAXIMUM). NOW \");\n        }\n        while (1) {\n            print(\"HOW MANY COLUMNS\");\n            c = parseInt(await input());\n            if (c <= 9)\n                break;\n            print(\"TOO MANY COLUMNS (9 IS MAXIMUM). NOW \");\n        }\n        print(\"\\n\");\n        init_board();\n        while (1) {\n            // Print the board\n            show_board();\n            // Get chomps for each player in turn\n            i1++;\n            p1 = i1 - Math.floor(i1 / p) * p;\n            if (p1 == 0)\n                p1 = p;\n            while (1) {\n                print(\"PLAYER \" + p1 + \"\\n\");\n                print(\"COORDINATES OF CHOMP (ROW,COLUMN)\");\n                str = await input();\n                r1 = parseInt(str);\n                c1 = parseInt(str.substr(str.indexOf(\",\") + 1));\n                if (r1 >= 1 && r1 <= r && c1 >= 1 && c1 <= c && a[r1][c1] != 0)\n                    break;\n                print(\"NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\\n\");\n            }\n            if (a[r1][c1] == -1)\n                break;\n            for (i = r1; i <= r; i++)\n                for (j = c1; j <= c; j++)\n                    a[i][j] = 0;\n        }\n        // End of game detected\n        print(\"YOU LOSE, PLAYER \" + p1 + \"\\n\");\n        print(\"\\n\");\n        print(\"AGAIN (1=YES, 0=NO!)\");\n        r = parseInt(await input());\n        if (r != 1)\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "26_Chomp/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "26_Chomp/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "26_Chomp/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "26_Chomp/perl/chomp.pl",
    "content": "#!/usr/bin/perl\n\n\nmy @cookie;\n\n&main;\n\nsub main {\n\tmy $answer = 1;\n\tuntil ($answer == 0) {\n\t\t$answer=&game_play;\n\t}\n}\n\nsub game_play {\n\n\t# the initial game set up\n\t&print_intro;\n\tmy ($players,$rows,$cols) = &get_user_info;\n\t&create_gameboard($rows,$cols);\n\t&print_gameboard($rows,$cols);\n\tmy $game_over = 0;\n\tmy $player = 0;\n\n\t# continuous loop until the poison pill is swallowed\n\tuntil ($game_over == 1) {\n\t\tif ($player > ($players-1)) {\t\t#checks to make sure we're just looping thru valid players\n\t\t\t$player = 0;\n\t\t}\n\t\t$player++;\n\t\tmy ($user_row,$user_col) = &get_player_row_col($player,$rows,$cols);\n\t\tif ($cookie[$user_row][$user_col] == -1) {\n\t\t\tprint \"YOU LOSE, PLAYER $player\\n\\n\";\n\t\t\tprint \"AGAIN (1=YES, 0=NO!)\\n\";\n\t\t\tmy $answer=<STDIN>;\n\t\t\tchomp($answer);\n\t\t\treturn($answer);\n\t\t}\n\t\t&modify_gameboard($rows,$cols,$user_row,$user_col);\n\t\t&print_gameboard($rows,$cols);\n\t}\n\n}\n\nsub get_player_row_col {\n\tmy ($player,$row,$col) = @_;\n\tmy @coords;\n\tmy $validity=\"invalid\";\n\t# Getting coordinates from user\n\tuntil ($validity eq \"valid\") {\n\t\tprint \"PLAYER $player COORDINATES OF CHOMP (ROW,COLUMN)\\n\";\n\t\tmy $input=<STDIN>;\n\t\tchomp($input);\n\t\t@coords = split/,/,$input;\n\n\t\t#verifying coordinates are valid\n\t\tif ($coords[0] < 1 || $coords[0] > $row || $coords[1] < 1 || $coords[1] > $col || $cookie[$coords[0]][$coords[1]] == 0) {\n\t\t\tprint \"NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\\n\";\n\t\t}\n\t\telse {\n\t\t\t$validity=\"valid\";\n\t\t}\n\t}\n\treturn($coords[0],$coords[1]);\n}\n\nsub get_user_info {\n\tmy ($players,$rows,$cols)=0;\n\tuntil ($players > 0) {\n\t\tprint \"HOW MANY PLAYERS\\n\";\n\t\t$players=<STDIN>;\n\t\tchomp($players);\n\t}\n\tuntil ($rows > 0 && $rows < 10) {\n\t\tprint \"HOW MANY ROWS\\n\";\n\t\t$rows=<STDIN>;\n\t\tchomp($rows);\n\t\tif ($rows > 9) {\n\t\t\tprint \"TOO MANY ROWS (9 IS MAXIMUM). NOW, \";\n\t\t}\n\t}\n\tuntil ($cols > 0 && $cols < 10) {\n\t\tprint \"HOW MANY COLUMNS\\n\";\n\t\t$cols=<STDIN>;\n\t\tchomp($cols);\n\t\tif ($cols > 9) {\n\t\t\tprint \"TOO MANY COLUMNS (9 IS MAXIMUM). NOW, \";\n\t\t}\n\t}\n\treturn($players,$rows,$cols);\n}\n\nsub print_intro{\n\tprint ' ' x 33 . \"CHOMP\\n\";\n\tprint ' ' x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\";\n\tprint \"THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\\n\";\n\tprint \"DO YOU WANT THE RULES (1=YES, 0=NO!)\";\n\tmy $answer = <STDIN>;\n\tchomp($answer);\n\tif ($answer == 0) {\n\t\treturn;\n\t}\n\telse {\n\t \tprint \"CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\\n\\n\";\n\t \tprint \"HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\\n\";\n\t\t&create_gameboard(5,7);\n\t\t&print_gameboard(5,7);\n\t \tprint \"THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\\n\";\n\t \tprint \"WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\\n\";\n\t \tprint \"CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\\n\";\n\t \tprint \"CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\\n\";\n\t \tprint \"ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\\n\";\n\t \tprint \"ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\\n\";\n\t \tprint \"(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\\n\";\n\t \tprint \"NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\\n\";\n\t \tprint \"OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\\n\\n\";\n\t \tprint \"HERE WE GO...\\n\";\n\t\tundef @cookie;\n\t}\n}\n\n#initial creation of the gameboard\nsub create_gameboard {\n\tmy $rows = shift;\n\tmy $cols = shift;\n\tforeach my $row (1..($rows)) {\n\t\tforeach my $col (1..($cols)) {\n\t\t\t$cookie[$row][$col]=1;\n\t\t}\n\t}\n\t$cookie[1][1]=-1;\n}\n\n#modification of the gameboard based on the input from the player\nsub modify_gameboard {\n\tmy ($rows,$cols,$user_row,$user_col) = @_;\n\tforeach my $row ($user_row..($rows)) {\n\t\tforeach my $col ($user_col..($cols)) {\n\t\t\t$cookie[$row][$col]=\"  \";\n\t\t}\n\t}\n}\n\n#prints the gameboard based on the current state of the gameboard\nsub print_gameboard {\n\tmy ($rows,$cols) = @_;\n\tforeach my $col (1..$cols) {\n\t\tif ($col == $cols) {\n\t\t\tprint \"$col\\n\";\n\t\t}\n\t\telsif ($col == 1) {\n\t\t\tprint \"\\t  $col \";\n\t\t}\n\t\telse {\n\t\t\tprint \"$col \";\n\t\t}\n\t}\n\tforeach my $row (1..($rows)) {\n\t\tprint \"\\t$row \";\n\t\tforeach my $col (1..($cols)) {\n\t\t\tif ($cookie[$row][$col] == 1) {\n\t\t\t\tprint \"* \";\n\t\t\t}\n\t\t\tif ($cookie[$row][$col] == 0) {\n\t\t\t\tprint \"  \";\n\t\t\t}\n\t\t\tif ($cookie[$row][$col] == -1) {\n\t\t\t\tprint \"P \";\n\t\t\t}\n\t\t}\n\t\tprint \"\\n\";\n\t}\n}\n"
  },
  {
    "path": "26_Chomp/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "26_Chomp/python/chomp.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nCHOMP\n\nConverted from BASIC to Python by Trevor Hobson\n\"\"\"\n\n\nclass Canvas:\n    \"\"\"For drawing the cookie\"\"\"\n\n    def __init__(self, width=9, height=9, fill=\"*\") -> None:\n        self._buffer = []\n        for _ in range(height):\n            line = [fill for _ in range(width)]\n            self._buffer.append(line)\n        self._buffer[0][0] = \"P\"\n\n    def render(self) -> str:\n        lines = [\"       1 2 3 4 5 6 7 8 9\"]\n        lines.extend(\n            f\" {str(row)}\" + \" \" * 5 + \" \".join(line)\n            for row, line in enumerate(self._buffer, start=1)\n        )\n        return \"\\n\".join(lines)\n\n    def chomp(self, r, c) -> str:\n        if not 1 <= r <= len(self._buffer) or not 1 <= c <= len(self._buffer[0]):\n            return \"Empty\"\n        elif self._buffer[r - 1][c - 1] == \" \":\n            return \"Empty\"\n        elif self._buffer[r - 1][c - 1] == \"P\":\n            return \"Poison\"\n        else:\n            for row in range(r - 1, len(self._buffer)):\n                for column in range(c - 1, len(self._buffer[row])):\n                    self._buffer[row][column] = \" \"\n            return \"Chomp\"\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n    players = 0\n    while players == 0:\n        try:\n            players = int(input(\"How many players \"))\n\n        except ValueError:\n            print(\"Please enter a number.\")\n    rows = 0\n    while rows == 0:\n        try:\n            rows = int(input(\"How many rows \"))\n            if rows > 9 or rows < 1:\n                rows = 0\n                print(\"Too many rows (9 is maximum).\")\n\n        except ValueError:\n            print(\"Please enter a number.\")\n    columns = 0\n    while columns == 0:\n        try:\n            columns = int(input(\"How many columns \"))\n            if columns > 9 or columns < 1:\n                columns = 0\n                print(\"Too many columns (9 is maximum).\")\n\n        except ValueError:\n            print(\"Please enter a number.\")\n    cookie = Canvas(width=columns, height=rows)\n    player = 0\n    alive = True\n    while alive:\n        print()\n        print(cookie.render())\n        print()\n        player += 1\n        if player > players:\n            player = 1\n        while True:\n            print(\"Player\", player)\n            player_row = -1\n            player_column = -1\n            while player_row == -1 or player_column == -1:\n                try:\n                    coordinates = [\n                        int(item)\n                        for item in input(\"Coordinates of chomp (Row, Column) \").split(\n                            \",\"\n                        )\n                    ]\n                    player_row = coordinates[0]\n                    player_column = coordinates[1]\n\n                except (ValueError, IndexError):\n                    print(\"Please enter valid coordinates.\")\n            result = cookie.chomp(player_row, player_column)\n            if result == \"Empty\":\n                print(\"No fair. You're trying to chomp on empty space!\")\n            elif result == \"Poison\":\n                print(\"\\nYou lose player\", player)\n                alive = False\n                break\n            else:\n                break\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"CHOMP\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n    print(\"THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\")\n    if input(\"Do you want the rules (1=Yes, 0=No!) \") != \"0\":\n        print(\"Chomp is for 1 or more players (Humans only).\\n\")\n        print(\"Here's how a board looks (This one is 5 by 7):\")\n        example = Canvas(width=7, height=5)\n        print(example.render())\n        print(\"\\nThe board is a big cookie - R rows high and C columns\")\n        print(\"wide. You input R and C at the start. In the upper left\")\n        print(\"corner of the cookie is a poison square (P). The one who\")\n        print(\"chomps the poison square loses. To take a chomp, type the\")\n        print(\"row and column of one of the squares on the cookie.\")\n        print(\"All of the squares below and to the right of that square\")\n        print(\"(Including that square, too) disappear -- CHOMP!!\")\n        print(\"No fair chomping squares that have already been chomped,\")\n        print(\"or that are outside the original dimensions of the cookie.\\n\")\n        print(\"Here we go...\")\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nAgain (1=Yes, 0=No!) \") == \"1\"\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "26_Chomp/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "26_Chomp/vbnet/Chomp.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Chomp\", \"Chomp.vbproj\", \"{F7F8E933-9679-4393-94F0-46F47D81B025}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F7F8E933-9679-4393-94F0-46F47D81B025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F7F8E933-9679-4393-94F0-46F47D81B025}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F7F8E933-9679-4393-94F0-46F47D81B025}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F7F8E933-9679-4393-94F0-46F47D81B025}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "26_Chomp/vbnet/Chomp.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Chomp</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "26_Chomp/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "27_Civil_War/README.md",
    "content": "### Civil War\n\nThis simulation is based on 14 battles in the Civil War. Facts and figures are based on the actual occurrence. If you follow the same strategy used in the actual battle, the results will be the same. Generally, this is a good strategy since the generals in the Civil War were fairly good military strategists. However, you can frequently outperform the Civil War generals, particularly in cases where they did not have good enemy intelligence and consequently followed a poor course of action. Naturally, it helps to know your Civil War history, although the computer gives you the rudiments.\n\nAfter each of the 14 battles, your casualties are compared to the actual casualties of the battle, and you are told whether you win or lose the battle.\n\nYou may play Civil War alone in which case the program simulates the Union general. Or two players may play in which case the computer becomes the moderator.\n\nCivil War was written in 1968 by three Students in Lexington High School, Massachusetts: L. Cram, L. Goodie, and D. Hibbard. It was modified into a 2-player game by G. Paul and R. Hess of TIES, St. Paul, Minnesota.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=46)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=61)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- At the end of a single-player game, the program reports strategies used by \"THE SOUTH\", but these are in fact strategies used by the North (the computer player) -- the South is always a human player.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "27_Civil_War/civilwar.bas",
    "content": "2 PRINT TAB(26) \"CIVIL WAR\"\n4 PRINT TAB(15) \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT : PRINT : PRINT\n20 REM ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S.\n30 REM MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973\n50  DIM S(4),C$(14),M1(14),M2(14),C1(14),C2(14),M(14)\n60  REM UNION INFO ON LIKELY CONFEDERATE STRATEGY\n70  S(1)=25 : S(2)=25 : S(3)=25 : S(4)=25\n82  REM READ HISTORICAL DATA.\n84  FOR D=1 TO 14\n86  READ C$(D),M1(D),M2(D),C1(D),C2(D),M(D)\n88  NEXT D\n89  LET D=RND(-1)\n90  PRINT\n100  PRINT \"DO YOU WANT INSTRUCTIONS\";\n110  INPUT X$\n120  IF X$=\"YES\" THEN 160\n130  IF X$=\"NO\" THEN 370\n140  PRINT \"YES OR NO -- \";\n150  GOTO 110\n160  PRINT : PRINT : PRINT : PRINT\n170  PRINT \"THIS IS A CIVIL WAR SIMULATION.\"\n180  PRINT \"TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS.\"\n190  PRINT \"REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR\"\n200  PRINT \"RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE\"\n210  PRINT \"BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT\"\n220  PRINT \"AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!\"\n230  PRINT\n240  PRINT \"THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS \";\n245  PRINT \"POSSIBLE.\"\n250  PRINT\n260  PRINT \"YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:\"\n270  PRINT \"        (1) ARTILLERY ATTACK\"\n280  PRINT \"        (2) FORTIFICATION AGAINST FRONTAL ATTACK\"\n290  PRINT \"        (3) FORTIFICATION AGAINST FLANKING MANEUVERS\"\n300  PRINT \"        (4) FALLING BACK\"\n310  PRINT \" YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:\"\n320  PRINT \"        (1) ARTILLERY ATTACK\"\n330  PRINT \"        (2) FRONTAL ATTACK\"\n340  PRINT \"        (3) FLANKING MANEUVERS\"\n350  PRINT \"        (4) ENCIRCLEMENT\"\n360  PRINT \"YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY.\"\n370  PRINT : PRINT : PRINT : PRINT \"ARE THERE TWO GENERALS PRESENT \";\n380  PRINT \"(ANSWER YES OR NO)\";\n390  INPUT B$\n400  IF B$=\"YES\" THEN 430\n410  IF B$ <> \"NO\" THEN 380\n420  PRINT : PRINT \"YOU ARE THE CONFEDERACY.   GOOD LUCK!\"\n425  PRINT\n430  LET D=1\n440  IF B$ <> \"YES\" THEN 460\n450  LET D=2\n460  PRINT \"SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON\"\n470  PRINT \"REQUEST.  TYPE ANY OTHER NUMBER TO END THE SIMULATION.\"\n480  PRINT \"BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION\"\n490  PRINT \"ALLOWING YOU TO REPLAY IT\"\n500  PRINT\n510  PRINT \"NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO \"\n520  PRINT \"USE THE ENTRIES FROM THE PREVIOUS BATTLE\"\n530  PRINT\n540  PRINT \"AFTER REQUESTING A BATTLE, DO YOU WISH \";\n550  PRINT \"BATTLE DESCRIPTIONS \";\n560  PRINT \"(ANSWER YES OR NO)\";\n570  INPUT X$\n580  IF X$=\"YES\" THEN 600\n590  IF X$ <> \"NO\" THEN 560\n600  L=0:W=0:R1=0:Q1=0:M3=0:M4=0:P1=0:P2=0:T1=0:T2=0\n610  F(2)=0:H(2)=0:B(2)=0:R2=0:Q2=0:C6=0:F=0:W0=0:Y=0:Y2=0:U=0:U2=0\n620  PRINT : PRINT : PRINT\n630  PRINT \"WHICH BATTLE DO YOU WISH TO SIMULATE\";\n640  INPUT A\n650  IF A <> 0 THEN 660\n655  IF R <> 0 THEN 1140\n660  IF A <=0 THEN 2860\n665  IF A >= 15 THEN 2860\n670  LET C$=C$(A)\n680  LET M1=M1(A)\n690  LET M2=M2(A)\n700  LET C1=C1(A)\n710  LET C2=C2(A)\n720  LET M=M(A)\n960  LET U=0\n970  REM  INFLATION CALC\n980  LET I1=10+(L-W)*2\n990  LET I2=10+(W-L)*2\n1000  REM - MONEY AVAILABLE\n1010  LET D(1)=100*INT((M1*(100-I1)/2000)*(1+(R1-Q1)/(R1+1))+.5)\n1020  LET D(2)=100*INT(M2*(100-I2)/2000+.5)\n1030  IF B$ <> \"YES\" THEN 1050\n1040  LET D(2)=100*INT((M2*(100-I2)/2000)*(1+(R2-Q2)/(R2+1))+.5)\n1050  REM - MEN   AVAILABLE\n1060  LET M5=INT(M1*(1+(P1-T1)/(M3+1)))\n1070  LET M6=INT(M2*(1+(P2-T2)/(M4+1)))\n1080  LET F1=5*M1/6\n1090  PRINT : PRINT : PRINT : PRINT : PRINT\n1100  PRINT \"THIS IS THE BATTLE OF \";C$\n1110  IF X$=\"NO\" THEN 1150\n1120  IF A>11 THEN 1130\n1125  ON A GOTO 3580,3620,3650,3690,3720,3750,3780,3800,3830,3860,3890\n1130  ON A-11 GOTO 3920,3950,3980\n1140  PRINT C$\" INSTANT REPLAY\"\n1150  PRINT\n1160  PRINT \" \",\"CONFEDERACY\",\" UNION\"\n1170  PRINT \"MEN\",\" \"M5,\" \"M6\n1180  PRINT \"MONEY\",\"$\";D(1),\"$\";D(2)\n1190  PRINT \"INFLATION\",\" \";I1+15;\"%\",\" \";I2;\"%\"\n1195  PRINT\n1200  REM - ONLY IN PRINTOUT IS CONFED INFLATION = I1+15%\n1210  REM - IF TWO GENERALS, INPUT CONFED. FIRST\n1220  FOR I=1 TO D\n1230  IF B$ <> \"YES\" THEN 1260\n1240  IF I=2 THEN 1260\n1250  PRINT \"CONFEDERATE GENERAL---\";\n1260  PRINT \"HOW MUCH DO YOU WISH TO SPEND FOR\"\n1270  PRINT \" - FOOD......\";\n1280  INPUT F\n1290  IF F >= 0 THEN 1360\n1300  IF R1 <> 0 THEN 1330\n1310  PRINT \"NO PREVIOUS ENTRIES\"\n1320  GOTO 1270\n1330  PRINT \"ASSUME YOU WANT TO KEEP SAME ALLOCATIONS\"\n1340  PRINT\n1350  GOTO 1510\n1360  LET F(I)=F\n1370  PRINT \" - SALARIES..\";\n1380  INPUT H(I)\n1390  LET N=1\n1400  IF H(I)<0 THEN 1490\n1410  PRINT \" - AMMUNITION\";\n1420  INPUT B(I)\n1430  LET N=2\n1440  IF B(I)<0 THEN 1490\n1450  PRINT\n1460  IF F(I)+H(I)+B(I) <= D(I) THEN 1510\n1470  PRINT \"THINK AGAIN! YOU HAVE ONLY $\"D(I)\n1480  GOTO 1270\n1490  PRINT \"NEGATIVE VALUES NOT ALLOWED.\"\n1500  ON N GOTO 1370,1410\n1510  IF B$ <> \"YES\" THEN 1550\n1520  IF I=2 THEN 1550\n1530  PRINT \"UNION GENERAL---\";\n1540  NEXT I\n1550  FOR Z=1 TO D\n1560  IF B$ <> \"YES\" THEN 1620\n1570  ON Z GOTO 1580,1600\n1580  PRINT \"CONFEDERATE \";\n1590  GOTO 1620\n1600  PRINT \"      UNION \";\n1610  REM - FIND MORALE\n1620  LET O=((2*F(Z)^2+H(Z)^2)/F1^2+1)\n1630  IF O<10 THEN 1660\n1640  PRINT \"MORALE IS HIGH\"\n1650  GOTO 1700\n1660  IF O<5 THEN 1690\n1670  PRINT \"MORALE IS FAIR\"\n1680  GOTO 1700\n1690  PRINT \"MORALE IS POOR\"\n1700  IF B$ <> \"YES\" THEN 1760\n1710  LET O(Z)=O\n1720  NEXT Z\n1730  LET O2=O(2)\n1740  LET O=O(1)\n1750  PRINT \"CONFEDERATE GENERAL---\";\n1760  REM - ACTUAL OFF/DEF BATTLE SITUATION\n1770  IF M <> 3 THEN 1800\n1780  PRINT \"YOU ARE ON THE OFFENSIVE\"\n1790  GOTO 1840\n1800  IF M <> 1 THEN 1830\n1810  PRINT \"YOU ARE ON THE DEFENSIVE\"\n1820  GOTO 1840\n1830  PRINT \"BOTH SIDES ARE ON THE OFFENSIVE \"\n1840  PRINT\n1850  REM - CHOOSE STRATEGIES\n1860  IF B$ <> \"YES\" THEN 1910\n1870  FOR I=1 TO 2\n1880  ON I GOTO 1890,1920\n1890  PRINT \"CONFEDERATE STRATEGY \";\n1900  GOTO 1920\n1910  PRINT \"YOUR STRATEGY \";\n1920  INPUT Y\n1930  IF ABS(Y-3)<3 THEN 1960\n1940  PRINT \"STRATEGY\";Y;\"NOT ALLOWED.\"\n1950  GOTO 1910\n1960  IF B$=\"YES\" THEN 2000\n1970  IF Y=5 THEN 2830\n1980  GOSUB 3110\n1990  GOTO 2170\n2000  IF I=2 THEN 2040\n2010  LET Y1=Y\n2020  PRINT \"UNION STRATEGY \";\n2030  NEXT I\n2040  LET Y2=Y\n2050  LET Y=Y1\n2060  IF Y2=5 THEN 2020\n2070  REM : SIMULATED LOSSES-NORTH\n2080  LET C6=(2*C2/5)*(1+1/(2*(ABS(Y2-Y)+1)))\n2090  LET C6=C6*(1.28+(5*M2/6)/(B(2)+1))\n2100  LET C6=INT(C6*(1+1/O2)+.5)\n2110  REM - IF LOSS > MEN PRESENT, RESCALE LOSSES\n2120  LET E2=100/O2\n2130  IF INT(C6+E2)<M6 THEN 2190\n2140  LET C6=INT(13*M6/20)\n2150  LET E2=7*C6/13\n2160  LET U2=1\n2170  REM - CALCULATE SIMULATED LOSSES\n2180  PRINT\n2190  PRINT : PRINT : PRINT ,\"CONFEDERACY\",\"UNION\"\n2200  LET C5=(2*C1/5)*(1+1/(2*(ABS(Y2-Y)+1)))\n2210  LET C5=INT(C5*(1+1/O)*(1.28+F1/(B(1)+1))+.5)\n2220  LET E=100/O\n2230  IF C5+100/O<M1*(1+(P1-T1)/(M3+1)) THEN 2270\n2240  LET C5=INT(13*M1/20*(1+(P1-T1)/(M3+1)))\n2250  LET E=7*C5/13\n2260  LET U=1\n2270  IF D=1 THEN 2500\n2280  PRINT \"CASUALTIES\",C5,C6\n2290  PRINT \"DESERTIONS\",INT(E),INT(E2)\n2300  PRINT\n2310  IF B$ <> \"YES\" THEN 2530\n2320  PRINT \"COMPARED TO THE ACTUAL CASUALTIES AT \"C$\n2330  PRINT \"CONFEDERATE:\"INT(100*(C5/C1)+.5)\"% OF THE ORIGINAL\"\n2340  PRINT \"UNION:      \"INT(100*(C6/C2)+.5)\"% OF THE ORIGINAL\"\n2350  PRINT\n2360  REM - 1 WHO WON\n2370  IF U <> 1 THEN 2380\n2375  IF U2=1 THEN 2460\n2380  IF U=1 THEN 2420\n2390  IF U2=1 THEN 2440\n2400  IF C5+E=C6+E2 THEN 2460\n2410  IF C5+E<C6+E2 THEN 2440\n2420  PRINT \"THE UNION WINS \"C$\n2430  GOTO 2600\n2440  PRINT \"THE CONFEDERACY WINS \"C$\n2450  GOTO 2660\n2460  PRINT \"BATTLE OUTCOME UNRESOLVED\"\n2470  LET W0=W0+1\n2480  IF A=0 THEN 2790\n2490  GOTO 2680\n2500  LET C6=INT(17*C2*C1/(C5*20))\n2510  LET E2=5*O\n2520  GOTO 2280\n2530  PRINT \"YOUR CASUALTIES WERE \"INT(100*(C5/C1)+.5)\"% OF \"\n2540  PRINT \"THE ACTUAL CASUALTIES AT \";C$\n2550  PRINT\n2560  REM - FIND WHO WON\n2570  IF U=1 THEN 2590\n2580  IF C5+E<17*C2*C1/(C5*20)+5*O THEN 2630\n2590  PRINT \"YOU LOSE \";C$\n2600  IF A=0 THEN 2790\n2610  LET L=L+1\n2620  GOTO 2680\n2630  PRINT \"YOU WIN \";C$\n2640  REM - CUMULATIVE BATTLE FACTORS WHICH ALTER HISTORICAL\n2650  REM  RESOURCES AVAILABLE.IF A REPLAY DON'T UPDATE.\n2660  IF A=0 THEN 2790\n2670  LET W=W+1\n2680  LET T1=T1+C5+E\n2690  LET T2=T2+C6+E2\n2700  LET P1=P1+C1\n2710  LET P2=P2+C2\n2720  LET Q1=Q1+(F(1)+H(1)+B(1))\n2730  LET Q2=Q2+(F(2)+H(2)+B(2))\n2740  LET R1=R1+M1*(100-I1)/20\n2750  LET R2=R2+M2*(100-I2)/20\n2760  LET M3=M3+M1\n2770  LET M4=M4+M2\n2780  GOSUB 3300\n2790  U=0:U2=0\n2800  PRINT \"---------------\"\n2810  GOTO 620\n2820  REM------FINISH OFF\n2830  PRINT \"THE CONFEDERACY HAS SURRENDERED\"\n2840  GOTO 2860\n2850  PRINT \"THE UNION HAS SURRENDERED.\"\n2860  PRINT : PRINT : PRINT : PRINT : PRINT : PRINT\n2870  PRINT \"THE CONFEDERACY \";\n2880  PRINT \"HAS WON \"W\" BATTLES AND LOST \"L\n2890  IF Y=5 THEN 2940\n2900  IF Y2=5 THEN 2920\n2910  IF W <= L THEN 2940\n2915  IF Y=5 THEN 2940\n2920  PRINT \"THE CONFEDERACY HAS WON THE WAR\"\n2930  GOTO 2950\n2940  PRINT \"THE UNION HAS WON THE WAR\"\n2950  PRINT\n2960  IF R1=0 THEN 3100\n2970  PRINT \"FOR THE \"W+L+W0\" BATTLES FOUGHT (EXCLUDING RERUNS)\"\n2980  PRINT \" \",\" \",\" \";\n2990  PRINT \"CONFEDERACY\",\" UNION\"\n3000  PRINT \"HISTORICAL LOSSES\",INT(P1+.5),INT(P2+.5)\n3010  PRINT \"SIMULATED LOSSES\",INT(T1+.5),INT(T2+.5)\n3020  PRINT\n3030  PRINT \"    % OF ORIGINAL\",INT(100*(T1/P1)+.5),INT(100*(T2/P2)+.5)\n3040  IF B$=\"YES\" THEN 3100\n3050  PRINT\n3060  PRINT \"UNION INTELLIGENCE SUGGESTS THAT THE SOUTH USED \"\n3070  PRINT \"STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES\"\n3080  PRINT S(1);S(2);S(3);S(4)\n3090  REM---------------------------------\n3100  STOP\n3110  REM - UNION STRATEGY IS COMPUTER CHOSEN\n3120  PRINT \"UNION STRATEGY IS \";\n3130  IF A <> 0 THEN 3180\n3140  INPUT Y2\n3150  IF Y2 <=0 THEN 3160\n3155  IF Y2<5 THEN 3290\n3160  PRINT \"ENTER 1 , 2 ,3 , OR 4 (USUALLY PREVIOUS UNION STRATEGY)\"\n3170  GOTO 3140\n3180  LET S0=0\n3190  LET R=100*RND(0)\n3200  FOR I=1 TO 4\n3210  LET S0=S0+S(I)\n3220  REM - IF ACTUAL STRATEGY INFO IS IN PROGRAM DATA STATEMENTS\n3230  REM   THEN R-100 IS EXTRA WEIGHT GIVEN TO THAT STATEGY.\n3240  IF R<S0 THEN 3270\n3250  NEXT I\n3260  REM - IF ACTUAL STRAT. IN,THEN HERE IS Y2= HIST. STRAT.\n3270  LET Y2=I\n3280  PRINT Y2\n3290  RETURN\n3300  REM LEARN  PRESENT STRATEGY, START FORGETTING OLD ONES\n3310  REM - PRESENT STRATEGY OF SOUTH GAINS 3*S, OTHERS LOSE S\n3320  REM   PROBABILITY POINTS, UNLESS A STRATEGY FALLS BELOW 5%.\n3330  LET S=3\n3340  LET S0=0\n3350  FOR I=1 TO 4\n3360  IF S(I) <= 5 THEN 3390\n3370  LET S(I)=S(I)-S\n3380  LET S0=S0+S\n3390  NEXT I\n3400  LET S(Y)=S(Y)+S0\n3410  RETURN\n3420  REM - HISTORICAL DATA...CAN ADD MORE (STRAT.,ETC) BY INSERTING\n3430  REM   DATA STATEMENTS AFTER APPRO. INFO, AND ADJUSTING READ\n3440  DATA \"BULL RUN\",18000,18500,1967,2708,1\n3450  DATA \"SHILOH\",40000.,44894.,10699,13047,3\n3460  DATA \"SEVEN DAYS\",95000.,115000.,20614,15849,3\n3470  DATA \"SECOND BULL RUN\",54000.,63000.,10000,14000,2\n3480  DATA \"ANTIETAM\",40000.,50000.,10000,12000,3\n3490  DATA \"FREDERICKSBURG\",75000.,120000.,5377,12653,1\n3500  DATA \"MURFREESBORO\",38000.,45000.,11000,12000,1\n3510  DATA \"CHANCELLORSVILLE\",32000,90000.,13000,17197,2\n3520  DATA \"VICKSBURG\",50000.,70000.,12000,19000,1\n3530  DATA \"GETTYSBURG\",72500.,85000.,20000,23000,3\n3540  DATA \"CHICKAMAUGA\",66000.,60000.,18000,16000,2\n3550  DATA \"CHATTANOOGA\",37000.,60000.,36700.,5800,2\n3560  DATA \"SPOTSYLVANIA\",62000.,110000.,17723,18000,2\n3570  DATA \"ATLANTA\",65000.,100000.,8500,3700,1\n3580  PRINT \"JULY 21, 1861.  GEN. BEAUREGARD, COMMANDING THE SOUTH, MET\"\n3590  PRINT \"UNION FORCES WITH GEN. MCDOWELL IN A PREMATURE BATTLE AT\"\n3600  PRINT \"BULL RUN. GEN. JACKSON HELPED PUSH BACK THE UNION ATTACK.\"\n3610  GOTO 1150\n3620  PRINT \"APRIL 6-7, 1862.  THE CONFEDERATE SURPRISE ATTACK AT\"\n3630  PRINT \"SHILOH FAILED DUE TO POOR ORGANIZATION.\"\n3640  GOTO 1150\n3650  PRINT \"JUNE 25-JULY 1, 1862.  GENERAL LEE (CSA) UPHELD THE\"\n3660  PRINT \"OFFENSIVE THROUGHOUT THE BATTLE AND FORCED GEN. MCCLELLAN\"\n3670  PRINT \"AND THE UNION FORCES AWAY FROM RICHMOND.\"\n3680  GOTO 1150\n3690  PRINT \"AUG 29-30, 1862.  THE COMBINED CONFEDERATE FORCES UNDER\";\n3695  PRINT \" LEE\"\n3700  PRINT \"AND JACKSON DROVE THE UNION FORCES BACK INTO WASHINGTON.\"\n3710  GOTO 1150\n3720  PRINT \"SEPT 17, 1862.  THE SOUTH FAILED TO INCORPORATE MARYLAND\"\n3730  PRINT \"INTO THE CONFEDERACY.\"\n3740  GOTO 1150\n3750  PRINT \"DEC 13, 1862.  THE CONFEDERACY UNDER LEE SUCCESSFULLY\"\n3760  PRINT \"REPULSED AN ATTACK BY THE UNION UNDER GEN. BURNSIDE.\"\n3770  GOTO 1150\n3780  PRINT \"DEC 31, 1862.  THE SOUTH UNDER GEN. BRAGG WON A CLOSE \";\n3785  PRINT \"BATTLE.\"\n3790  GOTO 1150\n3800  PRINT \"MAY 1-6, 1863.  THE SOUTH HAD A COSTLY VICTORY AND LOST\"\n3810  PRINT \"ONE OF THEIR OUTSTANDING GENERALS, 'STONEWALL' JACKSON.\"\n3820  GOTO 1150\n3830  PRINT \"JULY 4, 1863.  VICKSBURG WAS A COSTLY DEFEAT FOR THE SOUTH\"\n3840  PRINT \"BECAUSE IT GAVE THE UNION ACCESS TO THE MISSISSIPPI.\"\n3850  GOTO 1150\n3860  PRINT \"JULY 1-3, 1863.  A SOUTHERN MISTAKE BY GEN. LEE AT \";\n3865  PRINT \"GETTYSBURG\"\n3870  PRINT \"COST THEM ONE OF THE MOST CRUCIAL BATTLES OF THE WAR.\"\n3880  GOTO 1150\n3890  PRINT \"SEPT. 15, 1863. CONFUSION IN A FOREST NEAR CHICKAMAUGA LED\"\n3900  PRINT \"TO A COSTLY SOUTHERN VICTORY.\"\n3910  GOTO 1150\n3920  PRINT \"NOV. 25, 1863. AFTER THE SOUTH HAD SIEGED GEN. ROSENCRANS'\"\n3930  PRINT \"ARMY FOR THREE MONTHS, GEN. GRANT BROKE THE SIEGE.\"\n3940  GOTO 1150\n3950  PRINT \"MAY 5, 1864.  GRANT'S PLAN TO KEEP LEE ISOLATED BEGAN TO\"\n3960  PRINT \"FAIL HERE, AND CONTINUED AT COLD HARBOR AND PETERSBURG.\"\n3970  GOTO 1150\n3980  PRINT \"AUGUST, 1864.  SHERMAN AND THREE VETERAN ARMIES CONVERGED\"\n3990  PRINT \"ON ATLANTA AND DEALT THE DEATH BLOW TO THE CONFEDERACY.\"\n4000  GOTO 1150\n4010  END\n"
  },
  {
    "path": "27_Civil_War/csharp/Army.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace CivilWar\n{\n    public class Army\n    {\n        private enum Resource\n        {\n            Food,\n            Salaries,\n            Ammunition\n        }\n\n        public Army(Side side)\n        {\n            Side = side;\n        }\n\n        public Side Side { get; }\n\n        // Cumulative\n        public int Wins { get; private set; } // W, L\n        public int Losses { get; private set; } // L, W\n        public int Draws { get; private set; } // W0\n        public int BattlesFought => Wins + Draws + Losses;\n        public bool Surrendered { get; private set; } // Y, Y2 == 5\n\n        public int CumulativeHistoricCasualties { get; private set; } // P1, P2\n        public int CumulativeSimulatedCasualties { get; private set; } // T1, T2\n        public int CumulativeHistoricMen { get; private set; } // M3, M4\n\n        private int income; // R1, R2\n        private int moneySpent; // Q1, Q2\n\n        private bool IsFirstBattle => income == 0;\n\n        // This battle\n        private int historicMen; // M1, M2\n        public int HistoricCasualties { get; private set; }\n\n        public int Money { get; private set; } // D(n)\n        public int Men { get; private set; } // M5, M6\n        public int Inflation { get; private set; } // I1, I2\n        public int InflationDisplay => Side == Side.Confederate ? Inflation + 15 : Inflation; // Confederate inflation is shown with 15 added - no idea why!\n\n        private readonly Dictionary<Resource, int> allocations = new(); // F(n), H(n), B(n) for food, salaries, ammunition\n\n        public int Strategy { get; protected set; } // Y1, Y2\n\n        public double Morale => (2.0 * allocations[Resource.Food] * allocations[Resource.Food] + allocations[Resource.Salaries] * allocations[Resource.Salaries]) / (reducedAvailableMen * reducedAvailableMen + 1); // O, O2\n\n        public int Casualties { get; protected set; } // C5, C6\n        public int Desertions { get; protected set; } // E, E2\n        public int MenLost => Casualties + Desertions;\n        public bool AllLost { get; private set; } // U, U2\n\n        private double reducedAvailableMen; // F1\n\n        protected virtual double FractionUnspent => (income - moneySpent) / (income + 1.0);\n\n        public void PrepareBattle(int men, int casualties)\n        {\n            historicMen = men;\n            HistoricCasualties = casualties;\n            Inflation = 10 + (Losses - Wins) * 2;\n            Money = 100 * (int)(men * (100 - Inflation) / 2000.0 * (1 + FractionUnspent) + 0.5);\n            Men = (int)(men * 1 + (CumulativeHistoricCasualties - CumulativeSimulatedCasualties) / (CumulativeHistoricMen + 1.0));\n            reducedAvailableMen = men * 5.0 / 6.0;\n        }\n\n        public virtual void AllocateResources()\n        {\n            Console.WriteLine($\"{Side} General ---\\nHow much do you wish to spend for\");\n            while (true)\n            {\n                foreach (Resource resource in Enum.GetValues<Resource>())\n                {\n                    if (EnterResource(resource))\n                        break;\n                }\n                if (allocations.Values.Sum() <= Money)\n                    return;\n                Console.WriteLine($\"Think again! You have only ${Money}\");\n            }\n        }\n\n        private bool EnterResource(Resource resource)\n        {\n            while (true)\n            {\n                Console.WriteLine($\" - {resource}\");\n                switch ((int.TryParse(Console.ReadLine(), out int val), val))\n                {\n                    case (false, _):\n                        Console.WriteLine(\"Not a valid number\");\n                        break;\n                    case (_, < 0):\n                        Console.WriteLine(\"Negative values not allowed\");\n                        break;\n                    case (_, 0) when IsFirstBattle:\n                        Console.WriteLine(\"No previous entries\");\n                        break;\n                    case (_, 0):\n                        Console.WriteLine(\"Assume you want to keep same allocations\");\n                        return true;\n                    case (_, > 0):\n                        allocations[resource] = val;\n                        return false;\n                }\n            }\n        }\n\n        public virtual void DisplayMorale()\n        {\n            Console.WriteLine($\"{Side} morale is {Morale switch { < 5 => \"Poor\", < 10 => \"Fair\", _ => \"High\" }}\");\n        }\n\n        public virtual bool ChooseStrategy(bool isReplay) => EnterStrategy(true, \"(1-5)\");\n\n        protected bool EnterStrategy(bool canSurrender, string hint)\n        {\n            Console.WriteLine($\"{Side} strategy {hint}\");\n            while (true)\n            {\n                switch ((int.TryParse(Console.ReadLine(), out int val), val))\n                {\n                    case (false, _):\n                        Console.WriteLine(\"Not a valid number\");\n                        break;\n                    case (_, 5) when canSurrender:\n                        Surrendered = true;\n                        Console.WriteLine($\"The {Side} general has surrendered\");\n                        return true;\n                    case (_, < 1 or >= 5):\n                        Console.WriteLine($\"Strategy {val} not allowed.\");\n                        break;\n                    default:\n                        Strategy = val;\n                        return false;\n                }\n            }\n        }\n\n        public virtual void CalculateLosses(Army opponent)\n        {\n            AllLost = false;\n            int stratFactor = 2 * (Math.Abs(Strategy - opponent.Strategy) + 1);\n            Casualties = (int)Math.Round(HistoricCasualties * 0.4 * (1 + 1.0 / stratFactor) * (1 + 1 / Morale) * (1.28 + reducedAvailableMen / (allocations[Resource.Ammunition] + 1)));\n            Desertions = (int)Math.Round(100 / Morale);\n\n            // If losses > men present, rescale losses\n            if (MenLost > Men)\n            {\n                Casualties = 13 * Men / 20;\n                Desertions = Men - Casualties;\n                AllLost = true;\n            }\n        }\n\n        public void RecordResult(Side winner)\n        {\n            if (winner == Side)\n                Wins++;\n            else if (winner == Side.Both)\n                Draws++;\n            else\n                Losses++;\n\n            CumulativeSimulatedCasualties += MenLost;\n            CumulativeHistoricCasualties += HistoricCasualties;\n            moneySpent += allocations.Values.Sum();\n            income += historicMen * (100 - Inflation) / 20;\n            CumulativeHistoricMen += historicMen;\n\n            LearnStrategy();\n        }\n\n        protected virtual void LearnStrategy() { }\n\n        public void DisplayWarResult(Army opponent)\n        {\n            Console.WriteLine(\"\\n\\n\\n\\n\");\n            Console.WriteLine($\"The {Side} general has won {Wins} battles and lost {Losses}\");\n            Side winner = (Surrendered, opponent.Surrendered, Wins < Losses) switch\n            {\n                (_, true, _) => Side,\n                (true, _, _) or (_, _, true) => opponent.Side,\n                _ => Side\n            };\n            Console.WriteLine($\"The {winner} general has won the war\\n\");\n        }\n\n        public virtual void DisplayStrategies() { }\n    }\n\n    class ComputerArmy : Army\n    {\n        public int[] StrategyProb { get; } = { 25, 25, 25, 25 }; // S(n)\n        private readonly Random strategyRng = new();\n\n        public ComputerArmy(Side side) : base(side) { }\n\n        protected override double FractionUnspent => 0.0;\n\n        public override void AllocateResources() { }\n\n        public override void DisplayMorale() { }\n\n        public override bool ChooseStrategy(bool isReplay)\n        {\n            if (isReplay)\n                return EnterStrategy(false, $\"(1-4; usually previous {Side} strategy)\");\n\n            // Basic code comments say \"If actual strategy info is in  data then r-100 is extra weight given to that strategy\" but there's no data or code to do it.\n            int strategyChosenProb = strategyRng.Next(100); // 0-99\n            int sumProbs = 0;\n            for (int i = 0; i < 4; i++)\n            {\n                sumProbs += StrategyProb[i];\n                if (strategyChosenProb < sumProbs)\n                {\n                    Strategy = i + 1;\n                    break;\n                }\n            }\n            Console.WriteLine($\"{Side} strategy is {Strategy}\");\n            return false;\n        }\n\n        protected override void LearnStrategy()\n        {\n            // Learn  present strategy, start forgetting old ones\n            // - present strategy gains 3 * s, others lose s probability points, unless a strategy falls below 5 %.\n            const int s = 3;\n            int presentGain = 0;\n            for (int i = 0; i < 4; i++)\n            {\n                if (StrategyProb[i] >= 5)\n                {\n                    StrategyProb[i] -= s;\n                    presentGain += s;\n                }\n            }\n            StrategyProb[Strategy - 1] += presentGain;\n        }\n\n        public override void CalculateLosses(Army opponent)\n        {\n            Casualties = (int)(17.0 * HistoricCasualties * opponent.HistoricCasualties / (opponent.Casualties * 20));\n            Desertions = (int)(5 * opponent.Morale);\n        }\n\n        public override void DisplayStrategies()\n        {\n            ConsoleUtils.WriteWordWrap($\"\\nIntelligence suggests that the {Side} general used strategies 1, 2, 3, 4 in the following percentages:\");\n            Console.WriteLine(string.Join(\", \", StrategyProb));\n        }\n    }\n}\n"
  },
  {
    "path": "27_Civil_War/csharp/Battle.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace CivilWar\n{\n    public enum Side { Confederate, Union, Both }\n    public enum Option { Battle, Replay, Quit }\n\n    public record Battle(string Name, int[] Men, int[] Casualties, Side Offensive, string Description)\n    {\n        public static readonly List<Battle> Historic = new()\n        {\n            new(\"Bull Run\", new[] { 18000, 18500 }, new[] { 1967, 2708 }, Side.Union, \"July 21, 1861.  Gen. Beauregard, commanding the south, met Union forces with Gen. McDowell in a premature battle at Bull Run. Gen. Jackson helped push back the union attack.\"),\n            new(\"Shiloh\", new[] { 40000, 44894 }, new[] { 10699, 13047 }, Side.Both, \"April 6-7, 1862.  The confederate surprise attack at Shiloh failed due to poor organization.\"),\n            new(\"Seven Days\", new[] { 95000, 115000 }, new[] { 20614, 15849 }, Side.Both, \"June 25-july 1, 1862.  General Lee (csa) upheld the offensive throughout the battle and forced Gen. McClellan and the union forces away from Richmond.\"),\n            new(\"Second Bull Run\", new[] { 54000, 63000 }, new[] { 10000, 14000 }, Side.Confederate, \"Aug 29-30, 1862.  The combined confederate forces under Lee and Jackson drove the union forces back into Washington.\"),\n            new(\"Antietam\", new[] { 40000, 50000 }, new[] { 10000, 12000 }, Side.Both, \"Sept 17, 1862.  The south failed to incorporate Maryland into the confederacy.\"),\n            new(\"Fredericksburg\", new[] { 75000, 120000 }, new[] { 5377, 12653 }, Side.Union, \"Dec 13, 1862.  The confederacy under Lee successfully repulsed an attack by the union under Gen. Burnside.\"),\n            new(\"Murfreesboro\", new[] { 38000, 45000 }, new[] { 11000, 12000 }, Side.Union, \"Dec 31, 1862.  The south under Gen. Bragg won a close battle.\"),\n            new(\"Chancellorsville\", new[] { 32000, 90000 }, new[] { 13000, 17197 }, Side.Confederate, \"May 1-6, 1863.  The south had a costly victory and lost one of their outstanding generals, 'stonewall' Jackson.\"),\n            new(\"Vicksburg\", new[] { 50000, 70000 }, new[] { 12000, 19000 }, Side.Union, \"July 4, 1863.  Vicksburg was a costly defeat for the south because it gave the union access to the Mississippi.\"),\n            new(\"Gettysburg\", new[] { 72500, 85000 }, new[] { 20000, 23000 }, Side.Both, \"July 1-3, 1863.  A southern mistake by Gen. Lee at Gettysburg cost them one of the most crucial battles of the war.\"),\n            new(\"Chickamauga\", new[] { 66000, 60000 }, new[] { 18000, 16000 }, Side.Confederate, \"Sept. 15, 1863. Confusion in a forest near Chickamauga led to a costly southern victory.\"),\n            new(\"Chattanooga\", new[] { 37000, 60000 }, new[] { 36700, 5800 }, Side.Confederate, \"Nov. 25, 1863. After the south had sieged Gen. Rosencrans’ army for three months, Gen. Grant broke the siege.\"),\n            new(\"Spotsylvania\", new[] { 62000, 110000 }, new[] { 17723, 18000 }, Side.Confederate, \"May 5, 1864.  Grant's plan to keep Lee isolated began to fail here, and continued at Cold Harbor and Petersburg.\"),\n            new(\"Atlanta\", new[] { 65000, 100000 }, new[] { 8500, 3700 }, Side.Union, \"August, 1864.  Sherman and three veteran armies converged on Atlanta and dealt the death blow to the confederacy.\"),\n        };\n\n        public static (Option, Battle?) SelectBattle()\n        {\n            Console.WriteLine(\"\\n\\n\\nWhich battle do you wish to simulate?\");\n            return int.Parse(Console.ReadLine() ?? \"\") switch\n            {\n                0 => (Option.Replay, null),\n                >0 and <15 and int n  => (Option.Battle, Historic[n-1]),\n                _ => (Option.Quit, null)\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "27_Civil_War/csharp/CivilWar.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "27_Civil_War/csharp/CivilWar.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31005.135\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"CivilWar\", \"CivilWar.csproj\", \"{4EE5EFE7-2D60-464A-9F8D-4BBD2A14AAC7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4EE5EFE7-2D60-464A-9F8D-4BBD2A14AAC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4EE5EFE7-2D60-464A-9F8D-4BBD2A14AAC7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4EE5EFE7-2D60-464A-9F8D-4BBD2A14AAC7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4EE5EFE7-2D60-464A-9F8D-4BBD2A14AAC7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {59BCA2DE-D5C7-40F7-BB99-B5C8D2416D8B}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "27_Civil_War/csharp/ConsoleUtils.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\n\nnamespace CivilWar\n{\n    static class ConsoleUtils\n    {\n        public static bool InputYesOrNo()\n        {\n            while (true)\n            {\n                var answer = Console.ReadLine();\n                switch (answer?.ToLower())\n                {\n                    case \"no\":\n                        return false;\n                    case \"yes\":\n                        return true;\n                    default:\n                        Console.WriteLine(\"(Answer Yes or No)\");\n                        break;\n                }\n            }\n        }\n\n        public static void WriteWordWrap(string text)\n        {\n            var line = new StringBuilder(Console.WindowWidth);\n            foreach (var paragraph in text.Split(Environment.NewLine))\n            {\n                line.Clear();\n                foreach (var word in paragraph.Split(' '))\n                {\n                    if (line.Length + word.Length < Console.WindowWidth)\n                    {\n                        if (line.Length > 0)\n                            line.Append(' ');\n                        line.Append(word);\n                    }\n                    else\n                    {\n                        Console.WriteLine(line.ToString());\n                        line.Clear().Append(word);\n                    }\n                }\n                Console.WriteLine(line.ToString());\n            }\n        }\n\n        public static void WriteTable<T>(ICollection<T> items, List<TableRow<T>> rows, bool transpose = false)\n        {\n            int cols = items.Count + 1;\n            var content = rows.Select(r => r.Format(items)).ToList();\n            if (transpose)\n            {\n                content = Enumerable.Range(0, cols).Select(col => content.Select(r => r[col]).ToArray()).ToList();\n                cols = rows.Count;\n            }\n            var colWidths = Enumerable.Range(0, cols).Select(col => content.Max(c => c[col].Length)).ToArray();\n\n            foreach (var row in content)\n            {\n                for (int col = 0; col < cols; col++)\n                {\n                    var space = new string(' ', colWidths[col] - row[col].Length);\n                    row[col] = col == 0 ? row[col] + space : space + row[col]; // left-align first col; right-align other cols\n                }\n            }\n\n            var sb = new StringBuilder();\n            var horizBars = colWidths.Select(w => new string('═', w)).ToArray();\n\n            void OneRow(string[] cells, char before, char between, char after)\n            {\n                sb.Append(before);\n                sb.AppendJoin(between, cells);\n                sb.Append(after);\n                sb.AppendLine();\n            }\n\n            OneRow(horizBars, '╔', '╦', '╗');\n            bool first = true;\n            foreach (var row in content)\n            {\n                if (first)\n                    first = false;\n                else\n                    OneRow(horizBars, '╠', '╬', '╣');\n                OneRow(row, '║', '║', '║');\n            }\n            OneRow(horizBars, '╚', '╩', '╝');\n\n            Console.WriteLine(sb.ToString());\n        }\n\n        public record TableRow<T>(string Name, Func<T, object> Data, string Before = \"\", string After = \"\")\n        {\n            private string FormatItem(T item) => $\" {Before}{Data(item)}{After} \";\n\n            public string[] Format(IEnumerable<T> items) => items.Select(FormatItem).Prepend($\" {Name} \").ToArray();\n        }\n    }\n}\n"
  },
  {
    "path": "27_Civil_War/csharp/GameOptions.cs",
    "content": "﻿using System;\n\nusing static CivilWar.ConsoleUtils;\n\nnamespace CivilWar\n{\n    public record GameOptions(bool TwoPlayers, bool ShowDescriptions)\n    {\n        public static GameOptions Input()\n        {\n            Console.WriteLine(\n@\"                          Civil War\n               Creative Computing, Morristown, New Jersey\n\n\nDo you want instructions?\");\n\n            const string instructions = @\"This is a civil war simulation.\nTo play type a response when the computer asks.\nRemember that all factors are interrelated and that your responses could change history. Facts and figures used are based on the actual occurrence. Most battles tend to result as they did in the civil war, but it all depends on you!!\n\nThe object of the game is to win as many battles as possible.\n\nYour choices for defensive strategy are:\n        (1) artillery attack\n        (2) fortification against frontal attack\n        (3) fortification against flanking maneuvers\n        (4) falling back\nYour choices for offensive strategy are:\n        (1) artillery attack\n        (2) frontal attack\n        (3) flanking maneuvers\n        (4) encirclement\nYou may surrender by typing a '5' for your strategy.\";\n\n            if (InputYesOrNo())\n                WriteWordWrap(instructions);\n\n            Console.WriteLine(\"\\n\\nAre there two generals present?\");\n            bool twoPlayers = InputYesOrNo();\n            if (!twoPlayers)\n                Console.WriteLine(\"\\nYou are the confederacy.  Good luck!\\n\");\n\n            WriteWordWrap(\n            @\"Select a battle by typing a number from 1 to 14 on request.  Type any other number to end the simulation. But '0' brings back exact previous battle situation allowing you to replay it.\n\nNote: a negative Food$ entry causes the program to use the entries from the previous battle\n\nAfter requesting a battle, do you wish battle descriptions (answer yes or no)\");\n            bool showDescriptions = InputYesOrNo();\n\n            return new GameOptions(twoPlayers, showDescriptions);\n        }\n    }\n}\n"
  },
  {
    "path": "27_Civil_War/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing CivilWar;\n\nvar options = GameOptions.Input();\nvar armies = new List<Army> { new Army(Side.Confederate), options.TwoPlayers ? new Army(Side.Union) : new ComputerArmy(Side.Union) };\n\nBattle? battle = null;\nwhile (OneBattle(ref battle)) { }\nDisplayResult();\n\nbool OneBattle(ref Battle? previous)\n{\n    var (option, selected) = Battle.SelectBattle();\n    var (battle, isReplay, quit) = option switch\n    {\n        Option.Battle => (selected!, false, false),\n        Option.Replay when previous != null => (previous, true, false), // can't replay if no previous battle\n        _ => (null!, false, true),\n    };\n    if (quit)\n        return false;\n\n    if (!isReplay)\n    {\n        Console.WriteLine($\"This is the battle of {battle.Name}.\");\n        if (options.ShowDescriptions)\n            ConsoleUtils.WriteWordWrap(battle.Description);\n        armies.ForEach(a => a.PrepareBattle(battle.Men[(int)a.Side], battle.Casualties[(int)a.Side]));\n    }\n\n    ConsoleUtils.WriteTable(armies, new()\n    {\n        new(\"\", a => a.Side),\n        new(\"Men\", a => a.Men),\n        new(\"Money\", a => a.Money, Before: \"$\"),\n        new(\"Inflation\", a => a.InflationDisplay, After: \"%\")\n    });\n\n    armies.ForEach(a => a.AllocateResources());\n    armies.ForEach(a => a.DisplayMorale());\n\n    string offensive = battle.Offensive switch\n    {\n        Side.Confederate => \"You are on the offensive\",\n        Side.Union => \"You are on the defensive\",\n        _ => \"Both sides are on the offensive\"\n    };\n    Console.WriteLine($\"Confederate general---{offensive}\");\n\n    if (armies.Any(a => a.ChooseStrategy(isReplay)))\n    {\n        return false; // someone surrendered\n    }\n    armies[0].CalculateLosses(armies[1]);\n    armies[1].CalculateLosses(armies[0]);\n\n    ConsoleUtils.WriteTable(armies, new()\n    {\n        new(\"\", a => a.Side),\n        new(\"Casualties\", a => a.Casualties),\n        new(\"Desertions\", a => a.Desertions),\n    });\n    if (options.TwoPlayers)\n    {\n        var oneDataCol = new[] { 1 };\n        Console.WriteLine($\"Compared to the actual casualties at {battle.Name}\");\n        ConsoleUtils.WriteTable(oneDataCol, armies.Select(a => new ConsoleUtils.TableRow<int>(\n            a.Side.ToString(),\n            _ => $\"{(double)a.Casualties / battle.Casualties[(int)a.Side]}\", After: \"% of the original\")\n        ).ToList());\n    }\n\n    Side winner;\n    switch (armies[0].AllLost, armies[1].AllLost, armies[0].MenLost - armies[1].MenLost)\n    {\n        case (true, true, _) or (false, false, 0):\n            Console.WriteLine(\"Battle outcome unresolved\");\n            winner = Side.Both; // Draw\n            break;\n        case (false, true, _) or (false, false, < 0):\n            Console.WriteLine($\"The Confederacy wins {battle.Name}\");\n            winner = Side.Confederate;\n            break;\n        case (true, false, _) or (false, false, > 0):\n            Console.WriteLine($\"The Union wins {battle.Name}\");\n            winner = Side.Union;\n            break;\n    }\n    if (!isReplay)\n    {\n        armies.ForEach(a => a.RecordResult(winner));\n    }\n    Console.WriteLine(\"---------------\");\n    previous = battle;\n    return true;\n}\n\nvoid DisplayResult()\n{\n    armies[0].DisplayWarResult(armies[1]);\n\n    int battles = armies[0].BattlesFought;\n    if (battles > 0)\n    {\n        Console.WriteLine($\"For the {battles} battles fought (excluding reruns)\");\n\n        ConsoleUtils.WriteTable(armies, new()\n        {\n            new(\"\", a => a.Side),\n            new(\"Historical Losses\", a => a.CumulativeHistoricCasualties),\n            new(\"Simulated Losses\", a => a.CumulativeSimulatedCasualties),\n            new(\"  % of original\", a => ((double)a.CumulativeSimulatedCasualties / a.CumulativeHistoricCasualties).ToString(\"p2\"))\n        }, transpose: true);\n\n        armies[1].DisplayStrategies();\n    }\n}\n"
  },
  {
    "path": "27_Civil_War/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "27_Civil_War/java/.gitignore",
    "content": "*.class\n*.iml\n.idea/\n"
  },
  {
    "path": "27_Civil_War/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "27_Civil_War/java/src/CivilWar.java",
    "content": "import java.io.PrintStream;\nimport java.util.InputMismatchException;\nimport java.util.List;\nimport java.util.Scanner;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\nimport static java.util.stream.Collectors.joining;\nimport static java.util.stream.IntStream.range;\n\n@SuppressWarnings(\"SpellCheckingInspection\")\npublic class CivilWar {\n\n    private final PrintStream out;\n    private final List<HistoricalDatum> data;\n\n    private final BattleResults results;\n\n    private BattleState currentBattle;\n    private int numGenerals;\n    private int battleNumber;\n    private boolean wantBattleDescriptions;\n    private final int[] strategies;\n\n    private int confedStrategy;\n    private int unionStrategy;\n\n    private final ArmyPair<ArmyResources> resources;\n    private final ArmyPair<Integer> totalExpectedCasualties;\n    private final ArmyPair<Integer> totalCasualties;\n    private final ArmyPair<Integer> revenue;\n    private final ArmyPair<Integer> inflation;\n    private final ArmyPair<Integer> totalExpenditure;\n    private final ArmyPair<Integer> totalTroops;\n\n    private boolean excessiveConfederateLosses;\n    private boolean excessiveUnionLosses;\n\n    private boolean confedSurrender;\n    private boolean unionSurrender;\n\n    private final static String YES_NO_REMINDER = \"(ANSWER YES OR NO)\";\n    private final static Predicate<String> YES_NO_CHECKER = i -> isYes(i) || isNo(i);\n\n    /**\n     * ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S.\n     * MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973\n     */\n    public static void main(String[] args) {\n        var x = new CivilWar(System.out);\n        x.showCredits();\n\n        // LET D=RND(-1) ???\n\n        System.out.print(\"DO YOU WANT INSTRUCTIONS? \");\n\n        if (isYes(inputString(YES_NO_CHECKER, YES_NO_REMINDER))) {\n            x.showHelp();\n        }\n\n        x.gameLoop();\n    }\n\n    private void gameLoop() {\n        out.println();\n        out.println();\n        out.println();\n        out.print(\"ARE THERE TWO GENERALS PRESENT (ANSWER YES OR NO)? \");\n\n        if (isYes(inputString(YES_NO_CHECKER, YES_NO_REMINDER))) {\n            this.numGenerals = 2;\n        } else {\n            this.numGenerals = 1;\n            out.println();\n            out.println(\"YOU ARE THE CONFEDERACY.   GOOD LUCK!\");\n            out.println();\n        }\n\n        out.println(\"SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON\");\n        out.println(\"REQUEST.  TYPE ANY OTHER NUMBER TO END THE SIMULATION.\");\n        out.println(\"BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION\");\n        out.println(\"ALLOWING YOU TO REPLAY IT\");\n        out.println();\n        out.println(\"NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO \");\n        out.println(\"USE THE ENTRIES FROM THE PREVIOUS BATTLE\");\n        out.println();\n\n        out.print(\"AFTER REQUESTING A BATTLE, DO YOU WISH BATTLE DESCRIPTIONS (ANSWER YES OR NO)? \");\n\n        this.wantBattleDescriptions = isYes(inputString(YES_NO_CHECKER, YES_NO_REMINDER));\n\n        while (true) {\n            var battle = startBattle();\n            if (battle == null) {\n                break;\n            }\n\n            this.currentBattle = battle;\n\n            offensiveLogic(battle.data);\n\n            calcLosses(battle);\n\n            reset();\n\n            if (this.confedSurrender) {\n                out.println(\"THE CONFEDERACY HAS SURRENDERED\");\n            } else if (unionSurrender) {  // FIXME Is this actually possible? 2850\n                out.println(\"THE UNION HAS SURRENDERED.\");\n            }\n        }\n\n        complete();\n    }\n\n    private BattleState startBattle() {\n        out.println();\n        out.println();\n        out.println();\n        out.print(\"WHICH BATTLE DO YOU WISH TO SIMULATE ? \");\n\n        var battleNumber = inputInt(i -> i >= 1 || (i == 0 && this.currentBattle != null), i -> \"BATTLE \" + i + \" NOT ALLOWED.\");\n\n        if (battleNumber == 0) {\n            out.println(this.currentBattle.data.name + \" INSTANT REPLAY\");\n            return this.currentBattle;\n        }\n\n        if (battleNumber > this.data.size()) {  // TYPE ANY OTHER NUMBER TO END THE SIMULATION\n            return null;\n        }\n\n        this.battleNumber = battleNumber;\n\n        var battle = this.data.get(this.battleNumber - 1);\n        var battleState = new BattleState(battle);\n\n\n        excessiveConfederateLosses = false;\n\n        // INFLATION CALC\n        // REM - ONLY IN PRINTOUT IS CONFED INFLATION = I1+15%\n        inflation.confederate = 10 + (results.union - results.confederate) * 2;\n        inflation.union = 10 + (results.confederate - results.union) * 2;\n\n        // MONEY AVAILABLE\n        resources.confederate.budget = 100 * (int) Math.floor((battle.troops.confederate * (100.0 - inflation.confederate) / 2000) * (1 + (revenue.confederate - totalExpenditure.confederate) / (revenue.confederate + 1.0)) + .5);\n\n        // MEN AVAILABLE\n        battleState.F1 = 5 * battle.troops.confederate / 6.0;\n\n        if (this.numGenerals == 2) {\n            resources.union.budget = 100 * (int) Math.floor((battle.troops.union * (100.0 - inflation.union) / 2000) * (1 + (revenue.union - totalExpenditure.union) / (revenue.union + 1.0)) + .5);\n        } else {\n            resources.union.budget = 100 * (int) Math.floor(battle.troops.union * (100.0 - inflation.union) / 2000 + .5);\n        }\n\n        out.println();\n        out.println();\n        out.println();\n        out.println();\n        out.println();\n        out.println(\"THIS IS THE BATTLE OF \" + battle.name);\n\n        if (this.wantBattleDescriptions) {\n            for (var eachLine : battle.blurb) {\n                out.println(eachLine);\n            }\n        }\n\n        out.println();\n        out.println(\"          CONFEDERACY     UNION\");\n        out.println(\"MEN         \" + getConfedTroops(battle) + \"          \" + getUnionTroops(battle));\n        out.println(\"MONEY     $ \" + resources.confederate.budget + \"       $ \" + resources.union.budget);\n        out.println(\"INFLATION   \" + (inflation.confederate + 15) + \"%          \" + inflation.union + \"%\");\n\n        // ONLY IN PRINTOUT IS CONFED INFLATION = I1+15%\n        // IF TWO GENERALS, INPUT CONFED. FIRST\n\n        var terminalInput = new Scanner(System.in);\n\n        for (int i = 0; i < numGenerals; i++) {\n            out.println();\n\n            ArmyResources currentResources;\n\n            if (this.numGenerals == 1 || i == 0) {\n                out.print(\"CONFEDERATE GENERAL --- \");\n                currentResources = resources.confederate;\n            } else {\n                out.print(\"UNION GENERAL --- \");\n                currentResources = resources.union;\n            }\n\n            var validInputs = false;\n            while (!validInputs) {\n                out.println(\"HOW MUCH DO YOU WISH TO SPEND FOR\");\n                out.print(\"- FOOD...... ? \");\n                var food = terminalInput.nextInt();\n                if (food == 0) {\n                    if (this.revenue.confederate != 0) {\n                        out.println(\"ASSUME YOU WANT TO KEEP SAME ALLOCATIONS\");\n                        out.println();\n                    }\n                } else {\n                    currentResources.food = food;\n                }\n\n                out.print(\"- SALARIES.. ? \");\n                currentResources.salaries = terminalInput.nextInt();\n\n                out.print(\"- AMMUNITION ? \");\n                currentResources.ammunition = terminalInput.nextInt();  // FIXME Retry if -ve\n\n                if (currentResources.getTotal() > currentResources.budget) {\n                    out.println(\"THINK AGAIN! YOU HAVE ONLY $\" + currentResources.budget);\n                } else {\n                    validInputs = true;\n                }\n            }\n        }\n\n        out.println();\n\n        // Record Morale\n        out.println(range(0, numGenerals).mapToObj(i -> moraleForArmy(battleState, i)).collect(joining(\", \")));\n\n        out.println();\n\n        return battleState;\n    }\n\n    private int getUnionTroops(HistoricalDatum battle) {\n        return (int) Math.floor(battle.troops.union * (1 + (totalExpectedCasualties.union - totalCasualties.union) / (totalTroops.union + 1.0)));\n    }\n\n    private int getConfedTroops(HistoricalDatum battle) {\n        return (int) Math.floor(battle.troops.confederate * (1 + (totalExpectedCasualties.confederate - totalCasualties.confederate) / (totalTroops.confederate + 1.0)));\n    }\n\n    private String moraleForArmy(BattleState battleState, int armyIdx) {\n        var builder = new StringBuilder();\n\n        ArmyResources currentResources;\n\n        if (this.numGenerals == 1 || armyIdx == 0) {\n            builder.append(\"CONFEDERATE \");\n            currentResources = resources.confederate;\n        } else {\n            builder.append(\"UNION \");\n            currentResources = resources.union;\n        }\n\n        // FIND MORALE\n        currentResources.morale = (2 * Math.pow(currentResources.food, 2) + Math.pow(currentResources.salaries, 2)) / Math.pow(battleState.F1, 2) + 1;\n        if (currentResources.morale >= 10) {\n            builder.append(\"MORALE IS HIGH\");\n        } else if (currentResources.morale >= 5) {\n            builder.append(\"MORALE IS FAIR\");\n        } else {\n            builder.append(\"MORALE IS POOR\");\n        }\n\n        return builder.toString();\n    }\n\n    private enum OffensiveStatus {\n        DEFENSIVE(\"YOU ARE ON THE DEFENSIVE\"), OFFENSIVE(\"YOU ARE ON THE OFFENSIVE\"), BOTH_OFFENSIVE(\"BOTH SIDES ARE ON THE OFFENSIVE\");\n\n        private final String label;\n\n        OffensiveStatus(String label) {\n            this.label = label;\n        }\n    }\n\n    private void offensiveLogic(HistoricalDatum battle) {\n        out.print(\"CONFEDERATE GENERAL---\");\n        // ACTUAL OFF/DEF BATTLE SITUATION\n        out.println(battle.offensiveStatus.label);\n\n        // CHOOSE STRATEGIES\n\n        if (numGenerals == 2) {\n            out.print(\"CONFEDERATE STRATEGY ? \");\n        } else {\n            out.print(\"YOUR STRATEGY ? \");\n        }\n\n        confedStrategy = inputInt(i -> i >= 1 && i <= 5, i -> \"STRATEGY \" + i + \" NOT ALLOWED.\");\n        if (confedStrategy == 5) {  // 1970\n            confedSurrender = true;\n        }\n\n        if (numGenerals == 2) {\n            out.print(\"UNION STRATEGY ? \");\n\n            unionStrategy = inputInt(i -> i >= 1 && i <= 5, i -> \"STRATEGY \" + i + \" NOT ALLOWED.\");\n            if (unionStrategy == 5) {  // 1970\n                unionSurrender = true;\n            }\n        } else {\n            unionStrategy();\n        }\n    }\n\n    // 2070  REM : SIMULATED LOSSES-NORTH\n    private UnionLosses simulateUnionLosses(HistoricalDatum battle) {\n        var losses = (2.0 * battle.expectedCasualties.union / 5) * (1 + 1.0 / (2 * (Math.abs(unionStrategy - confedStrategy) + 1)));\n        losses = losses * (1.28 + (5.0 * battle.troops.union / 6) / (resources.union.ammunition + 1));\n        losses = Math.floor(losses * (1 + 1 / resources.union.morale) + 0.5);\n        // IF LOSS > MEN PRESENT, RESCALE LOSSES\n        var moraleFactor = 100 / resources.union.morale;\n\n        if (Math.floor(losses + moraleFactor) >= getUnionTroops(battle)) {\n            losses = Math.floor(13.0 * getUnionTroops(battle) / 20);\n            moraleFactor = 7 * losses / 13;\n            excessiveUnionLosses = true;\n        }\n\n        return new UnionLosses((int) losses, (int) Math.floor(moraleFactor));\n    }\n\n    // 2170: CALCULATE SIMULATED LOSSES\n    private void calcLosses(BattleState battle) {\n        // 2190\n        out.println();\n        out.println(\"            CONFEDERACY    UNION\");\n\n        var C5 = (2 * battle.data.expectedCasualties.confederate / 5) * (1 + 1.0 / (2 * (Math.abs(unionStrategy - confedStrategy) + 1)));\n        C5 = (int) Math.floor(C5 * (1 + 1.0 / resources.confederate.morale) * (1.28 + battle.F1 / (resources.confederate.ammunition + 1.0)) + .5);\n        var E = 100 / resources.confederate.morale;\n\n        if (C5 + 100 / resources.confederate.morale >= battle.data.troops.confederate * (1 + (totalExpectedCasualties.confederate - totalCasualties.confederate) / (totalTroops.confederate + 1.0))) {\n            C5 = (int) Math.floor(13.0 * battle.data.troops.confederate / 20 * (1 + (totalExpectedCasualties.union - totalCasualties.confederate) / (totalTroops.confederate + 1.0)));\n            E = 7 * C5 / 13.0;\n            excessiveConfederateLosses = true;\n        }\n\n        /////  2270\n\n        final UnionLosses unionLosses;\n\n        if (this.numGenerals == 1) {\n            unionLosses = new UnionLosses((int) Math.floor(17.0 * battle.data.expectedCasualties.union * battle.data.expectedCasualties.confederate / (C5 * 20)), (int) Math.floor(5 * resources.confederate.morale));\n        } else {\n            unionLosses = simulateUnionLosses(battle.data);\n        }\n\n        out.println(\"CASUALTIES:  \" + rightAlignInt(C5) + \"        \" + rightAlignInt(unionLosses.losses));\n        out.println(\"DESERTIONS:  \" + rightAlignInt(E) + \"        \" + rightAlignInt(unionLosses.desertions));\n        out.println();\n\n        if (numGenerals == 2) {\n            out.println(\"COMPARED TO THE ACTUAL CASUALTIES AT \" + battle.data.name);\n            out.println(\"CONFEDERATE: \" + (int) Math.floor(100 * (C5 / (double) battle.data.expectedCasualties.confederate) + 0.5) + \" % OF THE ORIGINAL\");\n            out.println(\"UNION:       \" + (int) Math.floor(100 * (unionLosses.losses / (double) battle.data.expectedCasualties.union) + 0.5) + \" % OF THE ORIGINAL\");\n\n            out.println();\n\n            // REM - 1 WHO WON\n            var winner = findWinner(C5 + E, unionLosses.losses + unionLosses.desertions);\n            switch (winner) {\n                case UNION -> {\n                    out.println(\"THE UNION WINS \" + battle.data.name);\n                    results.union++;\n                }\n                case CONFED -> {\n                    out.println(\"THE CONFEDERACY WINS \" + battle.data.name);\n                    results.confederate++;\n                }\n                case INDECISIVE -> {\n                    out.println(\"BATTLE OUTCOME UNRESOLVED\");\n                    results.indeterminate++;\n                }\n            }\n        } else {\n            out.println(\"YOUR CASUALTIES WERE \" + Math.floor(100 * (C5 / (double) battle.data.expectedCasualties.confederate) + 0.5) + \"% OF THE ACTUAL CASUALTIES AT \" + battle.data.name);\n\n            // FIND WHO WON\n\n            if (excessiveConfederateLosses) {\n                out.println(\"YOU LOSE \" + battle.data.name);\n\n                if (this.battleNumber != 0) {\n                    results.union++;\n                }\n            } else {\n                out.println(\"YOU WIN \" + battle.data.name);\n                // CUMULATIVE BATTLE FACTORS WHICH ALTER HISTORICAL RESOURCES AVAILABLE.IF A REPLAY DON'T UPDATE.\n                results.confederate++;\n            }\n        }\n\n        if (this.battleNumber != 0) {\n            totalCasualties.confederate += (int) (C5 + E);\n            totalCasualties.union += unionLosses.losses + unionLosses.desertions;\n            totalExpectedCasualties.confederate += battle.data.expectedCasualties.confederate;\n            totalExpectedCasualties.union += battle.data.expectedCasualties.union;\n            totalExpenditure.confederate += resources.confederate.getTotal();\n            totalExpenditure.union += resources.union.getTotal();\n            revenue.confederate += battle.data.troops.confederate * (100 - inflation.confederate) / 20;\n            revenue.union += battle.data.troops.union * (100 - inflation.union) / 20;\n            totalTroops.confederate += battle.data.troops.confederate;\n            totalTroops.union += battle.data.troops.union;\n\n            updateStrategies(this.confedStrategy);\n        }\n    }\n\n    // 2790\n    private void reset() {\n        excessiveConfederateLosses = excessiveUnionLosses = false;\n\n        out.println(\"---------------\");\n    }\n\n    // 2820  REM------FINISH OFF\n    private void complete() {\n        out.println();\n        out.println();\n        out.println();\n        out.println();\n        out.println();\n        out.println();\n        out.println(\"THE CONFEDERACY HAS WON \" + results.confederate + \" BATTLES AND LOST \" + results.union);\n\n        if (this.unionStrategy == 5) {\n            out.println(\"THE CONFEDERACY HAS WON THE WAR\");\n        }\n\n        if (this.confedStrategy == 5 || results.confederate <= results.union) {\n            out.println(\"THE UNION HAS WON THE WAR\");\n        }\n\n        out.println();\n\n        // FIXME 2960  IF R1=0 THEN 3100\n\n        out.println(\"FOR THE \" + results.getTotal() + \" BATTLES FOUGHT (EXCLUDING RERUNS)\");\n        out.println(\"                       CONFEDERACY    UNION\");\n        out.println(\"HISTORICAL LOSSES      \" + (int) Math.floor(totalExpectedCasualties.confederate + .5) + \"          \" + (int) Math.floor(totalExpectedCasualties.union + .5));\n        out.println(\"SIMULATED LOSSES       \" + (int) Math.floor(totalCasualties.confederate + .5) + \"          \" + (int) Math.floor(totalCasualties.union + .5));\n        out.println();\n        out.println(\"    % OF ORIGINAL      \" + (int) Math.floor(100 * ((double) totalCasualties.confederate / totalExpectedCasualties.confederate) + .5) + \"             \" + (int) Math.floor(100 * ((double) totalCasualties.union / totalExpectedCasualties.union) + .5));\n\n        if (this.numGenerals == 1) {\n            out.println();\n            out.println(\"UNION INTELLIGENCE SUGGESTS THAT THE SOUTH USED \");\n            out.println(\"STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES\");\n            out.println(this.strategies[0] + \",\" + this.strategies[1] + \",\" + this.strategies[2] + \",\" + this.strategies[3]);\n        }\n    }\n\n    private Winner findWinner(double confLosses, double unionLosses) {\n        if (this.excessiveConfederateLosses && this.excessiveUnionLosses) {\n            return Winner.INDECISIVE;\n        }\n\n        if (this.excessiveConfederateLosses) {\n            return Winner.UNION;\n        }\n\n        if (this.excessiveUnionLosses || confLosses < unionLosses) {\n            return Winner.CONFED;\n        }\n\n        if (confLosses == unionLosses) {\n            return Winner.INDECISIVE;\n        }\n\n        return Winner.UNION;  // FIXME Really? 2400-2420 ?\n    }\n\n    private enum Winner {\n        CONFED, UNION, INDECISIVE\n    }\n\n    private void unionStrategy() {\n        // 3130 ... so you can only input / override Union strategy on re-run??\n        if (this.battleNumber == 0) {\n            out.print(\"UNION STRATEGY ? \");\n            var terminalInput = new Scanner(System.in);\n            unionStrategy = terminalInput.nextInt();\n            if (unionStrategy < 0) {\n                out.println(\"ENTER 1, 2, 3, OR 4 (USUALLY PREVIOUS UNION STRATEGY)\");\n                // FIXME Retry Y2 input !!!\n            }\n\n            if (unionStrategy < 5) {  // 3155\n                return;\n            }\n        }\n\n        var S0 = 0;\n        var r = 100 * Math.random();\n\n        for (unionStrategy = 1; unionStrategy <= 4; unionStrategy++) {\n            S0 += this.strategies[unionStrategy - 1];\n            // IF ACTUAL STRATEGY INFO IS IN PROGRAM DATA STATEMENTS THEN R-100 IS EXTRA WEIGHT GIVEN TO THAT STATEGY.\n            if (r < S0) {\n                break;\n            }\n        }\n        // IF ACTUAL STRAT. IN,THEN HERE IS Y2= HIST. STRAT.\n        out.println(\"UNION STRATEGY IS \" + unionStrategy);\n    }\n\n    public CivilWar(PrintStream out) {\n        this.out = out;\n\n        this.results = new BattleResults();\n\n        this.totalCasualties = new ArmyPair<>(0, 0);\n        this.totalExpectedCasualties = new ArmyPair<>(0, 0);\n        this.totalExpenditure = new ArmyPair<>(0, 0);\n        this.totalTroops = new ArmyPair<>(0, 0);\n\n        this.revenue = new ArmyPair<>(0, 0);\n        this.inflation = new ArmyPair<>(0, 0);\n\n        this.resources = new ArmyPair<>(new ArmyResources(), new ArmyResources());\n\n        // UNION INFO ON LIKELY CONFEDERATE STRATEGY\n        this.strategies = new int[]{25, 25, 25, 25};\n\n        // READ HISTORICAL DATA.\n        // HISTORICAL DATA...CAN ADD MORE (STRAT.,ETC) BY INSERTING DATA STATEMENTS AFTER APPRO. INFO, AND ADJUSTING READ\n        this.data = List.of(\n                new HistoricalDatum(\"BULL RUN\", new ArmyPair<>(18000, 18500), new ArmyPair<>(1967, 2708), OffensiveStatus.DEFENSIVE, new String[]{\"JULY 21, 1861.  GEN. BEAUREGARD, COMMANDING THE SOUTH, MET\", \"UNION FORCES WITH GEN. MCDOWELL IN A PREMATURE BATTLE AT\", \"BULL RUN. GEN. JACKSON HELPED PUSH BACK THE UNION ATTACK.\"}),\n                new HistoricalDatum(\"SHILOH\", new ArmyPair<>(40000, 44894), new ArmyPair<>(10699, 13047), OffensiveStatus.OFFENSIVE, new String[]{\"APRIL 6-7, 1862.  THE CONFEDERATE SURPRISE ATTACK AT\", \"SHILOH FAILED DUE TO POOR ORGANIZATION.\"}),\n                new HistoricalDatum(\"SEVEN DAYS\", new ArmyPair<>(95000, 115000), new ArmyPair<>(20614, 15849), OffensiveStatus.OFFENSIVE, new String[]{\"JUNE 25-JULY 1, 1862.  GENERAL LEE (CSA) UPHELD THE\", \"OFFENSIVE THROUGHOUT THE BATTLE AND FORCED GEN. MCCLELLAN\", \"AND THE UNION FORCES AWAY FROM RICHMOND.\"}),\n                new HistoricalDatum(\"SECOND BULL RUN\", new ArmyPair<>(54000, 63000), new ArmyPair<>(10000, 14000), OffensiveStatus.BOTH_OFFENSIVE, new String[]{\"AUG 29-30, 1862.  THE COMBINED CONFEDERATE FORCES UNDER\", \" LEE\", \"AND JACKSON DROVE THE UNION FORCES BACK INTO WASHINGTON.\"}),\n                new HistoricalDatum(\"ANTIETAM\", new ArmyPair<>(40000, 50000), new ArmyPair<>(10000, 12000), OffensiveStatus.OFFENSIVE, new String[]{\"SEPT 17, 1862.  THE SOUTH FAILED TO INCORPORATE MARYLAND\", \"INTO THE CONFEDERACY.\"}),\n                new HistoricalDatum(\"FREDERICKSBURG\", new ArmyPair<>(75000, 120000), new ArmyPair<>(5377, 12653), OffensiveStatus.DEFENSIVE, new String[]{\"DEC 13, 1862.  THE CONFEDERACY UNDER LEE SUCCESSFULLY\", \"REPULSED AN ATTACK BY THE UNION UNDER GEN. BURNSIDE.\"}),\n                new HistoricalDatum(\"MURFREESBORO\", new ArmyPair<>(38000, 45000), new ArmyPair<>(11000, 12000), OffensiveStatus.DEFENSIVE, new String[]{\"DEC 31, 1862.  THE SOUTH UNDER GEN. BRAGG WON A CLOSE BATTLE.\"}),\n                new HistoricalDatum(\"CHANCELLORSVILLE\", new ArmyPair<>(32000, 90000), new ArmyPair<>(13000, 17197), OffensiveStatus.BOTH_OFFENSIVE, new String[]{\"MAY 1-6, 1863.  THE SOUTH HAD A COSTLY VICTORY AND LOST\", \"ONE OF THEIR OUTSTANDING GENERALS, 'STONEWALL' JACKSON.\"}),\n                new HistoricalDatum(\"VICKSBURG\", new ArmyPair<>(50000, 70000), new ArmyPair<>(12000, 19000), OffensiveStatus.DEFENSIVE, new String[]{\"JULY 4, 1863.  VICKSBURG WAS A COSTLY DEFEAT FOR THE SOUTH\", \"BECAUSE IT GAVE THE UNION ACCESS TO THE MISSISSIPPI.\"}),\n                new HistoricalDatum(\"GETTYSBURG\", new ArmyPair<>(72500, 85000), new ArmyPair<>(20000, 23000), OffensiveStatus.OFFENSIVE, new String[]{\"JULY 1-3, 1863.  A SOUTHERN MISTAKE BY GEN. LEE AT GETTYSBURG\", \"COST THEM ONE OF THE MOST CRUCIAL BATTLES OF THE WAR.\"}),\n                new HistoricalDatum(\"CHICKAMAUGA\", new ArmyPair<>(66000, 60000), new ArmyPair<>(18000, 16000), OffensiveStatus.BOTH_OFFENSIVE, new String[]{\"SEPT. 15, 1863. CONFUSION IN A FOREST NEAR CHICKAMAUGA LED\", \"TO A COSTLY SOUTHERN VICTORY.\"}),\n                new HistoricalDatum(\"CHATTANOOGA\", new ArmyPair<>(37000, 60000), new ArmyPair<>(36700, 5800), OffensiveStatus.BOTH_OFFENSIVE, new String[]{\"NOV. 25, 1863. AFTER THE SOUTH HAD SIEGED GEN. ROSENCRANS'\", \"ARMY FOR THREE MONTHS, GEN. GRANT BROKE THE SIEGE.\"}),\n                new HistoricalDatum(\"SPOTSYLVANIA\", new ArmyPair<>(62000, 110000), new ArmyPair<>(17723, 18000), OffensiveStatus.BOTH_OFFENSIVE, new String[]{\"MAY 5, 1864.  GRANT'S PLAN TO KEEP LEE ISOLATED BEGAN TO\", \"FAIL HERE, AND CONTINUED AT COLD HARBOR AND PETERSBURG.\"}),\n                new HistoricalDatum(\"ATLANTA\", new ArmyPair<>(65000, 100000), new ArmyPair<>(8500, 3700), OffensiveStatus.DEFENSIVE, new String[]{\"AUGUST, 1864.  SHERMAN AND THREE VETERAN ARMIES CONVERGED\", \"ON ATLANTA AND DEALT THE DEATH BLOW TO THE CONFEDERACY.\"})\n        );\n    }\n\n    private void showCredits() {\n        out.println(\" \".repeat(26) + \"CIVIL WAR\");\n        out.println(\" \".repeat(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        out.println();\n        out.println();\n        out.println();\n    }\n\n    private void updateStrategies(int strategy) {\n        // REM LEARN  PRESENT STRATEGY, START FORGETTING OLD ONES\n        // REM - PRESENT STRATEGY OF SOUTH GAINS 3*S, OTHERS LOSE S\n        // REM   PROBABILITY POINTS, UNLESS A STRATEGY FALLS BELOW 5%.\n\n        var S = 3;\n        var S0 = 0;\n        for (int i = 0; i < 4; i++) {\n            if (this.strategies[i] <= 5) {\n                continue;\n            }\n\n            this.strategies[i] -= S;\n            S0 += S;\n\n        }\n        this.strategies[strategy - 1] += S0;\n\n    }\n\n    private void showHelp() {\n        out.println();\n        out.println();\n        out.println();\n        out.println();\n        out.println(\"THIS IS A CIVIL WAR SIMULATION.\");\n        out.println(\"TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS.\");\n        out.println(\"REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR\");\n        out.println(\"RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE\");\n        out.println(\"BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT\");\n        out.println(\"AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!\");\n        out.println();\n        out.println(\"THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS \");\n        out.println(\"POSSIBLE.\");\n        out.println();\n        out.println(\"YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:\");\n        out.println(\"        (1) ARTILLERY ATTACK\");\n        out.println(\"        (2) FORTIFICATION AGAINST FRONTAL ATTACK\");\n        out.println(\"        (3) FORTIFICATION AGAINST FLANKING MANEUVERS\");\n        out.println(\"        (4) FALLING BACK\");\n        out.println(\" YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:\");\n        out.println(\"        (1) ARTILLERY ATTACK\");\n        out.println(\"        (2) FRONTAL ATTACK\");\n        out.println(\"        (3) FLANKING MANEUVERS\");\n        out.println(\"        (4) ENCIRCLEMENT\");\n        out.println(\"YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY.\");\n    }\n\n    private static final int MAX_NUM_LENGTH = 6;\n\n    private String rightAlignInt(int number) {\n        var s = String.valueOf(number);\n        return \" \".repeat(MAX_NUM_LENGTH - s.length()) + s;\n    }\n\n    private String rightAlignInt(double number) {\n        return rightAlignInt((int) Math.floor(number));\n    }\n\n    private static String inputString(Predicate<String> validator, String reminder) {\n        while (true) {\n            try {\n                var input = new Scanner(System.in).nextLine();\n                if (validator.test(input)) {\n                    return input;\n                }\n            } catch (InputMismatchException e) {\n                // Ignore\n            }\n            System.out.println(reminder);\n        }\n    }\n\n    private static int inputInt(Predicate<Integer> validator, Function<Integer, String> reminder) {\n        while (true) {\n            try {\n                var input = new Scanner(System.in).nextInt();\n                if (validator.test(input)) {\n                    return input;\n                }\n                System.out.println(reminder.apply(input));\n            } catch (InputMismatchException e) {\n                System.out.println(reminder.apply(0));\n            }\n        }\n    }\n\n    private static boolean isYes(String s) {\n        if (s == null) {\n            return false;\n        }\n        var uppercase = s.toUpperCase();\n        return uppercase.equals(\"Y\") || uppercase.equals(\"YES\");\n    }\n\n    private static boolean isNo(String s) {\n        if (s == null) {\n            return false;\n        }\n        var uppercase = s.toUpperCase();\n        return uppercase.equals(\"N\") || uppercase.equals(\"NO\");\n    }\n\n    private static class BattleState {\n        private final HistoricalDatum data;\n        private double F1;\n\n        public BattleState(HistoricalDatum data) {\n            this.data = data;\n        }\n    }\n\n    private static class ArmyPair<T> {\n        private T confederate;\n        private T union;\n\n        public ArmyPair(T confederate, T union) {\n            this.confederate = confederate;\n            this.union = union;\n        }\n    }\n\n    private static class BattleResults {\n        private int confederate;\n        private int union;\n        private int indeterminate;\n\n        public int getTotal() {\n            return confederate + union + indeterminate;\n        }\n    }\n\n    private static class ArmyResources {\n        private int food;\n        private int salaries;\n        private int ammunition;\n        private int budget;\n\n        private double morale;  // TODO really here?\n\n        public int getTotal() {\n            return this.food + this.salaries + this.ammunition;\n        }\n    }\n\n    private record HistoricalDatum(String name, ArmyPair<Integer> troops,\n                                   ArmyPair<Integer> expectedCasualties,\n                                   OffensiveStatus offensiveStatus, String[] blurb) {\n    }\n\n    private record UnionLosses(int losses, int desertions) {\n    }\n}\n"
  },
  {
    "path": "27_Civil_War/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "27_Civil_War/javascript/civilwar.html",
    "content": "<html>\n<head>\n<title>CIVIL WAR</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"civilwar.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "27_Civil_War/javascript/civilwar.js",
    "content": "// CIVIL WAR\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Historical data...can add more (strat., etc) by inserting\n// data statements after appro. info, and adjusting read\n//                      0 - C$     1-M1  2-M2  3-C1 4-C2 5-D\nvar historical_data = [,\n                       [\"BULL RUN\",18000,18500,1967,2708,1],\n                       [\"SHILOH\",40000.,44894.,10699,13047,3],\n                       [\"SEVEN DAYS\",95000.,115000.,20614,15849,3],\n                       [\"SECOND BULL RUN\",54000.,63000.,10000,14000,2],\n                       [\"ANTIETAM\",40000.,50000.,10000,12000,3],\n                       [\"FREDERICKSBURG\",75000.,120000.,5377,12653,1],\n                       [\"MURFREESBORO\",38000.,45000.,11000,12000,1],\n                       [\"CHANCELLORSVILLE\",32000,90000.,13000,17197,2],\n                       [\"VICKSBURG\",50000.,70000.,12000,19000,1],\n                       [\"GETTYSBURG\",72500.,85000.,20000,23000,3],\n                       [\"CHICKAMAUGA\",66000.,60000.,18000,16000,2],\n                       [\"CHATTANOOGA\",37000.,60000.,36700.,5800,2],\n                       [\"SPOTSYLVANIA\",62000.,110000.,17723,18000,2],\n                       [\"ATLANTA\",65000.,100000.,8500,3700,1]];\nvar sa = [];\nvar da = [];\nvar fa = [];\nvar ha = [];\nvar ba = [];\nvar oa = [];\n\n// Main program\nasync function main()\n{\n    print(tab(26) + \"CIVIL WAR\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // Original game design: Cram, Goodie, Hibbard Lexington H.S.\n    // Modifications: G. Paul, R. Hess (Ties), 1973\n    // Union info on likely confederate strategy\n    sa[1] = 25;\n    sa[2] = 25;\n    sa[3] = 25;\n    sa[4] = 25;\n    d = Math.random();\n    print(\"\\n\");\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    while (1) {\n        str = await input();\n        if (str == \"YES\" || str == \"NO\")\n            break;\n        print(\"YES OR NO -- \\n\");\n    }\n    if (str == \"YES\") {\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"THIS IS A CIVIL WAR SIMULATION.\\n\");\n        print(\"TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS.\\n\");\n        print(\"REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR\\n\");\n        print(\"RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE\\n\");\n        print(\"BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT\\n\");\n        print(\"AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!\\n\");\n        print(\"\\n\");\n        print(\"THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS \");\n        print(\"POSSIBLE.\\n\");\n        print(\"\\n\");\n        print(\"YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:\\n\");\n        print(\"        (1) ARTILLERY ATTACK\\n\");\n        print(\"        (2) FORTIFICATION AGAINST FRONTAL ATTACK\\n\");\n        print(\"        (3) FORTIFICATION AGAINST FLANKING MANEUVERS\\n\");\n        print(\"        (4) FALLING BACK\\n\");\n        print(\" YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:\\n\");\n        print(\"        (1) ARTILLERY ATTACK\\n\");\n        print(\"        (2) FRONTAL ATTACK\\n\");\n        print(\"        (3) FLANKING MANEUVERS\\n\");\n        print(\"        (4) ENCIRCLEMENT\\n\");\n        print(\"YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"ARE THERE TWO GENERALS PRESENT \");\n    while (1) {\n        print(\"(ANSWER YES OR NO)\");\n        bs = await input();\n        if (bs == \"YES\") {\n            d = 2;\n            break;\n        } else if (bs == \"NO\") {\n            print(\"\\n\");\n            print(\"YOU ARE THE CONFEDERACY.   GOOD LUCK!\\n\");\n            print(\"\\n\");\n            d = 1;\n            break;\n        }\n    }\n    print(\"SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON\\n\");\n    print(\"REQUEST.  TYPE ANY OTHER NUMBER TO END THE SIMULATION.\\n\");\n    print(\"BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION\\n\");\n    print(\"ALLOWING YOU TO REPLAY IT\\n\");\n    print(\"\\n\");\n    print(\"NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO \\n\");\n    print(\"USE THE ENTRIES FROM THE PREVIOUS BATTLE\\n\");\n    print(\"\\n\");\n    print(\"AFTER REQUESTING A BATTLE, DO YOU WISH \");\n    print(\"BATTLE DESCRIPTIONS \");\n    while (1) {\n        print(\"(ANSWER YES OR NO)\");\n        xs = await input();\n        if (xs == \"YES\" || xs == \"NO\")\n            break;\n    }\n    l = 0;\n    w = 0;\n    r1 = 0;\n    q1 = 0;\n    m3 = 0;\n    m4 = 0;\n    p1 = 0;\n    p2 = 0;\n    t1 = 0;\n    t2 = 0;\n    for (i = 1; i <= 2; i++) {\n        da[i] = 0;\n        fa[i] = 0;\n        ha[i] = 0;\n        ba[i] = 0;\n        oa[i] = 0;\n    }\n    r2 = 0;\n    q2 = 0;\n    c6 = 0;\n    f = 0;\n    w0 = 0;\n    y = 0;\n    y2 = 0;\n    u = 0;\n    u2 = 0;\n    while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"WHICH BATTLE DO YOU WISH TO SIMULATE\");\n        a = parseInt(await input());\n        if (a < 1 || a > 14)\n            break;\n        if (a != 0 || r == 0) {\n            cs = historical_data[a][0];\n            m1 = historical_data[a][1];\n            m2 = historical_data[a][2];\n            c1 = historical_data[a][3];\n            c2 = historical_data[a][4];\n            m = historical_data[a][5];\n            u = 0;\n            // Inflation calc\n            i1 = 10 + (l - w) * 2;\n            i2 = 10 + (w - l) * 2;\n            // Money available\n            da[1] = 100 * Math.floor((m1 * (100 - i1) / 2000) * (1 + (r1 - q1) / (r1 + 1)) + 0.5);\n            da[2] = 100 * Math.floor(m2 * (100 - i2) / 2000 + 0.5);\n            if (bs == \"YES\") {\n                da[2] = 100 * Math.floor((m2 * (100 - i2) / 2000) * (1 + (r2 - q2) / (r2 + 1)) + 0.5);\n            }\n            // Men available\n            m5 = Math.floor(m1 * (1 + (p1 - t1) / (m3 + 1)));\n            m6 = Math.floor(m2 * (1 + (p2 - t2) / (m4 + 1)));\n            f1 = 5 * m1 / 6;\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"THIS IS THE BATTLE OF \" + cs + \"\\n\");\n            if (xs != \"NO\") {\n                switch (a) {\n                    case 1:\n                        print(\"JULY 21, 1861.  GEN. BEAUREGARD, COMMANDING THE SOUTH, MET\\n\");\n                        print(\"UNION FORCES WITH GEN. MCDOWELL IN A PREMATURE BATTLE AT\\n\");\n                        print(\"BULL RUN. GEN. JACKSON HELPED PUSH BACK THE UNION ATTACK.\\n\");\n                        break;\n                    case 2:\n                        print(\"APRIL 6-7, 1862.  THE CONFEDERATE SURPRISE ATTACK AT\\n\");\n                        print(\"SHILOH FAILED DUE TO POOR ORGANIZATION.\\n\");\n                        break;\n                    case 3:\n                        print(\"JUNE 25-JULY 1, 1862.  GENERAL LEE (CSA) UPHELD THE\\n\");\n                        print(\"OFFENSIVE THROUGHOUT THE BATTLE AND FORCED GEN. MCCLELLAN\\n\");\n                        print(\"AND THE UNION FORCES AWAY FROM RICHMOND.\\n\");\n                        break;\n                    case 4:\n                        print(\"AUG 29-30, 1862.  THE COMBINED CONFEDERATE FORCES UNDER LEE\\n\");\n                        print(\"AND JACKSON DROVE THE UNION FORCES BACK INTO WASHINGTON.\\n\");\n                        break;\n                    case 5:\n                        print(\"SEPT 17, 1862.  THE SOUTH FAILED TO INCORPORATE MARYLAND\\n\");\n                        print(\"INTO THE CONFEDERACY.\\n\");\n                        break;\n                    case 6:\n                        print(\"DEC 13, 1862.  THE CONFEDERACY UNDER LEE SUCCESSFULLY\\n\");\n                        print(\"REPULSED AN ATTACK BY THE UNION UNDER GEN. BURNSIDE.\\n\");\n                        break;\n                    case 7:\n                        print(\"DEC 31, 1862.  THE SOUTH UNDER GEN. BRAGG WON A CLOSE BATTLE.\\n\");\n                        break;\n                    case 8:\n                        print(\"MAY 1-6, 1863.  THE SOUTH HAD A COSTLY VICTORY AND LOST\\n\");\n                        print(\"ONE OF THEIR OUTSTANDING GENERALS, 'STONEWALL' JACKSON.\\n\");\n                        break;\n                    case 9:\n                        print(\"JULY 4, 1863.  VICKSBURG WAS A COSTLY DEFEAT FOR THE SOUTH\\n\");\n                        print(\"BECAUSE IT GAVE THE UNION ACCESS TO THE MISSISSIPPI.\\n\");\n                        break;\n                    case 10:\n                        print(\"JULY 1-3, 1863.  A SOUTHERN MISTAKE BY GEN. LEE AT GETTYSBURG\\n\");\n                        print(\"COST THEM ONE OF THE MOST CRUCIAL BATTLES OF THE WAR.\\n\");\n                        break;\n                    case 11:\n                        print(\"SEPT. 15, 1863. CONFUSION IN A FOREST NEAR CHICKAMAUGA LED\\n\");\n                        print(\"TO A COSTLY SOUTHERN VICTORY.\\n\");\n                        break;\n                    case 12:\n                        print(\"NOV. 25, 1863. AFTER THE SOUTH HAD SIEGED GEN. ROSENCRANS'\\n\");\n                        print(\"ARMY FOR THREE MONTHS, GEN. GRANT BROKE THE SIEGE.\\n\");\n                        break;\n                    case 13:\n                        print(\"MAY 5, 1864.  GRANT'S PLAN TO KEEP LEE ISOLATED BEGAN TO\\n\");\n                        print(\"FAIL HERE, AND CONTINUED AT COLD HARBOR AND PETERSBURG.\\n\");\n                        break;\n                    case 14:\n                        print(\"AUGUST, 1864.  SHERMAN AND THREE VETERAN ARMIES CONVERGED\\n\");\n                        print(\"ON ATLANTA AND DEALT THE DEATH BLOW TO THE CONFEDERACY.\\n\");\n                        break;\n                }\n            }\n        } else {\n            print(cs + \" INSTANT REPLAY\\n\");\n        }\n        print(\"\\n\");\n        print(\" \\tCONFEDERACY\\t UNION\\n\"),\n        print(\"MEN\\t  \" + m5 + \"\\t\\t \" + m6 + \"\\n\");\n        print(\"MONEY\\t $\" + da[1] + \"\\t\\t$\" + da[2] + \"\\n\");\n        print(\"INFLATION\\t \" + (i1 + 15) + \"%\\t \" + i2 + \"%\\n\");\n        print(\"\\n\");\n        // ONLY IN PRINTOUT IS CONFED INFLATION = I1 + 15%\n        // IF TWO GENERALS, INPUT CONFED, FIRST\n        for (i = 1; i <= d; i++) {\n            if (bs == \"YES\" && i == 1)\n                print(\"CONFEDERATE GENERAL---\");\n            print(\"HOW MUCH DO YOU WISH TO SPEND FOR\\n\");\n            while (1) {\n                print(\" - FOOD......\");\n                f = parseInt(await input());\n                if (f < 0) {\n                    if (r1 == 0) {\n                        print(\"NO PREVIOUS ENTRIES\\n\");\n                        continue;\n                    }\n                    print(\"ASSUME YOU WANT TO KEEP SAME ALLOCATIONS\\n\");\n                    print(\"\\n\");\n                    break;\n                }\n                fa[i] = f;\n                while (1) {\n                    print(\" - SALARIES..\");\n                    ha[i] = parseInt(await input());\n                    if (ha[i] >= 0)\n                        break;\n                    print(\"NEGATIVE VALUES NOT ALLOWED.\\n\");\n                }\n                while (1) {\n                    print(\" - AMMUNITION\");\n                    ba[i] = parseInt(await input());\n                    if (ba[i] >= 0)\n                        break;\n                    print(\"NEGATIVE VALUES NOT ALLOWED.\\n\");\n                }\n                print(\"\\n\");\n                if (fa[i] + ha[i] + ba[i] > da[i]) {\n                    print(\"THINK AGAIN! YOU HAVE ONLY $\" + da[i] + \"\\n\");\n                } else {\n                    break;\n                }\n            }\n            if (bs != \"YES\" || i == 2)\n                break;\n            print(\"UNION GENERAL---\");\n        }\n        for (z = 1; z <= d; z++) {\n            if (bs == \"YES\") {\n                if (z == 1)\n                    print(\"CONFEDERATE \");\n                else\n                    print(\"      UNION \");\n            }\n            // Find morale\n            o = ((2 * Math.pow(fa[z], 2) + Math.pow(ha[z], 2)) / Math.pow(f1, 2) + 1);\n            if (o >= 10) {\n                print(\"MORALE IS HIGH\\n\");\n            } else if (o >= 5) {\n                print(\"MORALE IS FAIR\\n\");\n            } else {\n                print(\"MORALE IS POOR\\n\");\n            }\n            if (bs != \"YES\")\n                break;\n            oa[z] = o;\n        }\n        o2 = oa[2];\n        o = oa[1];\n        print(\"CONFEDERATE GENERAL---\");\n        // Actual off/def battle situation\n        if (m == 3) {\n            print(\"YOU ARE ON THE OFFENSIVE\\n\");\n        } else if (m == 1) {\n            print(\"YOU ARE ON THE DEFENSIVE\\n\");\n        } else {\n            print(\"BOTH SIDES ARE ON THE OFFENSIVE \\n\");\n        }\n        print(\"\\n\");\n        // Choose strategies\n        if (bs != \"YES\") {\n            print(\"YOUR STRATEGY \");\n            while (1) {\n                y = parseInt(await input());\n                if (Math.abs(y - 3) < 3)\n                    break;\n                print(\"STRATEGY \" + y + \" NOT ALLOWED.\\n\");\n            }\n            if (y == 5) {\n                print(\"THE CONFEDERACY HAS SURRENDERED.\\n\");\n                break;\n            }\n            // Union strategy is computer choesn\n            print(\"UNION STRATEGY IS \");\n            if (a == 0) {\n                while (1) {\n                    y2 = parseInt(await input());\n                    if (y2 > 0 && y2 < 5)\n                        break;\n                    print(\"ENTER 1, 2, 3, OR 4 (USUALLY PREVIOUS UNION STRATEGY)\\n\");\n                }\n            } else {\n                s0 = 0;\n                r = Math.random() * 100;\n                for (i = 1; i <= 4; i++) {\n                    s0 += sa[i];\n                    // If actual strategy info is in program data statements\n                    // then r-100 is extra weight given to that strategy.\n                    if (r < s0)\n                        break;\n                }\n                y2 = i;\n                print(y2 + \"\\n\");\n            }\n        } else {\n            for (i = 1; i <= 2; i++) {\n                if (i == 1)\n                    print(\"CONFEDERATE STRATEGY \");\n                while (1) {\n                    y = parseInt(await input());\n                    if (Math.abs(y - 3) < 3)\n                        break;\n                    print(\"STRATEGY \" + y + \" NOT ALLOWED.\\n\");\n                }\n                if (i == 2) {\n                    y2 = y;\n                    y = y1;\n                    if (y2 != 5)\n                        break;\n                } else {\n                    y1 = y;\n                }\n                print(\"UNION STRATEGY \");\n            }\n            // Simulated losses - North\n            c6 = (2 * c2 / 5) * (1 + 1 / (2 * (Math.abs(y2 - y) + 1)));\n            c6 = c6 * (1.28 + (5 * m2 / 6) / (ba[2] + 1));\n            c6 = Math.floor(c6 * (1 + 1 / o2) + 0.5);\n            // If loss > men present, rescale losses\n            e2 = 100 / o2;\n            if (Math.floor(c6 + e2) >= m6) {\n                c6 = Math.floor(13 * m6 / 20);\n                e2 = 7 * c6 / 13;\n                u2 = 1;\n            }\n        }\n        // Calculate simulated losses\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\t\\tCONFEDERACY\\tUNION\\n\");\n        c5 = (2 * c1 / 5) * (1 + 1 / (2 * (Math.abs(y2 - y) + 1)));\n        c5 = Math.floor(c5 * (1 + 1 / o) * (1.28 + f1 / (ba[1] + 1)) + 0.5);\n        e = 100 / o;\n        if (c5 + 100 / o >= m1 * (1 + (p1 - t1) / (m3 + 1))) {\n            c5 = Math.floor(13 * m1 / 20 * (1 + (p1 - t1) / (m3 + 1)));\n            e = 7 * c5 / 13;\n            u = 1;\n        }\n        if (d == 1) {\n            c6 = Math.floor(17 * c2 * c1 / (c5 * 20));\n            e2 = 5 * o;\n        }\n        print(\"CASUALTIES\\t\" + c5 + \"\\t\\t\" + c6 + \"\\n\");\n        print(\"DESERTIONS\\t\" + Math.floor(e) + \"\\t\\t\" + Math.floor(e2) + \"\\n\");\n        print(\"\\n\");\n        if (bs == \"YES\") {\n            print(\"COMPARED TO THE ACTUAL CASUALTIES AT \" + cs + \"\\n\");\n            print(\"CONFEDERATE: \" + Math.floor(100 * (c5 / c1) + 0.5) + \"% OF THE ORIGINAL\\n\");\n            print(\"UNION:       \" + Math.floor(100 * (c6 / c2) + 0.5) + \"% OF THE ORIGINAL\\n\");\n        }\n        print(\"\\n\");\n        // 1 Who one\n        if (u == 1 && u2 == 1 || (u != 1 && u2 != 1 && c5 + e == c6 + e2)) {\n            print(\"BATTLE OUTCOME UNRESOLVED\\n\");\n            w0++;\n        } else if (u == 1 || (u != 1 && u2 != 1 && c5 + e > c6 + e2)) {\n            print(\"THE UNION WINS \" + cs + \"\\n\");\n            if (a != 0)\n                l++;\n        } else  {\n            print(\"THE CONFEDERACY WINS \" + cs + \"\\n\");\n            if (a != 0)\n                w++;\n        }\n        // Lines 2530 to 2590 from original are unreachable.\n        if (a != 0) {\n            t1 += c5 + e;\n            t2 += c6 + e2;\n            p1 += c1;\n            p2 += c2;\n            q1 += fa[1] + ha[1] + ba[1];\n            q2 += fa[2] + ha[2] + ba[2];\n            r1 += m1 * (100 - i1) / 20;\n            r2 += m2 * (100 - i2) / 20;\n            m3 += m1;\n            m4 += m2;\n            // Learn present strategy, start forgetting old ones\n            // present startegy of south gains 3*s, others lose s\n            // probability points, unless a strategy falls below 5%.\n            s = 3;\n            s0 = 0;\n            for (i = 1; i <= 4; i++) {\n                if (sa[i] <= 5)\n                    continue;\n                sa[i] -= 5;\n                s0 += s;\n            }\n            sa[y] += s0;\n        }\n        u = 0;\n        u2 = 0;\n        print(\"---------------\");\n        continue;\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THE CONFEDERACY HAS WON \" + w + \" BATTLES AND LOST \" + l + \"\\n\");\n    if (y == 5 || (y2 != 5 && w <= l)) {\n        print(\"THE UNION HAS WON THE WAR\\n\");\n    } else {\n        print(\"THE CONFEDERACY HAS WON THE WAR\\n\");\n    }\n    print(\"\\n\");\n    if (r1) {\n        print(\"FOR THE \" + (w + l + w0) + \" BATTLES FOUGHT (EXCLUDING RERUNS)\\n\");\n        print(\" \\t \\t \");\n        print(\"CONFEDERACY\\t UNION\\n\");\n        print(\"HISTORICAL LOSSES\\t\" + Math.floor(p1 + 0.5) + \"\\t\" + Math.floor(p2 + 0.5) + \"\\n\");\n        print(\"SIMULATED LOSSES\\t\" + Math.floor(t1 + 0.5) + \"\\t\" + Math.floor(t2 + 0.5) + \"\\n\");\n        print(\"\\n\");\n        print(\"    % OF ORIGINAL\\t\" + Math.floor(100 * (t1 / p1) + 0.5) + \"\\t\" + Math.floor(100 * (t2 / p2) + 0.5) + \"\\n\");\n        if (bs != \"YES\") {\n            print(\"\\n\");\n            print(\"UNION INTELLIGENCE SUGGEST THAT THE SOUTH USED \\n\");\n            print(\"STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES\\n\");\n            print(sa[1] + \" \" + sa[2] + \" \" + sa[3] + \" \" + sa[4] + \"\\n\");\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "27_Civil_War/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "27_Civil_War/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "27_Civil_War/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "27_Civil_War/python/Civilwar.py",
    "content": "\"\"\"\nOriginal game design: Cram, Goodie, Hibbard Lexington H.S.\nModifications: G. Paul, R. Hess (Ties), 1973\n\"\"\"\nimport enum\nimport math\nimport random\nfrom dataclasses import dataclass\nfrom typing import Dict, List, Literal, Tuple\n\n\nclass AttackState(enum.Enum):\n    DEFENSIVE = 1\n    BOTH_OFFENSIVE = 2\n    OFFENSIVE = 3\n\n\nCONF = 1\nUNION = 2\n\n\n@dataclass\nclass PlayerStat:\n    food: float = 0\n    salaries: float = 0\n    ammunition: float = 0\n\n    desertions: float = 0\n    casualties: float = 0\n    morale: float = 0\n    strategy: int = 0\n    available_men: int = 0\n    available_money: int = 0\n\n    army_c: float = 0\n    army_m: float = 0  # available_men ????\n    inflation: float = 0\n\n    r: float = 0\n    t: float = 0  # casualties + desertions\n    q: float = 0  # accumulated cost?\n    p: float = 0\n    m: float = 0\n\n    is_player = False\n    excessive_losses = False\n\n    def set_available_money(self):\n        factor = 1 + (self.r - self.q) / (self.r + 1) if self.is_player else 1\n        self.available_money = 100 * math.floor(\n            (self.army_m * (100 - self.inflation) / 2000) * factor + 0.5\n        )\n\n    def get_cost(self) -> float:\n        return self.food + self.salaries + self.ammunition\n\n    def get_army_factor(self) -> float:\n        return 1 + (self.p - self.t) / (self.m + 1)\n\n    def get_present_men(self) -> float:\n        return self.army_m * self.get_army_factor()\n\n\ndef simulate_losses(player1: PlayerStat, player2: PlayerStat) -> float:\n    \"\"\"Simulate losses of player 1\"\"\"\n    tmp = (2 * player1.army_c / 5) * (\n        1 + 1 / (2 * (abs(player1.strategy - player2.strategy) + 1))\n    )\n    tmp = tmp * (1.28 + (5 * player1.army_m / 6) / (player1.ammunition + 1))\n    return math.floor(tmp * (1 + 1 / player1.morale) + 0.5)\n\n\ndef update_army(player: PlayerStat, enemy: PlayerStat, use_factor=False) -> None:\n    player.casualties = simulate_losses(player, enemy)\n    player.desertions = 100 / player.morale\n\n    loss = player.casualties + player.desertions\n    if not use_factor:\n        present_men: float = player.available_men\n    else:\n        present_men = player.get_present_men()\n    if loss >= present_men:\n        factor = player.get_army_factor()\n        if not use_factor:\n            factor = 1\n        player.casualties = math.floor(13 * player.army_m / 20 * factor)\n        player.desertions = 7 * player.casualties / 13\n        player.excessive_losses = True\n\n\ndef get_choice(prompt: str, choices: List[str]) -> str:\n    while True:\n        choice = input(prompt)\n        if choice in choices:\n            break\n    return choice\n\n\ndef get_morale(stat: PlayerStat, enemy: PlayerStat) -> float:\n    \"\"\"Higher is better\"\"\"\n    enemy_strength = 5 * enemy.army_m / 6\n    return (2 * math.pow(stat.food, 2) + math.pow(stat.salaries, 2)) / math.pow(\n        enemy_strength, 2\n    ) + 1\n\n\ndef main() -> None:\n    battles = [\n        [\n            \"JULY 21, 1861.  GEN. BEAUREGARD, COMMANDING THE SOUTH, MET\",\n            \"UNION FORCES WITH GEN. MCDOWELL IN A PREMATURE BATTLE AT\",\n            \"BULL RUN. GEN. JACKSON HELPED PUSH BACK THE UNION ATTACK.\",\n        ],\n        [\n            \"APRIL 6-7, 1862.  THE CONFEDERATE SURPRISE ATTACK AT\",\n            \"SHILOH FAILED DUE TO POOR ORGANIZATION.\",\n        ],\n        [\n            \"JUNE 25-JULY 1, 1862.  GENERAL LEE (CSA) UPHELD THE\",\n            \"OFFENSIVE THROUGHOUT THE BATTLE AND FORCED GEN. MCCLELLAN\",\n            \"AND THE UNION FORCES AWAY FROM RICHMOND.\",\n        ],\n        [\n            \"AUG 29-30, 1862.  THE COMBINED CONFEDERATE FORCES UNDER LEE\",\n            \"AND JACKSON DROVE THE UNION FORCES BACK INTO WASHINGTON.\",\n        ],\n        [\n            \"SEPT 17, 1862.  THE SOUTH FAILED TO INCORPORATE MARYLAND\",\n            \"INTO THE CONFEDERACY.\",\n        ],\n        [\n            \"DEC 13, 1862.  THE CONFEDERACY UNDER LEE SUCCESSFULLY\",\n            \"REPULSED AN ATTACK BY THE UNION UNDER GEN. BURNSIDE.\",\n        ],\n        [\"DEC 31, 1862.  THE SOUTH UNDER GEN. BRAGG WON A CLOSE BATTLE.\"],\n        [\n            \"MAY 1-6, 1863.  THE SOUTH HAD A COSTLY VICTORY AND LOST\",\n            \"ONE OF THEIR OUTSTANDING GENERALS, 'STONEWALL' JACKSON.\",\n        ],\n        [\n            \"JULY 4, 1863.  VICKSBURG WAS A COSTLY DEFEAT FOR THE SOUTH\",\n            \"BECAUSE IT GAVE THE UNION ACCESS TO THE MISSISSIPPI.\",\n        ],\n        [\n            \"JULY 1-3, 1863.  A SOUTHERN MISTAKE BY GEN. LEE AT GETTYSBURG\",\n            \"COST THEM ONE OF THE MOST CRUCIAL BATTLES OF THE WAR.\",\n        ],\n        [\n            \"SEPT. 15, 1863. CONFUSION IN A FOREST NEAR CHICKAMAUGA LED\",\n            \"TO A COSTLY SOUTHERN VICTORY.\",\n        ],\n        [\n            \"NOV. 25, 1863. AFTER THE SOUTH HAD SIEGED GEN. ROSENCRANS'\",\n            \"ARMY FOR THREE MONTHS, GEN. GRANT BROKE THE SIEGE.\",\n        ],\n        [\n            \"MAY 5, 1864.  GRANT'S PLAN TO KEEP LEE ISOLATED BEGAN TO\",\n            \"FAIL HERE, AND CONTINUED AT COLD HARBOR AND PETERSBURG.\",\n        ],\n        [\n            \"AUGUST, 1864.  SHERMAN AND THREE VETERAN ARMIES CONVERGED\",\n            \"ON ATLANTA AND DEALT THE DEATH BLOW TO THE CONFEDERACY.\",\n        ],\n    ]\n\n    historical_data: List[Tuple[str, float, float, float, int, AttackState]] = [\n        (\"\", 0, 0, 0, 0, AttackState.DEFENSIVE),\n        (\"BULL RUN\", 18000, 18500, 1967, 2708, AttackState.DEFENSIVE),\n        (\"SHILOH\", 40000.0, 44894.0, 10699, 13047, AttackState.OFFENSIVE),\n        (\"SEVEN DAYS\", 95000.0, 115000.0, 20614, 15849, AttackState.OFFENSIVE),\n        (\"SECOND BULL RUN\", 54000.0, 63000.0, 10000, 14000, AttackState.BOTH_OFFENSIVE),\n        (\"ANTIETAM\", 40000.0, 50000.0, 10000, 12000, AttackState.OFFENSIVE),\n        (\"FREDERICKSBURG\", 75000.0, 120000.0, 5377, 12653, AttackState.DEFENSIVE),\n        (\"MURFREESBORO\", 38000.0, 45000.0, 11000, 12000, AttackState.DEFENSIVE),\n        (\"CHANCELLORSVILLE\", 32000, 90000.0, 13000, 17197, AttackState.BOTH_OFFENSIVE),\n        (\"VICKSBURG\", 50000.0, 70000.0, 12000, 19000, AttackState.DEFENSIVE),\n        (\"GETTYSBURG\", 72500.0, 85000.0, 20000, 23000, AttackState.OFFENSIVE),\n        (\"CHICKAMAUGA\", 66000.0, 60000.0, 18000, 16000, AttackState.BOTH_OFFENSIVE),\n        (\"CHATTANOOGA\", 37000.0, 60000.0, 36700.0, 5800, AttackState.BOTH_OFFENSIVE),\n        (\"SPOTSYLVANIA\", 62000.0, 110000.0, 17723, 18000, AttackState.BOTH_OFFENSIVE),\n        (\"ATLANTA\", 65000.0, 100000.0, 8500, 3700, AttackState.DEFENSIVE),\n    ]\n    confederate_strategy_prob_distribution = {}\n\n    # What do you spend money on?\n    stats: Dict[int, PlayerStat] = {\n        CONF: PlayerStat(),\n        UNION: PlayerStat(),\n    }\n\n    print(\" \" * 26 + \"CIVIL WAR\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    # Union info on likely confederate strategy\n    confederate_strategy_prob_distribution[1] = 25\n    confederate_strategy_prob_distribution[2] = 25\n    confederate_strategy_prob_distribution[3] = 25\n    confederate_strategy_prob_distribution[4] = 25\n    print()\n    show_instructions = get_choice(\n        \"DO YOU WANT INSTRUCTIONS? YES OR NO -- \", [\"YES\", \"NO\"]\n    )\n\n    if show_instructions == \"YES\":\n        print()\n        print()\n        print()\n        print()\n        print(\"THIS IS A CIVIL WAR SIMULATION.\")\n        print(\"TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS.\")\n        print(\"REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR\")\n        print(\"RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE\")\n        print(\"BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT\")\n        print(\"AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!\")\n        print()\n        print(\"THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS \")\n        print(\"POSSIBLE.\")\n        print()\n        print(\"YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:\")\n        print(\"        (1) ARTILLERY ATTACK\")\n        print(\"        (2) FORTIFICATION AGAINST FRONTAL ATTACK\")\n        print(\"        (3) FORTIFICATION AGAINST FLANKING MANEUVERS\")\n        print(\"        (4) FALLING BACK\")\n        print(\" YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:\")\n        print(\"        (1) ARTILLERY ATTACK\")\n        print(\"        (2) FRONTAL ATTACK\")\n        print(\"        (3) FLANKING MANEUVERS\")\n        print(\"        (4) ENCIRCLEMENT\")\n        print(\"YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY.\")\n\n    print()\n    print()\n    print()\n    print(\"ARE THERE TWO GENERALS PRESENT \", end=\"\")\n    two_generals = get_choice(\"(ANSWER YES OR NO) \", [\"YES\", \"NO\"]) == \"YES\"\n    stats[CONF].is_player = True\n    if two_generals:\n        party: Literal[1, 2] = 2  # number of players in the game\n        stats[UNION].is_player = True\n    else:\n        party = 1\n        print()\n        print(\"YOU ARE THE CONFEDERACY.   GOOD LUCK!\")\n        print()\n\n    print(\"SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON\")\n    print(\"REQUEST.  TYPE ANY OTHER NUMBER TO END THE SIMULATION.\")\n    print(\"BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION\")\n    print(\"ALLOWING YOU TO REPLAY IT\")\n    print()\n    print(\"NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO \")\n    print(\"USE THE ENTRIES FROM THE PREVIOUS BATTLE\")\n    print()\n    print(\"AFTER REQUESTING A BATTLE, DO YOU WISH \", end=\"\")\n    print(\"BATTLE DESCRIPTIONS \", end=\"\")\n    xs = get_choice(\"(ANSWER YES OR NO) \", [\"YES\", \"NO\"])\n    confederacy_lost = 0\n    confederacy_win = 0\n    for i in [CONF, UNION]:\n        stats[i].p = 0\n        stats[i].m = 0\n        stats[i].t = 0\n        stats[i].available_money = 0\n        stats[i].food = 0\n        stats[i].salaries = 0\n        stats[i].ammunition = 0\n        stats[i].strategy = 0\n        stats[i].excessive_losses = False\n    confederacy_unresolved = 0\n    random_nb: float = 0\n    while True:\n        print()\n        print()\n        print()\n        simulated_battle_index = int(\n            get_choice(\n                \"WHICH BATTLE DO YOU WISH TO SIMULATE? (0-14) \",\n                [str(i) for i in range(15)],\n            )\n        )\n        if simulated_battle_index < 1 or simulated_battle_index > 14:\n            break\n        if simulated_battle_index != 0 or random_nb == 0:\n            loaded_battle = historical_data[simulated_battle_index]\n            battle_name = loaded_battle[0]\n            stats[CONF].army_m = loaded_battle[1]\n            stats[UNION].army_m = loaded_battle[2]\n            stats[CONF].army_c = loaded_battle[3]\n            stats[UNION].army_c = loaded_battle[4]\n            stats[CONF].excessive_losses = False\n\n            # Inflation calc\n            stats[CONF].inflation = 10 + (confederacy_lost - confederacy_win) * 2\n            stats[UNION].inflation = 10 + (confederacy_win - confederacy_lost) * 2\n\n            # Money and Men available\n            for i in [CONF, UNION]:\n                stats[i].set_available_money()\n                stats[i].available_men = math.floor(stats[i].get_army_factor())\n            print()\n            print()\n            print()\n            print()\n            print()\n            print(f\"THIS IS THE BATTLE OF {battle_name}\")\n            if xs != \"NO\":\n                print(\"\\n\".join(battles[simulated_battle_index - 1]))\n\n        else:\n            print(f\"{battle_name} INSTANT REPLAY\")\n\n        print()\n        print(\"          CONFEDERACY\\t UNION\")\n        print(f\"MEN       {stats[CONF].available_men}\\t\\t {stats[UNION].available_men}\")\n        print(\n            f\"MONEY    ${stats[CONF].available_money}\\t${stats[UNION].available_money}\"\n        )\n        print(f\"INFLATION {stats[CONF].inflation + 15}%\\t\\t {stats[UNION].inflation}%\")\n        print()\n        # ONLY IN PRINTOUT IS CONFED INFLATION = I1 + 15 %\n        # IF TWO GENERALS, INPUT CONFED, FIRST\n        for player_index in range(1, party + 1):\n            if two_generals and player_index == 1:\n                print(\"CONFEDERATE GENERAL---\", end=\"\")\n            print(\"HOW MUCH DO YOU WISH TO SPEND FOR\")\n            while True:\n                food_input = int(input(\" - FOOD...... ? \"))\n                if food_input < 0:\n                    if stats[CONF].r == 0:\n                        print(\"NO PREVIOUS ENTRIES\")\n                        continue\n                    print(\"ASSUME YOU WANT TO KEEP SAME ALLOCATIONS\")\n                    print()\n                    break\n                stats[player_index].food = food_input\n                while True:\n                    stats[player_index].salaries = int(input(\" - SALARIES.. ? \"))\n                    if stats[player_index].salaries >= 0:\n                        break\n                    print(\"NEGATIVE VALUES NOT ALLOWED.\")\n                while True:\n                    stats[player_index].ammunition = int(input(\" - AMMUNITION ? \"))\n                    if stats[player_index].ammunition >= 0:\n                        break\n                    print(\"NEGATIVE VALUES NOT ALLOWED.\")\n                print()\n                if stats[player_index].get_cost() > stats[player_index].available_money:\n                    print(\n                        f\"THINK AGAIN! YOU HAVE ONLY ${stats[player_index].available_money}\"\n                    )\n                else:\n                    break\n\n            if not two_generals or player_index == 2:\n                break\n            print(\"UNION GENERAL---\", end=\"\")\n\n        for player_index in range(1, party + 1):\n            if two_generals:\n                if player_index == 1:\n                    print(\"CONFEDERATE \", end=\"\")\n                else:\n                    print(\"      UNION \", end=\"\")\n            morale = get_morale(stats[player_index], stats[1 + player_index % 2])\n\n            if morale >= 10:\n                print(\"MORALE IS HIGH\")\n            elif morale >= 5:\n                print(\"MORALE IS FAIR\")\n            else:\n                print(\"MORALE IS POOR\")\n            if not two_generals:\n                break\n            stats[player_index].morale = morale  # type: ignore\n\n        stats[UNION].morale = get_morale(stats[UNION], stats[CONF])\n        stats[CONF].morale = get_morale(stats[CONF], stats[UNION])\n        print(\"CONFEDERATE GENERAL---\")\n        # Actual off/def battle situation\n        if loaded_battle[5] == AttackState.OFFENSIVE:\n            print(\"YOU ARE ON THE OFFENSIVE\")\n        elif loaded_battle[5] == AttackState.DEFENSIVE:\n            print(\"YOU ARE ON THE DEFENSIVE\")\n        else:\n            print(\"BOTH SIDES ARE ON THE OFFENSIVE\")\n\n        print()\n        # Choose strategies\n        if not two_generals:\n            while True:\n                stats[CONF].strategy = int(input(\"YOUR STRATEGY \"))\n                if abs(stats[CONF].strategy - 3) < 3:\n                    break\n                print(f\"STRATEGY {stats[CONF].strategy} NOT ALLOWED.\")\n            if stats[CONF].strategy == 5:\n                print(\"THE CONFEDERACY HAS SURRENDERED.\")\n                break\n            # Union strategy is computer chosen\n            if simulated_battle_index == 0:\n                while True:\n                    stats[UNION].strategy = int(input(\"UNION STRATEGY IS \"))\n                    if stats[UNION].strategy > 0 and stats[UNION].strategy < 5:\n                        break\n                    print(\"ENTER 1, 2, 3, OR 4 (USUALLY PREVIOUS UNION STRATEGY)\")\n            else:\n                s0 = 0\n                random_nb = random.random() * 100\n                for player_index in range(1, 5):\n                    s0 += confederate_strategy_prob_distribution[player_index]\n                    # If actual strategy info is in program data statements\n                    # then r-100 is extra weight given to that strategy.\n                    if random_nb < s0:\n                        break\n                stats[UNION].strategy = player_index\n                print(stats[UNION].strategy)\n        else:\n            for player_index in [1, 2]:\n                if player_index == 1:\n                    print(\"CONFEDERATE STRATEGY ? \", end=\"\")\n                while True:\n                    stats[CONF].strategy = int(input())\n                    if abs(stats[CONF].strategy - 3) < 3:\n                        break\n                    print(f\"STRATEGY {stats[CONF].strategy} NOT ALLOWED.\")\n                    print(\"YOUR STRATEGY ? \", end=\"\")\n                if player_index == 2:\n                    stats[UNION].strategy = stats[CONF].strategy\n                    stats[CONF].strategy = previous_strategy  # type: ignore # noqa: F821\n                    if stats[UNION].strategy != 5:\n                        break\n                else:\n                    previous_strategy = stats[CONF].strategy  # noqa: F841\n                print(\"UNION STRATEGY ? \", end=\"\")\n\n            update_army(stats[UNION], stats[CONF], use_factor=False)\n\n        # Calculate simulated losses\n        print()\n        print()\n        print()\n        print(\"\\t\\tCONFEDERACY\\tUNION\")\n        update_army(stats[CONF], stats[UNION], use_factor=True)\n\n        if party == 1:\n            stats[UNION].casualties = math.floor(\n                17\n                * stats[UNION].army_c\n                * stats[CONF].army_c\n                / (stats[CONF].casualties * 20)\n            )\n            stats[CONF].desertions = 5 * morale\n\n        print(\n            \"CASUALTIES\\t\"\n            + str(stats[CONF].casualties)\n            + \"\\t\\t\"\n            + str(stats[UNION].casualties)\n        )\n        print(\n            \"DESERTIONS\\t\"\n            + str(math.floor(stats[CONF].desertions))\n            + \"\\t\\t\"\n            + str(math.floor(stats[UNION].desertions))\n        )\n        print()\n        if two_generals:\n            print(\"COMPARED TO THE ACTUAL CASUALTIES AT \" + str(battle_name))\n            print(\n                \"CONFEDERATE: \"\n                + str(\n                    math.floor(\n                        100 * (stats[CONF].casualties / stats[CONF].army_c) + 0.5\n                    )\n                )\n                + \"% OF THE ORIGINAL\"\n            )\n            print(\n                \"UNION:       \"\n                + str(\n                    math.floor(\n                        100 * (stats[UNION].casualties / stats[UNION].army_c) + 0.5\n                    )\n                )\n                + \"% OF THE ORIGINAL\"\n            )\n\n        print()\n        # Find who won\n        if (\n            stats[CONF].excessive_losses\n            and stats[UNION].excessive_losses\n            or (\n                not stats[CONF].excessive_losses\n                and not stats[UNION].excessive_losses\n                and stats[CONF].casualties + stats[CONF].desertions\n                == stats[UNION].casualties + stats[CONF].desertions\n            )\n        ):\n            print(\"BATTLE OUTCOME UNRESOLVED\")\n            confederacy_unresolved += 1\n        elif stats[CONF].excessive_losses or (\n            not stats[CONF].excessive_losses\n            and not stats[UNION].excessive_losses\n            and stats[CONF].casualties + stats[CONF].desertions\n            > stats[UNION].casualties + stats[CONF].desertions\n        ):\n            print(f\"THE UNION WINS {battle_name}\")\n            if simulated_battle_index != 0:\n                confederacy_lost += 1\n        else:\n            print(f\"THE CONFEDERACY WINS {battle_name}\")\n            if simulated_battle_index != 0:\n                confederacy_win += 1\n\n        # Lines 2530 to 2590 from original are unreachable.\n        if simulated_battle_index != 0:\n            for i in [CONF, UNION]:\n                stats[i].t += stats[i].casualties + stats[i].desertions\n                stats[i].p += stats[i].army_c\n                stats[i].q += stats[i].get_cost()\n                stats[i].r += stats[i].army_m * (100 - stats[i].inflation) / 20\n                stats[i].m += stats[i].army_m\n            # Learn present strategy, start forgetting old ones\n            # present strategy of south gains 3*s, others lose s\n            # probability points, unless a strategy falls below 5 % .\n            s = 3\n            s0 = 0\n            for player_index in range(1, 5):\n                if confederate_strategy_prob_distribution[player_index] <= 5:\n                    continue\n                confederate_strategy_prob_distribution[player_index] -= 5\n                s0 += s\n            confederate_strategy_prob_distribution[stats[CONF].strategy] += s0\n\n        stats[CONF].excessive_losses = False\n        stats[UNION].excessive_losses = False\n        print(\"---------------\")\n        continue\n\n    print()\n    print()\n    print()\n    print()\n    print()\n    print()\n    print(\n        f\"THE CONFEDERACY HAS WON {confederacy_win} BATTLES AND LOST {confederacy_lost}\"\n    )\n    if stats[CONF].strategy == 5 or (\n        stats[UNION].strategy != 5 and confederacy_win <= confederacy_lost\n    ):\n        print(\"THE UNION HAS WON THE WAR\")\n    else:\n        print(\"THE CONFEDERACY HAS WON THE WAR\")\n    print()\n    if stats[CONF].r > 0:\n        print(\n            f\"FOR THE {confederacy_win + confederacy_lost + confederacy_unresolved} BATTLES FOUGHT (EXCLUDING RERUNS)\"\n        )\n        print(\" \\t \\t \")\n        print(\"CONFEDERACY\\t UNION\")\n        print(\n            f\"HISTORICAL LOSSES\\t{math.floor(stats[CONF].p + 0.5)}\\t{math.floor(stats[UNION].p + 0.5)}\"\n        )\n        print(\n            f\"SIMULATED LOSSES\\t{math.floor(stats[CONF].t + 0.5)}\\t{math.floor(stats[UNION].t + 0.5)}\"\n        )\n        print()\n        print(\n            f\"    % OF ORIGINAL\\t{math.floor(100 * (stats[CONF].t / stats[CONF].p) + 0.5)}\\t{math.floor(100 * (stats[UNION].t / stats[UNION].p) + 0.5)}\"\n        )\n        if not two_generals:\n            print()\n            print(\"UNION INTELLIGENCE SUGGEST THAT THE SOUTH USED\")\n            print(\"STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES\")\n            print(\n                f\"{confederate_strategy_prob_distribution[CONF]} {confederate_strategy_prob_distribution[UNION]} {confederate_strategy_prob_distribution[3]} {confederate_strategy_prob_distribution[4]}\"\n            )\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "27_Civil_War/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "27_Civil_War/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "27_Civil_War/vbnet/CivilWar.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"CivilWar\", \"CivilWar.vbproj\", \"{D726A817-AF69-43B9-9092-876453960C19}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D726A817-AF69-43B9-9092-876453960C19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D726A817-AF69-43B9-9092-876453960C19}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D726A817-AF69-43B9-9092-876453960C19}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D726A817-AF69-43B9-9092-876453960C19}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "27_Civil_War/vbnet/CivilWar.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>CivilWar</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "27_Civil_War/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "28_Combat/README.md",
    "content": "### Combat\n\nIn this game, you are fighting a small-scale war with the computer. You have 72,000 troops which you first ust distribute among your Army, Navy, and Air Force. You may distribute them in any way you choose as long as you don’t use more than 72,000.\n\nYou then attack your opponent (the computer) and input which service and the number of men you wish to use. The computer then tells you the outcome of the battle, gives you the current statistics and allows you to determine your next move.\n\nAfter the second battle, it is decided from the total statistics whether you win or lose or if a treaty is signed.\n\nThis program was created by Bob Dores of Milton, Massachusetts.\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=50)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=65)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The original game misspells \"unguarded\" on line 1751.\n- In an initial army attack, the program claims that the computer loses 2/3 of its army, but it actually loses its entire army (lines 150-155).\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "28_Combat/combat.bas",
    "content": "1 PRINT TAB(33);\"COMBAT\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT: PRINT: PRINT\n4 PRINT \"I AM AT WAR WITH YOU.\": PRINT \"WE HAVE 72000 SOLDIERS APIECE.\"\n5 PRINT:PRINT \"DISTRIBUTE YOUR FORCES.\"\n6 PRINT ,\"ME\",\"  YOU\"\n7 PRINT \"ARMY\",30000,\n8 INPUT A\n9 PRINT \"NAVY\",20000,\n10 INPUT B\n11 PRINT \"A. F.\",22000,\n12 INPUT C\n13 IF A+B+C>72000 THEN 5\n14 D=30000\n15 E=20000\n16 F=22000\n17 PRINT \"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\"\n18 PRINT \"AND (3) FOR AIR FORCE.\"\n19 INPUT Y\n20 PRINT \"HOW MANY MEN\"\n21 INPUT X\n22 IF X<0 THEN 20\n23 ON Y GOTO 100,200,300\n100 IF X>A THEN 20\n105 IF X<A/3 THEN 120\n110 IF X<2*A/3 THEN 150\n115 GOTO 270\n120 PRINT \"YOU LOST\";X;\"MEN FROM YOUR ARMY.\"\n125 A=INT(A-X)\n130 GOTO 500\n150 PRINT \"YOU LOST\";INT(X/3);\"MEN, BUT I LOST \";INT(2*D/3)\n155 A=INT(A-X/3)\n160 D=0\n165 GOTO 500\n200 IF X>B THEN 20\n210 IF X<E/3 THEN 230\n215 IF X<2*E/3 THEN 250\n220 GOTO 270\n230 PRINT \"YOUR ATTACK WAS STOPPED!\"\n232 B=INT(B-X)\n235 GOTO 500\n250 PRINT \"YOU DESTROYED\";INT(2*E/3);\"OF MY ARMY.\"\n255 E=INT(E/3)\n260 GOTO 500\n270 PRINT \"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\"\n275 PRINT \"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\"\n280 A=INT(A/3)\n285 C=INT(C/3)\n290 E=INT(2*E/3)\n293 GOTO 500\n300 IF X>C THEN 20\n310 IF X<C/3 THEN 350\n320 IF X<2*C/3 THEN 370\n330 GOTO 380\n350 PRINT \"YOUR ATTACK WAS WIPED OUT.\"\n355 C=INT(C-X)\n360 GOTO 500\n370 PRINT \"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\"\n375 D=INT(2*D/3)\n377 E=INT(E/3)\n378 F=INT(F/3)\n379 GOTO 500\n380 PRINT \"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\"\n381 PRINT \"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\"\n385 A=INT(A/4)\n387 B=INT(B/3)\n390 D=INT(2*D/3)\n500 PRINT\n501 PRINT,\"YOU\",\"ME\"\n510 PRINT \"ARMY\",A,D\n520 PRINT \"NAVY\",B,E\n530 PRINT \"A. F.\",C,F\n1000 PRINT \"WHAT IS YOUR NEXT MOVE?\"\n1010 PRINT \"ARMY=1  NAVY=2  AIR FORCE=3\"\n1020 INPUT G\n1030 PRINT \"HOW MANY MEN\"\n1040 INPUT T\n1045 IF T<0 THEN 1030\n1050 ON G GOTO 1600,1700,1800\n1600 IF T>A THEN 1030\n1610 IF T<D/2 THEN 1630\n1615 PRINT \"YOU DESTROYED MY ARMY!\"\n1616 D=0\n1617 GOTO 2000\n1630 PRINT \"I WIPED OUT YOUR ATTACK!\"\n1635 A=A-T\n1640 GOTO 2000\n1700 IF T>B THEN 1030\n1710 IF T<E/2 THEN 1750\n1720 GOTO 1770\n1750 PRINT \"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\"\n1751 PRINT \"WIPED OUT YOUR UNGAURDED CAPITOL.\"\n1755 A=A/4\n1760 B=B/2\n1765 GOTO 2000\n1770 PRINT \"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\"\n1771 PRINT \"AND SUNK THREE BATTLESHIPS.\"\n1775 F=2*F/3\n1780 E=(E/2)\n1790 GOTO 2000\n1800 IF T>C THEN 1030\n1810 IF T>F/2 THEN 1830\n1820 GOTO 1850\n1830 PRINT \"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\"\n1831 PRINT \"YOUR COUNTRY IN SHAMBLES.\"\n1835 A=A/3\n1837 B=B/3\n1840 C=C/3\n1845 GOTO 2000\n1850 PRINT \"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\"\n1851 PRINT \"MY COUNTRY FELL APART.\"\n1860 GOTO 2010\n2000 PRINT\n2001 PRINT \"FROM THE RESULTS OF BOTH OF YOUR ATTACKS,\"\n2002 IF A+B+C>3/2*(D+E+F) THEN 2010\n2005 IF A+B+C<2/3*(D+E+F) THEN 2015\n2006 PRINT \"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\"\n2007 PRINT \"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\"\n2008 GOTO 2020\n2010 PRINT \"YOU WON, OH! SHUCKS!!!!\"\n2012 GOTO 2020\n2015 PRINT \"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\"\n2016 PRINT \"RIGHT FOR PLAYING THIS STUPID GAME!!!\"\n2020 END\n"
  },
  {
    "path": "28_Combat/csharp/ArmedForces.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Represents the armed forces for a country.\n    /// </summary>\n    public record ArmedForces\n    {\n        /// <summary>\n        /// Gets the number of men and women in the army.\n        /// </summary>\n        public int Army { get; init; }\n\n        /// <summary>\n        /// Gets the number of men and women in the navy.\n        /// </summary>\n        public int Navy { get; init; }\n\n        /// <summary>\n        /// Gets the number of men and women in the air force.\n        /// </summary>\n        public int AirForce { get; init; }\n\n        /// <summary>\n        /// Gets the total number of troops in the armed forces.\n        /// </summary>\n        public int TotalTroops => Army + Navy + AirForce;\n\n        /// <summary>\n        /// Gets the number of men and women in the given branch.\n        /// </summary>\n        public int this[MilitaryBranch branch] =>\n            branch switch\n            {\n                MilitaryBranch.Army     => Army,\n                MilitaryBranch.Navy     => Navy,\n                MilitaryBranch.AirForce => AirForce,\n                _                       => throw new ArgumentException(\"INVALID BRANCH\")\n            };\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/Ceasefire.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Represents the state of the game after reaching a ceasefire.\n    /// </summary>\n    public sealed class Ceasefire : WarState\n    {\n        /// <summary>\n        /// Gets a flag indicating whether the player achieved absolute victory.\n        /// </summary>\n        public override bool IsAbsoluteVictory { get; }\n\n        /// <summary>\n        /// Gets the outcome of the war.\n        /// </summary>\n        public override WarResult? FinalOutcome\n        {\n            get\n            {\n                if (IsAbsoluteVictory || PlayerForces.TotalTroops > 3 / 2 * ComputerForces.TotalTroops)\n                    return WarResult.PlayerVictory;\n                else\n                if (PlayerForces.TotalTroops < 2 / 3 * ComputerForces.TotalTroops)\n                    return WarResult.ComputerVictory;\n                else\n                    return WarResult.PeaceTreaty;\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the Ceasefire class.\n        /// </summary>\n        /// <param name=\"computerForces\">\n        /// The computer's forces.\n        /// </param>\n        /// <param name=\"playerForces\">\n        /// The player's forces.\n        /// </param>\n        /// <param name=\"absoluteVictory\">\n        /// Indicates whether the player acheived absolute victory (defeating\n        /// the computer without destroying its military).\n        /// </param>\n        public Ceasefire(ArmedForces computerForces, ArmedForces playerForces, bool absoluteVictory = false)\n            : base(computerForces, playerForces)\n        {\n            IsAbsoluteVictory = absoluteVictory;\n        }\n\n        protected override (WarState nextState, string message) AttackWithArmy(int attackSize) =>\n            throw new InvalidOperationException(\"THE WAR IS OVER\");\n\n        protected override (WarState nextState, string message) AttackWithNavy(int attackSize) =>\n            throw new InvalidOperationException(\"THE WAR IS OVER\");\n\n        protected override (WarState nextState, string message) AttackWithAirForce(int attackSize) =>\n            throw new InvalidOperationException(\"THE WAR IS OVER\");\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/Combat.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "28_Combat/csharp/Combat.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31321.278\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Combat\", \"Combat.csproj\", \"{F7CEEC00-CF2C-436C-883B-55A20C21AB93}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F7CEEC00-CF2C-436C-883B-55A20C21AB93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F7CEEC00-CF2C-436C-883B-55A20C21AB93}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F7CEEC00-CF2C-436C-883B-55A20C21AB93}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F7CEEC00-CF2C-436C-883B-55A20C21AB93}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1EBA7488-1DA6-4B0B-8234-F10A65E96BDB}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "28_Combat/csharp/Controller.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for interacting with the user.\n    /// </summary>\n    public class Controller\n    {\n        /// <summary>\n        /// Gets the player's initial armed forces distribution.\n        /// </summary>\n        /// <param name=\"computerForces\">\n        /// The computer's initial armed forces.\n        /// </param>\n        public static ArmedForces GetInitialForces(ArmedForces computerForces)\n        {\n            var playerForces = default(ArmedForces);\n\n            // BUG: This loop allows the player to assign negative values to\n            //  some branches, leading to strange results.\n            do\n            {\n                View.ShowDistributeForces();\n\n                View.PromptArmySize(computerForces.Army);\n                var army = InputInteger();\n\n                View.PromptNavySize(computerForces.Navy);\n                var navy = InputInteger();\n\n                View.PromptAirForceSize(computerForces.AirForce);\n                var airForce = InputInteger();\n\n                playerForces = new ArmedForces\n                {\n                    Army     = army,\n                    Navy     = navy,\n                    AirForce = airForce\n                };\n            }\n            while (playerForces.TotalTroops > computerForces.TotalTroops);\n\n            return playerForces;\n        }\n\n        /// <summary>\n        /// Gets the military branch for the user's next attack.\n        /// </summary>\n        public static MilitaryBranch GetAttackBranch(WarState state, bool isFirstTurn)\n        {\n            if (isFirstTurn)\n                View.PromptFirstAttackBranch();\n            else\n                View.PromptNextAttackBranch(state.ComputerForces, state.PlayerForces);\n\n            // If the user entered an invalid branch number in the original\n            // game, the code fell through to the army case.  We'll preserve\n            // that behaviour here.\n            return Console.ReadLine() switch\n            {\n                \"2\" => MilitaryBranch.Navy,\n                \"3\" => MilitaryBranch.AirForce,\n                _   => MilitaryBranch.Army\n            };\n        }\n\n        /// <summary>\n        /// Gets a valid attack size from the player for the given branch\n        /// of the armed forces.\n        /// </summary>\n        /// <param name=\"troopsAvailable\">\n        /// The number of troops available.\n        /// </param>\n        public static int GetAttackSize(int troopsAvailable)\n        {\n            var attackSize = 0;\n\n            do\n            {\n                View.PromptAttackSize();\n                attackSize = InputInteger();\n            }\n            while (attackSize < 0 || attackSize > troopsAvailable);\n\n            return attackSize;\n        }\n\n        /// <summary>\n        /// Gets an integer value from the user.\n        /// </summary>\n        public static int InputInteger()\n        {\n            var value = default(int);\n\n            while (!Int32.TryParse(Console.ReadLine(), out value))\n                View.PromptValidInteger();\n\n            return value;\n        }\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/FinalCampaign.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Represents the state of the game during the final campaign of the war.\n    /// </summary>\n    public sealed class FinalCampaign : WarState\n    {\n        /// <summary>\n        /// Initializes a new instance of the FinalCampaign class.\n        /// </summary>\n        /// <param name=\"computerForces\">\n        /// The computer's forces.\n        /// </param>\n        /// <param name=\"playerForces\">\n        /// The player's forces.\n        /// </param>\n        public FinalCampaign(ArmedForces computerForces, ArmedForces playerForces)\n            : base(computerForces, playerForces)\n        {\n        }\n\n        protected override (WarState nextState, string message) AttackWithArmy(int attackSize)\n        {\n            if (attackSize < ComputerForces.Army / 2)\n            {\n                return\n                (\n                    new Ceasefire(\n                        ComputerForces,\n                        PlayerForces with\n                        {\n                            Army = PlayerForces.Army - attackSize\n                        }),\n                    \"I WIPED OUT YOUR ATTACK!\"\n                );\n            }\n            else\n            {\n                return\n                (\n                    new Ceasefire(\n                        ComputerForces with\n                        {\n                            Army = 0\n                        },\n                        PlayerForces),\n                    \"YOU DESTROYED MY ARMY!\"\n                );\n            }\n        }\n\n        protected override (WarState nextState, string message) AttackWithNavy(int attackSize)\n        {\n            if (attackSize < ComputerForces.Navy / 2)\n            {\n                return\n                (\n                    new Ceasefire(\n                        ComputerForces,\n                        PlayerForces with\n                        {\n                            Army = PlayerForces.Army / 4,\n                            Navy = PlayerForces.Navy / 2\n                        }),\n                    \"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\\n\" +\n                    \"WIPED OUT YOUR UNGAURDED CAPITOL.\"\n                );\n            }\n            else\n            {\n                return\n                (\n                    new Ceasefire(\n                        ComputerForces with\n                        {\n                            AirForce = 2 * ComputerForces.AirForce / 3,\n                            Navy     = ComputerForces.Navy / 2\n                        },\n                        PlayerForces),\n                    \"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\\n\" +\n                    \"AND SUNK THREE BATTLESHIPS.\"\n                );\n            }\n        }\n\n        protected override (WarState nextState, string message) AttackWithAirForce(int attackSize)\n        {\n            // BUG? Usually, larger attacks lead to better outcomes.\n            //  It seems odd that the logic is suddenly reversed here,\n            //  but this could be intentional.\n            if (attackSize > ComputerForces.AirForce / 2)\n            {\n                return\n                (\n                    new Ceasefire(\n                        ComputerForces,\n                        PlayerForces with\n                        {\n                            Army     = PlayerForces.Army  / 3,\n                            Navy     = PlayerForces.Navy / 3,\n                            AirForce = PlayerForces.AirForce / 3\n                        }),\n                    \"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\\n\" +\n                    \"YOUR COUNTRY IN SHAMBLES.\"\n                );\n            }\n            else\n            {\n                return\n                (\n                    new Ceasefire(\n                        ComputerForces,\n                        PlayerForces,\n                        absoluteVictory: true),\n                    \"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\\n\" +\n                    \"MY COUNTRY FELL APART.\"\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/InitialCampaign.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Represents the state of the game during the initial campaign of the war.\n    /// </summary>\n    public sealed class InitialCampaign : WarState\n    {\n        /// <summary>\n        /// Initializes a new instance of the InitialCampaign class.\n        /// </summary>\n        /// <param name=\"computerForces\">\n        /// The computer's forces.\n        /// </param>\n        /// <param name=\"playerForces\">\n        /// The player's forces.\n        /// </param>\n        public InitialCampaign(ArmedForces computerForces, ArmedForces playerForces)\n            : base(computerForces, playerForces)\n        {\n        }\n\n        protected override (WarState nextState, string message) AttackWithArmy(int attackSize)\n        {\n            // BUG: Why are we comparing attack size to the size of our own\n            //   military?  This leads to some truly absurd results if our\n            //   army is tiny.\n            if (attackSize < PlayerForces.Army / 3)\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces,\n                        PlayerForces with\n                        {\n                            Army = PlayerForces.Army - attackSize\n                        }),\n                    $\"YOU LOST {attackSize} MEN FROM YOUR ARMY.\"\n                );\n            }\n            else\n            if (attackSize < 2 * PlayerForces.Army / 3)\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces with\n                        {\n                            // BUG: Clearly not what we claim below...\n                            Army = 0\n                        },\n                        PlayerForces with\n                        {\n                            Army = PlayerForces.Army - attackSize / 3\n                        }),\n                    $\"YOU LOST {attackSize / 3} MEN, BUT I LOST {2 * ComputerForces.Army / 3}\"\n                );\n            }\n            else\n            {\n                // BUG? This is identical to the third outcome when attacking\n                //  with the navy.  It seems unlikely that this was the\n                //  intent.  Probably line 115 in the original source was\n                //  supposed to say \"GOTO 170\" instead of \"GOTO 270\".\n                //  (Line 170 is conspicuously absent.)\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces with\n                        {\n                            Navy = 2 * ComputerForces.Navy / 3\n                        },\n                        PlayerForces with\n                        {\n                            Army     = PlayerForces.Army / 3,\n                            AirForce = PlayerForces.AirForce / 3\n                        }),\n                    \"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\\n\" +\n                    \"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\"\n                );\n            }\n        }\n\n        protected override (WarState nextState, string message) AttackWithNavy(int attackSize)\n        {\n            if (attackSize < ComputerForces.Navy / 3)\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces,\n                        PlayerForces with\n                        {\n                            Navy = PlayerForces.Navy - attackSize\n                        }),\n                    \"YOUR ATTACK WAS STOPPED!\"\n                );\n            }\n            else\n            if (attackSize < 2 * ComputerForces.Navy / 3)\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces with\n                        {\n                            Navy = ComputerForces.Navy / 3\n                        },\n                        PlayerForces),\n                    $\"YOU DESTROYED {2 * ComputerForces.Navy / 3} OF MY ARMY.\"\n                );\n            }\n            else\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces with\n                        {\n                            Navy = 2 * ComputerForces.Navy / 3\n                        },\n                        PlayerForces with\n                        {\n                            Army     = PlayerForces.Army / 3,\n                            AirForce = PlayerForces.AirForce / 3\n                        }),\n                    \"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\\n\" +\n                    \"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\"\n                );\n            }\n        }\n\n        protected override (WarState nextState, string message) AttackWithAirForce(int attackSize)\n        {\n            // BUG: Why are we comparing the attack size to the size of\n            //  our own air force?  Surely we meant to compare to the\n            //  computer's air force.\n            if (attackSize < PlayerForces.AirForce / 3)\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces,\n                        PlayerForces with\n                        {\n                            AirForce = PlayerForces.AirForce - attackSize\n                        }),\n                    \"YOUR ATTACK WAS WIPED OUT.\"\n                );\n            }\n            else\n            if (attackSize < 2 * PlayerForces.AirForce / 3)\n            {\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces with\n                        {\n                            Army     = 2 * ComputerForces.Army / 3,\n                            Navy     = ComputerForces.Navy / 3,\n                            AirForce = ComputerForces.AirForce / 3\n                        },\n                        PlayerForces),\n                    \"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\"\n                );\n            }\n            else\n            {\n\n                return\n                (\n                    new FinalCampaign(\n                        ComputerForces with\n                        {\n                            Army = 2 * ComputerForces.Army / 3\n                        },\n                        PlayerForces with\n                        {\n                            Army = PlayerForces.Army / 4,\n                            Navy = PlayerForces.Navy / 3\n                        }),\n                    \"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\" +\n                    \"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\"\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/MilitaryBranch.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different branches of the military.\n    /// </summary>\n    public enum MilitaryBranch\n    {\n        Army,\n        Navy,\n        AirForce\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/Program.cs",
    "content": "﻿namespace Game\n{\n    class Program\n    {\n        static void Main()\n        {\n            View.ShowBanner();\n            View.ShowInstructions();\n\n            var computerForces = new ArmedForces { Army = 30000, Navy = 20000, AirForce = 22000 };\n            var playerForces   = Controller.GetInitialForces(computerForces);\n\n            var state = (WarState) new InitialCampaign(computerForces, playerForces);\n            var isFirstTurn = true;\n\n            while (!state.FinalOutcome.HasValue)\n            {\n                var branch = Controller.GetAttackBranch(state, isFirstTurn);\n                var attackSize = Controller.GetAttackSize(state.PlayerForces[branch]);\n\n                var (nextState, message) = state.LaunchAttack(branch, attackSize);\n                View.ShowMessage(message);\n\n                state = nextState;\n                isFirstTurn = false;\n            }\n\n            View.ShowResult(state);\n        }\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\nThe original BASIC code has a surprising number of bugs for such a small program.\nFor the sake of preserving the original behaviour, I've left them in place and\ncommented the ones I noticed.\n"
  },
  {
    "path": "28_Combat/csharp/View.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for displaying information to the user.\n    /// </summary>\n    public static class View\n    {\n        public static void ShowBanner()\n        {\n            Console.WriteLine(\"                                 COMBAT\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        }\n\n        public static void ShowInstructions()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"I AM AT WAR WITH YOU.\");\n            Console.WriteLine(\"WE HAVE 72000 SOLDIERS APIECE.\");\n        }\n\n        public static void ShowDistributeForces()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"DISTRIBUTE YOUR FORCES.\");\n            Console.WriteLine(\"\\tME\\t  YOU\");\n        }\n\n        public static void ShowMessage(string message)\n        {\n            Console.WriteLine(message);\n        }\n\n        public static void ShowResult(WarState finalState)\n        {\n            if (!finalState.IsAbsoluteVictory)\n            {\n                Console.WriteLine();\n                Console.WriteLine(\"FROM THE RESULTS OF BOTH OF YOUR ATTACKS,\");\n            }\n\n            switch (finalState.FinalOutcome)\n            {\n            case WarResult.ComputerVictory:\n                Console.WriteLine(\"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\");\n                Console.WriteLine(\"RIGHT FOR PLAYING THIS STUPID GAME!!!\");\n                break;\n            case WarResult.PlayerVictory:\n                Console.WriteLine(\"YOU WON, OH! SHUCKS!!!!\");\n                break;\n            case WarResult.PeaceTreaty:\n                Console.WriteLine(\"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\");\n                Console.WriteLine(\"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\");\n                break;\n            }\n        }\n\n        public static void PromptArmySize(int computerArmySize)\n        {\n            Console.Write($\"ARMY\\t{computerArmySize}\\t? \");\n        }\n\n        public static void PromptNavySize(int computerNavySize)\n        {\n            Console.Write($\"NAVY\\t{computerNavySize}\\t? \");\n        }\n\n        public static void PromptAirForceSize(int computerAirForceSize)\n        {\n            Console.Write($\"A. F.\\t{computerAirForceSize}\\t? \");\n        }\n\n        public static void PromptFirstAttackBranch()\n        {\n            Console.WriteLine(\"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\");\n            Console.WriteLine(\"AND (3) FOR AIR FORCE.\");\n            Console.Write(\"? \");\n        }\n\n        public static void PromptNextAttackBranch(ArmedForces computerForces, ArmedForces playerForces)\n        {\n            // BUG: More of a nit-pick really, but the order of columns in the\n            //  table is reversed from what we showed when distributing troops.\n            //  The tables should be consistent.\n            Console.WriteLine();\n            Console.WriteLine(\"\\tYOU\\tME\");\n            Console.WriteLine($\"ARMY\\t{playerForces.Army}\\t{computerForces.Army}\");\n            Console.WriteLine($\"NAVY\\t{playerForces.Navy}\\t{computerForces.Navy}\");\n            Console.WriteLine($\"A. F.\\t{playerForces.AirForce}\\t{computerForces.AirForce}\");\n\n            Console.WriteLine(\"WHAT IS YOUR NEXT MOVE?\");\n            Console.WriteLine(\"ARMY=1  NAVY=2  AIR FORCE=3\");\n            Console.Write(\"? \");\n        }\n\n        public static void PromptAttackSize()\n        {\n            Console.WriteLine(\"HOW MANY MEN\");\n            Console.Write(\"? \");\n        }\n\n        public static void PromptValidInteger()\n        {\n            Console.WriteLine(\"ENTER A VALID INTEGER VALUE\");\n        }\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/WarResult.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the possible outcomes of the war.\n    /// </summary>\n    public enum WarResult\n    {\n        ComputerVictory,\n\n        PlayerVictory,\n\n        PeaceTreaty\n    }\n}\n"
  },
  {
    "path": "28_Combat/csharp/WarState.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Represents the current state of the war.\n    /// </summary>\n    public abstract class WarState\n    {\n        /// <summary>\n        /// Gets the computer's armed forces.\n        /// </summary>\n        public ArmedForces ComputerForces { get; }\n\n        /// <summary>\n        /// Gets the player's armed forces.\n        /// </summary>\n        public ArmedForces PlayerForces { get; }\n\n        /// <summary>\n        /// Gets a flag indicating whether this state represents absolute\n        /// victory for the player.\n        /// </summary>\n        public virtual bool IsAbsoluteVictory => false;\n\n        /// <summary>\n        /// Gets the final outcome of the war.\n        /// </summary>\n        /// <remarks>\n        /// If the war is ongoing, this property will be null.\n        /// </remarks>\n        public virtual WarResult? FinalOutcome => null;\n\n        /// <summary>\n        /// Initializes a new instance of the state class.\n        /// </summary>\n        /// <param name=\"computerForces\">\n        /// The computer's forces.\n        /// </param>\n        /// <param name=\"playerForces\">\n        /// The player's forces.\n        /// </param>\n        public WarState(ArmedForces computerForces, ArmedForces playerForces) =>\n            (ComputerForces, PlayerForces) = (computerForces, playerForces);\n\n        /// <summary>\n        /// Launches an attack.\n        /// </summary>\n        /// <param name=\"branch\">\n        /// The branch of the military to use for the attack.\n        /// </param>\n        /// <param name=\"attackSize\">\n        /// The number of men and women to use for the attack.\n        /// </param>\n        /// <returns>\n        /// The new state of the game resulting from the attack and a message\n        /// describing the result.\n        /// </returns>\n        public (WarState nextState, string message) LaunchAttack(MilitaryBranch branch, int attackSize) =>\n            branch switch\n            {\n                MilitaryBranch.Army     => AttackWithArmy(attackSize),\n                MilitaryBranch.Navy     => AttackWithNavy(attackSize),\n                MilitaryBranch.AirForce => AttackWithAirForce(attackSize),\n                _               => throw new ArgumentException(\"INVALID BRANCH\")\n            };\n\n        /// <summary>\n        /// Conducts an attack with the player's army.\n        /// </summary>\n        /// <param name=\"attackSize\">\n        /// The number of men and women used in the attack.\n        /// </param>\n        /// <returns>\n        /// The new game state and a message describing the result.\n        /// </returns>\n        protected abstract (WarState nextState, string message) AttackWithArmy(int attackSize);\n\n        /// <summary>\n        /// Conducts an attack with the player's navy.\n        /// </summary>\n        /// <param name=\"attackSize\">\n        /// The number of men and women used in the attack.\n        /// </param>\n        /// <returns>\n        /// The new game state and a message describing the result.\n        /// </returns>\n        protected abstract (WarState nextState, string message) AttackWithNavy(int attackSize);\n\n        /// <summary>\n        /// Conducts an attack with the player's air force.\n        /// </summary>\n        /// <param name=\"attackSize\">\n        /// The number of men and women used in the attack.\n        /// </param>\n        /// <returns>\n        /// The new game state and a message describing the result.\n        /// </returns>\n        protected abstract (WarState nextState, string message) AttackWithAirForce(int attackSize);\n    }\n}\n"
  },
  {
    "path": "28_Combat/java/Combat.java",
    "content": "import java.lang.Math;\nimport java.util.Scanner;\n\n/**\n * Game of Combat\n * <p>\n * Based on the BASIC game of Combat here\n * https://github.com/coding-horror/basic-computer-games/blob/main/28%20Combat/combat.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Combat {\n\n  private static final int MAX_UNITS = 72000;  // Maximum number of total units per player\n\n  private final Scanner scan;  // For user input\n\n  private boolean planeCrashWin = false;\n\n  private int usrArmy = 0;      // Number of user Army units\n  private int usrNavy = 0;      // Number of user Navy units\n  private int usrAir = 0;       // Number of user Air Force units\n  private int cpuArmy = 30000;  // Number of cpu Army units\n  private int cpuNavy = 20000;  // Number of cpu Navy units\n  private int cpuAir = 22000;   // Number of cpu Air Force units\n\n  public Combat() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Combat\n\n  public void play() {\n\n    showIntro();\n    getForces();\n    attackFirst();\n    attackSecond();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"COMBAT\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n    System.out.println(\"I AM AT WAR WITH YOU.\");\n    System.out.println(\"WE HAVE \" + MAX_UNITS + \" SOLDIERS APIECE.\\n\");\n\n  }  // End of method showIntro\n\n  private void getForces() {\n\n    do {\n      System.out.println(\"DISTRIBUTE YOUR FORCES.\");\n      System.out.println(\"              ME              YOU\");\n      System.out.print(\"ARMY           \" + cpuArmy + \"        ? \");\n      usrArmy = scan.nextInt();\n      System.out.print(\"NAVY           \" + cpuNavy + \"        ? \");\n      usrNavy = scan.nextInt();\n      System.out.print(\"A. F.          \" + cpuAir + \"        ? \");\n      usrAir = scan.nextInt();\n\n    } while ((usrArmy + usrNavy + usrAir) > MAX_UNITS);  // Avoid exceeding the maximum number of total units\n\n  }  // End of method getForces\n\n  private void attackFirst() {\n\n    int numUnits = 0;\n    int unitType = 0;\n\n    do {\n      System.out.println(\"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\");\n      System.out.println(\"AND (3) FOR AIR FORCE.\");\n      System.out.print(\"? \");\n      unitType = scan.nextInt();\n    } while ((unitType < 1) || (unitType > 3));  // Avoid out-of-range values\n\n    do {\n      System.out.println(\"HOW MANY MEN\");\n      System.out.print(\"? \");\n      numUnits = scan.nextInt();\n    } while ((numUnits < 0) ||                // Avoid negative values\n             ((unitType == 1) && (numUnits > usrArmy)) ||  // Avoid exceeding the number of available Army units\n             ((unitType == 2) && (numUnits > usrNavy)) ||  // Avoid exceeding the number of available Navy units\n             ((unitType == 3) && (numUnits > usrAir)));    // Avoid exceeding the number of available Air Force units\n\n    // Begin handling deployment type\n    switch (unitType) {\n      case 1:  // Army deployed\n\n        if (numUnits < (usrArmy / 3.0)) {  // User deployed less than one-third of their Army units\n          System.out.println(\"YOU LOST \" + numUnits + \" MEN FROM YOUR ARMY.\");\n          usrArmy = usrArmy - numUnits;\n        }\n        else if (numUnits < (2.0 * usrArmy / 3.0)) {  // User deployed less than two-thirds of their Army units\n          System.out.println(\"YOU LOST \" + (int) Math.floor(numUnits / 3.0) + \" MEN, BUT I LOST \" + (int) Math.floor(2.0 * cpuArmy / 3.0));\n          usrArmy = (int) Math.floor(usrArmy - numUnits / 3.0);\n          cpuArmy = 0;\n        }\n        else {  // User deployed two-thirds or more of their Army units\n          System.out.println(\"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\");\n          System.out.println(\"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\");\n          usrArmy = (int) Math.floor(usrArmy / 3.0);\n          usrAir = (int) Math.floor(usrAir / 3.0);\n          cpuNavy = (int) Math.floor(2.0 * cpuNavy / 3.0);\n        }\n        break;\n\n      case 2:  // Navy deployed\n\n        if (numUnits < (cpuNavy / 3.0)) {  // User deployed less than one-third relative to cpu Navy units\n          System.out.println(\"YOUR ATTACK WAS STOPPED!\");\n          usrNavy = usrNavy - numUnits;\n        }\n        else if (numUnits < (2.0 * cpuNavy / 3.0)) {  // User deployed less than two-thirds relative to cpu Navy units\n          System.out.println(\"YOU DESTROYED \" + (int) Math.floor(2.0 * cpuNavy / 3.0) + \" OF MY ARMY.\");\n          cpuNavy = (int) Math.floor(cpuNavy / 3.0);\n        }\n        else {  // User deployed two-thirds or more relative to cpu Navy units\n          System.out.println(\"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\");\n          System.out.println(\"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\");\n          usrArmy = (int) Math.floor(usrArmy / 3.0);\n          usrAir = (int) Math.floor(usrAir / 3.0);\n          cpuNavy = (int) Math.floor(2.0 * cpuNavy / 3.0);\n        }\n        break;\n\n      case 3:  // Air Force deployed\n\n        if (numUnits < (usrAir / 3.0)) {  // User deployed less than one-third of their Air Force units\n          System.out.println(\"YOUR ATTACK WAS WIPED OUT.\");\n          usrAir = usrAir - numUnits;\n        }\n        else if (numUnits < (2.0 * usrAir / 3.0)) {  // User deployed less than two-thirds of their Air Force units\n          System.out.println(\"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\");\n          cpuArmy = (int) Math.floor(2.0 * cpuArmy / 3.0);\n          cpuNavy = (int) Math.floor(cpuNavy / 3.0);\n          cpuAir = (int) Math.floor(cpuAir / 3.0);\n        }\n        else {  // User deployed two-thirds or more of their Air Force units\n          System.out.println(\"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\");\n          System.out.println(\"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\");\n          usrArmy = (int) Math.floor(usrArmy / 4.0);\n          usrNavy = (int) Math.floor(usrNavy / 3.0);\n          cpuArmy = (int) Math.floor(2.0 * cpuArmy / 3.0);\n        }\n        break;\n\n    }  // End handling deployment type\n\n  }  // End of method attackFirst\n\n  private void attackSecond() {\n\n    int numUnits = 0;\n    int unitType = 0;\n\n    System.out.println(\"\");\n    System.out.println(\"              YOU           ME\");\n    System.out.print(\"ARMY           \");\n    System.out.format(\"%-14s%s\\n\", usrArmy, cpuArmy);\n    System.out.print(\"NAVY           \");\n    System.out.format(\"%-14s%s\\n\", usrNavy, cpuNavy);\n    System.out.print(\"A. F.          \");\n    System.out.format(\"%-14s%s\\n\", usrAir, cpuAir);\n\n    do {\n      System.out.println(\"WHAT IS YOUR NEXT MOVE?\");\n      System.out.println(\"ARMY=1  NAVY=2  AIR FORCE=3\");\n      System.out.print(\"? \");\n      unitType = scan.nextInt();\n    } while ((unitType < 1) || (unitType > 3));  // Avoid out-of-range values\n\n    do {\n      System.out.println(\"HOW MANY MEN\");\n      System.out.print(\"? \");\n      numUnits = scan.nextInt();\n    } while ((numUnits < 0) ||                // Avoid negative values\n             ((unitType == 1) && (numUnits > usrArmy)) ||  // Avoid exceeding the number of available Army units\n             ((unitType == 2) && (numUnits > usrNavy)) ||  // Avoid exceeding the number of available Navy units\n             ((unitType == 3) && (numUnits > usrAir)));    // Avoid exceeding the number of available Air Force units\n\n    // Begin handling deployment type\n    switch (unitType) {\n      case 1:  // Army deployed\n\n        if (numUnits < (cpuArmy / 2.0)) {  // User deployed less than half relative to cpu Army units\n          System.out.println(\"I WIPED OUT YOUR ATTACK!\");\n          usrArmy = usrArmy - numUnits;\n        }\n        else {  // User deployed half or more relative to cpu Army units\n          System.out.println(\"YOU DESTROYED MY ARMY!\");\n          cpuArmy = 0;\n        }\n        break;\n\n      case 2:  // Navy deployed\n\n        if (numUnits < (cpuNavy / 2.0)) {  // User deployed less than half relative to cpu Navy units\n          System.out.println(\"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\");\n          System.out.println(\"WIPED OUT YOUR UNGUARDED CAPITOL.\");\n          usrArmy = (int) Math.floor(usrArmy / 4.0);\n          usrNavy = (int) Math.floor(usrNavy / 2.0);\n        }\n        else { // User deployed half or more relative to cpu Navy units\n          System.out.println(\"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\");\n          System.out.println(\"AND SUNK THREE BATTLESHIPS.\");\n          cpuAir = (int) Math.floor(2.0 * cpuAir / 3.0);\n          cpuNavy = (int) Math.floor(cpuNavy / 2.0);\n        }\n        break;\n\n      case 3:  // Air Force deployed\n\n        if (numUnits > (cpuAir / 2.0)) {  // User deployed more than half relative to cpu Air Force units\n          System.out.println(\"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\");\n          System.out.println(\"YOUR COUNTRY IN SHAMBLES.\");\n          usrArmy = (int) Math.floor(usrArmy / 3.0);\n          usrNavy = (int) Math.floor(usrNavy / 3.0);\n          usrAir = (int) Math.floor(usrAir / 3.0);\n        }\n        else {  // User deployed half or less relative to cpu Air Force units\n          System.out.println(\"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\");\n          System.out.println(\"MY COUNTRY FELL APART.\");\n          planeCrashWin = true;\n        }\n        break;\n\n    }  // End handling deployment type\n\n    // Suppress message for plane crashes\n    if (planeCrashWin == false) {\n      System.out.println(\"\");\n      System.out.println(\"FROM THE RESULTS OF BOTH OF YOUR ATTACKS,\");\n    }\n\n    // User wins\n    if ((planeCrashWin == true) ||\n        ((usrArmy + usrNavy + usrAir) > ((int) Math.floor((3.0 / 2.0 * (cpuArmy + cpuNavy + cpuAir)))))) {\n      System.out.println(\"YOU WON, OH! SHUCKS!!!!\");\n    }\n    // User loses\n    else if ((usrArmy + usrNavy + usrAir) < ((int) Math.floor((2.0 / 3.0 * (cpuArmy + cpuNavy + cpuAir))))) {  // User loss\n      System.out.println(\"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\");\n      System.out.println(\"RIGHT FOR PLAYING THIS STUPID GAME!!!\");\n    }\n    // Peaceful outcome\n    else {\n      System.out.println(\"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\");\n      System.out.println(\"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\");\n    }\n\n  }  // End of method attackSecond\n\n  public static void main(String[] args) {\n\n    Combat combat = new Combat();\n    combat.play();\n\n  }  // End of method main\n\n}  // End of class Combat\n"
  },
  {
    "path": "28_Combat/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "28_Combat/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "28_Combat/javascript/combat.html",
    "content": "<html>\n<head>\n<title>COMBAT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"combat.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "28_Combat/javascript/combat.js",
    "content": "// COMBAT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"COMBAT\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"I AM AT WAR WITH YOU.\\n\");\n    print(\"WE HAVE 72000 SOLDIERS APIECE.\\n\");\n    do {\n        print(\"\\n\");\n        print(\"DISTRIBUTE YOUR FORCES.\\n\");\n        print(\"\\tME\\t  YOU\\n\");\n        print(\"ARMY\\t30000\\t\");\n        a = parseInt(await input());\n        print(\"NAVY\\t20000\\t\");\n        b = parseInt(await input());\n        print(\"A. F.\\t22000\\t\");\n        c = parseInt(await input());\n    } while (a + b + c > 72000) ;\n    d = 30000;\n    e = 20000;\n    f = 22000;\n    print(\"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\\n\");\n    print(\"AND (3) FOR AIR FORCE.\\n\");\n    y = parseInt(await input());\n    do {\n        print(\"HOW MANY MEN\\n\");\n        x = parseInt(await input());\n    } while ((y == 1 && x > a) || (y == 2 && x > b) || (y == 3 && x > c)) ;\n    switch (y) {\n        case 1:\n            if (x < a / 3.0) {\n                print(\"YOU LOST \" + x + \" MEN FROM YOUR ARMY.\\n\");\n                a -= x;\n                break;\n            }\n            if (x < 2 * a / 3) {\n                print(\"YOU LOST \" + Math.floor(x / 3.0) + \" MEN, BUT I LOST \" + Math.floor(2 * d / 3.0) + \"\\n\");\n                a = Math.floor(a - x / 3.0);\n                d = 0;\n                break;\n            }\n            print(\"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\\n\");\n            print(\"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\\n\");\n            a = Math.floor(a / 3.0);\n            c = Math.floor(c / 3.0);\n            e = Math.floor(2 * e / 3.0);\n            break;\n        case 2:\n            if (x < e / 3) {\n                print(\"YOUR ATTACK WAS STOPPED!\\n\");\n                b -= x;\n                break;\n            }\n            if (x < 2 * e / 3) {\n                print(\"YOU DESTROYED \" + Math.floor(2 * e / 3.0) + \" OF MY ARMY.\\n\");\n                e = Math.floor(e / 3.0);\n                break;\n            }\n            print(\"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\\n\");\n            print(\"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\\n\");\n            a = Math.floor(a / 3.0);\n            c = Math.floor(c / 3.0);\n            e = Math.floor(2 * e / 3.0);\n            break;\n        case 3:\n            if (x < c / 3.0) {\n                print(\"YOUR ATTACK WAS WIPED OUT.\\n\");\n                c -= x;\n                break;\n            }\n            if (x < 2 * c / 3) {\n                print(\"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\\n\");\n                d = Math.floor(2 * d / 3.0);\n                e = Math.floor(e / 3.0);\n                f = Math.floor(f / 3.0);\n                break;\n            }\n            print(\"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\\n\");\n            print(\"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\\n\");\n            a = Math.floor(a / 4);\n            b = Math.floor(b / 3.0);\n            d = Math.floor(2 * d / 3.0);\n            break;\n    }\n    print(\"\\n\");\n    print(\"\\tYOU\\tME\\n\");\n    print(\"ARMY\\t\" + a + \"\\t\" + d + \"\\n\");\n    print(\"NAVY\\t\" + b + \"\\t\" + e + \"\\n\");\n    print(\"A. F.\\t\" + c + \"\\t\" + f + \"\\n\");\n    print(\"WHAT IS YOUR NEXT MOVE?\\n\");\n    print(\"ARMY=1  NAVY=2  AIR FORCE=3\\n\");\n    g = parseInt(await input());\n    do {\n        print(\"HOW MANY MEN\\n\");\n        t = parseInt(await input());\n    } while (t < 0 || (g == 1 && t > a) || (g == 2 && t > b) || (g == 3 && t > c)) ;\n    crashed = false;\n    switch (g) {\n        case 1:\n            if (t < d / 2) {\n                print(\"I WIPED OUT YOUR ATTACK!\\n\");\n                a -= t;\n            } else {\n                print(\"YOU DESTROYED MY ARMY!\\n\");\n                d = 0;\n            }\n            break;\n        case 2:\n            if (t < e / 2) {\n                print(\"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\\n\");\n                print(\"WIPED OUT YOUR UNGUARDED CAPITOL.\\n\");\n                a /= 4.0;\n                b /= 2.0;\n                break;\n            }\n            print(\"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES.\\n\");\n            print(\"AND SUNK THREE BATTLESHIPS.\\n\");\n            f = 2 * f / 3;\n            e /= 2;\n            break;\n        case 3:\n            if (t > f / 2) {\n                print(\"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\\n\");\n                print(\"YOUR COUNTRY IN SHAMBLES.\\n\");\n                a /= 3.0;\n                b /= 3.0;\n                c /= 3.0;\n                break;\n            }\n            print(\"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\\n\");\n            print(\"MY COUNTRY FELL APART.\\n\");\n            crashed = true;\n            won = 1;\n            break;\n    }\n    if (!crashed) {\n        won = 0;\n        print(\"\\n\");\n        print(\"FROM THE RESULTS OF BOTH OF YOUR ATTACKS,\\n\");\n        if (a + b + c > 3.0 / 2.0 * (d + e + f))\n            won = 1;\n        if (a + b + c < 2.0 / 3.0 * (d + e + f))\n            won = 2;\n    }\n    if (won == 0) {\n        print(\"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\\n\");\n        print(\"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\\n\");\n    } else if (won == 1) {\n        print(\"YOU WON, OH! SHUCKS!!!!\\n\");\n    } else if (won == 2) {\n        print(\"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\\n\");\n        print(\"RIGHT FOR PLAYING THIS STUPID GAME!!!\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "28_Combat/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "28_Combat/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "28_Combat/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "28_Combat/perl/combat.pl",
    "content": "#!/usr/bin/perl\n\n# Combat program in Perl\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $User_army;\nmy $User_navy;\nmy $User_AF;\nmy $Comp_army = 30000;\nmy $Comp_navy = 20000;\nmy $Comp_AF = 22000;\nmy $Attack_type;\nmy $Attack_num;\n\nprint \"\\n\";\nprint \" \" x 33, \"COMBAT\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\nprint \"I AM AT WAR WITH YOU.\\nWE HAVE 72000 SOLDIERS APIECE.\\n\\n\";\n\ndo {\n    print \"DISTRIBUTE YOUR FORCES.\\n\";\n    print \"\\tME\\t  YOU\\n\";\n    print \"ARMY\\t$Comp_army\\t\";\n    chomp($User_army = <>);\n    print \"NAVY\\t$Comp_navy\\t\";\n    chomp($User_navy = <>);\n    print \"A. F.\\t$Comp_AF\\t\";\n    chomp($User_AF = <>);\n} while ($User_army + $User_navy + $User_AF > 72000);\n\ndo {\n    print \"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\\n\";\n    print \"AND (3) FOR AIR FORCE.\\n\";\n    chomp($Attack_num = <>);\n} while ($Attack_type < 1 && $Attack_type > 3);\ndo {\n    print \"HOW MANY MEN\\n\";\n    chomp($Attack_type = <>);\n} while ($Attack_type < 0\n         || ($Attack_num == 1 && $Attack_type > $User_army)\n         || ($Attack_num == 2 && $Attack_type > $User_navy)\n         || ($Attack_num == 3 && $Attack_type > $User_AF));\n\nif ($Attack_num == 1)\n{\n    if ($Attack_type<$User_army/3)\n    {\n        print \"YOU LOST $Attack_type MEN FROM YOUR ARMY.\\n\";\n        $User_army = int($User_army-$Attack_type);\n    }\n    if ($Attack_type<2*$User_army/3)\n    {\n        print \"YOU LOST \", int($Attack_type/3), \" MEN, BUT I LOST \", int(2*$Comp_army/3), \"\\n\";\n        $User_army = int($User_army-$Attack_type/3);\n        $Comp_army = int(2*$Comp_army/3);\n    }\n    else\n    {\n        s270();\n    }\n}\nelsif ($Attack_num == 2)\n{\n    if ($Attack_type < $Comp_navy/3)\n    {\n        print \"YOUR ATTACK WAS STOPPED!\\n\";\n        $User_navy = int($User_navy-$Attack_type);\n    }\n    if ($Attack_type < 2*$Comp_navy/3)\n    {\n        print \"YOU DESTROYED \", int(2*$Comp_navy/3), \" OF MY ARMY.\\n\";\n        $Comp_navy = int(2*$Comp_navy/3);\n    }\n    else\n    {\n        s270();\n    }\n}\nelse # $Attack_num == 3\n{\n    if ($Attack_type < $User_AF/3)\n    {\n        print \"YOUR ATTACK WAS WIPED OUT.\\n\";\n        $User_AF = int($User_AF-$Attack_type);\n    }\n    if ($Attack_type < 2*$User_AF/3)\n    {\n        print \"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\\n\";\n        $Comp_army = int(2*$Comp_army/3);\n        $Comp_navy = int($Comp_navy/3);\n        $Comp_AF = int($Comp_AF/3);\n    }\n    else\n    {\n        print \"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\\n\";\n        print \"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\\n\";\n        $User_army = int($User_army/4);\n        $User_navy = int($User_navy/3);\n        $User_AF = int(2*$User_AF/3);\n    }\n}\n\nprint \"\\n\\tYOU\\tME\\n\";\nprint \"ARMY\\t$User_army\\t$Comp_army\\n\";\nprint \"NAVY\\t$User_navy\\t$Comp_navy\\n\";\nprint \"A. F.\\t$User_AF\\t$Comp_AF\\n\";\ndo {\n    print \"WHAT IS YOUR NEXT MOVE?\\n\";\n    print \"ARMY=1  NAVY=2  AIR FORCE=3\\n\";\n    chomp($Attack_type = <>);\n} while ($Attack_type < 1 && $Attack_type > 3);\ndo {\n    print \"HOW MANY MEN\\n\";\n    chomp($Attack_num = <>);\n} while ($Attack_num < 0\n         || ($Attack_type == 1 && $Attack_num > $User_army)\n         || ($Attack_type == 2 && $Attack_num > $User_navy)\n         || ($Attack_type == 3 && $Attack_num > $User_AF));\n\nif ($Attack_num == 1)\n{\n    if ($Attack_num < $Comp_army/2)\n    {\n        print \"I WIPED OUT YOUR ATTACK!\\n\";\n        $User_army -= $Attack_num;\n    }\n    else\n    {\n        print \"YOU DESTROYED MY ARMY!\\n\";\n        $Comp_army = 0;\n    }\n}\nelsif ($Attack_num == 2)\n{\n    if ($Attack_num < $Comp_navy/2)\n    {\n        print \"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\\n\";\n        print \"WIPED OUT YOUR UNGAURDED CAPITOL.\\n\";\n        $User_army /= 4;\n        $User_navy /= 2;\n    }\n    else\n    {\n        print \"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\\n\";\n        print \"AND SUNK THREE BATTLESHIPS.\\n\";\n        $Comp_AF = 2*$Comp_AF/3;\n        $Comp_navy /= 2;\n    }\n}\nelse # $Attack_num == 3\n{\n    if ($Attack_num > $Comp_AF/2)\n    {\n        print \"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\\n\";\n        print \"YOUR COUNTRY IN SHAMBLES.\\n\";\n        $User_army /= 3;\n        $User_navy /= 3;\n        $User_AF /= 3;\n    }\n    else\n    {\n        print \"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\\n\";\n        print \"MY COUNTRY FELL APART.\\n\";\n        $Comp_army = $Comp_navy = $Comp_AF = 0;\n    }\n}\n\nprint \"\\nFROM THE RESULTS OF BOTH OF YOUR ATTACKS,\\n\";\nmy $total_user = $User_army+$User_navy+$User_AF;\nmy $total_comp = $Comp_army+$Comp_navy+$Comp_AF;\nif ($total_user > 3/2*($total_comp))\n{\n    print \"YOU WON, OH! SHUCKS!!!!\\n\";\n}\nelsif ($total_user < 2/3*($total_comp))\n{\n    print \"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\\n\";\n    print \"RIGHT FOR PLAYING THIS STUPID GAME!!!\\n\";\n}\nelse\n{\n    print \"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\\n\";\n    print \"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\\n\";\n}\nprint \"\\n\";\nexit(0);\n\n#######################################################\n\nsub s270\n{\n    print \"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\\n\";\n    print \"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\\n\";\n    $User_army = int($User_army/3);\n    $User_AF = int($User_AF/3);\n    $Comp_navy = int(2*$Comp_navy/3);\n}\n"
  },
  {
    "path": "28_Combat/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "28_Combat/python/combat.py",
    "content": "MAX_UNITS = 72000\nplane_crash_win = False\nusr_army = 0\nusr_navy = 0\nusr_air = 0\ncpu_army = 30000\ncpu_navy = 20000\ncpu_air = 22000\n\n\ndef show_intro() -> None:\n    global MAX_UNITS\n\n    print(\" \" * 32 + \"COMBAT\")\n    print(\" \" * 14 + \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n    print(\"I AM AT WAR WITH YOU.\")\n    print(f\"WE HAVE {str(MAX_UNITS)} SOLDIERS APIECE.\")\n\n\ndef get_forces() -> None:\n    global usr_army, usr_navy, usr_air\n\n    while True:\n        print(\"DISTRIBUTE YOUR FORCES.\")\n        print(\"              ME              YOU\")\n        print(f\"ARMY           {str(cpu_army)}        ? \", end=\"\")\n        usr_army = int(input())\n        print(f\"NAVY           {str(cpu_navy)}        ? \", end=\"\")\n        usr_navy = int(input())\n        print(f\"A. F.          {str(cpu_air)}        ? \", end=\"\")\n        usr_air = int(input())\n        if (usr_army + usr_navy + usr_air) <= MAX_UNITS:\n            break\n\n\ndef attack_first() -> None:\n    global usr_army, usr_navy, usr_air\n    global cpu_army, cpu_navy, cpu_air\n\n    unit_type = 0\n\n    while True:\n        print(\"YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\")\n        print(\"AND (3) FOR AIR FORCE.\")\n        print(\"?\", end=\" \")\n        unit_type = int(input())\n        if unit_type >= 1 and unit_type <= 3:\n            break\n\n    num_units = 0\n    while True:\n        print(\"HOW MANY MEN\")\n        print(\"?\", end=\" \")\n        num_units = int(input())\n        if (\n            num_units >= 0\n            and (unit_type != 1 or num_units <= usr_army)\n            and (unit_type != 2 or num_units <= usr_navy)\n            and (unit_type != 3 or num_units <= usr_air)\n        ):\n            break\n\n    if unit_type == 1:\n        if num_units < (usr_army / 3):\n            print(f\"YOU LOST {str(num_units)} MEN FROM YOUR ARMY.\")\n            usr_army = usr_army - num_units\n        elif num_units < (2 * usr_army / 3):\n            print(f\"YOU LOST {int(num_units / 3)} MEN, BUT I LOST {int(2 * cpu_army / 3)}\")\n            usr_army = int(usr_army - (num_units / 3))\n            cpu_army = 0\n        else:\n            print(\"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\")\n            print(\"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\")\n            usr_army = int(usr_army / 3)\n            usr_air = int(usr_air / 3)\n            cpu_navy = int(2 * cpu_navy / 3)\n    elif unit_type == 2:\n        if num_units < cpu_navy / 3:\n            print(\"YOUR ATTACK WAS STOPPED!\")\n            usr_navy = usr_navy - num_units\n        elif num_units < 2 * cpu_navy / 3:\n            print(f\"YOU DESTROYED {int(2 * cpu_navy / 3)} OF MY ARMY.\")\n            cpu_navy = int(cpu_navy / 3)\n        else:\n            print(\"YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\")\n            print(\"OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\")\n            usr_army = int(usr_army / 3)\n            usr_air = int(usr_air / 3)\n            cpu_navy = int(2 * cpu_navy / 3)\n    elif unit_type == 3:\n        if num_units < usr_air / 3:\n            print(\"YOUR ATTACK WAS WIPED OUT.\")\n            usr_air = usr_air - num_units\n        elif num_units < 2 * usr_air / 3:\n            print(\"WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\")\n            cpu_army = int(2 * cpu_army / 3)\n            cpu_navy = int(cpu_navy / 3)\n            cpu_air = int(cpu_air / 3)\n        else:\n            print(\"YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\")\n            print(\"TWO NAVY BASES AND BOMBED THREE ARMY BASES.\")\n            usr_army = int(usr_army / 4)\n            usr_navy = int(usr_navy / 3)\n            cpu_army = int(2 * cpu_army / 3)\n\n\ndef attack_second() -> None:\n    global usr_army, usr_navy, usr_air, cpu_army, cpu_navy, cpu_air\n    global plane_crash_win\n    unit_type = 0\n\n    print()\n    print(\"              YOU           ME\")\n    print(\"ARMY           \", end=\"\")\n    print(\"%-14s%s\\n\" % (usr_army, cpu_army), end=\"\")\n    print(\"NAVY           \", end=\"\")\n    print(\"%-14s%s\\n\" % (usr_navy, cpu_navy), end=\"\")\n    print(\"A. F.          \", end=\"\")\n    print(\"%-14s%s\\n\" % (usr_air, cpu_air), end=\"\")\n\n    while True:\n        print(\"WHAT IS YOUR NEXT MOVE?\")\n        print(\"ARMY=1  NAVY=2  AIR FORCE=3\")\n        print(\"? \", end=\"\")\n        unit_type = int(input())\n        if unit_type >= 1 and unit_type <= 3:\n            break\n\n    num_units = 0\n    while True:\n        print(\"HOW MANY MEN\")\n        print(\"? \", end=\"\")\n        num_units = int(input())\n        if (\n            num_units >= 0\n            and (unit_type != 1 or num_units <= usr_army)\n            and (unit_type != 2 or num_units <= usr_navy)\n            and (unit_type != 3 or num_units <= usr_air)\n        ):\n            break\n\n    if unit_type == 1:\n        if num_units < (cpu_army / 2):\n            print(\"I WIPED OUT YOUR ATTACK!\")\n            usr_army = usr_army - num_units\n        else:\n            print(\"YOU DESTROYED MY ARMY!\")\n            cpu_army = 0\n    elif unit_type == 2:\n        if num_units < (cpu_navy / 2):\n            print(\"I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\")\n            print(\"WIPED OUT YOUR UNGUARDED CAPITOL.\")\n            usr_army = int(usr_army / 4)\n            usr_navy = int(usr_navy / 2)\n        else:\n            print(\"YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\")\n            print(\"AND SUNK THREE BATTLESHIPS.\")\n            cpu_air = int(2 * cpu_air / 3)\n            cpu_navy = int(cpu_navy / 2)\n    elif unit_type == 3:\n        if num_units > (cpu_air / 2):\n            print(\"MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\")\n            print(\"YOUR COUNTRY IN SHAMBLES.\")\n            usr_army = int(usr_army / 3)\n            usr_navy = int(usr_navy / 3)\n            usr_air = int(usr_air / 3)\n        else:\n            print(\"ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\")\n            print(\"MY COUNTRY FELL APART.\")\n            plane_crash_win = True\n\n    if not plane_crash_win:\n        print()\n        print(\"FROM THE RESULTS OF BOTH OF YOUR ATTACKS,\")\n\n    if plane_crash_win or (\n        (usr_army + usr_navy + usr_air) > (int(3 / 2 * (cpu_army + cpu_navy + cpu_air)))\n    ):\n        print(\"YOU WON, OH! SHUCKS!!!!\")\n    elif (usr_army + usr_navy + usr_air) < int(2 / 3 * (cpu_army + cpu_navy + cpu_air)):\n        print(\"YOU LOST-I CONQUERED YOUR COUNTRY.  IT SERVES YOU\")\n        print(\"RIGHT FOR PLAYING THIS STUPID GAME!!!\")\n    else:\n        print(\"THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\")\n        print(\"RESPECTIVE COUNTRIES AND LIVE IN PEACE.\")\n\n\ndef main() -> None:\n    show_intro()\n    get_forces()\n    attack_first()\n    attack_second()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "28_Combat/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "28_Combat/vbnet/Combat.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Combat\", \"Combat.vbproj\", \"{B7C67E0E-1493-4957-9FD9-A384D038F024}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B7C67E0E-1493-4957-9FD9-A384D038F024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B7C67E0E-1493-4957-9FD9-A384D038F024}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B7C67E0E-1493-4957-9FD9-A384D038F024}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B7C67E0E-1493-4957-9FD9-A384D038F024}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "28_Combat/vbnet/Combat.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Combat</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "28_Combat/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "29_Craps/README.md",
    "content": "### Craps\n\nThis game simulates the game of craps played according to standard Nevada craps table rules. That is:\n1. A 7 or 11 on the first roll wins\n2. A 2, 3, or 12 on the first roll loses\n3. Any other number rolled becomes your “point.”\n    - You continue to roll, if you get your point, you win.\n    - If you roll a 7, you lose and the dice change hands when this happens.\n\nThis version of craps was modified by Steve North of Creative Computing. It is based on an original which appeared one day on a computer at DEC.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=52)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=67)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n    15 LET R=0\n\n`R` is a variable that tracks winnings and losings.  Unlike other games that\nstart out with a lump sum of cash to spend this game assumes the user has as\nmuch money as they want and we only track how much they lost or won.\n\n      21 LET T=1\n      22 PRINT \"PICK A NUMBER AND INPUT TO ROLL DICE\";\n      23 INPUT Z\n      24 LET X=(RND(0))\n      25 LET T =T+1\n      26 IF T<=Z THEN 24\n\nThis block of code does nothing other than try to scramble the random number\ngenerator. Random number generation is not random, they are generated from the\nprevious generated number. Because of the slow speed of these systems back then,\ngaming random number generators was a concern, mostly for gameplay quality.\nIf you could know the \"seed value\" to the generator then you could effectively\nknow how to get the exact same dice rolls to happen and change your bet to\nmaximize your winnings and minimize your losses.\n\nThe first reason this is an example of bad coding practice is the user is asked\nto input a number but no clue is given as to the use of this number. This number\nhas no bearing on the game and as we'll see only has bearing on the internal\nimplementation of somehow trying to get an un-game-able seed for the random number\ngenerator (since all future random numbers generated are based off this seed value.)\n\nThe `RND(1)` command generates a number from a seed value that is always\nthe same, everytime, from when the machine is booted up (old C64 behavior). In\norder to avoid the same dice rolls being generated, a special call to `RND(-TI)`\nwould initialize the random generator with something else. But RND(-TI) is not\na valid command on all systems. So `RND(0)`, which generates a random number\nfrom the system clock is used. But technically this could be gamed because the\nsystem clock was driven by the bootup time, there wasn't a BIOS battery on these\nsystems that kept an internal real time clock going even when the system was\nturned off, unlike your regular PC. Therefore, in order to ensure as true\nrandomness as possible, insert human reaction time by asking for human input.\n\nBut a human could just be holding down the enter key on bootup and that would\njust skip any kind of multi-millisecond variance assigned by a natural human\nreaction time. So, paranoia being a great motivator, a number is asked of the\nuser to avoid just holding down the enter key which negates the timing variance\nof a human reaction.\n\nWhat comes next is a bit of nonsense. The block of code loops a counter, recalling\nthe `RND(0)` function (and thus reseeding it with the system clock value)\nand then comparing the counter to the user's number input\nin order to bail out of the loop. Because the `RND(0)` function is based off the\nsystem clock and the loop of code has no branching other than the bailout\ncondition, the loop also takes a fixed amount of time to execute, thus making\nrepeated calls to `RND(0)` predictive and this scheming to get a better random\nnumber is pointless. Furthermore, the loop is based on the number the user inputs\nso a huge number like ten million causes a very noticable delay and leaves the\nuser wondering if the program has errored. The author could have simply called\n`RND(0)` once and used a prompt that made more sense like asking for the users\nname and then using that name in the game's replies.\n\nIt is advised that you use whatever your languages' random number generator\nprovides and simply skip trying to recreate this bit of nonsense including\nthe user input.\n\n      27 PRINT\"INPUT THE AMOUNT OF YOUR WAGER.\";\n      28 INPUT F\n      30 PRINT \"I WILL NOW THROW THE DICE\"\n      40 LET E=INT(7*RND(1))\n      41 LET S=INT(7*RND(1))\n      42 LET X=E+S\n      .... a bit later ....\n      60 IF X=1 THEN 40\n      65 IF X=0 THEN 40\n\n`F` is a variable that represents the users wager for this betting round.\n`E` and `S` represent the two individual and random dice being rolled.\nThis code is actually wrong because it returns a value between 0 and 6.\n`X` is the sum of these dice rolls. As you'll see though further down in the\ncode, if `X` is zero or one it re-rolls the dice to maintain a potential\noutcome of the sum of two dice between 2 and 12. This skews the normal distribution\nof dice values to favor lower numbers because it does not consider that `E`\ncould be zero and `S` could be 2 or higher. To show this skewing of values\nyou can run the `distribution.bas` program which creates a histogram of the\ndistribution of the bad dice throw code and proper dice throw code.\n\nHere are the results:\n\n      DISTRIBUTION OF DICE ROLLS WITH  INT(7*RND(1))  VS  INT(6*RND(1)+1)\n      THE INT(7*RND(1)) DISTRIBUTION:\n      2             3             4             5             6             7             8             9             10            11            12\n      6483          8662          10772         13232         15254         13007         10746         8878          6486          4357          2123\n      THE INT(6*RND(1)+1) DISTRIBUTION\n      2             3             4             5             6             7             8             9             10            11            12\n      2788          5466          8363          11072         13947         16656         13884         11149         8324          5561          2790\nIf the dice rolls are fair then we should see the largest occurrence be a 7 and\nthe smallest should be 2 and 12. Furthermore the occurrences should be\nsymetrical meaning there should be roughly the same amount of 2's as 12's, the\nsame amount of 3's as 11's, 4's as 10's and so on until you reach the middle, 7.\nBut notice in the skewed dice roll, 6 is the most rolled number not 7, and the\nrest of the numbers are not symetrical, there are many more 2's than 12's.\nSo the lesson is test your code.\n\nThe proper way to model a dice throw, in almost every language is\n    `INT(6*RND(1)+1)` or `INT(6*RND(1))+1`\n\nSideNote: `X` was used already in the\nprevious code block discussed but its value was never used. This is another\npoor coding practice: **Don't reuse variable names for different purposes.**\n\n      50 IF X=7 THEN 180\n      55 IF X=11 THEN 180\n      60 IF X=1 THEN 40\n      62 IF X=2 THEN 195\n      65 IF X=0 THEN 40\n      70 IF X=2 THEN 200\n      80 IF X=3 THEN 200\n      90 IF X=12 THEN 200\n      125 IF X=5 THEN 220\n      130 IF X =6 THEN 220\n      140 IF X=8 THEN 220\n      150 IF X=9 THEN 220\n      160 IF X =10 THEN 220\n      170 IF X=4 THEN 220\n\nThis bit of code determines the routing of where to go for payout, or loss.\nOf course, line 60 and 65 are pointless as we've just shown and should be removed\nas long as the correct dice algorithm is also changed.\n\n      62 IF X=2 THEN 195\n      ....\n      70 IF X=2 THEN 200\nThe check for a 2 has already been made and the jump is done. Line 70 is\ntherefore redundant and can be left out. The purpose of line 62 is only to\nprint a special output, \"SNAKE EYES!\" which we'll see in the next block creates\nduplicate code.\n\nLines 125-170 are also pointlessly checked because we know previous values have\nbeen ruled out, only these last values must remain, and they are all going to\nthe same place, line 220. Line 125-170 could have simply been replaced with\n`GOTO 220`\n\n\n\n      180 PRINT X \"- NATURAL....A WINNER!!!!\"\n      185 PRINT X\"PAYS EVEN MONEY, YOU WIN\"F\"DOLLARS\"\n      190 GOTO 210\n      195 PRINT X\"- SNAKE EYES....YOU LOSE.\"\n      196 PRINT \"YOU LOSE\"F \"DOLLARS.\"\n      197 LET F=0-F\n      198 GOTO 210\n      200 PRINT X \" - CRAPS...YOU LOSE.\"\n      205 PRINT \"YOU LOSE\"F\"DOLLARS.\"\n      206 LET F=0-F\n      210 LET R= R+F\n      211 GOTO 320\n\nThis bit of code manages instant wins or losses due to 7,11 or 2,3,12. As\nmentioned previously, lines 196 and 197 are essentially the same as lines\n205 and 206. A simpler code would be just to jump after printing the special\nmessage of \"SNAKE EYES!\" to line 205.\n\nLines 197 and 206 just negate the wager by subtracting it from zero. Just saying\n`F = -F` would have sufficed. Line 210 updates your running total of winnings\nor losses with this bet.\n\n      220 PRINT X \"IS THE POINT. I WILL ROLL AGAIN\"\n      230 LET H=INT(7*RND(1))\n      231 LET Q=INT(7*RND(1))\n      232 LET O=H+Q\n      240 IF O=1 THEN 230\n      250 IF O=7 THEN 290\n      255 IF O=0 THEN 230\n\nThis code sets the point, the number you must re-roll to win without rolling\na 7, the most probable number to roll. Except in this case again, it has the\nsame incorrect dice rolling code and therefore 6 is the most probable number\nto roll. The concept of DRY (don't repeat yourself) is a coding practice which\nencourages non-duplication of code because if there is an error in the code, it\ncan be fixed in one place and not multiple places like in this code. The scenario\nmight be that a programmer sees some wrong code, fixes it, but neglects to\nconsider that there might be duplicates of the same wrong code elsewhere.  If\nyou practice DRY then you never worry much about behaviors in your code diverging\ndue to duplicate code snippets.\n\n      260 IF O=X THEN 310\n      270 PRINT O \" - NO POINT. I WILL ROLL AGAIN\"\n      280 GOTO 230\n      290 PRINT O \"- CRAPS. YOU LOSE.\"\n      291 PRINT \"YOU LOSE $\"F\n      292 F=0-F\n      293 GOTO 210\n      300 GOTO 320\n      310 PRINT X\"- A WINNER.........CONGRATS!!!!!!!!\"\n      311 PRINT X \"AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...\"2*F\"DOLLARS\"\n      312 LET F=2*F\n      313 GOTO 210\n\nThis is the code to keep rolling until the point is made or a seven is rolled.\nAgain we see the negated `F` wager and lose message duplicated. This code could\nhave been reorganized using a subroutine, or in BASIC, the GOSUB command, but\nin your language its most likely just known as a function or method. You can\ndo a `grep -r 'GOSUB'` from the root directory to see other BASIC programs in\nthis set that use GOSUB.\n\nThe rest of the code if fairly straight forward, replay the game or end with\na report of your winnings or losings.\n"
  },
  {
    "path": "29_Craps/craps.bas",
    "content": "5 PRINT TAB(33);\"CRAPS\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n12 PRINT:PRINT:PRINT\n15 LET R=0\n20 PRINT\"2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS.\"\n21 LET T=1\n22 PRINT \"PICK A NUMBER AND INPUT TO ROLL DICE\";\n23 INPUT Z\n24 LET X=(RND(0))\n25 LET T =T+1\n26 IF T<=Z THEN 24\n27 PRINT\"INPUT THE AMOUNT OF YOUR WAGER.\";\n28 INPUT F\n30 PRINT \"I WILL NOW THROW THE DICE\"\n40 LET E=INT(7*RND(1))\n41 LET S=INT(7*RND(1))\n42 LET X=E+S\n50 IF X=7 THEN 180\n55 IF X=11 THEN 180\n60 IF X=1 THEN 40\n62 IF X=2 THEN 195\n65 IF X=0 THEN 40\n70 IF X=2 THEN 200\n80 IF X=3 THEN 200\n90 IF X=12 THEN 200\n125 IF X=5 THEN 220\n130 IF X =6 THEN 220\n140 IF X=8 THEN 220\n150 IF X=9 THEN 220\n160 IF X =10 THEN 220\n170 IF X=4 THEN 220\n180 PRINT X \"- NATURAL....A WINNER!!!!\"\n185 PRINT X\"PAYS EVEN MONEY, YOU WIN\"F\"DOLLARS\"\n190 GOTO 210\n195 PRINT X\"- SNAKE EYES....YOU LOSE.\"\n196 PRINT \"YOU LOSE\"F \"DOLLARS.\"\n197 LET F=0-F\n198 GOTO 210\n200 PRINT X \" - CRAPS...YOU LOSE.\"\n205 PRINT \"YOU LOSE\"F\"DOLLARS.\"\n206 LET F=0-F\n210 LET R= R+F\n211 GOTO 320\n220 PRINT X \"IS THE POINT. I WILL ROLL AGAIN\"\n230 LET H=INT(7*RND(1))\n231 LET Q=INT(7*RND(1))\n232 LET O=H+Q\n240 IF O=1 THEN 230\n250 IF O=7 THEN 290\n255 IF O=0 THEN 230\n260 IF O=X THEN 310\n270 PRINT O \" - NO POINT. I WILL ROLL AGAIN\"\n280 GOTO 230\n290 PRINT O \"- CRAPS. YOU LOSE.\"\n291 PRINT \"YOU LOSE $\"F\n292 F=0-F\n293 GOTO 210\n300 GOTO 320\n310 PRINT X\"- A WINNER.........CONGRATS!!!!!!!!\"\n311 PRINT X \"AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...\"2*F\"DOLLARS\"\n312 LET F=2*F\n313 GOTO 210\n320 PRINT \" IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2\";\n330 INPUT M\n331 IF R<0 THEN 334\n332 IF R>0 THEN 336\n333 IF R=0 THEN 338\n334 PRINT \"YOU ARE NOW UNDER $\";-R\n335 GOTO 340\n336 PRINT \"YOU ARE NOW AHEAD $\";R\n337 GOTO 340\n338 PRINT \"YOU ARE NOW EVEN AT 0\"\n340 IF M=5 THEN 27\n341 IF R<0 THEN 350\n342 IF R>0 THEN 353\n343 IF R=0 THEN 355\n350 PRINT\"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN.\"\n351 GOTO 360\n353 PRINT\"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\"\n354 GOTO 360\n355 PRINT\"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR\"\n360 END\n"
  },
  {
    "path": "29_Craps/csharp/.gitignore",
    "content": ".vs\nTestResults\nbin\nobj\n"
  },
  {
    "path": "29_Craps/csharp/Craps/Craps.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "29_Craps/csharp/Craps/CrapsGame.cs",
    "content": "﻿namespace Craps\n{\n    public enum Result\n    {\n        // It's not used in this program but it's often a good idea to include a \"none\"\n        // value in an enum so that you can set an instance of the enum to \"invalid\" or\n        // initialise it to \"none of the valid values\".\n        noResult,\n        naturalWin,\n        snakeEyesLoss,\n        naturalLoss,\n        pointLoss,\n        pointWin,\n    };\n\n    class CrapsGame\n    {\n        private readonly UserInterface ui;\n        private Dice dice1 = new Dice();\n        private Dice dice2 = new Dice();\n\n        public CrapsGame(ref UserInterface ui)\n        {\n            this.ui = ui;\n        }\n\n        public Result Play(out int diceRoll)\n        {\n            diceRoll = dice1.Roll() + dice2.Roll();\n\n            if (Win(diceRoll))\n            {\n                return Result.naturalWin;\n            }\n            else if (Lose(diceRoll))\n            {\n                return (diceRoll == 2) ? Result.snakeEyesLoss : Result.naturalLoss;\n            }\n            else\n            {\n                var point = diceRoll;\n                ui.Point(point);\n\n                while (true)\n                {\n                    var newRoll = dice1.Roll() + dice2.Roll();\n                    if (newRoll == point)\n                    {\n                        diceRoll = newRoll;\n                        return Result.pointWin;\n                    }\n                    else if (newRoll == 7)\n                    {\n                        diceRoll = newRoll;\n                        return Result.pointLoss;\n                    }\n\n                    ui.NoPoint(newRoll);\n                }\n            }\n        }\n\n        private bool Lose(int diceRoll)\n        {\n            return diceRoll == 2 || diceRoll == 3 || diceRoll == 12;\n        }\n\n        private bool Win(int diceRoll)\n        {\n            return diceRoll == 7 || diceRoll == 11;\n        }\n    }\n}\n"
  },
  {
    "path": "29_Craps/csharp/Craps/Dice.cs",
    "content": "﻿using System;\n\n\nnamespace Craps\n{\n    public class Dice\n    {\n        private Random rand = new Random();\n        public readonly int sides;\n\n        public Dice()\n        {\n            sides = 6;\n        }\n\n        public Dice(int sides)\n        {\n            this.sides = sides;\n        }\n\n        public int Roll() => rand.Next(1, sides + 1);\n    }\n}\n"
  },
  {
    "path": "29_Craps/csharp/Craps/Program.cs",
    "content": "﻿using System.Diagnostics;\n\n\n\nnamespace Craps\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            var ui = new UserInterface();\n            var game = new CrapsGame(ref ui);\n            int winnings = 0;\n\n            ui.Intro();\n\n            do\n            {\n\t            var bet = ui.PlaceBet();\n                var result = game.Play(out int diceRoll);\n\n                switch (result)\n                {\n                    case Result.naturalWin:\n                        winnings += bet;\n                        break;\n\n                    case Result.naturalLoss:\n                    case Result.snakeEyesLoss:\n                    case Result.pointLoss:\n                        winnings -= bet;\n                        break;\n\n                    case Result.pointWin:\n                        winnings += (2 * bet);\n                        break;\n\n                    // Include a default so that we will be warned if the values of the enum\n                    // ever change and we forget to add code to handle the new value.\n                    default:\n                        Debug.Assert(false); // We should never get here.\n                        break;\n                }\n\n                ui.ShowResult(result, diceRoll, bet);\n            } while (ui.PlayAgain(winnings));\n\n            ui.GoodBye(winnings);\n        }\n    }\n}\n"
  },
  {
    "path": "29_Craps/csharp/Craps/UserInterface.cs",
    "content": "using System;\nusing System.Diagnostics;\n\n\n\nnamespace Craps\n{\n    public class UserInterface\n\t{\n        public void Intro()\n        {\n            Console.WriteLine(\"                                 CRAPS\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\");\n            Console.WriteLine(\"2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS.\");\n\n            // In the original game a random number would be generated and then thrown away for as many\n            // times as the number the user entered. This is presumably something to do with ensuring\n            // that different random numbers will be generated each time the program is run.\n            //\n            // This is not necessary in C#; the random number generator uses the current time as a seed\n            // so the results will always be different every time it is run.\n            //\n            // So that the game exactly matches the original game we ask the question but then ignore\n            // the answer.\n            Console.Write(\"PICK A NUMBER AND INPUT TO ROLL DICE \");\n            GetInt();\n        }\n\n        public int PlaceBet()\n        {\n            Console.Write(\"INPUT THE AMOUNT OF YOUR WAGER. \");\n            int n = GetInt();\n            Console.WriteLine(\"I WILL NOW THROW THE DICE\");\n\n            return n;\n        }\n\n        public bool PlayAgain(int winnings)\n        {\n            // Goodness knows why we have to enter 5 to play\n            // again but that's what the original game asked.\n            Console.Write(\"IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2 \");\n\n            bool playAgain = (GetInt() == 5);\n\n            if (winnings < 0)\n            {\n                Console.WriteLine($\"YOU ARE NOW UNDER ${-winnings}\");\n            }\n            else if (winnings > 0)\n            {\n                Console.WriteLine($\"YOU ARE NOW OVER ${winnings}\");\n            }\n            else\n            {\n                Console.WriteLine($\"YOU ARE NOW EVEN AT ${winnings}\");\n            }\n\n            return playAgain;\n        }\n\n        public void GoodBye(int winnings)\n        {\n            if (winnings < 0)\n            {\n                Console.WriteLine(\"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN.\");\n            }\n            else if (winnings > 0)\n            {\n                Console.WriteLine(\"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\");\n            }\n            else\n            {\n                Console.WriteLine(\"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR\");\n            }\n        }\n\n        public void NoPoint(int diceRoll)\n        {\n            Console.WriteLine($\"{diceRoll} - NO POINT. I WILL ROLL AGAIN \");\n        }\n\n        public void Point(int point)\n        {\n            Console.WriteLine($\"{point} IS THE POINT. I WILL ROLL AGAIN\");\n        }\n\n        public void ShowResult(Result result, int diceRoll, int bet)\n        {\n            switch (result)\n            {\n                case Result.naturalWin:\n                    Console.WriteLine($\"{diceRoll} - NATURAL....A WINNER!!!!\");\n                    Console.WriteLine($\"{diceRoll} PAYS EVEN MONEY, YOU WIN {bet} DOLLARS\");\n                    break;\n\n                case Result.naturalLoss:\n                    Console.WriteLine($\"{diceRoll} - CRAPS...YOU LOSE.\");\n                    Console.WriteLine($\"YOU LOSE {bet} DOLLARS.\");\n                    break;\n\n                case Result.snakeEyesLoss:\n                    Console.WriteLine($\"{diceRoll} - SNAKE EYES....YOU LOSE.\");\n                    Console.WriteLine($\"YOU LOSE {bet} DOLLARS.\");\n                    break;\n\n                case Result.pointLoss:\n                    Console.WriteLine($\"{diceRoll} - CRAPS. YOU LOSE.\");\n                    Console.WriteLine($\"YOU LOSE ${bet}\");\n                    break;\n\n                case Result.pointWin:\n                    Console.WriteLine($\"{diceRoll} - A WINNER.........CONGRATS!!!!!!!!\");\n                    Console.WriteLine($\"AT 2 TO 1 ODDS PAYS YOU...LET ME SEE... {2 * bet} DOLLARS\");\n                    break;\n\n                // Include a default so that we will be warned if the values of the enum\n                // ever change and we forget to add code to handle the new value.\n                default:\n                    Debug.Assert(false); // We should never get here.\n                    break;\n            }\n        }\n\n        private int GetInt()\n        {\n            while (true)\n            {\n\t            string input = Console.ReadLine();\n                if (int.TryParse(input, out int n))\n                {\n                    return n;\n                }\n                else\n                {\n                    Console.Write(\"ENTER AN INTEGER \");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "29_Craps/csharp/Craps.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31112.23\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Craps\", \"Craps\\Craps.csproj\", \"{783A49D7-DADE-477A-9973-D9457258573B}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"CrapsTester\", \"CrapsTester\\CrapsTester.csproj\", \"{44DFE8DB-715F-428E-992D-A97C34D47B98}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{783A49D7-DADE-477A-9973-D9457258573B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{783A49D7-DADE-477A-9973-D9457258573B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{783A49D7-DADE-477A-9973-D9457258573B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{783A49D7-DADE-477A-9973-D9457258573B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{44DFE8DB-715F-428E-992D-A97C34D47B98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{44DFE8DB-715F-428E-992D-A97C34D47B98}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{44DFE8DB-715F-428E-992D-A97C34D47B98}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{44DFE8DB-715F-428E-992D-A97C34D47B98}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {871679FF-B86C-468B-960E-DFC625CDB5D0}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "29_Craps/csharp/CrapsTester/CrapsTester.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.5.0\" />\n    <PackageReference Include=\"MSTest.TestAdapter\" Version=\"2.1.0\" />\n    <PackageReference Include=\"MSTest.TestFramework\" Version=\"2.1.0\" />\n    <PackageReference Include=\"coverlet.collector\" Version=\"1.2.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Craps\\Craps.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "29_Craps/csharp/CrapsTester/CrapsTests.cs",
    "content": "using Craps;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\n\n\n\nnamespace CrapsTester\n{\n    [TestClass]\n    public class DiceTests\n    {\n        [TestMethod]\n        public void SixSidedDiceReturnsValidRolls()\n        {\n            var dice = new Dice();\n            for (int i = 0; i < 100000; i++)\n            {\n                var roll = dice.Roll();\n                Assert.IsTrue(roll >= 1 && roll <= dice.sides);\n            }\n        }\n\n        [TestMethod]\n        public void TwentySidedDiceReturnsValidRolls()\n        {\n            var dice = new Dice(20);\n            for (int i = 0; i < 100000; i++)\n            {\n                var roll = dice.Roll();\n                Assert.IsTrue(roll >= 1 && roll <= dice.sides);\n            }\n        }\n\n        [TestMethod]\n        public void DiceRollsAreRandom()\n        {\n            // Roll 600,000 dice and count how many rolls there are for each side.\n\n            var dice = new Dice();\n\n            int numOnes = 0;\n            int numTwos = 0;\n            int numThrees = 0;\n            int numFours = 0;\n            int numFives = 0;\n            int numSixes = 0;\n            int numErrors = 0;\n\n            for (int i = 0; i < 600000; i++)\n            {\n                switch (dice.Roll())\n                {\n                    case 1:\n                        numOnes++;\n                        break;\n\n                    case 2:\n                        numTwos++;\n                        break;\n\n                    case 3:\n                        numThrees++;\n                        break;\n\n                    case 4:\n                        numFours++;\n                        break;\n\n                    case 5:\n                        numFives++;\n                        break;\n\n                    case 6:\n                        numSixes++;\n                        break;\n\n                    default:\n                        numErrors++;\n                        break;\n                }\n            }\n\n            // We'll assume that a variation of 10% in rolls for the different numbers is random enough.\n            // Perfectly random rolling would produce 100000 rolls per side, +/- 5% of this gives the\n            // range 90000..110000.\n            const int minRolls = 95000;\n            const int maxRolls = 105000;\n            Assert.IsTrue(numOnes >= minRolls && numOnes <= maxRolls);\n            Assert.IsTrue(numTwos >= minRolls && numTwos <= maxRolls);\n            Assert.IsTrue(numThrees >= minRolls && numThrees <= maxRolls);\n            Assert.IsTrue(numFours >= minRolls && numFours <= maxRolls);\n            Assert.IsTrue(numFives >= minRolls && numFives <= maxRolls);\n            Assert.IsTrue(numSixes >= minRolls && numSixes <= maxRolls);\n            Assert.AreEqual(numErrors, 0);\n        }\n    }\n}\n"
  },
  {
    "path": "29_Craps/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "29_Craps/distributions.bas",
    "content": "10 PRINT \"DISTRIBUTION OF DICE ROLLS WITH  INT(7*RND(1))  VS  INT(6*RND(1)+1)\"\n20 DIM A(12)\n30 DIM B(12)\n100 FOR X = 1 TO 100000 : REM CHOOSE A LARGE NUMBER TO GET A FINER GRAINED HISTOGRAM\n140 REM GET A NUMBER FROM 0 TO 6 INCLUSIVE WITH THE INTENT TO THROW AWAY ZEROES.\n150 LET D1 = INT(7*RND(1))\n155 LET D2 = INT(7*RND(1))\n160 LET S1 = D1+D2\n165 REM IF THIS SUM IS LESS THAN TWO THEN TRY AGAIN.\n170 IF S1<2 THEN 150\n199 REM GET A NUMBER FROM 0 TO 5 THEN ADD 1 TO IT TO MAKE IT 1 TO 6\n200 LET D3 = INT(6*RND(1))+1\n210 LET D4 = INT(6*RND(1))+1\n220 LET S2 = D3+D4\n245 REM USE OUR ARRAY AS A HISTOGRAM, COUNTING EACH OCCURRENCE OF DICE ROLL\n250 A(S1) = A(S1) + 1\n260 B(S2) = B(S2) + 1\n290 NEXT X\n300 PRINT \"THE INT(7*RND(1)) DISTRIBUTION:\"\n310 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT\n320 FOR I = 2 TO 12 :PRINT A(I),:NEXT:PRINT\n325 PRINT \"THE INT(6*RND(1)+1) DISTRIBUTION\"\n330 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT\n340 FOR I = 2 TO 12 :PRINT B(I),:NEXT:PRINT\n"
  },
  {
    "path": "29_Craps/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "29_Craps/java/src/Craps.java",
    "content": "import java.util.Random;\nimport java.util.Scanner;\n\n/**\n *  Port of Craps from BASIC to Java 17.\n */\npublic class Craps {\n  public static final Random random = new Random();\n\n  public static void main(String[] args) {\n    System.out.println(\"\"\"\n                                                            CRAPS\n                                          CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n                           2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS.\n                           \"\"\");\n    double winnings = 0.0;\n    do {\n      winnings = playCraps(winnings);\n    } while (stillInterested(winnings));\n    winningsReport(winnings);\n  }\n\n  public static double playCraps(double winnings) {\n    double wager = getWager();\n    System.out.println(\"I WILL NOW THROW THE DICE\");\n    int roll = rollDice();\n    double payout = switch (roll) {\n      case 7, 11 -> naturalWin(roll, wager);\n      case 2, 3, 12 -> lose(roll, wager);\n      default -> setPoint(roll, wager);\n    };\n    return winnings + payout;\n  }\n\n  public static int rollDice() {\n    return random.nextInt(1, 7) + random.nextInt(1, 7);\n  }\n\n  private static double setPoint(int point, double wager) {\n    System.out.printf(\"%1$ d IS THE POINT. I WILL ROLL AGAIN%n\",point);\n    return makePoint(point, wager);\n  }\n\n  private static double makePoint(int point, double wager) {\n    int roll = rollDice();\n    if (roll == 7)\n      return lose(roll, wager);\n    if (roll == point)\n      return win(roll, wager);\n    System.out.printf(\"%1$ d - NO POINT. I WILL ROLL AGAIN%n\", roll);\n    return makePoint(point, wager);  // recursive\n  }\n\n  private static double win(int roll, double wager) {\n    double payout = 2 * wager;\n    System.out.printf(\"%1$ d - A WINNER.........CONGRATS!!!!!!!!%n\", roll);\n    System.out.printf(\"%1$ d AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...$%2$3.2f%n\",\n                      roll, payout);\n    return payout;\n  }\n\n  private static double lose(int roll, double wager) {\n    String msg = roll == 2 ? \"SNAKE EYES.\":\"CRAPS\";\n    System.out.printf(\"%1$ d - %2$s...YOU LOSE.%n\", roll, msg);\n    System.out.printf(\"YOU LOSE $%3.2f%n\", wager);\n    return -wager;\n  }\n\n  public static double naturalWin(int roll, double wager) {\n    System.out.printf(\"%1$ d - NATURAL....A WINNER!!!!%n\", roll);\n    System.out.printf(\"%1$ d PAYS EVEN MONEY, YOU WIN $%2$3.2f%n\", roll, wager);\n    return wager;\n  }\n\n  public static void winningsUpdate(double winnings) {\n    System.out.println(switch ((int) Math.signum(winnings)) {\n      case 1 -> \"YOU ARE NOW AHEAD $%3.2f\".formatted(winnings);\n      case 0 -> \"YOU ARE NOW EVEN AT 0\";\n      default -> \"YOU ARE NOW UNDER $%3.2f\".formatted(-winnings);\n    });\n  }\n\n  public static void winningsReport(double winnings) {\n    System.out.println(\n        switch ((int) Math.signum(winnings)) {\n          case 1 -> \"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\";\n          case 0 -> \"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR\";\n          default -> \"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN.\";\n        }\n    );\n  }\n\n  public static boolean stillInterested(double winnings) {\n    System.out.print(\" IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2 \");\n    int fiveOrTwo = (int)getInput();\n    winningsUpdate(winnings);\n    return fiveOrTwo == 5;\n  }\n\n  public static double getWager() {\n    System.out.print(\"INPUT THE AMOUNT OF YOUR WAGER. \");\n    return getInput();\n  }\n\n  public static double getInput() {\n    Scanner scanner = new Scanner(System.in);\n    System.out.print(\"> \");\n    while (true) {\n      try {\n        return scanner.nextDouble();\n      } catch (Exception ex) {\n        try {\n          scanner.nextLine(); // flush whatever this non number stuff is.\n        } catch (Exception ns_ex) { // received EOF (ctrl-d or ctrl-z if windows)\n          System.out.println(\"END OF INPUT, STOPPING PROGRAM.\");\n          System.exit(1);\n        }\n      }\n      System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n      System.out.print(\"> \");\n    }\n  }\n}\n"
  },
  {
    "path": "29_Craps/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "29_Craps/javascript/craps.html",
    "content": "<html>\n<head>\n<title>CRAPS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"craps.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "29_Craps/javascript/craps.js",
    "content": "// CRAPS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nfunction roll()\n{\n    return Math.floor(6 * Math.random())+1 + Math.floor(6 * Math.random())+1;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"CRAPS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    r = 0;\n    print(\"2,3,12 ARE LOSERS: 4,5,6,8,9,10 ARE POINTS: 7,11 ARE NATURAL WINNERS.\\n\");\n    while (1) {\n        print(\"INPUT THE AMOUNT OF YOUR WAGER.\");\n        f = parseInt(await input());\n        print(\"I WILL NOW THROW THE DICE\\n\");\n        x = roll();\n        if (x == 7 || x == 11) {\n            print(x + \" - NATURAL....A WINNER!!!!\\n\");\n            print(x + \" PAYS EVEN MONEY, YOU WIN \" + f + \" DOLLARS\\n\");\n            r += f;\n        } else if (x == 2) {\n            print(x + \" - SNAKE EYES....YOU LOSE.\\n\");\n            print(\"YOU LOSE \" + f + \" DOLLARS.\\n\");\n            r -= f;\n        } else if (x == 3 || x == 12) { // Original duplicates comparison in line 70\n            print(x + \" - CRAPS....YOU LOSE.\\n\");\n            print(\"YOU LOSE \" + f + \" DOLLARS.\\n\");\n            r -= f;\n        } else {\n            print(x + \" IS THE POINT. I WILL ROLL AGAIN\\n\");\n            while (1) {\n                o = roll();\n                if (o == 7) {\n                    print(o + \" - CRAPS, YOU LOSE.\\n\");\n                    print(\"YOU LOSE $\" + f + \"\\n\");\n                    r -= f;\n                    break;\n                }\n                if (o == x) {\n                    print(x + \" - A WINNER.........CONGRATS!!!!!!!!\\n\");\n                    print(x + \" AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...\" + 2 * f + \" DOLLARS\\n\");\n                    r += f * 2;\n                    break;\n                }\n                print(o + \" - NO POINT. I WILL ROLL AGAIN\\n\");\n            }\n        }\n        print(\" IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2\");\n        m = parseInt(await input());\n        if (r < 0) {\n            print(\"YOU ARE NOW UNDER $\" + -r + \"\\n\");\n        } else if (r > 0) {\n            print(\"YOU ARE NOW AHEAD $\" + r + \"\\n\");\n        } else {\n            print(\"YOU ARE NOW EVEN AT 0\\n\");\n        }\n        if (m != 5)\n            break;\n    }\n    if (r < 0) {\n        print(\"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN.\\n\");\n    } else if (r > 0) {\n        print(\"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\\n\");\n    } else {\n        print(\"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR\\n\");\n    }\n\n}\n\nmain();\n"
  },
  {
    "path": "29_Craps/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "29_Craps/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/) by Alex Conconi\n\n---\n\n### Lua porting notes\n\n-  The `craps_main` function contains the main game loop, which iteratively\nplays craps rounds by calling `play_round` and tracks winnings and losings.\n- Replaced the original routine that tries to scramble the random number\ngenerator with a proper seed initializer in Lua: `math.randomseed(os.time())`\n(as advised in the general porting notes). \n- Added basic input validation to accept only positive integers for the\nwager and the answer to the \"If you want to play again print 5\" question.\n- \"If you want to play again print 5 if not print 2\" reads a bit odd but\nwe decided to leave it as is and stay true to the BASIC original version."
  },
  {
    "path": "29_Craps/lua/craps.lua",
    "content": "--[[\nCraps\n\nFrom: BASIC Computer Games (1978)\nEdited by David H. Ahl\n\n    This game simulates the games of craps played according to standard\n    Nevada craps table rules. That is:\n    1. A 7 or 11 on the first roll wins\n    2. A 2, 3, or 12 on the first roll loses\n    3. Any other number rolled becomes your \"point.\" You continue to roll;\n    if you get your point you win. If you roll a 7, you lose and the dice\n    change hands when this happens.\n\n    This version of craps was modified by Steve North of Creative Computing.\n    It is based on an original which appeared one day one a computer at DEC.\n\n\nLua port by Alex Conconi, 2022\n--]]\n\n\n--- Throw two dice and return their sum.\nlocal function throw_dice()\n    return math.random(1, 6) + math.random(1, 6)\nend\n\n\n--- Print prompt and read a number > 0 from stdin.\nlocal function input_number(prompt)\n    while true do\n        io.write(prompt)\n        local number = tonumber(io.stdin:read(\"*l\"))\n        if number and number > 0 then\n            return number\n        else\n            print(\"Please enter a number greater than zero.\")\n        end\n    end\nend\n\n\n--- Print custom balance message depending on balance value\nlocal function print_balance(balance, under_msg, ahead_msg, even_msg)\n    if balance < 0 then\n        print(under_msg)\n    elseif balance > 0 then\n        print(ahead_msg)\n    else\n        print(even_msg)\n    end\nend\n\n\n--- Play a round and return winnings or losings.\nlocal function play_round()\n    -- Input the wager\n    local wager = input_number(\"Input the amount of your wager: \")\n\n    -- Roll the die for the first time.\n    print(\"I will now throw the dice\")\n    local first_roll = throw_dice()\n\n    -- A 7 or 11 on the first roll wins.\n    if first_roll == 7 or first_roll == 11 then\n        print(string.format(\"%d - natural.... a winner!!!!\", first_roll))\n        print(string.format(\"%d pays even money, you win %d dollars\", first_roll, wager))\n        return wager\n    end\n\n    -- A 2, 3, or 12 on the first roll loses.\n    if first_roll == 2 or first_roll == 3 or first_roll == 12 then\n        if first_roll == 2 then\n            -- Special 'you lose' message for 'snake eyes'\n            print(string.format(\"%d - snake eyes.... you lose.\", first_roll))\n        else\n            -- Default 'you lose' message\n            print(string.format(\"%d - craps.... you lose.\", first_roll))\n        end\n        print(string.format(\"You lose %d dollars\", wager))\n        return -wager\n    end\n\n    -- Any other number rolled becomes the \"point\".\n    -- Continue to roll until rolling a 7 or point.\n    print(string.format(\"%d is the point. I will roll again\", first_roll))\n    while true do\n        local second_roll = throw_dice()\n        if second_roll == first_roll then\n            -- Player gets point and wins\n            print(string.format(\"%d - a winner.........congrats!!!!!!!!\", first_roll))\n            print(string.format(\"%d at 2 to 1 odds pays you...let me see... %d dollars\", first_roll, 2 * wager))\n            return 2 * wager\n        end\n        if second_roll == 7 then\n            -- Player rolls a 7 and loses\n            print(string.format(\"%d - craps. You lose.\", second_roll))\n            print(string.format(\"You lose $ %d\", wager))\n            return -wager\n        end\n        --  Continue to roll\n        print(string.format(\"%d  - no point. I will roll again\", second_roll))\n    end\nend\n\n\n--- Main game function.\nlocal function craps_main()\n    -- Print the introduction to the game\n    print(string.rep(\" \", 32) .. \"Craps\")\n    print(string.rep(\" \", 14) .. \"Creative Computing  Morristown, New Jersey\\n\\n\")\n    print(\"2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.\")\n\n    -- Initialize random number generator seed\n    math.randomseed(os.time())\n\n    -- Initialize balance to track winnings and losings\n    local balance = 0\n\n    -- Main game loop\n    local keep_playing = true\n    while keep_playing do\n        -- Play a round\n        balance = balance + play_round()\n\n        -- If player's answer is 5, then stop playing\n        keep_playing = (input_number(\"If you want to play again print 5 if not print 2: \") == 5)\n\n        -- Print an update on winnings or losings\n        print_balance(\n            balance,\n            string.format(\"You are now under $%d\", -balance),\n            string.format(\"You are now ahead $%d\", balance),\n            \"You are now even at 0\"\n        )\n    end\n\n    -- Game over, print the goodbye message\n    print_balance(\n        balance,\n        \"Too bad, you are in the hole. Come again.\",\n        \"Congratulations---you came out a winner. Come again.\",\n        \"Congratulations---you came out even, not bad for an amateur\"\n    )\nend\n\n\n--- Run the game.\ncraps_main()\n"
  },
  {
    "path": "29_Craps/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "29_Craps/perl/craps.pl",
    "content": "#!/usr/bin/perl\n#\n\nmy $bank = 0;\n\n&main;\n\nsub main {\n\t&print_intro;\n\tmy $continue=5;\n\tuntil ($continue != 5) {\n\t\t$continue=&game_play;\n\t\t&print_bank;\n\t}\n\t&final_bank;\n}\n\nsub game_play {\n\tmy $point = 0;\n\tmy $continue = 1;\n\tprint \"INPUT THE AMOUNT OF YOUR WAGER.\\n\";\n\tchomp(my $wager=<STDIN>);\n\tprint \"I WILL NOW THROW THE DICE\\n\";\n\tuntil ($continue == 0) {\n\t\tmy $roll = &roll_dice;\n\t\t$continue = &check_value($roll,$wager);\n\t}\n\tprint \"IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2\\n\";\n\tchomp(my $ans=<STDIN>);\n\treturn $ans;\n}\n\nsub print_bank {\n\tif ($bank < 0) {\n\t\tprint \"YOU ARE NOW UNDER \\$$bank\\n\";\n\t}\n\telsif ($bank > 0) {\n\t\tprint \"YOU ARE NOW AHEAD \\$$bank\\n\";\n\t}\n\telse {\n\t\tprint \"YOU ARE EVEN AT 0\\n\";\n\t}\n}\n\nsub final_bank {\n\tif ($bank < 0) {\n\t\tprint \"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN\\n\";\n\t}\n\telsif ($bank > 0) {\n\t\tprint \"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!\\n\";\n\t}\n\telse {\n\t\tprint \"CONGRATULATIONS---YOU CAME OUT EVEN. NOT BAD FOR AN AMATEUR!\\n\";\n\t}\n}\n\nsub check_value {\n\tmy $roll = shift;\n\tmy $wager = shift;\n\tif ($roll == 7 || $roll == 11) {\n\t\tprint \"$roll - NATURAL....A WINNER!!!!\\n\";\n\t\tprint \"$roll PAYS EVEN MONEY, YOU WIN $wager DOLLARS\\n\";\n\t\t$bank += $wager;\n\t\treturn 0;\n\t}\n\telsif ($roll == 2 || $roll == 3 || $roll == 12) {\n\t\tif ($roll == 2) {\n\t\t\tprint \"$roll - SNAKE EYES....YOU LOSE.\\n\";\n\t\t\tprint \"YOU LOSE $wager DOLLARS.\\n\";\n\t\t}\n\t\telse {\n\t\t\tprint \"$roll - CRAPS...YOU LOSE.\\n\";\n\t\t\tprint \"YOU LOSE $wager DOLLARS.\\n\";\n\t\t}\n\t\t$bank -= $wager;\n\t\treturn 0;\n\t}\n\telse {\n\t\tmy $point = $roll;\n\t\tprint \"$point IS THE POINT. I WILL ROLL AGAIN\\n\";\n\t\tuntil (1==2) {\n\t\t\t$roll = &roll_dice;\n\t\t\tif ($roll == 7) {\n\t\t\t\tprint \"$roll YOU LOSE $wager\\n\";\n\t\t\t\t$bank -= $wager;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\telsif ($roll == $point) {\n\t\t\t\tprint \"$roll - A WINNER..........CONGRATS!!!!!!!!\\n\";\n\t\t\t\tmy $payout = $wager * 2;\n\t\t\t\tprint \"$roll AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...$payout DOLLARS\\n\";\n\t\t\t\t$bank += $payout;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tprint \"$roll - NO POINT. I WILL ROLL AGAIN\\n\";\n\t\t\t\tsleep(1);\n\t\t\t}\n\t\t}\n\t}\n}\n\nsub roll_dice {\n\tmy $die1 = 1+int rand(6);\n\tmy $die2 = 1+int rand(6);\n\treturn ($die1 + $die2);\n}\n\nsub print_intro {\n\tprint ' ' x 33 . \"CRAPS\\n\";\n\tprint ' ' x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\tprint \"2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS.\\n\";\n}\n"
  },
  {
    "path": "29_Craps/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "29_Craps/python/craps.py",
    "content": "#!/usr/bin/env python3\n\"\"\"This game simulates the games of craps played according to standard Nevada craps table rules.\n\nThat is:\n\n1. A 7 or 11 on the first roll wins\n2. A 2, 3, or 12 on the first roll loses\n3. Any other number rolled becomes your \"point.\" You continue to roll; if you get your point you win. If you\n   roll a 7, you lose and the dice change hands when this happens.\n\nThis version of craps was modified by Steve North of Creative Computing. It is based on an original which\nappeared one day one a computer at DEC.\n\"\"\"\nfrom random import randint\n\n\ndef throw_dice() -> int:\n    return randint(1, 6) + randint(1, 6)\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"Craps\")\n    print(\" \" * 15 + \"Creative Computing  Morristown, New Jersey\\n\\n\\n\")\n\n    winnings = 0\n    print(\"2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.\")\n\n    play_again = True\n    while play_again:\n        wager = int(input(\"Input the amount of your wager: \"))\n\n        print(\"I will now throw the dice\")\n        roll_1 = throw_dice()\n\n        if roll_1 in [7, 11]:\n            print(f\"{roll_1} - natural.... a winner!!!!\")\n            print(f\"{roll_1} pays even money, you win {wager} dollars\")\n            winnings += wager\n        elif roll_1 == 2:\n            print(f\"{roll_1} - snake eyes.... you lose.\")\n            print(f\"You lose {wager} dollars\")\n            winnings -= wager\n        elif roll_1 in [3, 12]:\n            print(f\"{roll_1} - craps.... you lose.\")\n            print(f\"You lose {wager} dollars\")\n            winnings -= wager\n        else:\n            print(f\"{roll_1} is the point. I will roll again\")\n            roll_2 = 0\n            while roll_2 not in [roll_1, 7]:\n                roll_2 = throw_dice()\n                if roll_2 == 7:\n                    print(f\"{roll_2} - craps. You lose.\")\n                    print(f\"You lose $ {wager}\")\n                    winnings -= wager\n                elif roll_2 == roll_1:\n                    print(f\"{roll_1} - a winner.........congrats!!!!!!!!\")\n                    print(\n                        f\"{roll_1} at 2 to 1 odds pays you...let me see... {2 * wager} dollars\"\n                    )\n                    winnings += 2 * wager\n                else:\n                    print(f\"{roll_2} - no point. I will roll again\")\n\n        m = input(\"  If you want to play again print 5 if not print 2: \")\n        if winnings < 0:\n            print(f\"You are now under ${-winnings}\")\n        elif winnings > 0:\n            print(f\"You are now ahead ${winnings}\")\n        else:\n            print(\"You are now even at 0\")\n        play_again = m == \"5\"\n\n    if winnings < 0:\n        print(\"Too bad, you are in the hole. Come again.\")\n    elif winnings > 0:\n        print(\"Congratulations---you came out a winner. Come again.\")\n    else:\n        print(\"Congratulations---you came out even, not bad for an amateur\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "29_Craps/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "29_Craps/ruby/craps.rb",
    "content": "class CRAPSGAME\n\n    # class variables start with a double \"@\"\n    @@standings = 0\n\n    def displayHeading\n        puts \"CRAPS\".center(80)\n        puts \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".center(80)\n        puts \"\\n\\n\\n\"\n        puts \"2,3,12 are losers\"\n        puts \"4,5,6,8,9,10 are points\"\n        puts \"7,11 are natural winners.\\n\\n\"\n    end\n\n    def displayStanding\n        if @@standings < 0\n            print \"you are in the hole by \"\n        elsif @@standings == 0\n            print \"you currently have \"\n        else\n            # show how much money we currently have\n            print \"you now have won \"\n        end\n           # print the absolute value of the amount in the standings\n        puts @@standings.abs.to_s + \" dollars\"\n    end\n\n    # dice can come up 2 through 12\n    # so return a minimum of 2 and add 0 through 10 to that\n    def rollDice\n        puts \"I will now throw the dice\"\n        return rand(5) + rand(5) + 2\n    end\n\n    def placeBet\n        print \"How much do you want to wager? \"\n        wager = gets.strip.to_i\n        return wager\n    end\n\n    def loseBetBy amount\n        @@standings -= amount\n    end\n\n    def winBetBy amount\n        @@standings += amount\n    end\n\n    def askQuit?\n        print \"\\nDo you want to play again? \"\n        # just the first character, make it uppercase\n        again = gets.strip.upcase[0]\n        return again != \"Y\"\n    end\n\n    def pointRoll point, wager\n        while true do\n            puts \" is the point.\"\n            puts \" I will roll again when you press Enter.\"\n            waitForIt = gets\n            roll = rollDice\n            print roll.to_s\n\n            # the only critical rolls here are 7 and the previous roll\n            # if anything else comes up we roll again.\n            case roll.to_i\n                when 7\n                    puts \" craps - you lose\"\n                    loseBetBy wager\n                    break\n                when point\n                    puts \" is a winner! congrats!\"\n                    puts \"at 2 to 1 odds pays you \" + (2 * wager).to_s + \" dollars\"\n                    winBetBy 2 * wager\n                    break\n                else\n                    print \" no point - \" + point.to_s\n           end\n        end\n    end\n\n    def play\n        displayHeading\n\n        while true do\n            wagerAmount = placeBet\n            roll = rollDice\n            print roll.to_s\n            case roll\n                when 2\n                    puts \" snake eyes - you lose\"\n                    loseBetBy wagerAmount\n                when 3, 12\n                    puts \" craps - you lose\"\n                    loseBetBy wagerAmount\n                when 4, 5, 6, 8, 9, 10\n                    pointRoll roll, wagerAmount\n                when 7, 11\n                    puts \" a natural - a winner\"\n                    puts \"pays even money: \" + wagerAmount.to_s + \" dollars\"\n                    winBetBy wagerAmount\n            end\n            displayStanding\n            if askQuit?\n                endPlay\n            end\n        end\n    end\n\n    def endPlay\n        case\n            when @@standings < 0\n                puts \"Too bad. You are in the hole \" + @@standings.abs.to_s + \" dollars. Come again.\"\n            when @@standings > 0\n                puts \"Congratulations --- You came out a winner of \" + @@standings.to_s + \" dollars. Come again!\"\n            when @@standings == 0\n                puts \"Congratulations --- You came out even, not bad for an amateur\"\n        end\n        exit\n    end\nend\n\ncraps = CRAPSGAME.new\ncraps.play\n"
  },
  {
    "path": "29_Craps/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "29_Craps/rust/src/craps_game.rs",
    "content": "use crate::util;\n\nenum GameState {\n    ComeOut,\n    PointRolls,\n    GameOver,\n}\n\npub struct CrapsGame {\n    wallet: usize,\n    bet: usize,\n    point: u8,\n    state: GameState,\n}\n\nimpl CrapsGame {\n    pub fn new() -> Self {\n        let wallet = util::read_numeric(\"\\nHow much money do you want to start with?\");\n\n        CrapsGame {\n            wallet,\n            bet: 0,\n            point: 0,\n            state: GameState::ComeOut,\n        }\n    }\n\n    pub fn tick(&mut self) -> bool {\n        use GameState::*;\n\n        match self.state {\n            ComeOut => self.new_round(),\n            PointRolls => self.point_roll(),\n            GameOver => false,\n        }\n    }\n\n    fn point_roll(&mut self) -> bool {\n        let point = self.point;\n\n        println!(\"Rolling {point} wins. 7 loses.\");\n\n        self.prompt_roll();\n        let roll = CrapsGame::roll();\n\n        if roll == point {\n            self.player_win();\n        } else if roll == 7 {\n            self.player_lose();\n        }\n\n        true\n    }\n\n    fn new_round(&mut self) -> bool {\n        println!(\"\\nCome out roll.\");\n        println!(\"7 and 11 win. 2, 3 and 12 lose.\\n\");\n\n        loop {\n            self.bet = util::read_numeric(\"Enter your bet:\");\n\n            if self.bet <= self.wallet {\n                break;\n            } else {\n                println!(\"You don't have that much money!\");\n            }\n        }\n\n        self.prompt_roll();\n        let point = CrapsGame::roll();\n\n        match point {\n            11 | 7 => {\n                self.player_win();\n            }\n            2 | 3 | 12 => {\n                self.player_lose();\n            }\n            _ => {\n                self.point = point;\n                self.state = GameState::PointRolls\n            }\n        }\n\n        true\n    }\n\n    fn player_win(&mut self) {\n        let bet = self.bet;\n\n        println!(\"You won ${bet}!\");\n\n        self.wallet += bet;\n        self.print_wallet();\n\n        self.state = GameState::ComeOut;\n    }\n\n    fn player_lose(&mut self) {\n        let bet = self.bet;\n\n        println!(\"You lost ${bet}!\");\n\n        self.wallet -= bet;\n        self.print_wallet();\n\n        if self.wallet == 0 {\n            self.game_over();\n        } else {\n            self.state = GameState::ComeOut;\n        }\n    }\n\n    fn print_wallet(&self) {\n        println!(\"\\nYou have ${} in your wallet.\", self.wallet);\n    }\n\n    fn roll() -> u8 {\n        use rand::Rng;\n\n        let roll = rand::thread_rng().gen_range(2..13);\n        println!(\"\\nYou rolled {}.\", roll);\n\n        roll\n    }\n\n    fn game_over(&mut self) {\n        self.state = GameState::GameOver;\n    }\n\n    fn prompt_roll(&mut self) {\n        use util::Response::*;\n\n        let response = util::prompt(\"Ready to roll?\");\n\n        match response {\n            Yes => (),\n            No => self.game_over(),\n        }\n    }\n}\n"
  },
  {
    "path": "29_Craps/rust/src/main.rs",
    "content": "mod craps_game;\nmod util;\nuse crate::craps_game::CrapsGame;\n\nfn main() {\n    println!(\"~~Craps~~\");\n    println!(\"Creative Computing Morristown, New Jersey\\n\");\n\n    let mut quit = false;\n\n    while !quit {\n        let mut game = CrapsGame::new();\n\n        loop {\n            if !game.tick() {\n                use util::Response::*;\n\n                match util::prompt(\"New Game?\") {\n                    Yes => (),\n                    No => quit = true,\n                }\n\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "29_Craps/rust/src/util.rs",
    "content": "use std::io;\n\npub enum Response {\n    Yes,\n    No,\n}\n\npub fn read_line() -> String {\n    let mut input = String::new();\n\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Error reading line.\");\n\n    input\n}\n\npub fn read_numeric(message: &str) -> usize {\n    loop {\n        println!(\"{}\", message);\n\n        let mut ok = true;\n\n        let input = read_line();\n\n        for c in input.trim().chars() {\n            if !c.is_numeric() {\n                println!(\"You can only enter a number!\");\n                ok = false;\n                break;\n            }\n        }\n\n        if ok {\n            let input = input.trim().parse();\n\n            let _ = match input {\n                Ok(i) => return i,\n                Err(e) => {\n                    println!(\"please input a number ({})\", e);\n                }\n            };\n        }\n    }\n}\n\npub fn prompt(msg: &str) -> Response {\n    use Response::*;\n\n    let mut _r = Response::Yes;\n\n    loop {\n        println!(\"\\n{}\", msg);\n\n        let response = read_line().trim().to_uppercase();\n\n        match response.as_str() {\n            \"YES\" | \"Y\" => {\n                _r = Yes;\n                break;\n            }\n            \"NO\" | \"N\" => {\n                _r = No;\n                break;\n            }\n            _ => println!(\"Please input (Y)es or (N)o.\"),\n        };\n    }\n\n    _r\n}\n"
  },
  {
    "path": "29_Craps/vbnet/Craps.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Craps\", \"Craps.vbproj\", \"{297AA824-815F-4E2B-948C-BDAD2266C5AF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{297AA824-815F-4E2B-948C-BDAD2266C5AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{297AA824-815F-4E2B-948C-BDAD2266C5AF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{297AA824-815F-4E2B-948C-BDAD2266C5AF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{297AA824-815F-4E2B-948C-BDAD2266C5AF}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "29_Craps/vbnet/Craps.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Craps</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "29_Craps/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "30_Cube/README.md",
    "content": "### Cube\n\nCUBE is a game played on the facing sides of a cube with a side dimension of 2. A location is designated by three numbers — e.g., 1, 2, 1. The object is to travel from 1, 1, 1 to 3, 3, 3 by moving one horizontal or vertical (not diagonal) square at a time without striking one of 5 randomly placed landmines. You are staked to $500; prior to each play of the game you may make a wager whether you will reach your destination. You lose if you hit a mine or try to make an illegal move — i.e., change more than one digit from your previous position.\n\nCube was created by Jerimac Ratliff of Fort Worth, Texas.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=53)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=68)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n##### Known Bugs\n\nThis program does very little validation of its input, enabling the user to cheat in two ways:\n- One can enter a large negative wager, purposely lose, and gain that much money.\n- One can move outside the cube (using coordinates 0 or 4), then safely walk \"around\" the standard play volume to the destination square.\n\nIt's remotely possible that these are clever solutions the user is intended to find, solving an otherwise purely random game.\n\n##### Randomization Logic\n\nThe BASIC code uses an interesting technique for choosing the random coordinates for the mines. The first coordinate is\nchosen like this:\n\n```basic\n380 LET A=INT(3*(RND(X)))\n390 IF A<>0 THEN 410\n400 LET A=3\n```\n\nwhere line 410 is the start of a similar block of code for the next coordinate. The behaviour of `RND(X)` depends on the\nvalue of `X`. If `X` is greater than zero then it returns a random value between 0 and 1. If `X` is zero it returns the\nlast random value generated, or 0 if no value has yet been generated.\n\nIf `X` is 1, therefore, the first line above set `A` to 0, 1, or 2. The next 2 lines replace a 0 with a 3. The\nreplacement values varies for the different coordinates with the result that the random selection is biased towards a\nspecific set of points. If `X` is 0, the `RND` calls all return 0, so the coordinates are the known. It appears that\nthis technique was probably used to allow testing the game with a well-known set of locations for the mines. However, in\nthe code as it comes to us, the value of `X` is never set and is thus 0, so the mine locations are never randomized.\n\nThe C# port implements the biased randomized mine locations, as seems to be the original intent, but includes a\ncommand-line switch to enable the deterministic execution as well.\n"
  },
  {
    "path": "30_Cube/csharp/Cube.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "30_Cube/csharp/Cube.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Cube\", \"Cube.csproj\", \"{CC2F0DBE-EBA0-4275-ACA4-7140E3202889}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{CC2F0DBE-EBA0-4275-ACA4-7140E3202889}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CC2F0DBE-EBA0-4275-ACA4-7140E3202889}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CC2F0DBE-EBA0-4275-ACA4-7140E3202889}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CC2F0DBE-EBA0-4275-ACA4-7140E3202889}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "30_Cube/csharp/Game.cs",
    "content": "namespace Cube;\n\ninternal class Game\n{\n    private const int _initialBalance = 500;\n    private readonly IEnumerable<(int, int, int)> _seeds = new List<(int, int, int)>\n    {\n        (3, 2, 3), (1, 3, 3), (3, 3, 2), (3, 2, 3), (3, 1, 3)\n    };\n    private readonly (float, float, float) _startLocation = (1, 1, 1);\n    private readonly (float, float, float) _goalLocation = (3, 3, 3);\n\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    public void Play()\n    {\n        _io.Write(Streams.Introduction);\n\n        if (_io.ReadNumber(\"\") != 0)\n        {\n            _io.Write(Streams.Instructions);\n        }\n\n        PlaySeries(_initialBalance);\n\n        _io.Write(Streams.Goodbye);\n    }\n\n    private void PlaySeries(float balance)\n    {\n        while (true)\n        {\n            var wager = _io.ReadWager(balance);\n\n            var gameWon = PlayGame();\n\n            if (wager.HasValue)\n            {\n                balance = gameWon ? (balance + wager.Value) : (balance - wager.Value);\n                if (balance <= 0)\n                {\n                    _io.Write(Streams.Bust);\n                    return;\n                }\n                _io.WriteLine(Formats.Balance, balance);\n            }\n\n            if (_io.ReadNumber(Prompts.TryAgain) != 1) { return; }\n        }\n    }\n\n    private bool PlayGame()\n    {\n        var mineLocations = _seeds.Select(seed => _random.NextLocation(seed)).ToHashSet();\n        var currentLocation = _startLocation;\n        var prompt = Prompts.YourMove;\n\n        while (true)\n        {\n            var newLocation = _io.Read3Numbers(prompt);\n\n            if (!MoveIsLegal(currentLocation, newLocation)) { return Lose(Streams.IllegalMove); }\n\n            currentLocation = newLocation;\n\n            if (currentLocation == _goalLocation) { return Win(Streams.Congratulations); }\n\n            if (mineLocations.Contains(currentLocation)) { return Lose(Streams.Bang); }\n\n            prompt = Prompts.NextMove;\n        }\n    }\n\n    private bool Lose(Stream text)\n    {\n        _io.Write(text);\n        return false;\n    }\n\n    private bool Win(Stream text)\n    {\n        _io.Write(text);\n        return true;\n    }\n\n    private bool MoveIsLegal((float, float, float) from, (float, float, float) to)\n        => (to.Item1 - from.Item1, to.Item2 - from.Item2, to.Item3 - from.Item3) switch\n        {\n            ( > 1, _, _) => false,\n            (_, > 1, _) => false,\n            (_, _, > 1) => false,\n            (1, 1, _) => false,\n            (1, _, 1) => false,\n            (_, 1, 1) => false,\n            _ => true\n        };\n}\n"
  },
  {
    "path": "30_Cube/csharp/IOExtensions.cs",
    "content": "namespace Cube;\n\ninternal static class IOExtensions\n{\n    internal static float? ReadWager(this IReadWrite io, float balance)\n    {\n        io.Write(Streams.Wager);\n        if (io.ReadNumber(\"\") == 0) { return null; }\n\n        var prompt = Prompts.HowMuch;\n\n        while(true)\n        {\n            var wager = io.ReadNumber(prompt);\n            if (wager <= balance) { return wager; }\n\n            prompt = Prompts.BetAgain;\n        }\n    }\n}\n"
  },
  {
    "path": "30_Cube/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\n\nglobal using static Cube.Resources.Resource;\n\nusing Cube;\n\nIRandom random = args.Contains(\"--non-random\") ? new ZerosGenerator() : new RandomNumberGenerator();\n\nnew Game(new ConsoleIO(), random).Play();\n"
  },
  {
    "path": "30_Cube/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\n#### Execution\n\nAs noted in the main Readme file, the randomization code in the BASIC program has a switch (the variable `X`) that\nallows the game to be run in a deterministic (non-random) mode.\n\nRunning the C# port without command-line parameters will play the game with random mine locations.\n\nRunning the port with a `--non-random` command-line switch will run the game with non-random mine locations.\n"
  },
  {
    "path": "30_Cube/csharp/RandomExtensions.cs",
    "content": "namespace Cube;\n\ninternal static class RandomExtensions\n{\n    internal static (float, float, float) NextLocation(this IRandom random, (int, int, int) bias)\n        => (random.NextCoordinate(bias.Item1), random.NextCoordinate(bias.Item2), random.NextCoordinate(bias.Item3));\n\n    private static float NextCoordinate(this IRandom random, int bias)\n    {\n        var value = random.Next(3);\n        if (value == 0) { value = bias; }\n        return value;\n    }\n}"
  },
  {
    "path": "30_Cube/csharp/Resources/Balance.txt",
    "content": "You now have {0} dollars."
  },
  {
    "path": "30_Cube/csharp/Resources/Bang.txt",
    "content": "******BANG******\nYou lose!\n\n\n"
  },
  {
    "path": "30_Cube/csharp/Resources/BetAgain.txt",
    "content": "Tried to fool me; bet again"
  },
  {
    "path": "30_Cube/csharp/Resources/Bust.txt",
    "content": "You bust.\n"
  },
  {
    "path": "30_Cube/csharp/Resources/Congratulations.txt",
    "content": "Congratulations!\n"
  },
  {
    "path": "30_Cube/csharp/Resources/Goodbye.txt",
    "content": "Tough luck!\n\nGoodbye.\n"
  },
  {
    "path": "30_Cube/csharp/Resources/HowMuch.txt",
    "content": "How much "
  },
  {
    "path": "30_Cube/csharp/Resources/IllegalMove.txt",
    "content": "\nIllegal move. You lose.\n"
  },
  {
    "path": "30_Cube/csharp/Resources/Instructions.txt",
    "content": "This is a game in which you will be playing against the\nrandom decision od the computer. The field of play is a\ncube of side 3. Any of the 27 locations can be designated\nby inputing three numbers such as 2,3,1. At the start,\nyou are automatically at location 1,1,1. The object of\nthe game is to get to location 3,3,3. One minor detail:\nthe computer will pick, at random, 5 locations at which\nit will play land mines. If you hit one of these locations\nyou lose. One other details: you may move only one space\nin one direction each move. For example: from 1,1,2 you\nmay move to 2,1,2 or 1,1,3. You may not change\ntwo of the numbers on the same move. If you make an illegal\nmove, you lose and the computer takes the money you may\nhave bet on that round.\n\n\nAll Yes or No questions will be answered by a 1 for Yes\nor a 0 (zero) for no.\n\nWhen stating the amount of a wager, print only the number\nof dollars (example: 250)  You are automatically started with\n500 dollars in your account.\n\nGood luck!\n"
  },
  {
    "path": "30_Cube/csharp/Resources/Introduction.txt",
    "content": "                                  Cube\n               Creative Computing  Morristown, New Jersey\n\n\n\nDo you want to see the instructions? (Yes--1,No--0)\n"
  },
  {
    "path": "30_Cube/csharp/Resources/NextMove.txt",
    "content": "Next move: "
  },
  {
    "path": "30_Cube/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Cube.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n        public static Stream Instructions => GetStream();\n        public static Stream Wager => GetStream();\n        public static Stream IllegalMove => GetStream();\n        public static Stream Bang => GetStream();\n        public static Stream Bust => GetStream();\n        public static Stream Congratulations => GetStream();\n        public static Stream Goodbye => GetStream();\n    }\n\n    internal static class Prompts\n    {\n        public static string HowMuch => GetString();\n        public static string BetAgain => GetString();\n        public static string YourMove => GetString();\n        public static string NextMove => GetString();\n        public static string TryAgain => GetString();\n    }\n\n    internal static class Formats\n    {\n        public static string Balance => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "30_Cube/csharp/Resources/TryAgain.txt",
    "content": "Do you want to try again "
  },
  {
    "path": "30_Cube/csharp/Resources/Wager.txt",
    "content": "Want to make a wager\n"
  },
  {
    "path": "30_Cube/csharp/Resources/YourMove.txt",
    "content": "\nIt's your move:  "
  },
  {
    "path": "30_Cube/csharp/ZerosGenerator.cs",
    "content": "namespace Cube;\n\ninternal class ZerosGenerator : IRandom\n{\n    public float NextFloat() => 0;\n\n    public float PreviousFloat() => 0;\n\n    public void Reseed(int seed) { }\n}"
  },
  {
    "path": "30_Cube/cube.bas",
    "content": "10 PRINT TAB(34);\"CUBE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT : PRINT : PRINT\n100 PRINT \"DO YOU WANT TO SEE THE INSTRUCTIONS? (YES--1,NO--0)\"\n110 INPUT B7\n120 IF B7=0 THEN 370\n130 PRINT\"THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE\"\n140 PRINT\"RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A\"\n150 PRINT\"CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED\"\n160 PRINT\"BY INPUTING THREE NUMBERS SUCH AS 2,3,1. AT THE START,\"\n170 PRINT\"YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF\"\n180 PRINT\"THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:\"\n190 PRINT\"THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH\"\n200 PRINT\"IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS\"\n210 PRINT\"YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE \"\n220 PRINT\"IN ONE DIRECTION EACH MOVE. FOR  EXAMPLE: FROM 1,1,2 YOU\"\n230 PRINT\"MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE\"\n240 PRINT\"TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL\"\n250 PRINT\"MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY\"\n260 PRINT\"HAVE BET ON THAT ROUND.\"\n270 PRINT\n280 PRINT\n290 PRINT\"ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES\"\n300 PRINT\"OR A 0 (ZERO) FOR NO.\"\n310 PRINT\n320 PRINT\"WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER\"\n330 PRINT\"OF DOLLARS (EXAMPLE: 250)  YOU ARE AUTOMATICALLY STARTED WITH\"\n340 PRINT\"500 DOLLARS IN YOUR ACCOUNT.\"\n350 PRINT\n360 PRINT \"GOOD LUCK!\"\n370 LET A1=500\n380 LET A=INT(3*(RND(X)))\n390 IF A<>0 THEN 410\n400 LET A=3\n410 LET B=INT(3*(RND(X)))\n420 IF B<>0 THEN 440\n430 LET B=2\n440 LET C=INT(3*(RND(X)))\n450 IF C<>0 THEN 470\n460 LET C=3\n470 LET D=INT(3*(RND(X)))\n480 IF D<>0 THEN 500\n490 LET D=1\n500 LET E=INT(3*(RND(X)))\n510 IF E<>0 THEN 530\n520 LET E=3\n530 LET F=INT(3*(RND(X)))\n540 IF F<>0 THEN 560\n550 LET F=3\n560 LET G=INT(3*(RND(X)))\n570 IF G<>0 THEN 590\n580 LET G=3\n590 LET H=INT(3*(RND(X)))\n600 IF H<>0 THEN 620\n610 LET H=3\n620 LET I=INT(3*(RND(X)))\n630 IF I<>0 THEN 650\n640 LET I=2\n650 LET J=INT(3*(RND(X)))\n660 IF J<>0 THEN 680\n670 LET J=3\n680 LET K=INT(3*(RND(X)))\n690 IF K<>0 THEN 710\n700 LET K=2\n710 LET L=INT(3*(RND(X)))\n720 IF L<>0 THEN 740\n730 LET L=3\n740 LET M=INT(3*(RND(X)))\n750 IF M<>0 THEN 770\n760 LET M=3\n770 LET N=INT(3*(RND(X)))\n780 IF N<>0 THEN 800\n790 LET N=1\n800 LET O=INT (3*(RND(X)))\n810 IF O <>0 THEN 830\n820 LET O=3\n830 PRINT \"WANT TO MAKE A WAGER?\"\n840 INPUT Z\n850 IF Z=0 THEN 880\n860 PRINT \"HOW MUCH \";\n870 INPUT Z1\n876 IF A1<Z1 THEN 1522\n880 LET W=1\n890 LET X=1\n900 LET Y=1\n910 PRINT\n920 PRINT \"IT'S YOUR MOVE:  \";\n930 INPUT P,Q,R\n940 IF P>W+1 THEN 1030\n950 IF P=W+1 THEN 1000\n960 IF Q>X+1 THEN 1030\n970 IF Q=(X+1) THEN 1010\n980 IF R >(Y+1)  THEN 1030\n990 GOTO 1050\n1000 IF Q>= X+1 THEN 1030\n1010 IF R>=Y+1 THEN 1030\n1020 GOTO 1050\n1030 PRINT:PRINT \"ILLEGAL MOVE. YOU LOSE.\"\n1040 GOTO 1440\n1050 LET W=P\n1060 LET X=Q\n1070 LET Y=R\n1080 IF P=3 THEN 1100\n1090 GOTO 1130\n1100 IF  Q=3 THEN 1120\n1110 GOTO 1130\n1120 IF R=3 THEN 1530\n1130 IF P=A THEN 1150\n1140 GOTO 1180\n1150 IF Q=B THEN 1170\n1160 GOTO 1180\n1170 IF R=C THEN 1400\n1180 IF P=D THEN 1200\n1190 GOTO 1230\n1200 IF Q=E THEN 1220\n1210 GOTO 1230\n1220 IF  R=F THEN 1400\n1230 IF P=G THEN 1250\n1240 GOTO 1280\n1250 IF Q=H THEN 1270\n1260 GOTO 1280\n1270 IF R=I THEN 1400\n1280 IF P=J THEN 1300\n1290 GOTO 1330\n1300 IF Q=K THEN 1320\n1310 GOTO 1330\n1320 IF R=L THEN 1400\n1330 IF P=M THEN 1350\n1340 GOTO 1380\n1350 IF Q=N THEN 1370\n1360 GOTO 1380\n1370 IF R=O THEN 1400\n1380 PRINT \"NEXT MOVE: \";\n1390 GOTO 930\n1400 PRINT\"******BANG******\"\n1410 PRINT \"YOU LOSE!\"\n1420 PRINT\n1430 PRINT\n1440 IF   Z=0 THEN 1580\n1450 PRINT\n1460 LET Z2=A1-Z1\n1470 IF Z2>0 THEN 1500\n1480 PRINT \"YOU BUST.\"\n1490 GOTO 1610\n1500 PRINT \" YOU NOW HAVE\"; Z2; \"DOLLARS.\"\n1510 LET A1=Z2\n1520 GOTO 1580\n1522 PRINT\"TRIED TO FOOL ME; BET AGAIN\";\n1525 GOTO 870\n1530 PRINT\"CONGRATULATIONS!\"\n1540 IF Z=0 THEN 1580\n1550 LET Z2=A1+Z1\n1560 PRINT \"YOU NOW HAVE\"; Z2;\"DOLLARS.\"\n1570 LET A1=Z2\n1580 PRINT\"DO YOU WANT TO TRY AGAIN \";\n1590 INPUT S\n1600 IF S=1 THEN 380\n1610 PRINT \"TOUGH LUCK!\"\n1620 PRINT\n1630 PRINT \"GOODBYE.\"\n1640 END\n"
  },
  {
    "path": "30_Cube/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "30_Cube/java/src/Cube.java",
    "content": "import java.io.PrintStream;\nimport java.util.HashSet;\nimport java.util.Random;\nimport java.util.Scanner;\nimport java.util.Set;\n\n/**\n * Game of Cube\n * <p>\n * Based on game of Cube at:\n * https://github.com/coding-horror/basic-computer-games/blob/main/30_Cube/cube.bas\n *\n *\n */\npublic class Cube {\n\n    //Current player location\n    private Location playerLocation;\n\n    //Current list of mines\n    private Set<Location> mines;\n\n    //System input / output objects\n    private PrintStream out;\n    private Scanner scanner;\n\n    //Player's current money\n    private int money;\n\n    /**\n     * Entry point, creates a new Cube object and calls the play method\n     * @param args Java execution arguments, not used in application\n     */\n    public static void main(String[] args) {\n        new Cube().play();\n    }\n\n    public Cube() {\n        out = System.out;\n        scanner = new Scanner(System.in);\n        money = 500;\n        mines = new HashSet<>(5);\n    }\n\n    /**\n     * Clears mines and places 5 new mines on the board\n     */\n    private void placeMines() {\n        mines.clear();\n        Random random = new Random();\n        for(int i = 0; i < 5; i++) {\n            int x = random.nextInt(1,4);\n            int y = random.nextInt(1,4);\n            int z = random.nextInt(1,4);\n            mines.add(new Location(x,y,z));\n        }\n    }\n\n    /**\n     * Runs the entire game until the player runs out of money or chooses to stop\n     */\n    public void play() {\n        out.println(\"DO YOU WANT TO SEE INSTRUCTIONS? (YES--1,NO--0)\");\n        if(readParsedBoolean()) {\n            printInstructions();\n        }\n        do {\n            placeMines();\n            out.println(\"WANT TO MAKE A WAGER?\");\n            int wager = 0 ;\n\n            if(readParsedBoolean()) {\n                out.println(\"HOW MUCH?\");\n                do {\n                    wager = Integer.parseInt(scanner.nextLine());\n                    if(wager > money) {\n                        out.println(\"TRIED TO FOOL ME; BET AGAIN\");\n                    }\n                } while(wager > money);\n            }\n\n            playerLocation = new Location(1,1,1);\n            while(playerLocation.x + playerLocation.y + playerLocation.z != 9) {\n                out.println(\"\\nNEXT MOVE\");\n                String input = scanner.nextLine();\n\n                String[] stringValues = input.split(\",\");\n\n                if(stringValues.length < 3) {\n                    out.println(\"ILLEGAL MOVE, YOU LOSE.\");\n                    return;\n                }\n\n                int x = Integer.parseInt(stringValues[0]);\n                int y = Integer.parseInt(stringValues[1]);\n                int z = Integer.parseInt(stringValues[2]);\n\n                Location location = new Location(x,y,z);\n\n                if(x < 1 || x > 3 || y < 1 || y > 3 || z < 1 || z > 3 || !isMoveValid(playerLocation,location)) {\n                    out.println(\"ILLEGAL MOVE, YOU LOSE.\");\n                    return;\n                }\n\n                playerLocation = location;\n\n                if(mines.contains(location)) {\n                    out.println(\"******BANG******\");\n                    out.println(\"YOU LOSE!\\n\\n\");\n                    money -= wager;\n                    break;\n                }\n            }\n\n            if(wager > 0) {\n                out.printf(\"YOU NOW HAVE %d DOLLARS\\n\",money);\n            }\n\n        } while(money > 0 && doAnotherRound());\n\n        out.println(\"TOUGH LUCK!\");\n        out.println(\"\\nGOODBYE.\");\n    }\n\n    /**\n     * Queries the user whether they want to play another round\n     * @return True if the player decides to play another round,\n     * False if the player would not like to play again\n     */\n    private boolean doAnotherRound() {\n        if(money > 0) {\n            out.println(\"DO YOU WANT TO TRY AGAIN?\");\n            return readParsedBoolean();\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * Prints the instructions to the game, copied from the original code.\n     */\n    public void printInstructions() {\n        out.println(\"THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE\");\n        out.println(\"RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A\");\n        out.println(\"CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED\");\n        out.println(\"BY INPUTTING THREE NUMBERS SUCH AS 2,3,1. AT THE START\");\n        out.println(\"YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF\");\n        out.println(\"THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:\");\n        out.println(\"THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH\");\n        out.println(\"IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS\");\n        out.println(\"YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE\");\n        out.println(\"IN ONE DIRECTION EACH MOVE. FOR  EXAMPLE: FROM 1,1,2 YOU\");\n        out.println(\"MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE\");\n        out.println(\"TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL\");\n        out.println(\"MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY\");\n        out.println(\"\\n\");\n        out.println(\"ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES\");\n        out.println(\"OR A 0 (ZERO) FOR NO.\");\n        out.println();\n        out.println(\"WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER\");\n        out.println(\"OF DOLLARS (EXAMPLE: 250)  YOU ARE AUTOMATICALLY STARTED WITH\");\n        out.println(\"500 DOLLARS IN YOUR ACCOUNT.\");\n        out.println();\n        out.println(\"GOOD LUCK!\");\n    }\n\n    /**\n     * Waits for the user to input a boolean value. This could either be (true,false), (1,0), (y,n), (yes,no), etc.\n     * By default, it will return false\n     * @return Parsed boolean value of the user input\n     */\n    private boolean readParsedBoolean() {\n        String in = scanner.nextLine();\n        try {\n            return in.toLowerCase().charAt(0) == 'y' || Boolean.parseBoolean(in) || Integer.parseInt(in) == 1;\n        } catch(NumberFormatException exception) {\n            return false;\n        }\n    }\n\n    /**\n     * Checks if a move is valid\n     * @param from The point that the player is at\n     * @param to The point that the player wishes to move to\n     * @return True if the player is only moving, at most, 1 location in any direction, False if the move is invalid\n     */\n    private boolean isMoveValid(Location from, Location to) {\n        return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) + Math.abs(from.z - to.z) <= 1;\n    }\n\n    public class Location {\n        int x,y,z;\n\n        public Location(int x, int y, int z) {\n            this.x = x;\n            this.y = y;\n            this.z = z;\n        }\n\n        /*\n        For use in HashSet and checking if two Locations are the same\n         */\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            Location location = (Location) o;\n\n            if (x != location.x) return false;\n            if (y != location.y) return false;\n            return z == location.z;\n        }\n\n        /*\n        For use in the HashSet to accordingly index the set\n         */\n        @Override\n        public int hashCode() {\n            int result = x;\n            result = 31 * result + y;\n            result = 31 * result + z;\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "30_Cube/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "30_Cube/javascript/cube.html",
    "content": "<html>\n<head>\n<title>CUBE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"cube.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "30_Cube/javascript/cube.js",
    "content": "// CUBE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"CUBE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"DO YOU WANT TO SEE THE INSTRUCTIONS? (YES--1,NO--0)\");\n    b7 = parseInt(await input());\n    if (b7 != 0) {\n        print(\"THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE\\n\");\n        print(\"RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A\\n\");\n        print(\"CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED\\n\");\n        print(\"BY INPUTING THREE NUMBERS SUCH AS 2,3,1. AT THE START,\\n\");\n        print(\"YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF\\n\");\n        print(\"THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:\\n\");\n        print(\"THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH\\n\");\n        print(\"IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS\\n\");\n        print(\"YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE \\n\");\n        print(\"IN ONE DIRECTION EACH MOVE. FOR  EXAMPLE: FROM 1,1,2 YOU\\n\");\n        print(\"MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE\\n\");\n        print(\"TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL\\n\");\n        print(\"MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY\\n\");\n        print(\"HAVE BET ON THAT ROUND.\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES\\n\");\n        print(\"OR A 0 (ZERO) FOR NO.\\n\");\n        print(\"\\n\");\n        print(\"WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER\\n\");\n        print(\"OF DOLLARS (EXAMPLE: 250)  YOU ARE AUTOMATICALLY STARTED WITH\\n\");\n        print(\"500 DOLLARS IN YOUR ACCOUNT.\\n\");\n        print(\"\\n\");\n        print(\"GOOD LUCK!\\n\");\n    }\n    a1 = 500;\n    while (1) {\n        a = Math.floor(3 * Math.random());\n        if (a == 0)\n            a = 3;\n        b = Math.floor(3 * Math.random());\n        if (b == 0)\n            b = 2;\n        c = Math.floor(3 * Math.random());\n        if (c == 0)\n            c = 3;\n        d = Math.floor(3 * Math.random());\n        if (d == 0)\n            d = 1;\n        e = Math.floor(3 * Math.random());\n        if (e == 0)\n            e = 3;\n        f = Math.floor(3 * Math.random());\n        if (f == 0)\n            f = 3;\n        g = Math.floor(3 * Math.random());\n        if (g == 0)\n            g = 3;\n        h = Math.floor(3 * Math.random());\n        if (h == 0)\n            h = 3;\n        i = Math.floor(3 * Math.random());\n        if (i == 0)\n            i = 2;\n        j = Math.floor(3 * Math.random());\n        if (j == 0)\n            j = 3;\n        k = Math.floor(3 * Math.random());\n        if (k == 0)\n            k = 2;\n        l = Math.floor(3 * Math.random());\n        if (l == 0)\n            l = 3;\n        m = Math.floor(3 * Math.random());\n        if (m == 0)\n            m = 3;\n        n = Math.floor(3 * Math.random());\n        if (n == 0)\n            n = 1;\n        o = Math.floor(3 * Math.random());\n        if (o == 0)\n            o = 3;\n        print(\"WANT TO MAKE A WAGER?\");\n        z = parseInt(await input());\n        if (z != 0) {\n            print(\"HOW MUCH \");\n            while (1) {\n                z1 = parseInt(await input());\n                if (a1 < z1) {\n                    print(\"TRIED TO FOOL ME; BET AGAIN\");\n                } else {\n                    break;\n                }\n            }\n        }\n        w = 1;\n        x = 1;\n        y = 1;\n        print(\"\\n\");\n        print(\"IT'S YOUR MOVE:  \");\n        while (1) {\n            str = await input();\n            p = parseInt(str);\n            q = parseInt(str.substr(str.indexOf(\",\") + 1));\n            r = parseInt(str.substr(str.lastIndexOf(\",\") + 1));\n            if (p > w + 1 || q > x + 1 || r > y + 1 || (p == w + 1 && (q >= x + 1 || r >= y + 1)) || (q == x + 1 && r >= y + 1)) {\n                print(\"\\n\");\n                print(\"ILLEGAL MOVE, YOU LOSE.\\n\");\n                break;\n            }\n            w = p;\n            x = q;\n            y = r;\n            if (p == 3 && q == 3 && r == 3) {\n                won = true;\n                break;\n            }\n            if (p == a && q == b && r == c\n             || p == d && q == e && r == f\n             || p == g && q == h && r == i\n             || p == j && q == k && r == l\n             || p == m && q == n && r == o) {\n                print(\"******BANG******\");\n                print(\"YOU LOSE!\");\n                print(\"\\n\");\n                print(\"\\n\");\n                won = false;\n                break;\n            }\n            print(\"NEXT MOVE: \");\n        }\n        if (won) {\n            print(\"CONGRATULATIONS!\\n\");\n            if (z != 0) {\n                z2 = a1 + z1;\n                print(\"YOU NOW HAVE \" + z2 + \" DOLLARS.\\n\");\n                a1 = z2;\n            }\n        } else {\n            if (z != 0) {\n                print(\"\\n\");\n                z2 = a1 - z1;\n                if (z2 <= 0) {\n                    print(\"YOU BUST.\\n\");\n                    break;\n                } else {\n                    print(\" YOU NOW HAVE \" + z2 + \" DOLLARS.\\n\");\n                    a1 = z2;\n                }\n            }\n        }\n        print(\"DO YOU WANT TO TRY AGAIN \");\n        s = parseInt(await input());\n        if (s != 1)\n            break;\n    }\n    print(\"TOUGH LUCK!\\n\");\n    print(\"\\n\");\n    print(\"GOODBYE.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "30_Cube/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "30_Cube/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "30_Cube/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "30_Cube/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "30_Cube/python/cube.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nCUBE\n\nConverted from BASIC to Python by Trevor Hobson\n\"\"\"\n\nimport random\nfrom typing import Tuple\n\n\ndef mine_position() -> Tuple[int, int, int]:\n    return (random.randint(1, 3), random.randint(1, 3), random.randint(1, 3))\n\n\ndef parse_move(move: str) -> Tuple[int, int, int]:\n    coordinates = [int(item) for item in move.split(\",\")]\n    if len(coordinates) == 3:\n        return tuple(coordinates)  # type: ignore\n    raise ValueError\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n\n    money = 500\n    print(\"\\nYou have\", money, \"dollars.\")\n    while True:\n        mines = []\n        for _ in range(5):\n            while True:\n                mine = mine_position()\n                if (\n                    mine not in mines\n                    and mine != (1, 1, 1)\n                    and mine != (3, 3, 3)\n                ):\n                    break\n            mines.append(mine)\n        wager = -1\n        while wager == -1:\n            try:\n                wager = int(input(\"\\nHow much do you want to wager? \"))\n                if not 0 <= wager <= money:\n                    wager = -1\n                    print(\"Tried to fool me; bet again\")\n            except ValueError:\n                print(\"Please enter a number.\")\n        prompt = \"\\nIt's your move: \"\n        position = (1, 1, 1)\n        while True:\n            move = (-1, -1, -1)\n            while move == (-1, -1, -1):\n                try:\n                    move = parse_move(input(prompt))\n                except (ValueError, IndexError):\n                    print(\"Please enter valid coordinates.\")\n            if (\n                abs(move[0] - position[0])\n                + abs(move[1] - position[1])\n                + abs(move[2] - position[2])\n            ) > 1:\n                print(\"\\nIllegal move. You lose\")\n                money = money - wager\n                break\n            elif (\n                move[0] not in [1, 2, 3]\n                or move[1] not in [1, 2, 3]\n                or move[2] not in [1, 2, 3]\n            ):\n                print(\"\\nIllegal move. You lose\")\n                money = money - wager\n                break\n            elif move == (3, 3, 3):\n                print(\"\\nCongratulations!\")\n                money = money + wager\n                break\n            elif move in mines:\n                print(\"\\n******BANG******\")\n                print(\"You lose!\")\n                money = money - wager\n                break\n            else:\n                position = move\n                prompt = \"\\nNext move: \"\n        if money > 0:\n            print(\"\\nYou now have\", money, \"dollars.\")\n            if not input(\"Do you want to try again \").lower().startswith(\"y\"):\n                break\n        else:\n            print(\"\\nYou bust.\")\n    print(\"\\nTough luck\")\n    print(\"\\nGoodbye.\")\n\n\ndef print_instructions() -> None:\n    print(\"\\nThis is a game in which you will be playing against the\")\n    print(\"random decisions of the computer. The field of play is a\")\n    print(\"cube of side 3. Any of the 27 locations can be designated\")\n    print(\"by inputing three numbers such as 2,3,1. At the start,\")\n    print(\"you are automatically at location 1,1,1. The object of\")\n    print(\"the game is to get to location 3,3,3. One minor detail:\")\n    print(\"the computer will pick, at random, 5 locations at which\")\n    print(\"it will plant land mines. If you hit one of these locations\")\n    print(\"you lose. One other detail: You may move only one space\")\n    print(\"in one direction each move. For example: From 1,1,2 you\")\n    print(\"may move to 2,1,2 or 1,1,3. You may not change\")\n    print(\"two of the numbers on the same move. If you make an illegal\")\n    print(\"move, you lose and the computer takes the money you may\")\n    print(\"have bet on that round.\\n\")\n    print(\"When stating the amount of a wager, print only the number\")\n    print(\"of dollars (example: 250) you are automatically started with\")\n    print(\"500 dollars in your account.\\n\")\n    print(\"Good luck!\")\n\n\ndef main() -> None:\n    print(\" \" * 34 + \"CUBE\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n    if input(\"Do you want to see the instructions \").lower().startswith(\"y\"):\n        print_instructions()\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nPlay again? (yes or no) \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "30_Cube/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "30_Cube/ruby/cube.rb",
    "content": "$landmines = Array.new\n\n$currentLocation = \"111\"\n\n$standings = 500 # starting amount\n\ndef getYesOrNoResponseTo prompt\n    print prompt\n    # strip leading and trailing whitespace from entry\n    yesno = gets.strip.upcase[0]\n    yesno == \"Y\"\nend\n\ndef greeting\n    puts \"CUBE\".center(80)\n    puts \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".center(80)\n    puts \"\\n\\n\\n\"\n    response = getYesOrNoResponseTo \"Do you want to see the INSTRUCTIONS?\"\n    if response\n        puts \"This is a game in which you will be playing against the\"\n        puts \"random decision of the computer. The field of play is a\"\n        puts \"cube of size 3. Any of your 27 locations can be designated\"\n        puts \"by inputting three numbers such as 231.\"\n        puts \"At the start you are automatically at location 1,1,1.\\n\"\n        puts \"The object of the game is to get to location 3,3,3.\\n\"\n\n        puts \"\\nONE MINOR DETAIL:\"\n        puts \"The computer will pick five random locations at which it will\"\n        puts \"plant land mines. if you hit one of these locations you lose.\\n\"\n\n        puts \"\\nONE OTHER DETAIL:\"\n        puts \"You may move only one space in one direction each move.\"\n        puts \"For example: from 1,1,2 you may move to 2,1,2 or 1,1,3.\"\n        puts \"You may not change more than one number on the same move.\"\n        puts \"If you make an illegal move, you lose and the computer takes\"\n        puts \"the money you may have bet on that round.\"\n        puts \"\"\n        puts \"When stating the amount of a wager, enter only the number\"\n        puts \"of dollars (example: 250)  You are automatically started with\"\n        puts \"500 dollars in your account.\"\n        puts\n        puts \"Good luck!\"\n    end\nend\n\ndef landMindStringFrom x, y, z\n    landMine = x.to_s + y.to_s + z.to_s\n    return landMine\nend\n\ndef assignLandMines\n    $landmines.clear\n\n    # put five unique entries into the landmines array\n    while $landmines.size < 5 do\n        a = rand(3)+1\n        b = rand(3)+1\n        c = rand(3)+1\n        landmine = landMindStringFrom(a, b, c)\n        if !$landmines.include?(landmine) && landmine != \"333\"\n# puts landmine     # debugging\n            $landmines.push landmine\n        end\n    end\n    $currentLocation = \"111\"\nend\n\ndef initializePot\n    $standings = 500 # starting amount\nend\n\ndef startGame\n    assignLandMines\n    displayStandings\n    response = getYesOrNoResponseTo \"WANT TO MAKE A WAGER? \"\n    if response\n        print \"HOW MUCH? \"\n        while true do\n        wager = gets.strip.tr('^0-9', '').to_i\n            if $standings < wager\n                puts \"TRIED TO FOOL ME; BET AGAIN \";\n            else\n                break\n            end\n        end\n    else\n        wager = 0\n    end\n\n    # start at location 1,1,1\n    $currentLocation = \"111\"\n    return wager\nend\n\ndef goodbye\n    puts \"TOUGH LUCK!\"\n    puts \"\"\n    puts \"GOODBYE.\"\n    exit\nend\n\ndef bust\n    puts \"YOU BUST.\"\n    goodbye\nend\n\ndef tryAgain\n    again = getYesOrNoResponseTo \"WANT TO TRY AGAIN? \"\n    if not again\n        exit\n    end\nend\n\ndef isLegalMove? newLocation\n    # test for illegal moves\n    # can only change one variable per move\n    # newLocation is the proposed new position\n    # can only move one space from the current position\n\n    moveX = newLocation[0].to_i\n    moveY = newLocation[1].to_i\n    moveZ = newLocation[2].to_i\n\n    # currentX, currentY, currentZ contains the current position\n    currentX = $currentLocation[0].to_i\n    currentY = $currentLocation[1].to_i\n    currentZ = $currentLocation[2].to_i\n\n    isLegalMove = true\n    errorString = \"\"\n   # ensure we're not moving off the cube\n    if not (moveX.between?(1,3) && moveY.between?(1,3) && moveZ.between?(1,3))\n        errorString = \"You moved off the cube!\"\n        return errorString\n    end\n\n    # test for only one move from current position\n    if not moveX.between?(currentX-1,currentX+1)\n        isLegalMove = false\n    end\n    if not moveY.between?(currentY-1,currentY+1)\n        isLegalMove = false\n    end\n    if not moveZ.between?(currentZ-1,currentZ+1)\n        isLegalMove = false\n    end\n        if not isLegalMove\n            errorString = \"You've gone too far\"\n        end\n\n    # only allow change to one variable at a time\n    if isLegalMove\n        if moveX != currentX\n            if moveY != currentY or moveZ != currentZ\n                isLegalMove = false\n            end\n        end\n        if moveY != currentY\n            if moveX != currentX or moveZ != currentZ\n                isLegalMove = false\n            end\n        end\n        if moveZ != currentZ\n            if moveY != currentY or moveX != currentX\n                isLegalMove = false\n            end\n        end\n        if not isLegalMove\n            errorString = \"You made too many changes\"\n        end\n   end\n\n    return errorString\nend\n\ndef displayStandings\n    print \"You now have \" + $standings.to_s\n    if $standings > 1\n        puts \" dollars\"\n    else\n        puts \" dollar\"\n    end\nend\n\ndef didWin? location\n    location == \"333\"\nend\n\ndef youWin amount\n    $standings += amount\n    puts \"*** You win \" + amount.to_s + \" dollars! ***\\n\\n\"\n    displayStandings\n    tryAgain\n    assignLandMines\n    puts \"*** new cube ***\"\n    puts \"different landmine locations\"\n    puts \"starting over at location 111\"\nend\n\ndef youLose amount\n    # subtract the bet amount from the standings\n    if amount > 0\n        puts \"You lose \" + amount.to_s + \" dollars!\\n\\n\"\n        $standings -= amount\n    end\n    if $standings <= 0\n        # no money left, so end the game\n        bust\n    else\n        displayStandings\n    end\n    tryAgain\n    $currentLocation = \"111\"\n    puts \"starting over at location 111\"\nend\n\ndef landMine betAmount\n    puts \"******BANG******\"\n    puts \"You hit a land mine at \" + $currentLocation + \"!\"\n    youLose betAmount\nend\n\ndef gameLoop betAmount\n    while true do\n        puts \"\"\n        print \"IT'S YOUR MOVE:  \"\n        # allow only integers: strip anything else from input\n        moveToLocation = gets.strip.tr('^0-9', '')\n\n        # test for illegal moves\n        # can only change one variable per move\n        # moveToLocation is the proposed new position\n\n        error = isLegalMove?(moveToLocation)\n        if error == \"\"\n            # assign the new position\n            $currentLocation = moveToLocation\n\n            # test for win\n            if didWin?(moveToLocation)\n                youWin betAmount\n            end\n\n            # haven't won yet, test the land mines\n            if $landmines.include? moveToLocation\n                landMine betAmount\n            end\n\n        else\n            puts \"Illegal move: \" + error\n            youLose betAmount\n        end\n\n    end\nend\n\n\ngreeting\ninitializePot\ngameLoop startGame\n"
  },
  {
    "path": "30_Cube/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "30_Cube/rust/src/game.rs",
    "content": "use crate::util;\n\npub type Position = (u8, u8, u8);\n\npub struct Game {\n    wallet: usize,\n    bet: Option<usize>,\n    landmines: Vec<Position>,\n    player: Position,\n}\n\nimpl Game {\n    pub fn new() -> Self {\n        Game {\n            wallet: 500,\n            bet: None,\n            landmines: util::get_landmines(),\n            player: (1, 1, 1),\n        }\n    }\n\n    pub fn play(&mut self) -> bool {\n        self.bet = self.get_bet();\n\n        let mut first_move = true;\n        let mut result = (false, \"******BANG!******\\nYOU LOSE\");\n\n        loop {\n            let msg = if first_move {\n                first_move = false;\n                \"ITS YOUR MOVE\"\n            } else {\n                \"NEXT MOVE\"\n            };\n\n            let (ok, p) = self.ask_position(msg);\n\n            if ok {\n                if p == (3, 3, 3) {\n                    result.0 = true;\n                    result.1 = \"CONGRATULATIONS!\";\n                    break;\n                } else if self.landmines.contains(&p) {\n                    break;\n                } else {\n                    self.player = p;\n                }\n            } else {\n                result.1 = \"ILLEGAL MOVE\\nYOU LOSE.\";\n                break;\n            }\n        }\n\n        println!(\"{}\", result.1);\n        self.calculate_wallet(result.0);\n        self.reset_game();\n\n        if self.wallet <= 0 {\n            println!(\"YOU ARE BROKE!\");\n            return false;\n        }\n\n        return util::prompt_bool(\"DO YOU WANT TO TRY AGAIN?\");\n    }\n\n    fn get_bet(&self) -> Option<usize> {\n        loop {\n            if util::prompt_bool(\"WANT TO MAKE A WAGER?\") {\n                let b = util::prompt_number(\"HOW MUCH?\");\n\n                if b != 0 && b <= self.wallet {\n                    return Some(b);\n                } else {\n                    println!(\"YOU CAN'T BET THAT!\");\n                }\n            } else {\n                return None;\n            };\n        }\n    }\n\n    fn ask_position(&self, msg: &str) -> (bool, Position) {\n        if let Some(p) = util::prompt_position(msg, self.player) {\n            return (true, p);\n        }\n        return (false, (0, 0, 0));\n    }\n\n    fn calculate_wallet(&mut self, win: bool) {\n        if let Some(b) = self.bet {\n            if win {\n                self.wallet += b;\n            } else {\n                self.wallet -= b;\n            }\n            self.bet = None;\n            println!(\"YOU NOW HAVE {} DOLLARS\", self.wallet);\n        }\n    }\n\n    fn reset_game(&mut self) {\n        self.player = (1, 1, 1);\n        self.landmines.clear();\n        self.landmines = util::get_landmines();\n    }\n}\n"
  },
  {
    "path": "30_Cube/rust/src/main.rs",
    "content": "use crate::game::Game;\n\nmod game;\nmod util;\n\nfn main() {\n    println!(\"\\n\\n\\t\\tCUBE\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n\n    if util::prompt_bool(\"DO YOU WANT TO SEE THE INSTRUCTIONS? (YES--1,NO--0)\") {\n        println!(\"\\nThis is a game in which you will be playing against the\");\n        println!(\"random decisions of the computer. The field of play is a\");\n        println!(\"cube of side 3. Any of the 27 locations can be designated\");\n        println!(\"by inputing three numbers such as 2,3,1. At the start,\");\n        println!(\"you are automatically at location 1,1,1. The object of\");\n        println!(\"the game is to get to location 3,3,3. One minor detail:\");\n        println!(\"the computer will pick, at random, 5 locations at which\");\n        println!(\"it will plant land mines. If you hit one of these locations\");\n        println!(\"you lose. One other detail: You may move only one space\");\n        println!(\"in one direction each move. For example: From 1,1,2 you\");\n        println!(\"may move to 2,1,2 or 1,1,3. You may not change\");\n        println!(\"two of the numbers on the same move. If you make an illegal\");\n        println!(\"move, you lose and the computer takes the money you may\");\n        println!(\"have bet on that round.\\n\");\n        println!(\"When stating the amount of a wager, print only the number\");\n        println!(\"of dollars (example: 250) you are automatically started with\");\n        println!(\"500 dollars in your account.\\n\");\n        println!(\"Good luck!\\n\");\n    }\n\n    let mut game = Game::new();\n\n    loop {\n        if !game.play() {\n            println!(\"\\nTOUGH LUCK\\n\\nGOODBYE!\\n\");\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "30_Cube/rust/src/util.rs",
    "content": "use std::num::ParseIntError;\n\nuse crate::game::Position;\n\npub fn get_random_position() -> Position {\n    (get_random_axis(), get_random_axis(), get_random_axis())\n}\n\nfn get_random_axis() -> u8 {\n    rand::Rng::gen_range(&mut rand::thread_rng(), 1..=3)\n}\n\npub fn get_landmines() -> Vec<Position> {\n    let mut landmines = Vec::new();\n\n    for _ in 0..5 {\n        let mut m = get_random_position();\n        while landmines.contains(&m) {\n            m = get_random_position();\n        }\n        landmines.push(m);\n    }\n\n    landmines\n}\n\nfn read_line() -> Result<usize, ParseIntError> {\n    let mut input = String::new();\n    std::io::stdin()\n        .read_line(&mut input)\n        .expect(\"~~Failed reading line!~~\");\n    input.trim().parse::<usize>()\n}\n\npub fn prompt_bool(msg: &str) -> bool {\n    loop {\n        println!(\"{}\", msg);\n\n        if let Ok(n) = read_line() {\n            if n == 1 {\n                return true;\n            } else if n == 0 {\n                return false;\n            }\n        }\n        println!(\"ENTER YES--1 OR NO--0\\n\");\n    }\n}\n\npub fn prompt_number(msg: &str) -> usize {\n    loop {\n        println!(\"{}\", msg);\n\n        if let Ok(n) = read_line() {\n            return n;\n        }\n        println!(\"ENTER A NUMBER\\n\");\n    }\n}\n\npub fn prompt_position(msg: &str, prev_pos: Position) -> Option<Position> {\n    loop {\n        println!(\"{}\", msg);\n\n        let mut input = String::new();\n        std::io::stdin()\n            .read_line(&mut input)\n            .expect(\"~~Failed reading line!~~\");\n\n        let input: Vec<&str> = input.trim().split(\",\").collect();\n\n        let pp = [prev_pos.0, prev_pos.1, prev_pos.2];\n        let mut pos = Vec::new();\n\n        if input.len() != 3 {\n            println!(\"YOU MUST ENTER 3 AXES!\");\n        } else {\n            for a in input {\n                if let Ok(n) = a.parse::<u8>() {\n                    if n == 0 || n > 3 {\n                        println!(\"YOU MUST ENTER AN AXIS BETWEEN 1 AND 3!\");\n                    } else {\n                        pos.push(n);\n                    }\n                } else {\n                    println!(\"INVALID LOCATION.\");\n                }\n            }\n\n            let mut moved = false;\n            for (i, p) in pos.iter().enumerate() {\n                let dt = ((*p as isize) - (pp[i] as isize)).abs();\n\n                if dt > 1 {\n                    return None;\n                }\n\n                if dt == 1 {\n                    if moved {\n                        return None;\n                    } else {\n                        moved = true;\n                    }\n                }\n            }\n        }\n\n        if pos.len() == 3 {\n            let pos = (pos[0], pos[1], pos[2]);\n            if pos == prev_pos {\n                println!(\"YOU ARE ALREADY THERE!\");\n            } else {\n                return Some(pos);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "30_Cube/vbnet/Cube.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Cube\", \"Cube.vbproj\", \"{C4AA207B-37EC-4746-B634-FBFC9522F3F8}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C4AA207B-37EC-4746-B634-FBFC9522F3F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C4AA207B-37EC-4746-B634-FBFC9522F3F8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C4AA207B-37EC-4746-B634-FBFC9522F3F8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C4AA207B-37EC-4746-B634-FBFC9522F3F8}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "30_Cube/vbnet/Cube.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Cube</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "30_Cube/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "31_Depth_Charge/README.md",
    "content": "### Depth Charge\n\nIn this program you are captain of the destroyer USS Computer. An enemy submarine has been causing trouble and your mission is to destroy it. You may select the seize of the “cube” of water you wish to search in. The computer then determines how many depth charges you get to destroy the submarine.\n\nEach depth charge is exploded by you specifying a trio of numbers; the first two are the surface coordinates (X,Y), the third is the depth. After each depth charge, your sonar observer will tell you where the explosion was relative to the submarine.\n\nDana Noftle wrote this program while a student at Acton High School, Acton, Massachusetts.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=55)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=70)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "31_Depth_Charge/csharp/Controller.cs",
    "content": "﻿using System;\n\nnamespace DepthCharge\n{\n    /// <summary>\n    /// Contains functions for reading input from the user.\n    /// </summary>\n    static class Controller\n    {\n        /// <summary>\n        /// Retrives a dimension for the play area from the user.\n        /// </summary>\n        /// <remarks>\n        /// Note that the original BASIC version would allow dimension values\n        /// of 0 or less.  We're doing a little extra validation here in order\n        /// to avoid strange behaviour.\n        /// </remarks>\n        public static int InputDimension()\n        {\n            View.PromptDimension();\n\n            while (true)\n            {\n                if (!Int32.TryParse(Console.ReadLine(), out var dimension))\n                    View.ShowInvalidNumber();\n                else\n                if (dimension < 1)\n                    View.ShowInvalidDimension();\n                else\n                    return dimension;\n            }\n        }\n\n        /// <summary>\n        /// Retrieves a set of coordinates from the user.\n        /// </summary>\n        /// <param name=\"trailNumber\">\n        /// The current trail number.\n        /// </param>\n        public static (int x, int y, int depth) InputCoordinates(int trailNumber)\n        {\n            View.PromptGuess(trailNumber);\n\n            while (true)\n            {\n                var coordinates = Console.ReadLine().Split(',');\n\n                if (coordinates.Length < 3)\n                    View.ShowTooFewCoordinates();\n                else\n                if (coordinates.Length > 3)\n                    View.ShowTooManyCoordinates();\n                else\n                if (!Int32.TryParse(coordinates[0], out var x) ||\n                    !Int32.TryParse(coordinates[1], out var y) ||\n                    !Int32.TryParse(coordinates[2], out var depth))\n                    View.ShowInvalidNumber();\n                else\n                    return (x, y, depth);\n            }\n        }\n\n        /// <summary>\n        /// Retrieves the user's intention to play again (or not).\n        /// </summary>\n        public static bool InputPlayAgain()\n        {\n            View.PromptPlayAgain();\n\n            while (true)\n            {\n                switch (Console.ReadLine())\n                {\n                    case \"Y\":\n                        return true;\n                    case \"N\":\n                        return false;\n                    default:\n                        View.ShowInvalidYesOrNo();\n                        break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "31_Depth_Charge/csharp/DepthCharge.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <RootNamespace>DepthCharge</RootNamespace>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "31_Depth_Charge/csharp/DepthCharge.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31129.286\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"DepthCharge\", \"DepthCharge.csproj\", \"{15CF71F3-72F3-4C81-B54F-139F2A1E3920}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{15CF71F3-72F3-4C81-B54F-139F2A1E3920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{15CF71F3-72F3-4C81-B54F-139F2A1E3920}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{15CF71F3-72F3-4C81-B54F-139F2A1E3920}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{15CF71F3-72F3-4C81-B54F-139F2A1E3920}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {738F08DD-89E9-44C5-B5AC-3F21C6AEEFA1}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "31_Depth_Charge/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace DepthCharge\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            var random = new Random();\n\n            View.ShowBanner();\n\n            var dimension = Controller.InputDimension();\n            var maximumGuesses = CalculateMaximumGuesses();\n\n            View.ShowInstructions(maximumGuesses);\n\n            do\n            {\n                View.ShowStartGame();\n\n                var submarineCoordinates = PlaceSubmarine();\n                var trailNumber = 1;\n                var guess = (0, 0, 0);\n\n                do\n                {\n                    guess = Controller.InputCoordinates(trailNumber);\n                    if (guess != submarineCoordinates)\n                        View.ShowGuessPlacement(submarineCoordinates, guess);\n                }\n                while (guess != submarineCoordinates && trailNumber++ < maximumGuesses);\n\n                View.ShowGameResult(submarineCoordinates, guess, trailNumber);\n            }\n            while (Controller.InputPlayAgain());\n\n            View.ShowFarewell();\n\n            int CalculateMaximumGuesses() =>\n                (int)Math.Log2(dimension) + 1;\n\n            (int x, int y, int depth) PlaceSubmarine() =>\n                (random.Next(dimension), random.Next(dimension), random.Next(dimension));\n        }\n    }\n}\n"
  },
  {
    "path": "31_Depth_Charge/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "31_Depth_Charge/csharp/View.cs",
    "content": "﻿using System;\n\nnamespace DepthCharge\n{\n    /// <summary>\n    /// Contains methods for displaying information to the user.\n    /// </summary>\n    static class View\n    {\n        public static void ShowBanner()\n        {\n            Console.WriteLine(\"                             DEPTH CHARGE\");\n            Console.WriteLine(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void ShowInstructions(int maximumGuesses)\n        {\n            Console.WriteLine(\"YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\");\n            Console.WriteLine(\"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\");\n            Console.WriteLine($\"MISSION IS TO DESTROY IT.  YOU HAVE {maximumGuesses} SHOTS.\");\n            Console.WriteLine(\"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\");\n            Console.WriteLine(\"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\");\n            Console.WriteLine(\"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\");\n            Console.WriteLine();\n        }\n\n        public static void ShowStartGame()\n        {\n            Console.WriteLine(\"GOOD LUCK !\");\n            Console.WriteLine();\n        }\n\n        public static void ShowGuessPlacement((int x, int y, int depth) actual, (int x, int y, int depth) guess)\n        {\n            Console.Write(\"SONAR REPORTS SHOT WAS \");\n            if (guess.y > actual.y)\n                Console.Write(\"NORTH\");\n            if (guess.y < actual.y)\n                Console.Write(\"SOUTH\");\n            if (guess.x > actual.x)\n                Console.Write(\"EAST\");\n            if (guess.x < actual.x)\n                Console.Write(\"WEST\");\n            if (guess.y != actual.y || guess.x != actual.y)\n                Console.Write(\" AND\");\n            if (guess.depth > actual.depth)\n                Console.Write (\" TOO LOW.\");\n            if (guess.depth < actual.depth)\n                Console.Write(\" TOO HIGH.\");\n            if (guess.depth == actual.depth)\n                Console.Write(\" DEPTH OK.\");\n\n            Console.WriteLine();\n        }\n\n        public static void ShowGameResult((int x, int y, int depth) submarineLocation, (int x, int y, int depth) finalGuess, int trailNumber)\n        {\n            Console.WriteLine();\n\n            if (submarineLocation == finalGuess)\n            {\n                Console.WriteLine($\"B O O M ! ! YOU FOUND IT IN {trailNumber} TRIES!\");\n            }\n            else\n            {\n                Console.WriteLine(\"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\");\n                Console.WriteLine($\"THE SUBMARINE WAS AT {submarineLocation.x}, {submarineLocation.y}, {submarineLocation.depth}\");\n            }\n        }\n\n        public static void ShowFarewell()\n        {\n            Console.WriteLine (\"OK.  HOPE YOU ENJOYED YOURSELF.\");\n        }\n\n        public static void ShowInvalidNumber()\n        {\n            Console.WriteLine(\"PLEASE ENTER A NUMBER\");\n        }\n\n        public static void ShowInvalidDimension()\n        {\n            Console.WriteLine(\"PLEASE ENTER A VALID DIMENSION\");\n        }\n\n        public static void ShowTooFewCoordinates()\n        {\n            Console.WriteLine(\"TOO FEW COORDINATES\");\n        }\n\n        public static void ShowTooManyCoordinates()\n        {\n            Console.WriteLine(\"TOO MANY COORDINATES\");\n        }\n\n        public static void ShowInvalidYesOrNo()\n        {\n            Console.WriteLine(\"PLEASE ENTER Y OR N\");\n        }\n\n        public static void PromptDimension()\n        {\n            Console.Write(\"DIMENSION OF SEARCH AREA? \");\n        }\n\n        public static void PromptGuess(int trailNumber)\n        {\n            Console.WriteLine();\n            Console.Write($\"TRIAL #{trailNumber}? \");\n        }\n\n        public static void PromptPlayAgain()\n        {\n            Console.WriteLine();\n            Console.Write(\"ANOTHER GAME (Y OR N)? \");\n        }\n    }\n}\n"
  },
  {
    "path": "31_Depth_Charge/depthcharge.bas",
    "content": "2 PRINT TAB(30);\"DEPTH CHARGE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n20 INPUT \"DIMENSION OF SEARCH AREA\";G: PRINT\n30 N=INT(LOG(G)/LOG(2))+1\n40 PRINT \"YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\"\n50 PRINT \"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\"\n60 PRINT \"MISSION IS TO DESTROY IT.  YOU HAVE\";N;\"SHOTS.\"\n70 PRINT \"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\"\n80 PRINT \"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\"\n90 PRINT \"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\"\n100 PRINT : PRINT \"GOOD LUCK !\": PRINT\n110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1))\n120 FOR D=1 TO N : PRINT : PRINT \"TRIAL #\";D; : INPUT X,Y,Z\n130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300\n140 GOSUB 500 : PRINT : NEXT D\n200 PRINT : PRINT \"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\"\n210 PRINT \"THE SUBMARINE WAS AT\";A;\",\";B;\",\";C : GOTO 400\n300 PRINT : PRINT \"B O O M ! ! YOU FOUND IT IN\";D;\"TRIES!\"\n400 PRINT : PRINT: INPUT \"ANOTHER GAME (Y OR N)\";A$\n410 IF A$=\"Y\" THEN 100\n420 PRINT \"OK.  HOPE YOU ENJOYED YOURSELF.\" : GOTO 600\n500 PRINT \"SONAR REPORTS SHOT WAS \";\n510 IF Y>B THEN PRINT \"NORTH\";\n520 IF Y<B THEN PRINT \"SOUTH\";\n530 IF X>A THEN PRINT \"EAST\";\n540 IF X<A THEN PRINT \"WEST\";\n550 IF Y<>B OR X<>A THEN PRINT \" AND\";\n560 IF Z>C THEN PRINT \" TOO LOW.\"\n570 IF Z<C THEN PRINT \" TOO HIGH.\"\n580 IF Z=C THEN PRINT \" DEPTH OK.\"\n590 RETURN\n600 END\n"
  },
  {
    "path": "31_Depth_Charge/java/DepthCharge.java",
    "content": "import java.util.Scanner;\nimport java.lang.Math;\n\n/**\n * Game of Depth Charge\n * <p>\n * Based on the BASIC game of Depth Charge here\n * https://github.com/coding-horror/basic-computer-games/blob/main/31%20Depth%20Charge/depthcharge.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class DepthCharge {\n\n  private final Scanner scan;  // For user input\n\n  public DepthCharge() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor DepthCharge\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(29) + \"DEPTH CHARGE\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    int searchArea = 0;\n    int shotNum = 0;\n    int shotTotal = 0;\n    int shotX = 0;\n    int shotY = 0;\n    int shotZ = 0;\n    int targetX = 0;\n    int targetY = 0;\n    int targetZ = 0;\n    int tries = 0;\n    String[] userCoordinates;\n    String userResponse = \"\";\n\n    System.out.print(\"DIMENSION OF SEARCH AREA? \");\n    searchArea = Integer.parseInt(scan.nextLine());\n    System.out.println(\"\");\n\n    shotTotal = (int) (Math.log10(searchArea) / Math.log10(2)) + 1;\n\n    System.out.println(\"YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\");\n    System.out.println(\"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\");\n    System.out.println(\"MISSION IS TO DESTROY IT.  YOU HAVE \" + shotTotal + \" SHOTS.\");\n    System.out.println(\"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\");\n    System.out.println(\"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\");\n    System.out.println(\"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\");\n\n    // Begin outer while loop\n    while (true) {\n\n      System.out.println(\"\");\n      System.out.println(\"GOOD LUCK !\");\n      System.out.println(\"\");\n\n      targetX = (int) ((searchArea + 1) * Math.random());\n      targetY = (int) ((searchArea + 1) * Math.random());\n      targetZ = (int) ((searchArea + 1) * Math.random());\n\n      // Begin loop through all shots\n      for (shotNum = 1; shotNum <= shotTotal; shotNum++) {\n\n        // Get user input\n        System.out.println(\"\");\n        System.out.print(\"TRIAL # \" + shotNum + \"? \");\n        userResponse = scan.nextLine();\n\n        // Split on commas\n        userCoordinates = userResponse.split(\",\");\n\n        // Assign to integer variables\n        shotX = Integer.parseInt(userCoordinates[0].trim());\n        shotY = Integer.parseInt(userCoordinates[1].trim());\n        shotZ = Integer.parseInt(userCoordinates[2].trim());\n\n        // Win condition\n        if (Math.abs(shotX - targetX) + Math.abs(shotY - targetY)\n            + Math.abs(shotZ - targetZ) == 0) {\n\n          System.out.println(\"B O O M ! ! YOU FOUND IT IN\" + shotNum + \" TRIES!\");\n          break;\n\n        }\n\n        this.getReport(targetX, targetY, targetZ, shotX, shotY, shotZ);\n\n        System.out.println(\"\");\n\n      }  // End loop through all shots\n\n      if (shotNum > shotTotal) {\n\n        System.out.println(\"\");\n        System.out.println(\"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\");\n        System.out.println(\"THE SUBMARINE WAS AT \" + targetX + \",\" + targetY + \",\" + targetZ);\n      }\n\n      System.out.println(\"\");\n      System.out.println(\"\");\n      System.out.print(\"ANOTHER GAME (Y OR N)? \");\n      userResponse = scan.nextLine();\n\n      if (!userResponse.toUpperCase().equals(\"Y\")) {\n        System.out.print(\"OK.  HOPE YOU ENJOYED YOURSELF.\");\n        return;\n      }\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public void getReport(int a, int b, int c, int x, int y, int z) {\n\n    System.out.print(\"SONAR REPORTS SHOT WAS \");\n\n    // Handle y coordinate\n    if (y > b) {\n\n      System.out.print(\"NORTH\");\n\n    } else if (y < b) {\n\n      System.out.print(\"SOUTH\");\n    }\n\n    // Handle x coordinate\n    if (x > a) {\n\n      System.out.print(\"EAST\");\n\n    } else if (x < a) {\n\n      System.out.print(\"WEST\");\n    }\n\n    if ((y != b) || (x != a)) {\n\n      System.out.print(\" AND\");\n    }\n\n    // Handle depth\n    if (z > c) {\n\n      System.out.println(\" TOO LOW.\");\n\n    } else  if (z < c) {\n\n      System.out.println(\" TOO HIGH.\");\n\n    } else {\n\n      System.out.println(\" DEPTH OK.\");\n    }\n\n    return;\n\n  }  // End of method getReport\n\n  public static void main(String[] args) {\n\n    DepthCharge game = new DepthCharge();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class DepthCharge\n"
  },
  {
    "path": "31_Depth_Charge/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "31_Depth_Charge/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "31_Depth_Charge/javascript/depthcharge.html",
    "content": "<html>\n<head>\n<title>DEPTH CHARGE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"depthcharge.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "31_Depth_Charge/javascript/depthcharge.js",
    "content": "// DEPTH CHARGE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"DEPTH CHARGE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"DIMENSION OF THE SEARCH AREA\");\n    g = Math.floor(await input());\n    n = Math.floor(Math.log(g) / Math.log(2)) + 1;\n    print(\"YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\\n\");\n    print(\"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\\n\");\n    print(\"MISSION IS TO DESTROY IT.  YOU HAVE \" + n + \" SHOTS.\\n\");\n    print(\"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\\n\");\n    print(\"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\\n\");\n    print(\"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\\n\");\n    do {\n        print(\"\\n\");\n        print(\"GOOD LUCK !\\n\");\n        print(\"\\n\");\n        a = Math.floor(Math.random() * g);\n        b = Math.floor(Math.random() * g);\n        c = Math.floor(Math.random() * g);\n        for (d = 1; d <= n; d++) {\n            print(\"\\n\");\n            print(\"TRIAL #\" + d + \" \");\n            str = await input();\n            x = parseInt(str);\n            y = parseInt(str.substr(str.indexOf(\",\") + 1));\n            z = parseInt(str.substr(str.lastIndexOf(\",\") + 1));\n            if (Math.abs(x - a) + Math.abs(y - b) + Math.abs(z - c) == 0)\n                break;\n            if (y > b)\n                print(\"NORTH\");\n            if (y < b)\n                print(\"SOUTH\");\n            if (x > a)\n                print(\"EAST\");\n            if (x < a)\n                print(\"WEST\");\n            if (y != b || x != a)\n                print(\" AND\");\n            if (z > c)\n                print(\" TOO LOW.\\n\");\n            if (z < c)\n                print(\" TOO HIGH.\\n\");\n            if (z == c)\n                print(\" DEPTH OK.\\n\");\n            print(\"\\n\");\n        }\n        if (d <= n) {\n            print(\"\\n\");\n            print(\"B O O M ! ! YOU FOUND IT IN \" + d + \" TRIES!\\n\");\n        } else {\n            print(\"\\n\");\n            print(\"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\\n\");\n            print(\"THE SUBMARINE WAS AT \" + a + \",\" + b + \",\" + c + \"\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"ANOTHER GAME (Y OR N)\");\n        str = await input();\n    } while (str.substr(0, 1) == \"Y\") ;\n    print(\"OK.  HOPE YOU ENJOYED YOURSELF.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "31_Depth_Charge/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "31_Depth_Charge/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "31_Depth_Charge/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\n## Conversion\n\nNot a difficult conversion - but a chance to throw in a few ways\nPerl makes life easy.\n\n * To get the sub permission which is a random location in the g x g x g grid we can use:\n   * assigning multiple variables in list form ($a,$b,$c) = (?,?,?)\n   * where the list on the right hand side is generated with a map function\n\n * We use ternarys to generate the message if you miss the sub.\n   * We use join to stitch the pieces of the string together.\n   * If we have a ternary where we don't want to return anything we return an empty list rather than an empty string - if you return the latter you still get the padding spaces.\n"
  },
  {
    "path": "31_Depth_Charge/perl/depth-charge.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\nprint '               Depth Charge\nCreative Computing Morristown, New Jersey\n\n\nDepth Charge Game\n\nDimensions of Search Area? ';\n\nmy $g = <STDIN>;\nmy $n = int( log($g) / log 2 ) + 1;\nprint '\nYou are the captain of the Destroyer USS Computer\nan enemy sub has been causing you trouble.  Your\nmission is to destroy it.  You have ',$n,' shots.\nSpecify depth charge explosion point with a\ntrio of number -- the first two are the surface\nco-ordinates; the third is the depth.\n';\n\nwhile(1) { ## Repeat until we say no....\n  print \"\\nGood luck!\\n\\n\";\n  my ($a,$b,$c) = map { int rand $g } 1..3; ## Get the location\n  my $hit = 0; ## Keep track if we have won yet!\n  foreach ( 1..$n ) {\n    print \"\\nTrial # $_ ? \";\n    my ( $x, $y, $z ) = split m{\\D+}, <STDIN>;\n    if( $x==$a && $y==$b && $z==$c ) {\n      $hit = 1; ## We have won\n      print \"\\n\\nB O O M ! ! You found it in $_ tries!\\n\";\n      last;\n    }\n    print join q( ), 'Sonar reports show was',\n      $y < $b              ? 'South'    : $y > $b ? 'North'   : (),\n      $x < $a              ? 'West'     : $x > $a ? 'East'    : (),\n      $x == $a && $y == $b ? ()         : 'and' ,\n      $z < $c              ? 'too high' : $z > $c ? 'too low' : 'depth OK',\n      \".\\n\";\n  }\n\n  ## Only show message if we haven't won...\n  print \"\\nYou have been torpedoed!  Abandon ship!\\nThe submarine was at $a, $b, $c\\n\" unless $hit;\n\n  print \"\\n\\nAnother game (Y or N)? \";\n  last unless <STDIN> =~ m{Y}i; ## Y or y not typed so leave loop\n}\n## Say good bye\nprint \"OK.  Hope you enjoyed yourself.\\n\\n\";\n"
  },
  {
    "path": "31_Depth_Charge/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "31_Depth_Charge/python/depth_charge.py",
    "content": "\"\"\"\nOriginal BASIC version as published in Basic Computer Games (1978)\nhttps://www.atariarchives.org/basicgames/showpage.php?page=55\n\nConverted to Python by Anson VanDoren in 2021\n\"\"\"\n\nimport math\nimport random\nfrom typing import Tuple\n\n\ndef show_welcome() -> None:\n    # Clear screen. chr(27) is `Esc`, and the control sequence is\n    # initiated by Ctrl+[\n    # `J` is \"Erase in Display\" and `2J` means clear the entire screen\n    print(f\"{chr(27)}[2J\")\n\n    # Show the intro text, centered\n    print(\"DEPTH CHARGE\".center(45))\n    print(\"Creative Computing  Morristown, New Jersey\\n\\n\".center(45))\n\n\ndef get_num_charges() -> Tuple[int, int]:\n    print(\"Depth Charge game\\n\")\n    while True:\n        search_area_str = input(\"Dimensions of search area? \")\n\n        # Make sure the input is an integer\n        try:\n            search_area = int(search_area_str)\n            break\n        except ValueError:\n            print(\"Must enter an integer number. Please try again...\")\n\n    num_charges = int(math.log2(search_area)) + 1\n    return search_area, num_charges\n\n\ndef ask_for_new_game() -> None:\n    answer = input(\"Another game (Y or N): \")\n    if answer.lower().strip()[0] == \"y\":\n        main()\n    else:\n        print(\"OK. Hope you enjoyed yourself\")\n        exit()\n\n\ndef show_shot_result(shot, location) -> None:\n    result = \"Sonar reports shot was \"\n    if shot[1] > location[1]:  # y-direction\n        result += \"north\"\n    elif shot[1] < location[1]:  # y-direction\n        result += \"south\"\n    if shot[0] > location[0]:  # x-direction\n        result += \"east\"\n    elif shot[0] < location[0]:  # x-direction\n        result += \"west\"\n    if shot[1] != location[1] or shot[0] != location[0]:\n        result += \" and \"\n\n    if shot[2] > location[2]:\n        result += \"too low.\"\n    elif shot[2] < location[2]:\n        result += \"too high.\"\n    else:\n        result += \"depth OK.\"\n    print(result)\n    return\n\n\ndef get_shot_input() -> Tuple[int, int, int]:\n    while True:\n        raw_guess = input(\"Enter coordinates: \")\n        try:\n            xyz = raw_guess.split()\n        except ValueError:\n            print(\"Please enter coordinates separated by spaces\")\n            print(\"Example: 3 2 1\")\n            continue\n        try:\n            x, y, z = (int(num) for num in xyz)\n            return x, y, z\n        except ValueError:\n            print(\"Please enter whole numbers only\")\n\n\ndef play_game(search_area, num_charges) -> None:\n    print(\"\\nYou are the captain of the destroyer USS Computer.\")\n    print(\"An enemy sub has been causing you trouble. Your\")\n    print(f\"mission is to destroy it. You have {num_charges} shots.\")\n    print(\"Specify depth charge explosion point with a\")\n    print(\"trio of numbers -- the first two are the\")\n    print(\"surface coordinates; the third is the depth.\")\n    print(\"\\nGood luck!\\n\")\n\n    # Generate position for submarine\n    a, b, c = (random.randint(0, search_area) for _ in range(3))\n\n    # Get inputs until win or lose\n    for i in range(num_charges):\n        print(f\"\\nTrial #{i+1}\")\n        x, y, z = get_shot_input()\n\n        if (x, y, z) == (a, b, c):\n            print(f\"\\nB O O M ! ! You found it in {i+1} tries!\\n\")\n            ask_for_new_game()\n        else:\n            show_shot_result((x, y, z), (a, b, c))\n\n    # out of shots\n    print(\"\\nYou have been torpedoed! Abandon ship!\")\n    print(f\"The submarine was at {a} {b} {c}\")\n    ask_for_new_game()\n\n\ndef main() -> None:\n    search_area, num_charges = get_num_charges()\n    play_game(search_area, num_charges)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "31_Depth_Charge/ruby/.editorconfig",
    "content": "# EditorConfig is awesome: https://EditorConfig.org\n# .editorconfig\n\n# Please see doc/developer_notes.md\n# If you find anything egregious or missing, please consider submitting a pull request\n# to https://github.com/theias/ias_package_shell\n\n\n# top-most EditorConfig file\nroot = true\n\n# Sensible defaults for everything\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\n\n# JavaScript\n[**.js]\nindent_style = space\nindent_size = 2\ninsert_final_newline = true\n\n# Ruby\n[**.rb]\nindent_style = space\nindent_size = 2\ntrim_trailing_whitespace = true\n\n# Python\n[**.py]\ncharset = utf-8\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\n\n# Perl\n[**.pl]\ncharset = utf-8\ninsert_final_newline = true\n[**.pm]\ncharset = utf-8\ninsert_final_newline = true\n\n# PHP\n[**.php]\ncharset = utf-8\nindent_size = 4\nindent_style = space\nend_of_line = lf\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n# Makefiles\n[Makefile]\nindent_style = tab\n\n[**.gmk]\nindent_style = tab\n\n# Configuration Files\n# Matches the exact files either package.json or .travis.yml\n[{package.json,.travis.yml}]\nindent_style = space\nindent_size = 2\n\n# Diff files\n[*.{diff,patch}]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": "31_Depth_Charge/ruby/.gitignore",
    "content": "# Package Shell Specific Things\n\n## Build Process\n\n/build\n\n## Transient files\n\n/src/input\n/src/output\n/src/log\n/drop\n\n# Programming Languages\n\n## Java\n/src/java/**/*.class\n\n## Rakudo / Perl6\n/src/**/.precomp\n\n## PHP\n/vendor/\n\n## Python\n*.swp\n__pycache__/\n*.pyc\n*.egg-info\n/dist\n\n## Ruby\n*.gem\n.bundle\n\n# Editors\n\n## Dia\n*.dia.autosave\n\n## Emacs\n\\#*\\#\n.\\#*\n\n\n## Vi / Vim\n*.swp\n\n# Filesystem Artifacts\n\n## Mac\n\n.DS_Store\n\n## NFS\n\n.nfs*\n"
  },
  {
    "path": "31_Depth_Charge/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "31_Depth_Charge/ruby/depthcharge.rb",
    "content": "#!/usr/bin/ruby\n\nclass DepthCharge\n  def run_game\n    output_title\n\n    loop do\n      puts \"----------\"\n      print_instructions\n      setup_game\n      puts\n      game_loop\n      break unless get_input_another_game\n    end\n\n    puts \"OK.  HOPE YOU ENJOYED YOURSELF.\"\n  end\n\n  def output_title\n    puts \"--- DEPTH CHARGE ---\"\n    puts \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    puts\n  end\n\n  def get_input_y_or_n(message)\n    loop do\n      print message\n\n      value = gets.chomp\n\n      if value.downcase == \"y\"\n        return true\n      elsif value.downcase == \"n\"\n        return false\n      end\n\n      puts \"PLEASE ENTER Y/y OR N/n...\"\n      puts\n    end\n  end\n\n  def get_input_positive_integer(message)\n    loop do\n      print message\n      value = gets.chomp\n\n      if value == \"d\"\n        debug_game\n        next\n      end\n\n      the_input = Integer(value) rescue 0\n\n      if the_input < 1\n        puts \"PLEASE ENTER A POSITIVE NUMBER\"\n        puts\n        next\n      end\n\n      return the_input\n    end\n  end\n\n  def print_instructions\n    puts <<~INSTRUCTIONS\n      YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\n      AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\n      MISSION IS TO DESTROY IT.\n\n      SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\n      TRIO OF NUMBERS -- THE FIRST TWO ARE THE\n      SURFACE COORDINATES (X, Y):\n          WEST < X < EAST\n          SOUTH < Y < NORTH\n\n      THE THIRD IS THE DEPTH (Z):\n        SHALLOW < Z < DEEP\n\n      GOOD LUCK !\n\n    INSTRUCTIONS\n  end\n\n  def debug_game\n    puts \"@enemy_x: %d\" % @enemy_x\n    puts \"@enemy_y: %d\" % @enemy_y\n    puts \"@enemy_z: %d\" % @enemy_z\n    puts \"@num_tries: %d\" % @num_tries\n    puts \"@trial: %d\" % @trial\n    puts\n  end\n\n  def setup_game\n    @search_area_dimension = get_input_positive_integer(\"DIMENSION OF SEARCH AREA: \")\n\n    @num_tries = Integer(Math.log(@search_area_dimension) / Math.log(2) + 1)\n    setup_enemy\n  end\n\n  def setup_enemy\n    @enemy_x = rand(1..@search_area_dimension)\n    @enemy_y = rand(1..@search_area_dimension)\n    @enemy_z = rand(1..@search_area_dimension)\n  end\n\n  def game_loop\n    for @trial in 1..@num_tries do\n      output_game_status()\n\n      @shot_x = get_input_positive_integer(\"X: \")\n      @shot_y = get_input_positive_integer(\"Y: \")\n      @shot_z = get_input_positive_integer(\"Z: \")\n\n\n      distance = (@enemy_x - @shot_x).abs +\n        (@enemy_y - @shot_y).abs +\n        (@enemy_z - @shot_z).abs\n\n      if distance == 0\n        you_win\n        return\n      else\n        missed_shot\n      end\n    end\n\n    puts\n\n    you_lose\n  end\n\n  def output_game_status\n    puts \"YOU HAVE %d SHOTS REMAINING.\" % @num_tries - @trial + 1\n    puts \"TRIAL \\#%d\" % @trial\n  end\n\n  def you_win\n    puts \"\\nB O O M ! ! YOU FOUND IT IN %d TRIES!\" % @trial\n    puts\n  end\n\n  def missed_shot\n    missed_directions = []\n\n    if @shot_x > @enemy_x\n      missed_directions.push('TOO FAR EAST')\n    elsif @shot_x < @enemy_x\n      missed_directions.push('TOO FAR WEST')\n    end\n\n    if @shot_y > @enemy_y\n      missed_directions.push('TOO FAR NORTH')\n    elsif @shot_y < @enemy_y\n      missed_directions.push('TOO FAR SOUTH')\n    end\n\n    if @shot_z > @enemy_z\n      missed_directions.push('TOO DEEP')\n    elsif @shot_z < @enemy_z\n      missed_directions.push('TOO SHALLOW')\n    end\n\n    puts \"SONAR REPORTS SHOT WAS: \"\n    puts \"\\t#{missed_directions.join(\"\\n\\t\")}\"\n  end\n\n  def you_lose\n    puts \"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\"\n    puts \"THE SUBMARINE WAS AT %d %d %d\" % [@enemy_x, @enemy_y, @enemy_z]\n  end\n\n  def get_input_another_game\n    return get_input_y_or_n(\"ANOTHER GAME (Y OR N): \")\n  end\nend\n\ngame = DepthCharge.new\ngame.run_game\n"
  },
  {
    "path": "31_Depth_Charge/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nrand = \"0.9.0\""
  },
  {
    "path": "31_Depth_Charge/rust/src/main.rs",
    "content": "/** DEPTH CHARGE GAME \n * https://github.com/marquesrs/basic-computer-games/blob/main/31_Depth_Charge/depthcharge.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 03/03/25\n*/\n\nuse std::io::Write;\nuse rand::Rng;\n\nfn input(msg: &str) -> String {\n    print!(\"{}\", msg);\n    let _ =std::io::stdout().flush().unwrap();\n    let mut input = String::new();\n    std::io::stdin().read_line(&mut input).unwrap();\n    return input.trim().to_uppercase();\n}\n\nfn main() {\n    // 2 PRINT TAB(30);\"DEPTH CHARGE\"\n    // 4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    // 6 PRINT: PRINT: PRINT\n    print!(\"{}\", format!(\"{}{}\\n{}{}\\n\\n\\n\\n\",\n        \" \".repeat(29),\n        \"DEPTH CHARGE\",\n        \" \".repeat(14),\n        \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    ));\n\n    // 20 INPUT \"DIMENSION OF SEARCH AREA\";G: PRINT\n    let g = input(\"DIMENSION OF SEARCH AREA: \").parse::<i32>().unwrap();\n\n    // 30 N=INT(LOG(G)/LOG(2))+1\n    let n = (f32::ln(g as f32) / f32::ln(2.0) + 1.0) as i32;\n\n    // 40 PRINT \"YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\"\n    // 50 PRINT \"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE.  YOUR\"\n    // 60 PRINT \"MISSION IS TO DESTROY IT.  YOU HAVE\";N;\"SHOTS.\"\n    // 70 PRINT \"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\"\n    // 80 PRINT \"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\"\n    // 90 PRINT \"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\"\n    // 100 PRINT : PRINT \"GOOD LUCK !\": PRINT\n    let a = (g * rand::rng().random_range(0..=1)) as i32;\n    let b = (g * rand::rng().random_range(0..=1)) as i32;\n    let c = (g * rand::rng().random_range(0..=1)) as i32;\n    print!(\"{}\", format!(\"{}{}{}{}{}{}{}{}{}{}{}\",\n        \"\\nYOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\\n\",\n        \"AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR\\n\",\n        \"MISSION IS TO DESTROY IT. YOU HAVE \",\n        n,\n        \" SHOTS.\\n\",\n        \"SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\\n\",\n        \"TRIO OF NUMBERS -- THE FIRST TWO ARE THE\\n\",\n        \"SURFACE COORDINATES; THE THIRD IS THE DEPTH.\\n\",\n        format!(\"EXAMPLE FOR DIMENSION {}: \", g),\n        format!(\"{}, {}, {}\", a, b, c),\n        \"\\nGOOD LUCK !\\n\"\n    ));\n\n    'main: loop {\n        // 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1))\n        let a = (g * rand::rng().random_range(0..=1)) as i32;\n        let b = (g * rand::rng().random_range(0..=1)) as i32;\n        let c = (g * rand::rng().random_range(0..=1)) as i32;\n        // 120 FOR D=1 TO N : PRINT : PRINT \"TRIAL #\";D; : INPUT X,Y,Z\n        let mut x;\n        let mut y;\n        let mut z;\n        for d in 1..=n {\n            print!(\"\\nTRIAL #{}\\n\", d);\n            x = input(\"X: \").parse::<i32>().unwrap();\n            y = input(\"Y: \").parse::<i32>().unwrap();\n            z = input(\"Z: \").parse::<i32>().unwrap();\n            // 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300\n            if i32::abs(x-a) + i32::abs(y-b) + i32::abs(z-c) == 0 {\n                // 300 PRINT : PRINT \"B O O M ! ! YOU FOUND IT IN\";D;\"TRIES!\"\n                print!(\"{}\", format!(\"{}{}{}{}{}\",\n                    \"\\n\",\n                    \"B O O M ! ! YOU FOUND IT IN \",\n                    d,\n                    \" TRIES!\\n\",\n                    \"\\n\"\n                ));\n                // 400 PRINT : PRINT: INPUT \"ANOTHER GAME (Y OR N)\";A$\n                if replay() { continue 'main; }\n                else { break 'main; }\n            }\n        \n            // 140 GOSUB 500 : PRINT : NEXT D\n            subroutine(x, y, z, a, b, c);\n            println!();\n        }\n        // 200 PRINT : PRINT \"YOU HAVE BEEN TORPEDOED!  ABANDON SHIP!\"\n        // 210 PRINT \"THE SUBMARINE WAS AT\";A;\",\";B;\",\";C : GOTO 400\n        print!(\"{}\", format!(\"{}{}{}{}{}{}{}{}\",\n            \"\\nYOU HAVE BEEN TORPEDOED! ABANDON SHIP!\\n\",\n            \"THE SUBMARINE WAS AT \",\n            a,\n            \",\",\n            b,\n            \",\",\n            c,\n            \"\\n\"\n        ));\n        \n        replay();\n    }\n    // 600 END\n}\n\n// 500 PRINT \"SONAR REPORTS SHOT WAS \";\n// 510 IF Y>B THEN PRINT \"NORTH\";\n// 520 IF Y<B THEN PRINT \"SOUTH\";\n// 530 IF X>A THEN PRINT \"EAST\";\n// 540 IF X<A THEN PRINT \"WEST\";\n// 550 IF Y<>B OR X<>A THEN PRINT \" AND\";\n// 560 IF Z>C THEN PRINT \" TOO LOW.\"\n// 570 IF Z<C THEN PRINT \" TOO HIGH.\"\n// 580 IF Z=C THEN PRINT \" DEPTH OK.\"\n// 590 RETURN\nfn subroutine(x: i32, y: i32, z:i32, a:i32, b:i32, c:i32) {\n    print!(\"SONAR REPORTS SHOT WAS \");\n    if y>b { print!(\"NORTH\"); };\n    if y<b { print!(\"SOUTH\"); };\n    if x>a { print!(\"EAST\"); };\n    if x<a { print!(\"WEST\"); };\n    if y!=b || x!=a { print!(\" AND\"); };\n    if z>c { print!(\" TOO LOW.\"); };\n    if z<c { print!(\" TOO HIGH.\"); };\n    if z==c { print!(\" DEPTH OK.\"); };\n}\n\nfn replay() -> bool {\n    let r = input(\"ANOTHER GAME (Y OR N): \");\n    // 410 IF A$=\"Y\" THEN 100\n    if r == \"Y\" {\n        return true;\n    }\n    else {\n        // 420 PRINT \"OK.  HOPE YOU ENJOYED YOURSELF.\" : GOTO 600\n        println!(\"OK. HOPE YOU ENJOYED YOURSELF.\");\n        return false; \n    }\n}"
  },
  {
    "path": "31_Depth_Charge/vbnet/DepthCharge.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"DepthCharge\", \"DepthCharge.vbproj\", \"{7F8404FE-7CF2-46AC-B4D4-2CAB5EF3FB2F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7F8404FE-7CF2-46AC-B4D4-2CAB5EF3FB2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7F8404FE-7CF2-46AC-B4D4-2CAB5EF3FB2F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7F8404FE-7CF2-46AC-B4D4-2CAB5EF3FB2F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7F8404FE-7CF2-46AC-B4D4-2CAB5EF3FB2F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "31_Depth_Charge/vbnet/DepthCharge.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>DepthCharge</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "31_Depth_Charge/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "32_Diamond/README.md",
    "content": "### Diamond\n\nThis program fills an 8.5x11 piece of paper with diamonds (plotted on a hard-copy terminal, of course). The program asks for an odd number to be input in the range 5 to 31. The diamonds printed will be this number of characters high and wide. The number of diamonds across the page will vary from 12 for 5-character wide diamonds to 1 for a diamond 31-characters wide. You can change the content of the pattern if you wish.\n\nThe program was written by David Ahl of Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=56)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=71)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "32_Diamond/csharp/Diamond.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "32_Diamond/csharp/Diamond.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Diamond\", \"Diamond.csproj\", \"{44B406C8-70F0-4183-B19A-5B045A1AEBA4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "32_Diamond/csharp/Pattern.cs",
    "content": "using System.Text;\nusing static Diamond.Resources.Resource;\n\nnamespace Diamond;\n\ninternal class Pattern\n{\n    private readonly IReadWrite _io;\n\n    public Pattern(IReadWrite io)\n    {\n        _io = io;\n        io.Write(Streams.Introduction);\n    }\n\n    public void Draw()\n    {\n        var diamondSize = _io.ReadNumber(Prompts.TypeNumber);\n        _io.WriteLine();\n\n        var diamondCount = (int)(60 / diamondSize);\n\n        var diamondLines = new List<string>(GetDiamondLines(diamondSize)).AsReadOnly();\n\n        for (int patternRow = 0; patternRow < diamondCount; patternRow++)\n        {\n            for (int diamondRow = 0; diamondRow < diamondLines.Count; diamondRow++)\n            {\n                var line = new StringBuilder();\n                for (int patternColumn = 0; patternColumn < diamondCount; patternColumn++)\n                {\n                    line.PadToLength((int)(patternColumn * diamondSize)).Append(diamondLines[diamondRow]);\n                }\n                _io.WriteLine(line);\n            }\n        }\n    }\n\n    public static IEnumerable<string> GetDiamondLines(float size)\n    {\n        for (var i = 1; i <= size; i += 2)\n        {\n            yield return GetLine(i);\n        }\n\n        for (var i = size - 2; i >= 1; i -= 2)\n        {\n            yield return GetLine(i);\n        }\n\n        string GetLine(float i) =>\n            string.Concat(\n                new string(' ', (int)(size - i) / 2),\n                new string('C', Math.Min((int)i, 2)),\n                new string('!', Math.Max(0, (int)i - 2)));\n    }\n}\n"
  },
  {
    "path": "32_Diamond/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nusing Diamond;\n\nnew Pattern(new ConsoleIO()).Draw();\n"
  },
  {
    "path": "32_Diamond/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "32_Diamond/csharp/Resources/Introduction.txt",
    "content": "                                 Diamond\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "32_Diamond/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Diamond.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n    }\n\n    internal static class Prompts\n    {\n        public static string TypeNumber => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "32_Diamond/csharp/Resources/Rules.txt",
    "content": "Chomp is for 1 or more players (humans only).\n\nHere's how a board looks (this one is 5 by 7):\n\n       1 2 3 4 5 6 7 8 9\n 1     P * * * * * *\n 2     * * * * * * *\n 3     * * * * * * *\n 4     * * * * * * *\n 5     * * * * * * *\n\n\nThe board is a big cookie - R rows high and C columns\nwide. You input R and C at the start. In the upper left\ncorner of the cookie is a poison square (P). The one who\nchomps the poison square loses. To take a chomp, type the\nrow and column of one of the squares on the cookie.\nAll of the squares below and to the right of that square\n(including that square, too) disappear -- Chomp!!\nNo fair chomping on squares that have already been chomped,\nor that are outside the original dimensions of the cookie.\n\n"
  },
  {
    "path": "32_Diamond/csharp/Resources/TypeNumber.txt",
    "content": "For a pretty diamond pattern,\ntype in an odd number between 5 and 21"
  },
  {
    "path": "32_Diamond/csharp/StringBuilderExtensions.cs",
    "content": "using System.Text;\n\nnamespace Diamond;\n\ninternal static class StringBuilderExtensions\n{\n    internal static StringBuilder PadToLength(this StringBuilder builder, int length) => \n        builder.Append(' ', length - builder.Length);\n}"
  },
  {
    "path": "32_Diamond/diamond.bas",
    "content": "1 PRINT TAB(33);\"DIAMOND\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"FOR A PRETTY DIAMOND PATTERN,\"\n5 INPUT \"TYPE IN AN ODD NUMBER BETWEEN 5 AND 21\";R:PRINT\n6 Q=INT(60/R):A$=\"CC\"\n8 FOR L=1 TO Q\n10 X=1:Y=R:Z=2\n20 FOR N=X TO Y STEP Z\n25 PRINT TAB((R-N)/2);\n28 FOR M=1 TO Q\n29 C=1\n30 FOR A=1 TO N\n32 IF C>LEN(A$) THEN PRINT \"!\";:GOTO 50\n34 PRINT MID$(A$,C,1);\n36 C=C+1\n50 NEXT A\n53 IF M=Q THEN 60\n55 PRINT TAB(R*M+(R-N)/2);\n56 NEXT M\n60 PRINT\n70 NEXT N\n83 IF X<>1 THEN 95\n85 X=R-2:Y=1:Z=-2\n90 GOTO 20\n95 NEXT L\n99 END\n"
  },
  {
    "path": "32_Diamond/java/Diamond.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of Diamond\n * <p>\n * Based on the BASIC game of Diamond here\n * https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Diamond {\n\n  private static final int LINE_WIDTH = 60;\n\n  private static final String PREFIX = \"CC\";\n\n  private static final char SYMBOL = '!';\n\n  private final Scanner scan;  // For user input\n\n\n  public Diamond() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Diamond\n\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n\n  private void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"DIAMOND\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n\n  private void startGame() {\n\n    int body = 0;\n    int column = 0;\n    int end = 0;\n    int fill = 0;\n    int increment = 2;\n    int numPerSide = 0;\n    int prefixIndex = 0;\n    int row = 0;\n    int start = 1;\n    int userNum = 0;\n\n    String lineContent = \"\";\n\n    // Get user input\n    System.out.println(\"FOR A PRETTY DIAMOND PATTERN,\");\n    System.out.print(\"TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? \");\n    userNum = scan.nextInt();\n    System.out.println(\"\");\n\n    // Calcuate number of diamonds to be drawn on each side of screen\n    numPerSide = (int) (LINE_WIDTH / userNum);\n\n    end = userNum;\n\n    // Begin loop through each row of diamonds\n    for (row = 1; row <= numPerSide; row++) {\n\n      // Begin loop through top and bottom halves of each diamond\n      for (body = start; increment < 0 ? body >= end : body <= end; body += increment) {\n\n        lineContent = \"\";\n\n        // Add whitespace\n        while (lineContent.length() < ((userNum - body) / 2)) {\n          lineContent += \" \";\n        }\n\n        // Begin loop through each column of diamonds\n        for (column = 1; column <= numPerSide; column++) {\n\n          prefixIndex = 1;\n\n          // Begin loop that fills each diamond with characters\n          for (fill = 1; fill <= body; fill++) {\n\n            // Right side of diamond\n            if (prefixIndex > PREFIX.length()) {\n\n              lineContent += SYMBOL;\n\n            }\n            // Left side of diamond\n            else {\n\n              lineContent += PREFIX.charAt(prefixIndex - 1);\n              prefixIndex++;\n\n            }\n\n          }  // End loop that fills each diamond with characters\n\n          // Column finished\n          if (column == numPerSide) {\n\n            break;\n\n          }\n          // Column not finishd\n          else {\n\n            // Add whitespace\n            while (lineContent.length() < (userNum * column + (userNum - body) / 2)) {\n              lineContent += \" \";\n            }\n\n          }\n\n        }  // End loop through each column of diamonds\n\n        System.out.println(lineContent);\n\n      }  // End loop through top and bottom half of each diamond\n\n      if (start != 1) {\n\n        start = 1;\n        end = userNum;\n        increment = 2;\n\n      }\n      else {\n\n        start = userNum - 2;\n        end = 1;\n        increment = -2;\n        row--;\n\n      }\n\n    }  // End loop through each row of diamonds\n\n  }  // End of method startGame\n\n\n  public static void main(String[] args) {\n\n    Diamond diamond = new Diamond();\n    diamond.play();\n\n  }  // End of method main\n\n}  // End of class Diamond\n"
  },
  {
    "path": "32_Diamond/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "32_Diamond/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "32_Diamond/javascript/diamond.html",
    "content": "<html>\n<head>\n<title>DIAMOND</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"diamond.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "32_Diamond/javascript/diamond.js",
    "content": "// DIAMOND\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"DIAMOND\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"FOR A PRETTY DIAMOND PATTERN,\\n\");\n    print(\"TYPE IN AN ODD NUMBER BETWEEN 5 AND 21\");\n    r = parseInt(await input());\n    q = Math.floor(60 / r);\n    as = \"CC\"\n    x = 1;\n    y = r;\n    z = 2;\n    for (l = 1; l <= q; l++) {\n        for (n = x; z < 0 ? n >= y : n <= y; n += z) {\n            str = \"\";\n            while (str.length < (r - n) / 2)\n                str += \" \";\n            for (m = 1; m <= q; m++) {\n                c = 1;\n                for (a = 1; a <= n; a++) {\n                    if (c > as.length)\n                        str += \"!\";\n                    else\n                        str += as[c++ - 1];\n                }\n                if (m == q)\n                    break;\n                while (str.length < r * m + (r - n) / 2)\n                    str += \" \";\n            }\n            print(str + \"\\n\");\n        }\n        if (x != 1) {\n            x = 1;\n            y = r;\n            z = 2;\n        } else {\n            x = r - 2;\n            y = 1;\n            z = -2;\n            l--;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "32_Diamond/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/), structure inspired from [the Java port](https://github.com/coding-horror/basic-computer-games/blob/main/32_Diamond/java/Diamond.java).\n\n### How to Run\n1. Install [kotlin command line](https://kotlinlang.org/docs/command-line.html) compiler from JetBrains.\n2. Compile with `kotlinc diamond.kt -include-runtime -d diamond.jar`\n3. Run with `java -jar diamond.jar`\n\n### Changes from Original\nThis version validates that user input is correct.\n\n"
  },
  {
    "path": "32_Diamond/kotlin/diamond.kt",
    "content": "\n/**\n * Game of Diamond\n * <p>\n * Based on the BASIC game of Diamond\n * https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.bas\n * <p>\n *\n * Changes From Original: Input is validated.\n *\n * Converted from BASIC to Kotlin by Martin Marconcini (@Gryzor)\n * Inspired in the Java code written by Darren Cardenas.\n */\n\n\nfun main() {\n\tDiamond().startGame()\n}\n\nclass Diamond {\n\tinit {\n\t\tprintIntro()\n\t}\n\n\tfun startGame() {\n\t\tvar body: Int\n\t\tvar end: Int\n\t\tvar start: Int = 1\n\t\tvar row: Int = 1\n\t\tvar numPerRow: Int\n\t\tvar increment: Int = 2\n\t\tvar lineContent: String\n\t\tvar prefixIndex: Int\n\t\t\n\t\tprintPrompt()\n\n\t\t// Read the user input\n\t\tval input = readLine()\n\n\t\t// Validate input\n\t\tval userInput: Int = try {\n\t\t\tinput?.toInt() ?: -1\n\t\t} catch (e: NumberFormatException) {\n\t\t\t-1\n\t\t}\n\t\tif (!isValid(userInput)) {\n\t\t\tprintInvalidInput()\n\t\t\treturn\n\t\t}\n\n\t\t// Calculate how many diamonds can horizontally fit in the given space\n\t\tnumPerRow = calculateDiamondsPerRow(userInput)\n\t\tend = userInput\n\n\t\t// Loop throw rows of Diamonds\n\t\twhile (row <= numPerRow) {\n\t\t\tbody = start\n\t\t\twhile (canLoop(increment, body, end)) {\n\t\t\t\tlineContent = \"\"\n\t\t\t\t\n\t\t\t\t// Add white spaces to the \"left\" of the leftmost diamond.\n\t\t\t\twhile (lineContent.length < ((userInput - body) / 2)) {\n\t\t\t\t\tlineContent += \" \"\n\t\t\t\t}\n\n\t\t\t\t// Begin loop through each column of diamonds\n\t\t\t\tfor (col in 1..numPerRow) {\n\t\t\t\t\tprefixIndex = 1\n\n\t\t\t\t\t// Begin loop that fills each diamond with characters (not whitespace)\n\t\t\t\t\tfor (fill in 1..body) {\n\t\t\t\t\t\t// Right side of diamond, if the index is greater than the prefix, put a Symbol.\n\t\t\t\t\t\tif (prefixIndex > PREFIX.length) {\n\t\t\t\t\t\t\tlineContent += SYMBOL\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Left side of diamond, pick a Prefix character (-1 since it starts at 0)\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tlineContent += PREFIX[prefixIndex - 1]\n\t\t\t\t\t\t\tprefixIndex++\n\t\t\t\t\t\t}\n\t\t\t\t\t}// End loop that fills each diamond with characters\n\n\t\t\t\t\t// Is Column finished?\n\t\t\t\t\tif (col == numPerRow) {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\t// Column is not finished...\n\t\t\t\t\telse {\n\t\t\t\t\t\t// Add whitespace on the \"right\" side of the current diamond, and fill the \"left\" side of the\n\t\t\t\t\t\t// next; doesn't fill the space to the right of the rightmost diamond.\n\t\t\t\t\t\twhile (lineContent.length < (userInput * col + (userInput - body) / 2)) {\n\t\t\t\t\t\t\tlineContent += \" \"\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}// End loop through each column of diamonds\n\n\t\t\t\t// Print the current Line\n\t\t\t\tprintln(lineContent)\n\n\t\t\t\t// Increment the body that moves\n\t\t\t\tbody += increment\n\t\t\t} //end While Loop throw rows of Diamonds\n\n\t\t\t// Increment the current Row of diamonds.\n\t\t\trow++\n\n\t\t\tif (start != 1) {\n\t\t\t\tstart = 1\n\t\t\t\tend = userInput\n\t\t\t\tincrement = 2\n\t\t\t} else {\n\t\t\t\t// We're rendering the \"bottom half\" of the total rendering.\n\t\t\t\t// Alter the parameters, and decrease the row number so the logic can loop again.\n\t\t\t\tstart = userInput - 2\n\t\t\t\tend = 1\n\t\t\t\tincrement = -2\n\t\t\t\trow--\n\t\t\t}\n\t\t} // End loop through each row of diamonds\n\t}\n\n\tprivate fun canLoop(increment: Int, body: Int, end: Int): Boolean = if (increment < 0) body >= end else body <= end\n\n\tprivate fun calculateDiamondsPerRow(totalDiamonds: Int): Int = LINE_WIDTH / totalDiamonds\n\n\tprivate fun isValid(input: Int): Boolean = (input in 5..21) && (input % 2 != 0)\n\n\tprivate fun printInvalidInput() = println(\"Invalid input\")\n\n\tprivate fun printPrompt() {\n\t\tprintln(\n\t\t\t\"\"\"\n\t\t\tFOR A PRETTY DIAMOND PATTERN\n\t\t\tTYPE IN AN ODD NUMBER BETWEEN 5 AND 21? \n\t\t\"\"\".trimIndent()\n\t\t)\n\t\tprintln()\n\t}\n\n\tprivate fun printIntro() {\n\t\tprintln(\" \".repeat(32) + \"DIAMOND\")\n\t\tprintln(\" \".repeat(14) + \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\")\n\t\tprintln()\n\t\tprintln()\n\t}\n\n\tcompanion object {\n\t\tconst val LINE_WIDTH = 60\n\t\tconst val PREFIX = \"CC\"\n\t\tconst val SYMBOL = \"!\"\n\t}\n}\n"
  },
  {
    "path": "32_Diamond/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "32_Diamond/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "32_Diamond/perl/diamond.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n################\n# PORTING NOTES:\n# * In basic \"Tab\" function are not spaces, but absolute col position on screen.\n# * It was too dificult to port this one, couldn't figure out the original algorithm.\n# * So the algorithm was remake.\n#\n\nprint ' 'x 33 . \"DIAMOND\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"FOR A PRETTY DIAMOND PATTERN,\\n\";\nprint \"TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? \"; chomp(my $R = <STDIN>); print \"\\n\";\n\n\nmy $Wid= int(60/$R)+1;\nmy $Dia=\"CC\". \"!\" x ($R-2);\n\nfor (my $J=1; $J<$Wid; $J++) {\n\tfor (my $K=1; $K<($R+2)*2-4; $K+=2) {\n\t\tmy $Size= $K;\n\t\tif ($K>$R) { $Size=$R+($R-$K); }\n\t\tmy $Chunk= substr($Dia, 0, $Size);\n\t\tfor (my $L=1; $L<$Wid; $L++) {\n\t\t\tmy $Space= \" \" x (($R-$Size)/2);\n\t\t\tif ($L>1) { $Space.=$Space; }\n\t\t\tprint $Space.$Chunk;\n\t\t\t}\n\t\tprint \"\\n\";\n\t\t}\n\t}\n\nexit;\n"
  },
  {
    "path": "32_Diamond/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "32_Diamond/python/diamond.py",
    "content": "\"\"\"\nDIAMOND\n\nPrints pretty diamond patterns to the screen.\n\nPorted by Dave LeCompte\n\"\"\"\n\n\ndef print_diamond(begin_width, end_width, step, width, count) -> None:\n    edge_string = \"CC\"\n    fill = \"!\"\n\n    n = begin_width\n    while True:\n        line_buffer = \" \" * ((width - n) // 2)\n        for across in range(count):\n            for a in range(n):\n                line_buffer += fill if a >= len(edge_string) else edge_string[a]\n            line_buffer += \" \" * (\n                (width * (across + 1) + (width - n) // 2) - len(line_buffer)\n            )\n        print(line_buffer)\n        if n == end_width:\n            return\n        n += step\n\n\ndef main() -> None:\n    print(\" \" * 33, \"DIAMOND\")\n    print(\" \" * 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"FOR A PRETTY DIAMOND PATTERN,\")\n    print(\"TYPE IN AN ODD NUMBER BETWEEN 5 AND 21\")\n    width = int(input())\n    print()\n\n    PAGE_WIDTH = 60\n\n    count = PAGE_WIDTH // width\n\n    for _down in range(count):\n        print_diamond(1, width, 2, width, count)\n        print_diamond(width - 2, 1, -2, width, count)\n\n    print()\n    print()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "32_Diamond/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "32_Diamond/ruby/diamond.rb",
    "content": "def intro\n  print \"                                 DIAMOND\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nFOR A PRETTY DIAMOND PATTERN,\nTYPE IN AN ODD NUMBER BETWEEN 5 AND 21? \"\nend\n\ndef get_facets\n  while true\n    number = gets.chomp\n    return number.to_i if /^\\d+$/.match(number)\n    puts \"!NUMBER EXPECTED - RETRY INPUT LINE\"\n    print \"? \"\n  end\nend\n\ndef get_diamond_lines(facets)\n  spacers = (facets - 1) / 2\n  lines = [' ' * spacers + 'C' + ' ' * spacers]\n  lines += (1...facets).step(2).to_a.map { |v|\n    spacers -= 1\n    ' ' * spacers + 'CC' + '!' * v + ' ' * spacers\n  }\n  lines + lines[0..-2].reverse\nend\n\ndef draw_diamonds(lines)\n  repeat = 60 / lines[0].length\n  (0...repeat).each { lines.map { |l| l * repeat }.each { |l| puts l } }\nend\n\ndef main\n  intro\n  facets = get_facets\n  puts\n  lines = get_diamond_lines(facets)\n  draw_diamonds(lines)\nend\n\ntrap \"SIGINT\" do puts; exit 130 end\n\nmain\n"
  },
  {
    "path": "32_Diamond/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "32_Diamond/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)"
  },
  {
    "path": "32_Diamond/rust/src/lib.rs",
    "content": "/*\n lib.rs contains all the logic of the program\n*/\n\nuse std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}};\n\n/// handles setup for the game\npub struct Config {\n    diamond_size: isize,\n}\nimpl Config {\n    /// creates and returns a new Config from user input\n    pub fn new() -> Result<Config, Box<dyn Error>> {\n        //DATA\n        let mut config: Config = Config { diamond_size: 0 };\n\n        //get data from user input\n\n        //get num players\n        println!(\"FOR A PRETTY DIAMOND PATTERN,\");\n        //input looop\n        config.diamond_size = loop {\n            match get_number_from_input(\"TYPE IN AN ODD NUMBER BETWEEN 5 AND 31 \", 5, 31) {\n                Ok(num) => {\n                    //ensure num is odd\n                    if num%2 == 0 {continue;}\n                    else {break num;}\n                },\n                Err(e) => {\n                    eprintln!(\"{}\",e);\n                    continue;\n                },\n            }\n        };\n\n        //return new config\n        return Ok(config);\n    }\n}\n\n/// run the program\npub fn run(config: &Config) -> Result<(), Box<dyn Error>> {\n    //DATA\n    let line_width: isize = 60;\n    let padding: char = 'C';\n    let pixel_width: isize = 1;\n    let filling: char = '!';\n    let border: char = '#';\n\n    let width_of_full_diamonds_in_line = (line_width/config.diamond_size) * config.diamond_size;\n\n    //print top border\n    println!(\"{}\", n_chars(width_of_full_diamonds_in_line+2, border));\n\n    //print out diamonds\n    for row in 0..width_of_full_diamonds_in_line {\n        print_diamond_line(config.diamond_size, row, line_width, pixel_width, padding, filling, border);\n    }\n\n    //print bottom border\n    println!(\"{}\", n_chars(width_of_full_diamonds_in_line+2, border));\n\n    //return to main\n    Ok(())\n}\n\n/// prints the next line of diamonds\nfn print_diamond_line(diamond_width: isize,row: isize,  line_width:isize, pixel_width:isize, padding:char, filling:char, border:char) {\n    //DATA\n    let diamonds_per_row = (line_width/pixel_width) / diamond_width;\n    //let row = row % (diamonds_per_row - 1);\n    let padding_amount; //total amount of padding before and after the filling of each diamond in this row\n    let filling_amount; //amount of \"diamond\" in each diamond in this row\n\n    //calculate padding\n    padding_amount = (2 * ( (row%(diamond_width-1)) - (diamond_width/2))).abs();\n    //calculate filling\n    filling_amount = -padding_amount + diamond_width;\n    \n    //print border before every row\n    print!(\"{}\", border);\n\n    //for every diamond in this row:\n    for _diamond in 0..diamonds_per_row {\n        //print leading padding\n        print!(\"{}\", n_chars( pixel_width * padding_amount/2, padding ) );\n        //print filling\n        print!(\"{}\", n_chars( pixel_width * filling_amount  , filling ) );\n        //print trailing padding\n        print!(\"{}\", n_chars( pixel_width * padding_amount/2, padding ) );\n    }\n\n    //print border after every row\n    print!(\"{}\", border);\n    //new line\n    println!(\"\");\n}\n\n/// returns n of the passed character, put into a string\nfn n_chars(n:isize, character: char) -> String {\n    let mut output = String::new();\n\n    for _i in 0..n {\n        output.push(character);\n    }\n\n    output\n}\n\n\n/// gets a string from user input\nfn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\", prompt);\n    //make sure it's printed before getting input\n    io::stdout().flush().unwrap();\n\n    //read user input from standard input, and store it to raw_input, then return it or an error as needed\n    raw_input.clear(); //clear input\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),\n        Err(err) => return Err(format!(\"ERROR: CANNOT READ INPUT!: {}\", err).into()),\n    }\n}\n\n/// generic function to get a number from the passed string (user input)\n/// pass a min lower  than the max to have minimun and maximun bounds\n/// pass a min higher than the max to only have a minumum bound\n/// pass a min equal   to  the max to only have a maximun bound\n/// \n/// Errors:\n/// no number on user input\nfn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {\n    //DATA\n    let raw_input: String;\n    let processed_input: String;\n\n    \n    //input looop\n    raw_input = loop {\n        match get_string_from_user_input(prompt) {\n            Ok(input) => break input,\n            Err(e) => {\n                eprintln!(\"{}\",e);\n                continue;\n            },\n        }\n    };\n\n    //filter out num-numeric characters from user input\n    processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();\n\n    //from input, try to read a number\n    match processed_input.trim().parse() {\n        Ok(i) => {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    return Ok(i); //exit the loop with the value i, returning it\n                } else { //print error message specific to this case\n                    return Err(format!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max).into());\n                } \n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO LESS THAN {}, PLEASE!\", min).into());\n                }\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO MORE THAN {}, PLEASE!\", max).into());\n                }\n            }\n        },\n        Err(_e) => return Err(format!(\"Error: couldn't find a valid number in {}\",raw_input).into()),\n    }\n}"
  },
  {
    "path": "32_Diamond/rust/src/main.rs",
    "content": "use std::process;       //allows for some better error handling\n\nmod lib;\nuse lib::Config;\n\n/// main function\n/// responsibilities:\n/// - Calling the command line logic with the argument values\n/// - Setting up any other configuration\n/// - Calling a run function in lib.rs\n/// - Handling the error if run returns an error\nfn main() {\n    //greet user\n    welcome();\n\n    // set up other configuration\n    let config = Config::new().unwrap_or_else(|err| {\n        eprintln!(\"Problem configuring program: {}\", err);\n        process::exit(1);\n    });\n\n    // run the program\n    if let Err(e) = lib::run(&config) {\n        eprintln!(\"Application Error: {}\", e); //use the eprintln! macro to output to standard error\n        process::exit(1); //exit the program with an error code\n    }\n\n    //end of program\n    println!(\"THANKS FOR PLAYING!\");\n}\n\n/// welcome message\nfn welcome() {\n    print!(\"\n                                DIAMOND    \n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n    \");\n}\n"
  },
  {
    "path": "32_Diamond/vbnet/Diamond.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Diamond\", \"Diamond.vbproj\", \"{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "32_Diamond/vbnet/Diamond.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Diamond</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "32_Diamond/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "33_Dice/README.md",
    "content": "### Dice\n\nNot exactly a game, this program simulates rolling a pair of dice a large number of times and prints out the frequency distribution. You simply input the number of rolls. It is interesting to see how many rolls are necessary to approach the theoretical distribution:\n\n|   |      |            |\n|---|------|------------|\n| 2 | 1/36 | 2.7777...% |\n| 3 | 2/36 | 5.5555...% |\n| 4 | 3/36 | 8.3333...% |\netc.\n\nDaniel Freidus wrote this program while in the seventh grade at Harrison Jr-Sr High School, Harrison, New York.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=57)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=72)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "33_Dice/csharp/Dice.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"TextUtil.cs\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "33_Dice/csharp/Dice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Dice\", \"Dice.csproj\", \"{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "33_Dice/csharp/Game.cs",
    "content": "﻿using System;\nusing System.Linq;\n\nnamespace BasicComputerGames.Dice\n{\n\tpublic class Game\n\t{\n\t\tprivate readonly RollGenerator _roller = new RollGenerator();\n\n\t\tpublic void GameLoop()\n\t\t{\n\t\t\tDisplayIntroText();\n\n\t\t\t// RollGenerator.ReseedRNG(1234);\t\t// hard-code seed for repeatabilty during testing\n\n\t\t\tdo\n\t\t\t{\n\t\t\t\tint numRolls = GetInput();\n\t\t\t\tvar counter = CountRolls(numRolls);\n\t\t\t\tDisplayCounts(counter);\n\t\t\t} while (TryAgain());\n\t\t}\n\n\t\tprivate void DisplayIntroText()\n\t\t{\n\t\t\tConsole.ForegroundColor = ConsoleColor.Yellow;\n\t\t\tConsole.WriteLine(\"Dice\");\n\t\t\tConsole.WriteLine(\"Creating Computing, Morristown, New Jersey.\"); Console.WriteLine();\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.DarkGreen;\n\t\t\tConsole.WriteLine(\"Original code by Danny Freidus.\");\n\t\t\tConsole.WriteLine(\"Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.\");\n\t\t\tConsole.WriteLine(\"Modernized and converted to C# in 2021 by James Curran (noveltheory.com).\");\n\t\t\tConsole.WriteLine();\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.Gray;\n\t\t\tConsole.WriteLine(\"This program simulates the rolling of a pair of dice.\");\n\t\t\tConsole.WriteLine(\"You enter the number of times you want the computer to\");\n\t\t\tConsole.WriteLine(\"'roll' the dice. Watch out, very large numbers take\");\n\t\t\tConsole.WriteLine(\"a long time. In particular, numbers over 10 million.\");\n\t\t\tConsole.WriteLine();\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.Yellow;\n\t\t\tConsole.WriteLine(\"Press any key start the game.\");\n\t\t\tConsole.ReadKey(true);\n\t\t}\n\n\t\tprivate int GetInput()\n\t\t{\n\t\t\tint num = -1;\n\t\t\tConsole.WriteLine();\n\t\t\tdo\n\t\t\t{\n\t\t\t\tConsole.WriteLine();\n\t\t\t\tConsole.Write(\"How many rolls? \");\n\t\t\t} while (!Int32.TryParse(Console.ReadLine(), out num));\n\n\t\t\treturn num;\n\t\t}\n\n\t\tprivate  void DisplayCounts(int[] counter)\n\t\t{\n\t\t\tConsole.WriteLine();\n\t\t\tConsole.WriteLine($\"\\tTotal\\tTotal Number\");\n\t\t\tConsole.WriteLine($\"\\tSpots\\tof Times\");\n\t\t\tConsole.WriteLine($\"\\t===\\t=========\");\n\t\t\tfor (var n = 1; n < counter.Length; ++n)\n\t\t\t{\n\t\t\t\tConsole.WriteLine($\"\\t{n + 1,2}\\t{counter[n],9:#,0}\");\n\t\t\t}\n\t\t\tConsole.WriteLine();\n\t\t}\n\n\t\tprivate  int[] CountRolls(int x)\n\t\t{\n\t\t\tvar counter = _roller.Rolls().Take(x).Aggregate(new int[12], (cntr, r) =>\n\t\t\t{\n\t\t\t\tcntr[r.die1 + r.die2 - 1]++;\n\t\t\t\treturn cntr;\n\t\t\t});\n\t\t\treturn counter;\n\t\t}\n\t\t/// <summary>\n\t\t/// Prompt the player to try again, and wait for them to press Y or N.\n\t\t/// </summary>\n\t\t/// <returns>Returns true if the player wants to try again, false if they have finished playing.</returns>\n\t\tprivate bool TryAgain()\n\t\t{\n\t\t\tConsole.ForegroundColor = ConsoleColor.White;\n\t\t\tConsole.WriteLine(\"Would you like to try again? (Press 'Y' for yes or 'N' for no)\");\n\n\t\t\tConsole.ForegroundColor = ConsoleColor.Yellow;\n\t\t\tConsole.Write(\"> \");\n\n\t\t\tchar pressedKey;\n\t\t\t// Keep looping until we get a recognised input\n\t\t\tdo\n\t\t\t{\n\t\t\t\t// Read a key, don't display it on screen\n\t\t\t\tConsoleKeyInfo key = Console.ReadKey(true);\n\t\t\t\t// Convert to upper-case so we don't need to care about capitalisation\n\t\t\t\tpressedKey = Char.ToUpper(key.KeyChar);\n\t\t\t\t// Is this a key we recognise? If not, keep looping\n\t\t\t} while (pressedKey != 'Y' && pressedKey != 'N');\n\t\t\t// Display the result on the screen\n\t\t\tConsole.WriteLine(pressedKey);\n\n\t\t\t// Return true if the player pressed 'Y', false for anything else.\n\t\t\treturn (pressedKey == 'Y');\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "33_Dice/csharp/Program.cs",
    "content": "﻿namespace BasicComputerGames.Dice\n{\n\tpublic class Program\n\t{\n\t\tpublic static void Main(string[] args)\n\t\t{\n\t\t\t// Create an instance of our main Game class\n\t\t\tGame game = new Game();\n\n\t\t\t// Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.\n\t\t\tgame.GameLoop();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "33_Dice/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) by James Curran (http://www.noveltheory.com)\n"
  },
  {
    "path": "33_Dice/csharp/RollGenerator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace BasicComputerGames.Dice\n{\n\tpublic class RollGenerator\n\t{\n\t\tstatic Random _rnd = new Random();\n\n\t\tpublic static void ReseedRNG(int seed) => _rnd = new Random(seed);\n\n\t\tpublic IEnumerable<(int die1, int die2)> Rolls()\n\t\t{\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tyield return (_rnd.Next(1, 7), _rnd.Next(1, 7));\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "33_Dice/dice.bas",
    "content": "2 PRINT TAB(34);\"DICE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 DIM F(12)\n20 REM  DANNY FREIDUS\n30 PRINT \"THIS PROGRAM SIMULATES THE ROLLING OF A\"\n40 PRINT \"PAIR OF DICE.\"\n50 PRINT \"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\"\n60 PRINT \"'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\"\n70 PRINT \"A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\"\n80 FOR Q=1 TO 12\n90 F(Q)=0\n100 NEXT Q\n110 PRINT:PRINT \"HOW MANY ROLLS\";\n120 INPUT X\n130 FOR S=1 TO X\n140 A=INT(6*RND(1)+1)\n150 B=INT(6*RND(1)+1)\n160 R=A+B\n170 F(R)=F(R)+1\n180 NEXT S\n185 PRINT\n190 PRINT \"TOTAL SPOTS\",\"NUMBER OF TIMES\"\n200 FOR V=2 TO 12\n210 PRINT V,F(V)\n220 NEXT V\n221 PRINT\n222 PRINT:PRINT \"TRY AGAIN\";\n223 INPUT Z$\n224 IF Z$=\"YES\" THEN 80\n240 END\n"
  },
  {
    "path": "33_Dice/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "33_Dice/java/src/Dice.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Dice\n * <p>\n * Based on the Basic game of Dice here\n * https://github.com/coding-horror/basic-computer-games/blob/main/33%20Dice/dice.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Dice {\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        START_GAME,\n        INPUT_AND_CALCULATE,\n        RESULTS,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private int[] spots;\n\n    public Dice() {\n        kbScanner = new Scanner(System.in);\n\n        gameState = GAME_STATE.START_GAME;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case START_GAME:\n                    intro();\n                    spots = new int[12];\n                    gameState = GAME_STATE.INPUT_AND_CALCULATE;\n                    break;\n\n                case INPUT_AND_CALCULATE:\n\n                    int howManyRolls = displayTextAndGetNumber(\"HOW MANY ROLLS? \");\n                    for (int i = 0; i < howManyRolls; i++) {\n                        int diceRoll = (int) (Math.random() * 6 + 1) + (int) (Math.random() * 6 + 1);\n                        // save dice roll in zero based array\n                        spots[diceRoll - 1]++;\n                    }\n                    gameState = GAME_STATE.RESULTS;\n                    break;\n\n                case RESULTS:\n                    System.out.println(\"TOTAL SPOTS\" + simulateTabs(8) + \"NUMBER OF TIMES\");\n                    for (int i = 1; i < 12; i++) {\n                        // show output using zero based array\n                        System.out.println(simulateTabs(5) + (i + 1) + simulateTabs(20) + spots[i]);\n                    }\n                    System.out.println();\n                    if (yesEntered(displayTextAndGetInput(\"TRY AGAIN? \"))) {\n                        gameState = GAME_STATE.START_GAME;\n                    } else {\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(34) + \"DICE\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THIS PROGRAM SIMULATES THE ROLLING OF A\");\n        System.out.println(\"PAIR OF DICE.\");\n        System.out.println(\"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\");\n        System.out.println(\"'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\");\n        System.out.println(\"A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\");\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text));\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n}\n"
  },
  {
    "path": "33_Dice/java/src/DiceGame.java",
    "content": "public class DiceGame {\n    public static void main(String[] args) {\n        Dice dice = new Dice();\n        dice.play();\n    }\n}\n"
  },
  {
    "path": "33_Dice/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "33_Dice/javascript/dice.html",
    "content": "<html>\n<head>\n<title>DICE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"dice.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "33_Dice/javascript/dice.js",
    "content": "// DICE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"DICE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    f = [];\n    // Danny Freidus\n    print(\"THIS PROGRAM SIMULATES THE ROLLING OF A\\n\");\n    print(\"PAIR OF DICE.\\n\");\n    print(\"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\\n\");\n    print(\"'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\\n\");\n    print(\"A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\\n\");\n    do {\n        for (q = 1; q <= 12; q++)\n            f[q] = 0;\n        print(\"\\n\");\n        print(\"HOW MANY ROLLS\");\n        x = parseInt(await input());\n        for (s = 1; s <= x; s++) {\n            a = Math.floor(Math.random() * 6 + 1);\n            b = Math.floor(Math.random() * 6 + 1);\n            r = a + b;\n            f[r]++;\n        }\n        print(\"\\n\");\n        print(\"TOTAL SPOTS\\tNUMBER OF TIMES\\n\");\n        for (v = 2; v <= 12; v++) {\n            print(\"\\t\" + v + \"\\t\" + f[v] + \"\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"TRY AGAIN\");\n        str = await input();\n    } while (str.substr(0, 1) == \"Y\") ;\n}\n\nmain();\n"
  },
  {
    "path": "33_Dice/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "33_Dice/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/) by Alex Conconi\n\n---\n\n### Porting notes for Lua\n\n- This is a straightfoward port with only minor modifications for input\nvalidation and text formatting.\n\n- The \"Try again?\" question accepts 'y', 'yes', 'n', 'no' (case insensitive),\nwhereas the original BASIC version defaults to no unless 'YES' is typed.\n\n- The \"How many rolls?\" question presents a more user friendly message\nin case of invalid input.\n"
  },
  {
    "path": "33_Dice/lua/dice.lua",
    "content": "--[[\nDice\n\nFrom: BASIC Computer Games (1978)\nEdited by David H. Ahl\n\n    \"Not exactly a game, this program simulates rolling\n    a pair of dice a large number of times and prints out\n    the frequency distribution.  You simply input the\n    number of rolls.  It is interesting to see how many\n    rolls are necessary to approach the theoretical\n    distribution:\n\n    2  1/36  2.7777...%\n    3  2/36  5.5555...%\n    4  3/36  8.3333...%\n    etc.\n\n    \"Daniel Freidus wrote this program while in the\n     seventh grade at Harrison Jr-Sr High School,\n    Harrison, New York.\"\n\n\nLua port by Alex Conconi, 2022.\n]]--\n\n\nlocal function print_intro()\n    print(\"\\n\" .. string.rep(\" \", 19) .. \"Dice\")\n    print(\"Creative Computing  Morristown, New Jersey\\n\\n\")\n    print(\"This program simulates the rolling of a\")\n    print(\"pair of dice.\")\n    print(\"You enter the number of times you want the computer to\")\n    print(\"'roll' the dice.   Watch out, very large numbers take\")\n    print(\"a long time.  In particular, numbers over 5000.\")\nend\n\n\nlocal function ask_how_many_rolls()\n    while true do\n        -- Print prompt and read a valid number from stdin\n        print(\"\\nHow many rolls?\")\n        local num_rolls = tonumber(io.stdin:read(\"*l\"))\n        if num_rolls then\n            return num_rolls\n        else\n            print(\"Please enter a valid number.\")\n        end\n    end\nend\n\n\nlocal function ask_try_again()\n    while true do\n        -- Print prompt and read a yes/no answer from stdin,\n        -- accepting only 'yes', 'y', 'no' or 'n' (case insensitive)\n        print(\"\\nTry again? ([y]es / [n]o)\")\n        local answer = string.lower(io.stdin:read(\"*l\"))\n        if answer == \"yes\" or  answer == \"y\" then\n            return true\n        elseif answer == \"no\" or answer == \"n\" then\n            return false\n        else\n            print(\"Please answer '[y]es' or '[n]o'.\")\n        end\n    end\nend\n\n\nlocal function roll_dice(num_rolls)\n    -- Initialize a table to track counts of roll outcomes\n    local counts = {}\n    for i=2, 12 do\n        counts[i] = 0\n    end\n\n    -- Roll the dice num_rolls times and update outcomes counts accordingly\n    for _=1, num_rolls do\n        local roll_total = math.random(1, 6) + math.random(1, 6)\n        counts[roll_total] = counts[roll_total] + 1\n    end\n\n    return counts\nend\n\n\nlocal function print_results(counts)\n    print(\"\\nTotal Spots   Number of Times\")\n    for roll_total, count in pairs(counts) do\n        print(string.format(\" %-14d%d\", roll_total, count))\n    end\nend\n\n\nlocal function dice_main()\n    print_intro()\n\n    -- initialize the random number generator\n    math.randomseed(os.time())\n\n    -- main game loop\n    local keep_playing = true\n    while keep_playing do\n        local num_rolls = ask_how_many_rolls()\n        local counts = roll_dice(num_rolls)\n        print_results(counts)\n        keep_playing = ask_try_again()\n    end\nend\n\n\ndice_main()\n"
  },
  {
    "path": "33_Dice/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "33_Dice/perl/dice.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 34 . \"DICE\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\nmy @F;\n\n#REM DANNY FREIDUS;\nprint \"THIS PROGRAM SIMULATES THE ROLLING OF A\\n\";\nprint \"PAIR OF DICE.\\n\";\nprint \"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\\n\";\nprint \"'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE\\n\";\nprint \"A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000.\\n\";\n\nmy $X;\nmy $Z;\ndo {\n\tfor (my $Q=1; $Q<=12; $Q++) {\n\t\t$F[$Q]=0;\n\t\t}\n\tprint \"\\n\"; print \"HOW MANY ROLLS\";\n\tprint \"? \"; chomp($X = <STDIN>);\n\tfor (my $S=1; $S<=$X; $S++) {\n\t\tmy $A=int(6*rand(1)+1);\n\t\tmy $B=int(6*rand(1)+1);\n\t\tmy $R=$A+$B;\n\t\t$F[$R]=$F[$R]+1;\n\t\t}\n\tprint \"\\n\";\n\tprint \"TOTAL SPOTS\\tNUMBER OF TIMES\\n\";\n\tfor (my $V=2; $V<=12; $V++) {\n\t\tprint \"$V\\t\\t$F[$V]\\n\";\n\t\t}\n\tprint \"\\n\";\n\tprint \"\\n\"; print \"TRY AGAIN\";\n\tprint \"? \"; chomp($Z = <STDIN>);\n\t} until (uc($Z) ne \"YES\");\nexit;\n"
  },
  {
    "path": "33_Dice/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "33_Dice/python/dice.py",
    "content": "\"\"\"\r\nDice\r\n\r\nFrom: BASIC Computer Games (1978)\r\n      Edited by David H. Ahl\r\n\r\n\"Not exactly a game, this program simulates rolling\r\n a pair of dice a large number of times and prints out\r\n the frequency distribution.  You simply input the\r\n number of rolls.  It is interesting to see how many\r\n rolls are necessary to approach the theoretical\r\n distribution:\r\n\r\n 2  1/36  2.7777...%\r\n 3  2/36  5.5555...%\r\n 4  3/36  8.3333...%\r\n   etc.\r\n\r\n\"Daniel Freidus wrote this program while in the\r\n seventh grade at Harrison Jr-Sr High School,\r\n Harrison, New York.\"\r\n\r\nPython port by Jeff Jetton, 2019\r\n\"\"\"\r\n\r\nimport random\r\n\r\n\r\ndef main() -> None:\r\n    # We'll track counts of roll outcomes in a 13-element list.\r\n    # The first two indices (0 & 1) are ignored, leaving just\r\n    # the indices that match the roll values (2 through 12).\r\n    freq = [0] * 13\r\n\r\n    # Display intro text\r\n    print(\"\\n                   Dice\")\r\n    print(\"Creative Computing  Morristown, New Jersey\")\r\n    print(\"\\n\\n\")\r\n    # \"Danny Freidus\"\r\n    print(\"This program simulates the rolling of a\")\r\n    print(\"pair of dice.\")\r\n    print(\"You enter the number of times you want the computer to\")\r\n    print(\"'roll' the dice.   Watch out, very large numbers take\")\r\n    print(\"a long time.  In particular, numbers over 5000.\")\r\n\r\n    still_playing = True\r\n    while still_playing:\r\n        print()\r\n        n = int(input(\"How many rolls? \"))\r\n\r\n        # Roll the dice n times\r\n        for _ in range(n):\r\n            die1 = random.randint(1, 6)\r\n            die2 = random.randint(1, 6)\r\n            roll_total = die1 + die2\r\n            freq[roll_total] += 1\r\n\r\n        # Display final results\r\n        print(\"\\nTotal Spots   Number of Times\")\r\n        for i in range(2, 13):\r\n            print(\" %-14d%d\" % (i, freq[i]))\r\n\r\n        # Keep playing?\r\n        print()\r\n        response = input(\"Try again? \")\r\n        if len(response) > 0 and response.upper()[0] == \"Y\":\r\n            # Clear out the frequency list\r\n            freq = [0] * 13\r\n        else:\r\n            # Exit the game loop\r\n            still_playing = False\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n\r\n########################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   A fairly straightforward port.  The only change is\r\n#   in the handling of the user's \"try again\" response.\r\n#   The original program only continued if the user\r\n#   entered \"YES\", whereas this version will continue\r\n#   if any word starting with \"Y\" or \"y\" is given.\r\n#\r\n#   The instruction text--which, like all these ports,\r\n#   was taken verbatim from the original listing--is\r\n#   charmingly quaint in its dire warning against\r\n#   setting the number of rolls too high.  At the time\r\n#   of this writing, on a fairly slow computer, a\r\n#   5000-roll run typically clocks in at well under\r\n#   1/10 of a second!\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   Have the results include a third column showing\r\n#   the percent of rolls each count represents.  Or\r\n#   (better yet) print a low-fi bar graph using\r\n#   rows of asterisks to represent relative values,\r\n#   with each asterisk representing one percent,\r\n#   for example.\r\n#\r\n#   Add a column showing the theoretically expected\r\n#   percentage, for comparison.\r\n#\r\n#   Keep track of how much time the series of rolls\r\n#   takes and add that info to the final report.\r\n#\r\n#   What if three (or four, or five...) dice were\r\n#   rolled each time?\r\n#\r\n########################################################\r\n"
  },
  {
    "path": "33_Dice/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "33_Dice/ruby/dice.rb",
    "content": "def intro\n  puts \"                                  DICE\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nTHIS PROGRAM SIMULATES THE ROLLING OF A\nPAIR OF DICE.\nYOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\n'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\nA LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\n\n\"\nend\n\ndef get_rolls\n  while true\n    number = gets.chomp\n    return number.to_i if /^\\d+$/.match(number)\n    puts \"!NUMBER EXPECTED - RETRY INPUT LINE\"\n    print \"? \"\n  end\nend\n\ndef dice_roll = rand(6) + 1 # ruby 3, woot!\n\ndef print_rolls(rolls)\n  values = Array.new(11, 0)\n  (1..rolls).each { values[dice_roll + dice_roll - 2] += 1 }\n  puts \"\\nTOTAL SPOTS   NUMBER OF TIMES\"\n  (0..10).each { |k| puts \" %-2d            %-2d\" % [k + 2, values[k]] }\nend\n\ndef main\n  intro\n  loop do\n    print \"HOW MANY ROLLS? \"\n    rolls = get_rolls\n\n    print_rolls(rolls)\n\n    print \"\\n\\nTRY AGAIN? \"\n    option = (gets || '').chomp.upcase\n    break unless option == 'YES'\n    puts\n  end\nend\n\ntrap \"SIGINT\" do puts; exit 130 end\n\nmain\n"
  },
  {
    "path": "33_Dice/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "33_Dice/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "33_Dice/rust/src/main.rs",
    "content": "////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// Dice\n//\n// From: BASIC Computer Games (1978)\n//       Edited by David H. Ahl\n//\n// \"Not exactly a game, this program simulates rolling\n//  a pair of dice a large number of times and prints out\n//  the frequency distribution.  You simply input the\n//  number of rolls.  It is interesting to see how many\n//  rolls are necessary to approach the theoretical\n//  distribution:\n//\n//  2  1/36  2.7777...%\n//  3  2/36  5.5555...%\n//  4  3/36  8.3333...%\n//    etc.\n//\n// \"Daniel Freidus wrote this program while in the\n//  seventh grade at Harrison Jr-Sr High School,\n//  Harrison, New York.\"\n//\n// Rust Port by Jay, 2022\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\nuse rand::Rng;\nuse std::io::{self, Write};\n\nfn main() {\n    let mut frequency: [i32; 13] = [0; 13];\n    println!(\n        \"{: >38}\\n{: >57}\\n\\n\",\n        \"DICE\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    // DANNY FREIDUS\n    println!(\"THIS PROGRAM SIMULATES THE ROLLING OF A\");\n    println!(\"PAIR OF DICE.\");\n    println!(\"YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\");\n    println!(\"'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\");\n    println!(\"A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\");\n    let mut playing = true;\n    while playing {\n        let n = match readinput(&\"HOW MANY ROLLS\").trim().parse::<i32>() {\n            Ok(num) => num,\n            Err(_) => {\n                println!(\"PLEASE ENTER A NUMBER\");\n                continue;\n            }\n        };\n        // Dice Rolled n times\n        for _i in 0..n {\n            let die_1 = rand::thread_rng().gen_range(1..=6);\n            let die_2 = rand::thread_rng().gen_range(1..=6);\n            let total = die_1 + die_2;\n            frequency[total] += 1;\n        }\n\n        // Results tabel\n        println!(\"\\nTOTAL SPOTS    NUMBER OF TIMES\");\n        for i in 2..13 {\n            println!(\"{:^4}\\t\\t{}\", i, frequency[i]);\n        }\n\n        // Continue the game\n        let reply = readinput(\"TRY AGAIN\").to_ascii_uppercase();\n        if reply.starts_with(\"Y\") || reply.eq(\"YES\") {\n            frequency = [0; 13];\n        } else {\n            playing = false;\n        }\n    }\n}\n\n// function for getting input on same line\nfn readinput(str: &str) -> String {\n    print!(\"\\n{}? \", str);\n    let mut input = String::new();\n    io::stdout().flush().unwrap();\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to get Input\");\n    input\n}\n"
  },
  {
    "path": "33_Dice/vbnet/Dice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Dice\", \"Dice.vbproj\", \"{6410CCD0-0D78-49C9-9B15-70F901A1EB19}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "33_Dice/vbnet/Dice.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Dice</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "33_Dice/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "33_Dice/vbnet/program.vb",
    "content": "Imports System\n\nModule Program\n    Sub Main(args As String())\n        Const header As String =\n\"                   DICE\nCREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nTHIS PROGRAM SIMULATES THE ROLLING OF A\nPAIR OF DICE.\nYOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\n/ROLL/ THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\nA LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\"\n\n        Console.WriteLine(header)\n\n        Dim D6 As New Random()\n        Dim continuePrompt As String = \"YES\"\n        While continuePrompt = \"YES\"\n            Console.Write($\"{vbCrLf}HOW MANY ROLLS? \")\n            Dim x As Integer = Convert.ToInt32(Console.ReadLine())\n            Dim F = Enumerable.Repeat(0, 11).ToList()\n            For s As Integer = 0 To x - 1\n                F(D6.Next(6) + D6.Next(6)) += 1\n            Next\n\n            Console.WriteLine($\"{vbCrLf}TOTAL SPOTS   NUMBER OF TIMES\")\n            For V As Integer = 0 To 10\n                Console.WriteLine($\" {V + 2}{vbTab,-8}{F(V)}\")\n            Next\n\n            Console.Write($\"{vbCrLf}TRY AGAIN \")\n            continuePrompt = Console.ReadLine().ToUpper()\n        End While\n    End Sub\nEnd Module\n"
  },
  {
    "path": "34_Digits/README.md",
    "content": "### Digits\n\nThe player writes down a set of 30 numbers (0, 1, or 2) at random prior to playing the game. The computer program, using pattern recognition techniques, attempts to guess the next number in your list.\n\nThe computer asks for 10 numbers at a time. It always guesses first and then examines the next number to see if it guessed correctly. By pure luck (or chance or probability), the computer ought to be right 10 times. It is uncanny how much better it generally does than that!\n\nThis program originated at Dartmouth; original author unknown.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=58)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=73)\n\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- The program contains a lot of mysterious and seemingly arbitrary constants.  It's not clear there is any logic or rationality behind it.\n- The key equation involved in the guess (line 700) involves a factor of `A`, but `A` is always 0, making that term meaningless.  As a result, all the work to build and update array K and value Z2 appear to be meaningless, too.\n"
  },
  {
    "path": "34_Digits/csharp/Digits.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "34_Digits/csharp/Digits.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Digits\", \"Digits.csproj\", \"{BB89211D-85FB-4FC0-AF62-715459227D7E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BB89211D-85FB-4FC0-AF62-715459227D7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BB89211D-85FB-4FC0-AF62-715459227D7E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BB89211D-85FB-4FC0-AF62-715459227D7E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BB89211D-85FB-4FC0-AF62-715459227D7E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "34_Digits/csharp/Game.cs",
    "content": "namespace Digits;\n\ninternal class GameSeries\n{\n    private readonly IReadOnlyList<int> _weights = new List<int> { 0, 1, 3 }.AsReadOnly();\n\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public GameSeries(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    internal void Play()\n    {\n        _io.Write(Streams.Introduction);\n\n        if (_io.ReadNumber(Prompts.ForInstructions) != 0)\n        {\n            _io.Write(Streams.Instructions);\n        }\n\n        do\n        {\n            new Game(_io, _random).Play();\n        } while (_io.ReadNumber(Prompts.WantToTryAgain) == 1);\n\n        _io.Write(Streams.Thanks);\n    }\n}\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n    private readonly Guesser _guesser;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _guesser = new Guesser(random);\n    }\n\n    public void Play()\n    {\n        var correctGuesses = 0;\n\n        for (int round = 0; round < 3; round++)\n        {\n            var digits = _io.Read10Digits(Prompts.TenNumbers, Streams.TryAgain);\n\n            correctGuesses = GuessDigits(digits, correctGuesses);\n        }\n\n        _io.Write(correctGuesses switch\n        {\n            < 10 => Streams.YouWin,\n            10 => Streams.ItsATie,\n            > 10 => Streams.IWin\n        });\n    }\n\n    private int GuessDigits(IEnumerable<int> digits, int correctGuesses)\n    {\n        _io.Write(Streams.Headings);\n\n        foreach (var digit in digits)\n        {\n            var guess = _guesser.GuessNextDigit();\n            if (guess == digit) { correctGuesses++; }\n\n            _io.WriteLine(Formats.GuessResult, guess, digit, guess == digit ? \"Right\" : \"Wrong\", correctGuesses);\n\n            _guesser.ObserveActualDigit(digit);\n        }\n\n        return correctGuesses;\n    }\n}\n"
  },
  {
    "path": "34_Digits/csharp/Guesser.cs",
    "content": "namespace Digits;\n\ninternal class Guesser\n{\n    private readonly Memory _matrices = new();\n    private readonly IRandom _random;\n\n    public Guesser(IRandom random)\n    {\n        _random = random;\n    }\n\n    public int GuessNextDigit()\n    {\n        var currentSum = 0;\n        var guess = 0;\n\n        for (int i = 0; i < 3; i++)\n        {\n            var sum = _matrices.GetWeightedSum(i);\n            if (sum > currentSum || _random.NextFloat() >= 0.5)\n            {\n                currentSum = sum;\n                guess = i;\n            }\n        }\n\n        return guess;\n    }\n\n    public void ObserveActualDigit(int digit) => _matrices.ObserveDigit(digit);\n}\n"
  },
  {
    "path": "34_Digits/csharp/IOExtensions.cs",
    "content": "namespace Digits;\n\ninternal static class IOExtensions\n{\n    internal static IEnumerable<int> Read10Digits(this IReadWrite io, string prompt, Stream retryText)\n    {\n        while (true)\n        {\n            var numbers = new float[10];\n            io.ReadNumbers(prompt, numbers);\n\n            if (numbers.All(n => n == 0 || n == 1 || n == 2))\n            {\n                return numbers.Select(n => (int)n);\n            }    \n\n            io.Write(retryText);\n        }\n    }\n}"
  },
  {
    "path": "34_Digits/csharp/Matrix.cs",
    "content": "namespace Digits;\n\ninternal class Matrix\n{\n    private readonly int _weight;\n    private readonly int[,] _values;\n\n    public Matrix(int width, int weight, Func<int, int, int> seedFactory)\n    {\n        _weight = weight;\n        _values = new int[width, 3];\n        \n        for (int i = 0; i < width; i++)\n        for (int j = 0; j < 3; j++)\n        {\n            _values[i, j] = seedFactory.Invoke(i, j);\n        }\n\n        Index = width - 1;\n    }\n\n    public int Index { get; set; }\n\n    public int GetWeightedValue(int row) => _weight * _values[Index, row];\n\n    public int IncrementValue(int row) => _values[Index, row]++;\n}"
  },
  {
    "path": "34_Digits/csharp/Memory.cs",
    "content": "namespace Digits;\n\npublic class Memory\n{\n    private readonly Matrix[] _matrices;\n\n    public Memory()\n    {\n        _matrices = new[] \n        {\n            new Matrix(27, 3, (_, _) => 1),\n            new Matrix(9, 1, (i, j) => i == 4 * j ? 2 : 3),\n            new Matrix(3, 0, (_, _) => 9)\n        };\n    }\n\n    public int GetWeightedSum(int row) => _matrices.Select(m => m.GetWeightedValue(row)).Sum();\n\n    public void ObserveDigit(int digit)\n    {\n        for (int i = 0; i < 3; i++)\n        {\n            _matrices[i].IncrementValue(digit);\n        }\n\n        _matrices[0].Index = _matrices[0].Index % 9 * 3 + digit;\n        _matrices[1].Index = _matrices[0].Index % 9;\n        _matrices[2].Index = digit;\n    }\n}"
  },
  {
    "path": "34_Digits/csharp/Program.cs",
    "content": "global using Digits;\nglobal using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using static Digits.Resources.Resource;\n\nnew GameSeries(new ConsoleIO(), new RandomNumberGenerator()).Play();"
  },
  {
    "path": "34_Digits/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "34_Digits/csharp/Resources/ForInstructions.txt",
    "content": "For instructions, type '1', else type '0'"
  },
  {
    "path": "34_Digits/csharp/Resources/GuessResult.txt",
    "content": "   {0}              {1}          {2}         {3}"
  },
  {
    "path": "34_Digits/csharp/Resources/Headings.txt",
    "content": "\nMy guess      Your no.      Result        No. right\n\n"
  },
  {
    "path": "34_Digits/csharp/Resources/IWin.txt",
    "content": "\nI guessed more than 1/3 of your numbers.\nI win.\n\n"
  },
  {
    "path": "34_Digits/csharp/Resources/Instructions.txt",
    "content": "\nPlease take a piece of paper and write down\nthe digits '0', '1', or '2' thirty times at random.\nArrange them in three lines of ten digits each.\nI will ask for then ten at a time.\nI will always guess them first and then look at your\nnext number to see if I was right. By pure luck,\nI ought to be right ten times. But I hope to do better\nthan that *****\n\n\n"
  },
  {
    "path": "34_Digits/csharp/Resources/Introduction.txt",
    "content": "                                 Digits\n               Creative Computing  Morristown, New Jersey\n\n\n\nThis is a game of guessing.\n"
  },
  {
    "path": "34_Digits/csharp/Resources/ItsATie.txt",
    "content": "\nI guessed exactly 1/3 of your numbers.\nIt's a tie game.\n\n"
  },
  {
    "path": "34_Digits/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Digits.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n        public static Stream Instructions => GetStream();\n        public static Stream TryAgain => GetStream();\n        public static Stream ItsATie => GetStream();\n        public static Stream IWin => GetStream();\n        public static Stream YouWin => GetStream();\n        public static Stream Thanks => GetStream();\n        public static Stream Headings => GetStream();\n    }\n\n    internal static class Prompts\n    {\n        public static string ForInstructions => GetString();\n        public static string TenNumbers => GetString();\n        public static string WantToTryAgain => GetString();\n    }\n\n    internal static class Formats\n    {\n        public static string GuessResult => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "34_Digits/csharp/Resources/TenNumbers.txt",
    "content": "\nTen numbers, please"
  },
  {
    "path": "34_Digits/csharp/Resources/Thanks.txt",
    "content": "\nThanks for the game\n"
  },
  {
    "path": "34_Digits/csharp/Resources/TryAgain.txt",
    "content": "Only use the digits '0', '1', or '2'.\nLet's try again.\n"
  },
  {
    "path": "34_Digits/csharp/Resources/WantToTryAgain.txt",
    "content": "Do you want to try again (1 for yes, 0 for no)"
  },
  {
    "path": "34_Digits/csharp/Resources/YouWin.txt",
    "content": "\nI guessed less than 1/3 of your numbers.\nYou beat me.  Congratulations *****\n\n"
  },
  {
    "path": "34_Digits/digits.bas",
    "content": "10 PRINT TAB(33);\"DIGITS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n210 PRINT \"THIS IS A GAME OF GUESSING.\"\n220 PRINT \"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0'\";\n230 INPUT E\n240 IF E=0 THEN 360\n250 PRINT\n260 PRINT \"PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\"\n270 PRINT \"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\"\n280 PRINT \"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\"\n290 PRINT \"I WILL ASK FOR THEN TEN AT A TIME.\"\n300 PRINT \"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\"\n310 PRINT \"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\"\n320 PRINT \"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\"\n330 PRINT \"THAN THAT *****\"\n340 PRINT:PRINT\n360 READ A,B,C\n370 DATA 0,1,3\n380 DIM M(26,2),K(2,2),L(8,2)\n400 FOR I=0 TO 26: FOR J=0 TO 2: M(I,J)=1: NEXT J: NEXT I\n410 FOR I=0 TO 2: FOR J=0 TO 2: K(I,J)=9: NEXT J: NEXT I\n420 FOR I=0 TO 8: FOR J=0 TO 2: L(I,J)=3: NEXT J: NEXT I\n450 L(0,0)=2: L(4,1)=2: L(8,2)=2\n480 Z=26: Z1=8: Z2=2\n510 X=0\n520 FOR T=1 TO 3\n530 PRINT\n540 PRINT \"TEN NUMBERS, PLEASE\";\n550 INPUT N(1),N(2),N(3),N(4),N(5),N(6),N(7),N(8),N(9),N(10)\n560 FOR I=1 TO 10\n570 W=N(I)-1\n580 IF W=SGN(W) THEN 620\n590 PRINT \"ONLY USE THE DIGITS '0', '1', OR '2'.\"\n600 PRINT \"LET'S TRY AGAIN.\":GOTO 530\n620 NEXT I\n630 PRINT: PRINT \"MY GUESS\",\"YOUR NO.\",\"RESULT\",\"NO. RIGHT\":PRINT\n660 FOR U=1 TO 10\n670 N=N(U): S=0\n690 FOR J=0 TO 2\n700 S1=A*K(Z2,J)+B*L(Z1,J)+C*M(Z,J)\n710 IF S>S1 THEN 760\n720 IF S<S1 THEN 740\n730 IF RND(1)<.5 THEN 760\n740 S=S1: G=J\n760 NEXT J\n770 PRINT \"  \";G,\"   \";N(U),\n780 IF G=N(U) THEN 810\n790 PRINT \" WRONG\",X\n800 GOTO 880\n810 X=X+1\n820 PRINT \" RIGHT\",X\n830 M(Z,N)=M(Z,N)+1\n840 L(Z1,N)=L(Z1,N)+1\n850 K(Z2,N)=K(Z2,N)+1\n860 Z=Z-INT(Z/9)*9\n870 Z=3*Z+N(U)\n880 Z1=Z-INT(Z/9)*9\n890 Z2=N(U)\n900 NEXT U\n910 NEXT T\n920 PRINT\n930 IF X>10 THEN 980\n940 IF X<10 THEN 1010\n950 PRINT \"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\"\n960 PRINT \"IT'S A TIE GAME.\"\n970 GOTO 1030\n980 PRINT \"I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\"\n990 PRINT \"I WIN.\": FOR Q=1 TO 10: PRINT CHR$(7);: NEXT Q\n1000 GOTO 1030\n1010 PRINT \"I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\"\n1020 PRINT \"YOU BEAT ME.  CONGRATULATIONS *****\"\n1030 PRINT\n1040 PRINT \"DO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO)\";\n1060 INPUT X\n1070 IF X=1 THEN 400\n1080 PRINT:PRINT \"THANKS FOR THE GAME.\"\n1090 END\n"
  },
  {
    "path": "34_Digits/java/Digits.java",
    "content": "import java.util.Arrays;\nimport java.util.InputMismatchException;\nimport java.util.Scanner;\n\n/**\n * DIGITS\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class Digits {\n\n\tpublic static void main(String[] args) {\n\t\tprintIntro();\n\t\tScanner scan = new Scanner(System.in);\n\n\t\tboolean showInstructions = readInstructionChoice(scan);\n\t\tif (showInstructions) {\n\t\t\tprintInstructions();\n\t\t}\n\n\t\tint a = 0, b = 1, c = 3;\n\t\tint[][] m = new int[27][3];\n\t\tint[][] k = new int[3][3];\n\t\tint[][] l = new int[9][3];\n\n\t\tboolean continueGame = true;\n\t\twhile (continueGame) {\n\t\t\tfor (int[] ints : m) {\n\t\t\t\tArrays.fill(ints, 1);\n\t\t\t}\n\t\t\tfor (int[] ints : k) {\n\t\t\t\tArrays.fill(ints, 9);\n\t\t\t}\n\t\t\tfor (int[] ints : l) {\n\t\t\t\tArrays.fill(ints, 3);\n\t\t\t}\n\n\t\t\tl[0][0] = 2;\n\t\t\tl[4][1] = 2;\n\t\t\tl[8][2] = 2;\n\n\t\t\tint z = 26, z1 = 8, z2 = 2, runningCorrect = 0;\n\n\t\t\tfor (int t = 1; t <= 3; t++) {\n\t\t\t\tboolean validNumbers = false;\n\t\t\t\tint[] numbers = new int[0];\n\t\t\t\twhile (!validNumbers) {\n\t\t\t\t\tSystem.out.println();\n\t\t\t\t\tnumbers = read10Numbers(scan);\n\t\t\t\t\tvalidNumbers = true;\n\t\t\t\t\tfor (int number : numbers) {\n\t\t\t\t\t\tif (number < 0 || number > 2) {\n\t\t\t\t\t\t\tSystem.out.println(\"ONLY USE THE DIGITS '0', '1', OR '2'.\");\n\t\t\t\t\t\t\tSystem.out.println(\"LET'S TRY AGAIN.\");\n\t\t\t\t\t\t\tvalidNumbers = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSystem.out.printf(\"\\n%-14s%-14s%-14s%-14s\", \"MY GUESS\", \"YOUR NO.\", \"RESULT\", \"NO. RIGHT\");\n\t\t\t\tfor (int number : numbers) {\n\t\t\t\t\tint s = 0;\n\t\t\t\t\tint myGuess = 0;\n\t\t\t\t\tfor (int j = 0; j <= 2; j++) {\n\t\t\t\t\t\t//What did the original author have in mind ? The first expression always results in 0 because a is always 0\n\t\t\t\t\t\tint s1 = a * k[z2][j] + b * l[z1][j] + c * m[z][j];\n\t\t\t\t\t\tif (s < s1) {\n\t\t\t\t\t\t\ts = s1;\n\t\t\t\t\t\t\tmyGuess = j;\n\t\t\t\t\t\t} else if (s1 == s) {\n\t\t\t\t\t\t\tif (Math.random() >= 0.5) {\n\t\t\t\t\t\t\t\tmyGuess = j;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tString result;\n\t\t\t\t\tif (myGuess != number) {\n\t\t\t\t\t\tresult = \"WRONG\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\trunningCorrect++;\n\t\t\t\t\t\tresult = \"RIGHT\";\n\t\t\t\t\t\tm[z][number] = m[z][number] + 1;\n\t\t\t\t\t\tl[z1][number] = l[z1][number] + 1;\n\t\t\t\t\t\tk[z2][number] = k[z2][number] + 1;\n\t\t\t\t\t\tz = z - (z / 9) * 9;\n\t\t\t\t\t\tz = 3 * z + number;\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.printf(\"\\n%-14d%-14d%-14s%-14d\", myGuess, number, result, runningCorrect);\n\n\t\t\t\t\tz1 = z - (z / 9) * 9;\n\t\t\t\t\tz2 = number;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//print summary report\n\t\t\tSystem.out.println();\n\t\t\tif (runningCorrect > 10) {\n\t\t\t\tSystem.out.println();\n\t\t\t\tSystem.out.println(\"I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\");\n\t\t\t\tSystem.out.println(\"I WIN.\\u0007\");\n\t\t\t} else if (runningCorrect < 10) {\n\t\t\t\tSystem.out.println(\"I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\");\n\t\t\t\tSystem.out.println(\"YOU BEAT ME.  CONGRATULATIONS *****\");\n\t\t\t} else {\n\t\t\t\tSystem.out.println(\"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\");\n\t\t\t\tSystem.out.println(\"IT'S A TIE GAME.\");\n\t\t\t}\n\n\t\t\tcontinueGame = readContinueChoice(scan);\n\t\t}\n\n\t\tSystem.out.println(\"\\nTHANKS FOR THE GAME.\");\n\t}\n\n\tprivate static boolean readContinueChoice(Scanner scan) {\n\t\tSystem.out.print(\"\\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? \");\n\t\tint choice;\n\t\ttry {\n\t\t\tchoice = scan.nextInt();\n\t\t\treturn choice == 1;\n\t\t} catch (InputMismatchException ex) {\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tscan.nextLine();\n\t\t}\n\t}\n\n\tprivate static int[] read10Numbers(Scanner scan) {\n\t\tSystem.out.print(\"TEN NUMBERS, PLEASE ? \");\n\t\tint[] numbers = new int[10];\n\n\t\tfor (int i = 0; i < numbers.length; i++) {\n\t\t\tboolean validInput = false;\n\t\t\twhile (!validInput) {\n\t\t\t\ttry {\n\t\t\t\t\tint n = scan.nextInt();\n\t\t\t\t\tvalidInput = true;\n\t\t\t\t\tnumbers[i] = n;\n\t\t\t\t} catch (InputMismatchException ex) {\n\t\t\t\t\tSystem.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n\t\t\t\t} finally {\n\t\t\t\t\tscan.nextLine();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn numbers;\n\t}\n\n\tprivate static void printInstructions() {\n\t\tSystem.out.println(\"\\n\");\n\t\tSystem.out.println(\"PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\");\n\t\tSystem.out.println(\"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\");\n\t\tSystem.out.println(\"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\");\n\t\tSystem.out.println(\"I WILL ASK FOR THEN TEN AT A TIME.\");\n\t\tSystem.out.println(\"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\");\n\t\tSystem.out.println(\"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\");\n\t\tSystem.out.println(\"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\");\n\t\tSystem.out.println(\"THAN THAT *****\");\n\t\tSystem.out.println();\n\t}\n\n\tprivate static boolean readInstructionChoice(Scanner scan) {\n\t\tSystem.out.print(\"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? \");\n\t\tint choice;\n\t\ttry {\n\t\t\tchoice = scan.nextInt();\n\t\t\treturn choice == 1;\n\t\t} catch (InputMismatchException ex) {\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tscan.nextLine();\n\t\t}\n\t}\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                DIGITS\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\");\n\t\tSystem.out.println(\"THIS IS A GAME OF GUESSING.\");\n\t}\n\n}\n"
  },
  {
    "path": "34_Digits/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "34_Digits/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "34_Digits/javascript/digits.html",
    "content": "<html>\n<head>\n<title>DIGITS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"digits.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "34_Digits/javascript/digits.js",
    "content": "// DIGITS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"DIGITS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS A GAME OF GUESSING.\\n\");\n    print(\"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0'\");\n    e = parseInt(await input());\n    if (e != 0) {\n        print(\"\\n\");\n        print(\"PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\\n\");\n        print(\"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\\n\");\n        print(\"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\\n\");\n        print(\"I WILL ASK FOR THEN TEN AT A TIME.\\n\");\n        print(\"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\\n\");\n        print(\"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\\n\");\n        print(\"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\\n\");\n        print(\"THAN THAT *****\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n    a = 0;\n    b = 1;\n    c = 3;\n    m = [];\n    k = [];\n    l = [];\n    n = [];\n    while (1) {\n        for (i = 0; i <= 26; i++) {\n            m[i] = [];\n            for (j = 0; j <= 2; j++) {\n                m[i][j] = 1;\n            }\n        }\n        for (i = 0; i <= 2; i++) {\n            k[i] = [];\n            for (j = 0; j <= 2; j++) {\n                k[i][j] = 9;\n            }\n        }\n        for (i = 0; i <= 8; i++) {\n            l[i] = [];\n            for (j = 0; j <= 2; j++) {\n                l[i][j] = 3;\n            }\n        }\n        l[0][0] = 2;\n        l[4][1] = 2;\n        l[8][2] = 2;\n        z = 26;\n        z1 = 8;\n        z2 = 2;\n        x = 0;\n        for (t = 1; t <= 3; t++) {\n            while (1) {\n                print(\"\\n\");\n                print(\"TEN NUMBERS, PLEASE\");\n                str = await input();\n                for (i = 1; i <= 10; i++) {\n                    n[i] = parseInt(str);\n                    j = str.indexOf(\",\");\n                    if (j >= 0) {\n                        str = str.substr(j + 1);\n                    }\n                    if (n[i] < 0 || n[i] > 2)\n                        break;\n                }\n                if (i <= 10) {\n                    print(\"ONLY USE THE DIGITS '0', '1', OR '2'.\\n\");\n                    print(\"LET'S TRY AGAIN.\\n\");\n                } else {\n                    break;\n                }\n            }\n            print(\"\\n\");\n            print(\"MY GUESS\\tYOUR NO.\\tRESULT\\tNO. RIGHT\\n\");\n            print(\"\\n\");\n            for (u = 1; u <= 10; u++) {\n                n2 = n[u];\n                s = 0;\n                for (j = 0; j <= 2; j++) {\n                    s1 = a * k[z2][j] + b * l[z1][j] + c * m[z][j];\n                    if (s > s1)\n                        continue;\n                    if (s < s1 || Math.random() >= 0.5) {\n                        s = s1;\n                        g = j;\n                    }\n                }\n                print(\"  \" + g + \"\\t\\t   \" + n[u] + \"\\t\\t\");\n                if (g == n[u]) {\n                    x++;\n                    print(\" RIGHT\\t \" + x + \"\\n\");\n                    m[z][n2]++;\n                    l[z1][n2]++;\n                    k[z2][n2]++;\n                    z = z % 9;\n                    z = 3 * z + n[u];\n                } else {\n                    print(\" WRONG\\t \" + x + \"\\n\");\n                }\n                z1 = z % 9;\n                z2 = n[u];\n            }\n        }\n        print(\"\\n\");\n        if (x > 10) {\n            print(\"I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\\n\");\n            print(\"I WIN.\\n\");\n        } else if (x == 10) {\n            print(\"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\\n\");\n            print(\"IT'S A TIE GAME.\\n\");\n        } else {\n            print(\"I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\\n\");\n            print(\"YOU BEAT ME.  CONGRATULATIONS *****\\n\");\n        }\n        print(\"\\n\");\n        print(\"DO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO)\");\n        x = parseInt(await input());\n        if (x != 1)\n            break;\n    }\n    print(\"\\n\");\n    print(\"THANKS FOR THE GAME.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "34_Digits/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "34_Digits/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "34_Digits/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "34_Digits/perl/digits.pl",
    "content": "#!/usr/bin/perl\n\n# Digits program in Perl\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $Answer;\n\nprint \"\\n\";\nprint \" \" x 33, \"DIGITS\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\nprint \"THIS IS A GAME OF GUESSING.\\n\";\nprint \"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0': \";\nchomp($Answer = <>);\nif ($Answer == 1)\n{\n    print \"\\nPLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\\n\";\n    print \"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\\n\";\n    print \"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\\n\";\n    print \"I WILL ASK FOR THEN TEN AT A TIME.\\n\";\n    print \"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\\n\";\n    print \"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\\n\";\n    print \"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\\n\";\n    print \"THAN THAT. *****\\n\\n\\n\";\n}\n\nmy ($A, $B, $C) = (0, 1, 3);\nmy (@M, @K, @L); # DIM M(26,2),K(2,2),L(8,2)\nwhile (1)\n{\n    for my $i (0 .. 26) { for my $j (0 .. 2) { $M[$i][$j] = 1; } }\n    for my $i (0 .. 2)  { for my $j (0 .. 2) { $K[$i][$j] = 9; } }\n    for my $i (0 .. 8)  { for my $j (0 .. 2) { $L[$i][$j] = 3; } }\n    $L[0][0] = $L[4][1] = $L[8][2] = 2;\n    my $Z = 26;\n    my $Z1 = 8;\n    my $Z2 = 2;\n    my $X = 0;\n    my @N;\n\n    for my $T (1 .. 3)\n    {\n        my $have_input = 0;\n        while (!$have_input)\n        {\n            $have_input = 1;\n            print \"\\nTEN NUMBERS, PLEASE: \";\n            chomp($Answer = <>);\n            $Answer = \"0 \" . $Answer; # need to be 1-based, so prepend a throw-away value for [0]\n            @N = split(/\\s+/, $Answer);\n            for my $i (1 .. 10)\n            {\n                if (!defined($N[$i]) || ($N[$i] != 0 && $N[$i] != 1 && $N[$i] != 2))\n                {\n                    print \"ONLY USE THE DIGITS '0', '1', OR '2'.\\n\";\n                    print \"LET'S TRY AGAIN.\";\n                    $have_input = 0;\n                    last;\n                }\n            }\n        }\n\n        print \"\\nMY GUESS\\tYOUR NO.\\tRESULT\\tNO. RIGHT\\n\\n\";\n        for my $U (1 .. 10)\n        {\n            my $num = $N[$U];\n            my $S = 0;\n            my $G;\n            for my $J (0 .. 2)\n            {\n                my $S1 = $A * $K[$Z2][$J] + $B * $L[$Z1][$J] + $C * $M[$Z][$J];\n                next if ($S > $S1);\n                if ($S >= $S1)\n                {\n                    next if (rand(1) < .5);\n                }\n                $S = $S1;\n                $G = $J;\n            } # NEXT J\n            print \"  $G\\t\\t$N[$U]\\t\\t\";\n            if ($G == $N[$U])\n            {\n                $X++;\n                print \"RIGHT\\t$X\\n\";\n                $M[$Z][$num]++;\n                $L[$Z1][$num]++;\n                $K[$Z2][$num]++;\n                $Z -= int($Z / 9) * 9;\n                $Z = 3 * $Z + $N[$U];\n            }\n            else\n            {\n                print \"WRONG\\t$X\\n\";\n            }\n            $Z1 = $Z - int($Z / 9) * 9;\n            $Z2 = $N[$U];\n        } # NEXT U\n    } # NEXT T\n\n    print \"\\n\";\n    if ($X == 10)\n    {\n        print \"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\\n\";\n        print \"IT'S A TIE GAME.\\n\";\n    }\n    elsif ($X > 10)\n    {\n        print \"I GUESSED MORE THAN 1/3, OR $X, OF YOUR NUMBERS.\\n\";\n        print \"I WIN.\\a\\a\\a\\a\\a\\a\\a\\a\\a\\a\"\n    }\n    else\n    {\n        print \"I GUESSED LESS THAN 1/3, OR $X, OF YOUR NUMBERS.\\n\";\n        print \"YOU BEAT ME.  CONGRATULATIONS *****\\n\";\n    }\n\n    print \"\\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO): \";\n    chomp($Answer = <>);\n    last if ($Answer != 1);\n}\nprint \"\\nTHANKS FOR THE GAME.\\n\";\n"
  },
  {
    "path": "34_Digits/python/Digits.py",
    "content": "import random\nfrom typing import List\n\n\ndef print_intro() -> None:\n    print(\"                                DIGITS\")\n    print(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n    print(\"THIS IS A GAME OF GUESSING.\")\n\n\ndef read_instruction_choice() -> bool:\n    print(\"FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? \")\n    try:\n        choice = int(input())\n        return choice == 1\n    except (ValueError, TypeError):\n        return False\n\n\ndef print_instructions() -> None:\n    print(\"\\n\")\n    print(\"PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\")\n    print(\"THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\")\n    print(\"ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\")\n    print(\"I WILL ASK FOR THEN TEN AT A TIME.\")\n    print(\"I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\")\n    print(\"NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\")\n    print(\"I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\")\n    print(\"THAN THAT *****\")\n    print()\n\n\ndef read_10_numbers() -> List[int]:\n    print(\"TEN NUMBERS, PLEASE ? \")\n    numbers = []\n\n    for _ in range(10):\n        valid_input = False\n        while not valid_input:\n            try:\n                n = int(input())\n                valid_input = True\n                numbers.append(n)\n            except (TypeError, ValueError):\n                print(\"!NUMBER EXPECTED - RETRY INPUT LINE\")\n\n    return numbers\n\n\ndef read_continue_choice() -> bool:\n    print(\"\\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? \")\n    try:\n        choice = int(input())\n        return choice == 1\n    except (ValueError, TypeError):\n        return False\n\n\ndef print_summary_report(running_correct: int) -> None:\n    print()\n    if running_correct > 10:\n        print()\n        print(\"I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\")\n        print(\"I WIN.\\u0007\")\n    elif running_correct < 10:\n        print(\"I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\")\n        print(\"YOU BEAT ME.  CONGRATULATIONS *****\")\n    else:\n        print(\"I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\")\n        print(\"IT'S A TIE GAME.\")\n\n\ndef main() -> None:\n    print_intro()\n    if read_instruction_choice():\n        print_instructions()\n\n    a = 0\n    b = 1\n    c = 3\n\n    m = [[1] * 3 for _ in range(27)]\n    k = [[9] * 3 for _ in range(3)]\n    l = [[3] * 3 for _ in range(9)]  # noqa: E741\n\n    continue_game = True\n    while continue_game:\n        l[0][0] = 2\n        l[4][1] = 2\n        l[8][2] = 2\n        z: float = 26\n        z1: float = 8\n        z2 = 2\n        running_correct = 0\n\n        for _round in range(1, 4):\n            valid_numbers = False\n            numbers = []\n            while not valid_numbers:\n                print()\n                numbers = read_10_numbers()\n                valid_numbers = True\n                for number in numbers:\n                    if number < 0 or number > 2:\n                        print(\"ONLY USE THE DIGITS '0', '1', OR '2'.\")\n                        print(\"LET'S TRY AGAIN.\")\n                        valid_numbers = False\n                        break\n\n            print(\n                \"\\n%-14s%-14s%-14s%-14s\"\n                % (\"MY GUESS\", \"YOUR NO.\", \"RESULT\", \"NO. RIGHT\")\n            )\n\n            for number in numbers:\n                s = 0\n                my_guess = 0\n                for j in range(0, 3):\n                    # What did the original author have in mind ?\n                    # The first expression always results in 0 because a is always 0\n                    s1 = a * k[z2][j] + b * l[int(z1)][j] + c * m[int(z)][j]\n                    if s < s1:\n                        s = s1\n                        my_guess = j\n                    elif s1 == s and random.random() >= 0.5:\n                        my_guess = j\n\n                result = \"\"\n\n                if my_guess != number:\n                    result = \"WRONG\"\n                else:\n                    running_correct += 1\n                    result = \"RIGHT\"\n                    m[int(z)][number] = m[int(z)][number] + 1\n                    l[int(z1)][number] = l[int(z1)][number] + 1\n                    k[int(z2)][number] = k[int(z2)][number] + 1\n                    z = z - (z / 9) * 9\n                    z = 3 * z + number\n                print(\n                    \"\\n%-14d%-14d%-14s%-14d\"\n                    % (my_guess, number, result, running_correct)\n                )\n\n                z1 = z - (z / 9) * 9\n                z2 = number\n\n        print_summary_report(running_correct)\n        continue_game = read_continue_choice()\n\n    print(\"\\nTHANKS FOR THE GAME.\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "34_Digits/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "34_Digits/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "34_Digits/vbnet/Digits.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Digits\", \"Digits.vbproj\", \"{837EB2E4-3EE6-447A-8AF7-91CA08841B93}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "34_Digits/vbnet/Digits.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Digits</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "34_Digits/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "35_Even_Wins/README.md",
    "content": "### Even Wins\n\nThis is a game between you and the computer. To play, an odd number of objects (marbles, chips, matches) are placed in a row. You take turns with the computer picking up between one and four objects each turn. The game ends when there are no objects left, and the winner is the one with an even number of objects picked up.\n\nTwo versions of this game are included. While to the player they appear similar, the programming approach is quite different. EVEN WINS, the first version, is deterministic — i.e., the computer plays by fixed, good rules and is impossible to beat if you don’t know how to play the game. It always starts with 27 objects, although you may change this.\n\nThe second version, GAME OF EVEN WINS, is much more interesting because the computer starts out only knowing the rules of the game. Using simple techniques of artificial intelligence (cybernetics), the computer gradually learns to play this game from its mistakes until it plays a very good game. After 20 games, the computer is a challenge to beat. Variation in the human’s style of play seems to make the computer learn more quickly. If you plot the learning curve of this program, it closely resembles classical human learning curves from psychological experiments.\n\nEric Peters at DEC wrote the GAME OF EVEN WINS. The original author of EVEN WINS is unknown.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=60)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=75)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "35_Even_Wins/csharp/EvenWins.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "35_Even_Wins/csharp/EvenWins.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"EvenWins\", \"EvenWins.csproj\", \"{84209510-4089-4147-B220-E41E534A228B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{84209510-4089-4147-B220-E41E534A228B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{84209510-4089-4147-B220-E41E534A228B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{84209510-4089-4147-B220-E41E534A228B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{84209510-4089-4147-B220-E41E534A228B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "35_Even_Wins/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "35_Even_Wins/evenwins.bas",
    "content": "1 PRINT TAB(31);\"EVEN WINS\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT\n4 Y1=0\n10 M1=0\n20 DIM M(20),Y(20)\n30 PRINT \"     THIS IS A TWO PERSON GAME CALLED 'EVEN WINS.'\"\n40 PRINT \"TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR\"\n50 PRINT \"OTHER OBJECTS ON A TABLE.\"\n60 PRINT\n70 PRINT\n80 PRINT \"     THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER\"\n90 PRINT \"REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE.  THE GAME\"\n100 PRINT \"ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER\"\n110 PRINT \"IS THE ONE WITH AN EVEN NUMBER OF MARBLES.\"\n120 PRINT\n130 PRINT\n140 PRINT \"     THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS,\"\n150 PRINT \"(2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN,\"\n160 PRINT \"AND (3) YOU CANNOT SKIP A TURN.\"\n170 PRINT\n180 PRINT\n190 PRINT\n200 PRINT \"     TYPE A '1' IF YOU WANT TO GO FIRST, AND TYPE\"\n210 PRINT \"A '0' IF YOU WANT ME TO GO FIRST.\"\n220 INPUT C\n225 PRINT\n230 IF C=0 THEN 250\n240 GOTO 1060\n250 T=27\n260 M=2\n270 PRINT:PRINT \"TOTAL=\";T:PRINT\n280 M1=M1+M\n290 T=T-M\n300 PRINT \"I PICK UP\";M;\"MARBLES.\"\n310 IF T=0 THEN 880\n320 PRINT:PRINT \"TOTAL=\";T\n330 PRINT\n340 PRINT \"     AND WHAT IS YOUR NEXT MOVE, MY TOTAL IS\";M1\n350 INPUT Y\n360 PRINT\n370 IF Y<1 THEN 1160\n380 IF Y>4 THEN 1160\n390 IF Y<=T THEN 430\n400 PRINT \"     YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE\"\n410 PRINT \"LEFT.  TRY AGAIN.\"\n420 GOTO 350\n430 Y1=Y1+Y\n440 T=T-Y\n450 IF T=0 THEN 880\n460 PRINT \"TOTAL=\";T\n470 PRINT\n480 PRINT \"YOUR TOTAL IS\";Y1\n490 IF T<.5 THEN 880\n500 R=T-6*INT(T/6)\n510 IF INT(Y1/2)=Y1/2 THEN 700\n520 IF T<4.2 THEN 580\n530 IF R>3.4 THEN 620\n540 M=R+1\n550 M1=M1+M\n560 T=T-M\n570 GOTO 300\n580 M=T\n590 T=T-M\n600 GOTO 830\n610 REM     250 IS WHERE I WIN.\n620 IF R<4.7 THEN 660\n630 IF R>3.5 THEN 660\n640 M=1\n650 GOTO 670\n660 M=4\n670 T=T-M\n680 M1=M1+M\n690 GOTO 300\n700 REM     I AM READY TO ENCODE THE STRAT FOR WHEN OPP TOT IS EVEN\n710 IF R<1.5 THEN 1020\n720 IF R>5.3 THEN 1020\n730 M=R-1\n740 M1=M1+M\n750 T=T-M\n760 IF T<.2 THEN 790\n770 REM     IS # ZERO HERE\n780 GOTO 300\n790 REM     IS = ZERO HERE\n800 PRINT \"I PICK UP\";M;\"MARBLES.\"\n810 PRINT\n820 GOTO 880\n830 REM    THIS IS WHERE I WIN\n840 PRINT \"I PICK UP\";M;\"MARBLES.\"\n850 PRINT\n860 PRINT \"TOTAL = 0\"\n870 M1=M1+M\n880 PRINT \"THAT IS ALL OF THE MARBLES.\"\n890 PRINT\n900 PRINT \" MY TOTAL IS\";M1;\", YOUR TOTAL IS\";Y1\n910 PRINT\n920 IF INT(M1/2)=M1/2 THEN 950\n930 PRINT \"     YOU WON.  DO YOU WANT TO PLAY\"\n940 GOTO 960\n950 PRINT \"     I WON.  DO YOU WANT TO PLAY\"\n960 PRINT \"AGAIN?  TYPE 1 FOR YES AND 0 FOR NO.\"\n970 INPUT A1\n980 IF A1=0 THEN 1030\n990 M1=0\n1000 Y1=0\n1010 GOTO 200\n1020 GOTO 640\n1030 PRINT\n1040 PRINT \"OK.  SEE YOU LATER.\"\n1050 GOTO 1230\n1060 T=27\n1070 PRINT\n1080 PRINT\n1090 PRINT\n1100 PRINT \"TOTAL=\";T\n1110 PRINT\n1120 PRINT\n1130 PRINT \"WHAT IS YOUR FIRST MOVE\";\n1140 INPUT Y\n1150 GOTO 360\n1160 PRINT\n1170 PRINT \"THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE\"\n1180 PRINT \"INTEGER BETWEEN 1 AND 4.\"\n1190 PRINT\n1200 PRINT \"     WHAT IS YOUR NEXT MOVE?\"\n1210 PRINT\n1220 GOTO 350\n1230 END\n"
  },
  {
    "path": "35_Even_Wins/gameofevenwins.bas",
    "content": "1 PRINT TAB(28);\"GAME OF EVEN WINS\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT\n4 INPUT \"DO YOU WANT INSTRUCTIONS (YES OR NO)\";A$:PRINT\n5 IF A$=\"NO\" THEN 20\n6 PRINT \"THE GAME IS PLAYED AS FOLLOWS:\":PRINT\n7 PRINT \"AT THE BEGINNING OF THE GAME, A RANDOM NUMBER OF CHIPS ARE\"\n8 PRINT \"PLACED ON THE BOARD.  THE NUMBER OF CHIPS ALWAYS STARTS\"\n9 PRINT \"AS AN ODD NUMBER.  ON EACH TURN, A PLAYER MUST TAKE ONE,\"\n10 PRINT \"TWO, THREE, OR FOUR CHIPS.  THE WINNER IS THE PLAYER WHO\"\n11 PRINT \"FINISHES WITH A TOTAL NUMBER OF CHIPS THAT IS EVEN.\"\n12 PRINT \"THE COMPUTER STARTS OUT KNOWING ONLY THE RULES OF THE\"\n13 PRINT \"GAME.  IT GRADUALLY LEARNS TO PLAY WELL.  IT SHOULD BE\"\n14 PRINT \"DIFFICULT TO BEAT THE COMPUTER AFTER TWENTY GAMES IN A ROW.\"\n15 PRINT \"TRY IT!!!!\": PRINT\n16 PRINT \"TO QUIT AT ANY TIME, TYPE A '0' AS YOUR MOVE.\": PRINT\n20 DIM R(1,5)\n25 L=0: B=0\n30 FOR I=0 TO 5\n40 R(1,I)=4\n50 R(0,I)=4\n60 NEXT I\n70 A=0: B=0\n90 P=INT((13*RND(1)+9)/2)*2+1\n100 IF P=1 THEN 530\n110 PRINT \"THERE ARE\";P;\"CHIPS ON THE BOARD.\"\n120 E1=E\n130 L1=L\n140 E=(A/2-INT(A/2))*2\n150 L=INT((P/6-INT(P/6))*6+.5)\n160 IF R(E,L)>=P THEN 320\n170 M=R(E,L)\n180 IF M<=0 THEN 370\n190 P=P-M\n200 IF M=1 THEN 510\n210 PRINT \"COMPUTER TAKES\";M;\"CHIPS LEAVING\";P;\"... YOUR MOVE\";\n220 B=B+M\n230 INPUT M\n240 M=INT(M)\n250 IF M<1 THEN 450\n260 IF M>4 THEN 460\n270 IF M>P THEN 460\n280 IF M=P THEN 360\n290 P=P-M\n300 A=A+M\n310 GOTO 100\n320 IF P=1 THEN 550\n330 PRINT \"COMPUTER TAKES\";P;\"CHIPS.\"\n340 R(E,L)=P\n350 B=B+P\n360 IF B/2=INT(B/2) THEN 420\n370 PRINT \"GAME OVER ... YOU WIN!!!\": PRINT\n390 IF R(E,L)=1 THEN 480\n400 R(E,L)=R(E,L)-1\n410 GOTO 70\n420 PRINT \"GAME OVER ... I WIN!!!\": PRINT\n430 GOTO 70\n450 IF M=0 THEN 570\n460 PRINT M;\"IS AN ILLEGAL MOVE ... YOUR MOVE\";\n470 GOTO 230\n480 IF R(E1,L1)=1 THEN 70\n490 R(E1,L1)=R(E1,L1)-1\n500 GOTO 70\n510 PRINT \"COMPUTER TAKES 1 CHIP LEAVING\";P;\"... YOUR MOVE\";\n520 GOTO 220\n530 PRINT \"THERE IS 1 CHIP ON THE BOARD.\"\n540 GOTO 120\n550 PRINT \"COMPUTER TAKES 1 CHIP.\"\n560 GOTO 340\n570 END\n"
  },
  {
    "path": "35_Even_Wins/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "35_Even_Wins/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "35_Even_Wins/javascript/evenwins.html",
    "content": "<html>\n<head>\n<title>EVEN WINS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"evenwins.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "35_Even_Wins/javascript/evenwins.js",
    "content": "// EVEN WINS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar ma = [];\nvar ya = [];\n\n// Main program\nasync function main()\n{\n    print(tab(31) + \"EVEN WINS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    y1 = 0;\n    m1 = 0;\n    print(\"     THIS IS A TWO PERSON GAME CALLED 'EVEN WINS.'\\n\");\n    print(\"TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR\\n\");\n    print(\"OTHER OBJECTS ON A TABLE.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"     THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER\\n\");\n    print(\"REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE.  THE GAME\\n\");\n    print(\"ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER\\n\");\n    print(\"IS THE ONE WITH AN EVEN NUMBER OF MARBLES.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"     THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS,\\n\");\n    print(\"(2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN,\\n\");\n    print(\"AND (3) YOU CANNOT SKIP A TURN.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"     TYPE A '1' IF YOU WANT TO GO FIRST, AND TYPE\\n\");\n        print(\"A '0' IF YOU WANT ME TO GO FIRST.\\n\");\n        c = parseInt(await input());\n        print(\"\\n\");\n        if (c != 0) {\n            t = 27;\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"TOTAL= \" + t + \"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"WHAT IS YOUR FIRST MOVE\");\n            m = 0;\n        } else {\n            t = 27;\n            m = 2;\n            print(\"\\n\");\n            print(\"TOTAL= \" + t + \"\\n\");\n            print(\"\\n\");\n            m1 += m;\n            t -= m;\n        }\n        while (1) {\n            if (m) {\n                print(\"I PICK UP \" + m + \" MARBLES.\\n\");\n                if (t == 0)\n                    break;\n                print(\"\\n\");\n                print(\"TOTAL= \" + t + \"\\n\");\n                print(\"\\n\");\n                print(\"     AND WHAT IS YOUR NEXT MOVE, MY TOTAL IS \" + m1 + \"\\n\");\n            }\n            while (1) {\n                y = parseInt(await input());\n                print(\"\\n\");\n                if (y < 1 || y > 4) {\n                    print(\"\\n\");\n                    print(\"THE NUMBER OF MARBLES YOU MUST TAKE BE A POSITIVE\\n\");\n                    print(\"INTEGER BETWEEN 1 AND 4.\\n\");\n                    print(\"\\n\");\n                    print(\"     WHAT IS YOUR NEXT MOVE?\\n\");\n                    print(\"\\n\");\n                } else if (y > t) {\n                    print(\"     YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE\\n\");\n                    print(\"LEFT.  TRY AGAIN.\\n\");\n                } else {\n                    break;\n                }\n            }\n\n            y1 += y;\n            t -= y;\n            if (t == 0)\n                break;\n            print(\"TOTAL= \" + t + \"\\n\");\n            print(\"\\n\");\n            print(\"YOUR TOTAL IS \" + y1 + \"\\n\");\n            if (t < 0.5)\n                break;\n            r = t % 6;\n            if (y1 % 2 != 0) {\n                if (t >= 4.2) {\n                    if (r <= 3.4) {\n                        m = r + 1;\n                        m1 += m;\n                        t -= m;\n                    } else if (r < 4.7 || r > 3.5) {\n                        m = 4;\n                        m1 += m;\n                        t -= m;\n                    } else {\n                        m = 1;\n                        m1 += m;\n                        t -= m;\n                    }\n                } else {\n                    m = t;\n                    t -= m;\n                    print(\"I PICK UP \" + m + \" MARBLES.\\n\");\n                    print(\"\\n\");\n                    print(\"TOTAL = 0\\n\");\n                    m1 += m;\n                    break;\n                }\n            } else {\n                if (r < 1.5 || r > 5.3) {\n                    m = 1;\n                    m1 += m;\n                    t -= m;\n                } else {\n                    m = r - 1;\n                    m1 += m;\n                    t -= m;\n                    if (t < 0.2) {\n                        print(\"I PICK UP \" + m + \" MARBLES.\\n\");\n                        print(\"\\n\");\n                        break;\n                    }\n                }\n            }\n        }\n        print(\"THAT IS ALL OF THE MARBLES.\\n\");\n        print(\"\\n\");\n        print(\" MY TOTAL IS \" + m1 + \", YOUR TOTAL IS \" + y1 +\"\\n\");\n        print(\"\\n\");\n        if (m1 % 2 != 0) {\n            print(\"     YOU WON.  DO YOU WANT TO PLAY\\n\");\n        } else {\n            print(\"     I WON.  DO YOU WANT TO PLAY\\n\");\n        }\n        print(\"AGAIN?  TYPE 1 FOR YES AND 0 FOR NO.\\n\");\n        a1 = parseInt(await input());\n        if (a1 == 0)\n            break;\n        m1 = 0;\n        y1 = 0;\n    }\n    print(\"\\n\");\n    print(\"OK.  SEE YOU LATER\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "35_Even_Wins/javascript/gameofevenwins.html",
    "content": "<html>\n<head>\n<title>GAME OF EVEN WINS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"gameofevenwins.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "35_Even_Wins/javascript/gameofevenwins.js",
    "content": "// GAME OF EVEN WINS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar r = [[], []];\n\n// Main program\nasync function main()\n{\n    print(tab(28) + \"GAME OF EVEN WINS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"DO YOU WANT INSTRUCTIONS (YES OR NO)\");\n    str = await input();\n    print(\"\\n\");\n    if (str != \"NO\") {\n        print(\"THE GAME IS PLAYED AS FOLLOWS:\\n\");\n        print(\"\\n\");\n        print(\"AT THE BEGINNING OF THE GAME, A RANDOM NUMBER OF CHIPS ARE\\n\");\n        print(\"PLACED ON THE BOARD.  THE NUMBER OF CHIPS ALWAYS STARTS\\n\");\n        print(\"AS AN ODD NUMBER.  ON EACH TURN, A PLAYER MUST TAKE ONE,\\n\");\n        print(\"TWO, THREE, OR FOUR CHIPS.  THE WINNER IS THE PLAYER WHO\\n\");\n        print(\"FINISHES WITH A TOTAL NUMBER OF CHIPS THAT IS EVEN.\\n\");\n        print(\"THE COMPUTER STARTS OUT KNOWING ONLY THE RULES OF THE\\n\");\n        print(\"GAME.  IT GRADUALLY LEARNS TO PLAY WELL.  IT SHOULD BE\\n\");\n        print(\"DIFFICULT TO BEAT THE COMPUTER AFTER TWENTY GAMES IN A ROW.\\n\");\n        print(\"TRY IT!!!!\\n\");\n        print(\"\\n\");\n        print(\"TO QUIT AT ANY TIME, TYPE A '0' AS YOUR MOVE.\\n\");\n        print(\"\\n\");\n    }\n    l = 0;\n    b = 0;\n    for (i = 0; i <= 5; i++) {\n        r[1][i] = 4;\n        r[0][i] = 4;\n    }\n    while (1) {\n        a = 0;\n        b = 0;\n        e = 0;\n        l = 0;\n        p = Math.floor((13 * Math.random() + 9) / 2) * 2 + 1;\n        while (1) {\n            if (p == 1) {\n                print(\"THERE IS 1 CHIP ON THE BOARD.\\n\");\n            } else {\n                print(\"THERE ARE \" + p + \" CHIPS ON THE BOARD.\\n\");\n            }\n            e1 = e;\n            l1 = l;\n            e = a % 2;\n            l = p % 6;\n            if (r[e][l] < p) {\n                m = r[e][l];\n                if (m <= 0) {\n                    m = 1;\n                    b = 1;\n                    break;\n                }\n                p -= m;\n                if (m == 1)\n                    print(\"COMPUTER TAKES 1 CHIP LEAVING \" + p + \"... YOUR MOVE\");\n                else\n                    print(\"COMPUTER TAKES \" + m + \" CHIPS LEAVING \" + p + \"... YOUR MOVE\");\n                b += m;\n                while (1) {\n                    m = parseInt(await input());\n                    if (m == 0)\n                        break;\n                    if (m < 1 || m > 4 || m > p) {\n                        print(m + \" IS AN ILLEGAL MOVE ... YOUR MOVE\");\n                    } else {\n                        break;\n                    }\n                }\n                if (m == 0)\n                    break;\n                if (m == p)\n                    break;\n                p -= m;\n                a += m;\n            } else {\n                if (p == 1) {\n                    print(\"COMPUTER TAKES 1 CHIP.\\n\");\n                } else {\n                    print(\"COMPUTER TAKES \" + p + \" CHIPS.\\n\");\n                }\n                r[e][l] = p;\n                b += p;\n                break;\n            }\n        }\n        if (m == 0)\n            break;\n        if (b % 2 != 0) {\n            print(\"GAME OVER ... YOU WIN!!!\\n\");\n            print(\"\\n\");\n            if (r[e][l] != 1) {\n                r[e][l]--;\n            } else if (r[e1][l1] != 1) {\n                r[e1][l1]--;\n            }\n        } else {\n            print(\"GAME OVER ... I WIN!!!\\n\");\n            print(\"\\n\");\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "35_Even_Wins/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "35_Even_Wins/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "35_Even_Wins/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "35_Even_Wins/perl/evenwins.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\n&main;\n\nsub main {\n\t&print_intro;\n\t&game_play;\n}\n\nsub game_play {\n\tmy $marbles = 27;\n\tmy $turn = 0;\n\tmy $player_total = 0;\n\tmy $computer_total = 0;\n\tprint \"TYPE A '1' IF YOU WANT TO GO FIRST AND TYPE A '0' IF YOU WANT ME TO GO FIRST\\n\";\n\tmy $choice = <STDIN>;\n\tchomp($choice);\n\tif ($choice == 0) {\n\t\tuntil ($marbles == 0) {\n\n\t\t\tmy $computer_choice = &computer_select($marbles,$turn,$player_total);\n\t\t\t$marbles = $marbles - $computer_choice;\n\t\t\t$computer_total = $computer_total + $computer_choice;\n\t\t\tprint \"MY TOTAL IS $computer_total\\n\";\n\n\t\t\tprint \"TOTAL= $marbles\\n\";\n\n\t\t\tif ($marbles == 0) {&determine_winner($computer_total,$player_total)};\n\n\t\t\tmy $player_choice = &player_select($marbles,$turn);\n\t\t\t$marbles = $marbles - $player_choice;\n\t\t\t$player_total = $player_total + $player_choice;\n\t\t\tprint \"YOUR TOTAL IS $player_total\\n\";\n\t\t\t$turn++;\n\t\t\tprint \"TOTAL= $marbles\\n\";\n\t\t\tif ($marbles == 0) {&determine_winner($computer_total,$player_total)};\n\t\t}\n\t}\n\telsif ($choice == 1) {\n\t\tuntil ($marbles == 0) {\n\n\t\t\tmy $player_choice = &player_select($marbles,$turn);\n\t\t\t$marbles = $marbles - $player_choice;\n\t\t\t$player_total = $player_total + $player_choice;\n\t\t\t$turn++;\n\t\t\tprint \"YOUR TOTAL IS $player_total\\n\";\n\n\t\t\tprint \"TOTAL= $marbles\\n\";\n\n\t\t\tif ($marbles == 0) {&determine_winner($computer_total,$player_total)};\n\n\t\t\tmy $computer_choice = &computer_select($marbles,$turn,$player_total);\n\t\t\t$marbles = $marbles - $computer_choice;\n\t\t\t$computer_total = $computer_total + $computer_choice;\n\t\t\tprint \"MY TOTAL IS $computer_total\\n\";\n\n\t\t\tprint \"TOTAL= $marbles\\n\";\n\n\t\t\tif ($marbles == 0) {&determine_winner($computer_total,$player_total)};\n\n\t\t}\n\t}\n}\n\nsub determine_winner {\n\tmy $computer = shift;\n\tmy $player = shift;\n\tprint \"THAT IS ALL OF THE MARBLES.\\n\\n\";\n\tprint \"MY TOTAL IS $computer, YOUR TOTAL IS $player\\n\";\n\tif ($player % 2 == 0) {\n\t\tprint \"     YOU WON.\\n\";\n\t}\n\tif ($computer % 2 == 0) {\n\t\tprint \"     I WON.\\n\";\n\t}\n\tmy $answer = -1;\n\tuntil ($answer == 1 || $answer == 0) {\n\t\tprint \"DO YOU WANT TO PLAY AGAIN? TYPE 1 FOR YES AND 0 FOR NO.\\n\";\n\t\t$answer=<STDIN>;\n\t\tchomp($answer);\n\t}\n\tif ($answer == 1) {\n\t\t&game_play;\n\t}\n\telse {\n\t\tprint \"OK. SEE YOU LATER.\\n\";\n\t\texit;\n\t}\n}\n\nsub player_select {\n\tmy $marbles = shift;\n\tmy $turn = shift;\n\tmy $validity=\"invalid\";\n\tif ($turn == 0) {\n\t\tprint \"WHAT IS YOUR FIRST MOVE\\n\";\n\t}\n\telse {\n\t\tprint \"WHAT IS YOUR NEXT MOVE\\n\";\n\t}\n\tuntil ($validity eq \"valid\") {\n\t\tmy $num = <STDIN>;\n\t\tchomp($num);\n\t\tmy $validity=&validity_check($marbles,$num);\n\t\tif ($validity eq \"valid\") {\n\t\t\treturn $num;\n\t\t}\n\t}\n}\n\nsub computer_select {\n\tmy $marbles = shift;\n\tmy $turn = shift;\n\tmy $player_total = shift;\n\tmy $num = 2;\n\tmy $validity = \"invalid\";\n\tif ($turn == 0) {\n\t\tprint \"I PICK UP $num MARBLES.\\n\\n\";\n\t}\n\telse {\n\t\tuntil ($validity eq \"valid\") {\n\t\t\tmy $R=$marbles-6*int(($marbles/6));\n\n\t\t\tif (int($player_total/2) == $player_total/2) {\n\t\t\t\tif ($R < 1.5 || $R > 5.3) {\n\t\t\t\t\t$num = 1;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t$num = $R - 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\telsif ($marbles < 4.2) {\n\t\t\t\t$num = $marbles;\n\t\t\t}\n\t\t\telsif ($R > 3.4) {\n\t\t\t\tif ($R < 4.7 || $R > 3.5) {\n\t\t\t\t\t$num = 4;\n\t\t\t\t}\n\t\t\telse {\n\t\t\t\t\t$num = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$validity=&validity_check($marbles,$num);\n\t\t}\n\t\tprint \"\\nI PICK UP $num MARBLES.\\n\\n\";\n\t}\n\treturn $num;\n}\n\nsub validity_check {\n\tmy $marbles = shift;\n\tmy $num = shift;\n\tif ($num > $marbles) {\n\t\tprint \"YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE LEFT. TRY AGAIN. THERE ARE $marbles MARBLES LEFT\\n\";\n\t\treturn \"invalid\";\n\t}\n\tif ($num > 0 && $num <= 4) {\n\t\treturn \"valid\";\n\t}\n\tif ($num < 1 || $num > 4) {\n\t\tprint \"THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE INTEGER BETWEEN 1 AND 4\\nWHAT IS YOUR NEXT MOVE?\\n\";\n\t\treturn \"invalid\";\n\t}\n\telse {\n\t\treturn \"invalid\";\n\t}\n}\n\nsub print_intro {\n\tprint ' ' x 31 . \"EVEN WINS\\n\";\n\tprint ' ' x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\tprint \"THIS IS A 2 PERSON GAME CALLED 'EVEN WINS'. TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR OTHER OBJECTS ON THE TABLE\\n\\n\";\n\tprint \"THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE. THE GAME ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER IS THE ONE WITH AN EVEN NUMBER OF MARBLES\\n\";\n\tprint \"THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS, (2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN, AND (3) YOU CANNOT SKIP A TURN.\\n\\n\";\n}\n"
  },
  {
    "path": "35_Even_Wins/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "35_Even_Wins/python/evenwins.py",
    "content": "\"\"\"\r\nThis version of evenwins.bas based on game decscription and does *not*\r\nfollow the source. The computer chooses marbles at random.\r\n\r\nFor simplicity, global variables are used to store the game state.\r\nA good exercise would be to replace this with a class.\r\nThe code is not short, but hopefully it is easy for beginners to understand\r\nand modify.\r\n\r\nInfinite loops of the style \"while True:\" are used to simplify some of the\r\ncode. The \"continue\" keyword is used in a few places to jump back to the top\r\nof the loop. The \"return\" keyword is also used to break out of functions.\r\nThis is generally considered poor style, but in this case it simplifies the\r\ncode and makes it easier to read (at least in my opinion). A good exercise\r\nwould be to remove these infinite loops, and uses of continue, to follow a\r\nmore structured style.\r\n\"\"\"\r\n\r\n\r\nfrom dataclasses import dataclass\r\nfrom typing import Literal, Tuple\r\n\r\nPlayerType = Literal[\"human\", \"computer\"]\r\n\r\n\r\n@dataclass\r\nclass MarbleCounts:\r\n    middle: int\r\n    human: int\r\n    computer: int\r\n\r\n\r\ndef print_intro() -> None:\r\n    print(\"Welcome to Even Wins!\")\r\n    print(\"Based on evenwins.bas from Creative Computing\")\r\n    print()\r\n    print(\"Even Wins is a two-person game. You start with\")\r\n    print(\"27 marbles in the middle of the table.\")\r\n    print()\r\n    print(\"Players alternate taking marbles from the middle.\")\r\n    print(\"A player can take 1 to 4 marbles on their turn, and\")\r\n    print(\"turns cannot be skipped. The game ends when there are\")\r\n    print(\"no marbles left, and the winner is the one with an even\")\r\n    print(\"number of marbles.\")\r\n    print()\r\n\r\n\r\ndef marbles_str(n: int) -> str:\r\n    return \"1 marble\" if n == 1 else f\"{n} marbles\"\r\n\r\n\r\ndef choose_first_player() -> PlayerType:\r\n    while True:\r\n        ans = input(\"Do you want to play first? (y/n) --> \")\r\n        if ans == \"y\":\r\n            return \"human\"\r\n        elif ans == \"n\":\r\n            return \"computer\"\r\n        else:\r\n            print()\r\n            print('Please enter \"y\" if you want to play first,')\r\n            print('or \"n\" if you want to play second.')\r\n            print()\r\n\r\n\r\ndef toggle_player(whose_turn: PlayerType) -> PlayerType:\r\n    return \"computer\" if whose_turn == \"human\" else \"human\"\r\n\r\n\r\ndef to_int(s: str) -> Tuple[bool, int]:\r\n    \"\"\"Convert a string s to an int, if possible.\"\"\"\r\n    try:\r\n        n = int(s)\r\n        return True, n\r\n    except Exception:\r\n        return False, 0\r\n\r\n\r\ndef print_board(marbles: MarbleCounts) -> None:\r\n    print()\r\n    print(f\" marbles in the middle: {marbles.middle} \" + marbles.middle * \"*\")\r\n    print(f\"    # marbles you have: {marbles.human}\")\r\n    print(f\"# marbles computer has: {marbles.computer}\")\r\n    print()\r\n\r\n\r\ndef human_turn(marbles: MarbleCounts) -> None:\r\n    \"\"\"get number in range 1 to min(4, marbles.middle)\"\"\"\r\n    max_choice = min(4, marbles.middle)\r\n    print(\"It's your turn!\")\r\n    while True:\r\n        s = input(f\"Marbles to take? (1 - {max_choice}) --> \")\r\n        ok, n = to_int(s)\r\n        if not ok:\r\n            print(f\"\\n  Please enter a whole number from 1 to {max_choice}\\n\")\r\n            continue\r\n        if n < 1:\r\n            print(\"\\n  You must take at least 1 marble!\\n\")\r\n            continue\r\n        if n > max_choice:\r\n            print(f\"\\n  You can take at most {marbles_str(max_choice)}\\n\")\r\n            continue\r\n        print(f\"\\nOkay, taking {marbles_str(n)} ...\")\r\n        marbles.middle -= n\r\n        marbles.human += n\r\n        return\r\n\r\n\r\ndef game_over(marbles: MarbleCounts) -> None:\r\n    print()\r\n    print(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\")\r\n    print(\"!! All the marbles are taken: Game Over!\")\r\n    print(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\")\r\n    print()\r\n    print_board(marbles)\r\n    if marbles.human % 2 == 0:\r\n        print(\"You are the winner! Congratulations!\")\r\n    else:\r\n        print(\"The computer wins: all hail mighty silicon!\")\r\n    print()\r\n\r\n\r\ndef computer_turn(marbles: MarbleCounts) -> None:\r\n    marbles_to_take = 0\r\n\r\n    print(\"It's the computer's turn ...\")\r\n    r = marbles.middle - 6 * int(marbles.middle / 6)\r\n\r\n    if int(marbles.human / 2) == marbles.human / 2:\r\n        marbles_to_take = 1 if r < 1.5 or r > 5.3 else r - 1\r\n    elif marbles.middle < 4.2:\r\n        marbles_to_take = marbles.middle\r\n    elif r > 3.4:\r\n        if r < 4.7 or r > 3.5:\r\n            marbles_to_take = 4\r\n    else:\r\n        marbles_to_take = r + 1\r\n\r\n    print(f\"Computer takes {marbles_str(marbles_to_take)} ...\")\r\n    marbles.middle -= marbles_to_take\r\n    marbles.computer += marbles_to_take\r\n\r\n\r\ndef play_game(whose_turn: PlayerType) -> None:\r\n    marbles = MarbleCounts(middle=27, human=0, computer=0)\r\n    print_board(marbles)\r\n\r\n    while True:\r\n        if marbles.middle == 0:\r\n            game_over(marbles)\r\n            return\r\n        elif whose_turn == \"human\":\r\n            human_turn(marbles)\r\n            print_board(marbles)\r\n            whose_turn = toggle_player(whose_turn)\r\n        elif whose_turn == \"computer\":\r\n            computer_turn(marbles)\r\n            print_board(marbles)\r\n            whose_turn = toggle_player(whose_turn)\r\n        else:\r\n            raise Exception(f\"whose_turn={whose_turn} is not 'human' or 'computer'\")\r\n\r\n\r\ndef main() -> None:\r\n    print_intro()\r\n\r\n    while True:\r\n        whose_turn = choose_first_player()\r\n        play_game(whose_turn)\r\n\r\n        print()\r\n        again = input(\"Would you like to play again? (y/n) --> \").lower()\r\n        if again == \"y\":\r\n            print(\"\\nOk, let's play again ...\\n\")\r\n        else:\r\n            print(\"\\nOk, thanks for playing ... goodbye!\\n\")\r\n            return\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n"
  },
  {
    "path": "35_Even_Wins/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "35_Even_Wins/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "35_Even_Wins/rust/src/main.rs",
    "content": "use std::io;\n\nfn print_intro() {\n    println!(\n        \"Welcome to Even Wins!\nBased on evenwins.bas from Creative Computing\n\nEven Wins is a two-person game. You start with\n27 marbles in the middle of the table.\n\nPlayers alternate taking marbles from the middle.\nA player can take 1 to 4 marbles on their turn, and\nturns cannot be skipped. The game ends when there are\nno marbles left, and the winner is the one with an even\nnumber of marbles.\n\"\n    );\n}\n\n#[derive(Debug)]\nenum PlayerType {\n    Human,\n    Computer,\n}\n\n#[derive(Debug)]\nstruct Game {\n    turn: PlayerType,\n    middle: u32,\n    human: u32,\n    computer: u32,\n    min_take: u32,\n    max_take: u32,\n}\n\nimpl Game {\n    fn get_max_take(&mut self) -> u32 {\n        if self.max_take > self.middle {\n            return self.middle;\n        }\n        return self.max_take;\n    }\n\n    fn take(&mut self, num: u32) -> bool {\n        let max_take = self.get_max_take();\n        if num > max_take {\n            println!(\"You can take at most {} marbles\", max_take);\n            return false;\n        }\n        if num < self.min_take {\n            println!(\"You must take at least {} marble!\", self.min_take);\n            return false;\n        }\n\n        self.middle -= num;\n        match self.turn {\n            PlayerType::Computer => self.computer += num,\n            PlayerType::Human => self.human += num,\n        }\n        return true;\n    }\n\n    fn next(&mut self) {\n        self.turn = match self.turn {\n            PlayerType::Computer => PlayerType::Human,\n            PlayerType::Human => PlayerType::Computer,\n        }\n    }\n\n    fn info(&mut self) {\n        println!(\"\");\n        println!(\n            \"marbles in the middle: {} **************************\",\n            self.middle\n        );\n        println!(\"# marbles you have: {}\", self.human);\n        println!(\"# marbles computer has: {}\", self.computer);\n        println!(\"\");\n    }\n\n    fn wininfo(&mut self) {\n        if self.middle != 0 {\n            return;\n        }\n        println!(\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n!! All the marbles are taken: Game Over!\\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\");\n        self.info();\n\n        if self.human % 2 == 0 {\n            println!(\"You are the winner! Congratulations!\");\n        } else {\n            println!(\"The computer wins: all hail mighty silicon!\");\n        }\n\n        println!(\"\");\n    }\n}\n\nfn human_play(game: &mut Game) {\n    println!(\"It's your turn!\");\n    loop {\n        let max_take = game.get_max_take();\n        println!(\"Marbles to take? ({} - {}) --> \", game.min_take, max_take);\n\n        let mut num = String::new();\n        io::stdin()\n            .read_line(&mut num)\n            .expect(\"Failed to read line\");\n\n        let _: u32 = match num.trim().to_uppercase().parse() {\n            Ok(num) => {\n                if game.take(num) {\n                    println!(\"Okay, taking {} marble ...\", num);\n                    break;\n                };\n                println!(\"\");\n                continue;\n            }\n            _ => {\n                println!(\"Please enter a whole number from 1 to 4\");\n                println!(\"\");\n                continue;\n            }\n        };\n    }\n}\n\nfn compute_play(game: &mut Game) {\n    println!(\"It's the computer's turn ...\");\n\n    let marbles_to_take: u32;\n\n    // the magic 6 and 1.5, 5.3 3.4 4.7 3.5 was copy from python implement\n    let r: f32 = (game.middle % 6) as f32;\n    if game.human % 2 == 0 {\n        if r < 1.5 || r > 5.3 {\n            marbles_to_take = 1;\n        } else {\n            marbles_to_take = (r - 1.0) as u32;\n        }\n    } else if game.middle <= 4 {\n        marbles_to_take = game.middle\n    } else if r > 3.4 {\n        if r < 4.7 || r > 3.5 {\n            marbles_to_take = 4;\n        } else {\n            marbles_to_take = 1;\n        }\n    } else {\n        marbles_to_take = (r + 1.0) as u32;\n    }\n\n    game.take(marbles_to_take);\n    println!(\"Computer takes {} marble ...\", marbles_to_take);\n}\n\nfn run_game(turn: PlayerType) {\n    let mut game = Game {\n        turn: turn,\n        middle: 27,\n        computer: 0,\n        human: 0,\n        min_take: 1,\n        max_take: 4,\n    };\n\n    while game.middle > 0 {\n        match game.turn {\n            PlayerType::Computer => {\n                compute_play(&mut game);\n            }\n            PlayerType::Human => {\n                human_play(&mut game);\n            }\n        }\n        game.info();\n        game.next();\n    }\n    game.wininfo();\n}\n\nfn choose_first_player() -> PlayerType {\n    loop {\n        println!(\"Do you want to play first? (y/n) -->\");\n\n        let mut flag = String::new();\n        io::stdin()\n            .read_line(&mut flag)\n            .expect(\"Failed to read line\");\n\n        match flag.trim().to_uppercase().as_str() {\n            \"Y\" => return PlayerType::Human,\n            \"N\" => return PlayerType::Computer,\n            _ => {\n                println!(\"Please enter \\\"y\\\" if you want to play first,\\nor \\\"n\\\" if you want to play second.\\n\");\n            }\n        };\n    }\n}\n\nfn choose_play_again() -> bool {\n    println!(\"Would you like to play again? (y/n) --> \");\n    let mut flag = String::new();\n    io::stdin()\n        .read_line(&mut flag)\n        .expect(\"Failed to read line\");\n\n    match flag.trim().to_uppercase().as_str() {\n        \"Y\" => {\n            println!(\"\\nOk, let's play again ...\\n\");\n            return true;\n        }\n        _ => {\n            println!(\"\\nOk, thanks for playing ... goodbye!\\n\");\n            return false;\n        }\n    }\n}\n\nfn main() {\n    print_intro();\n    loop {\n        let first = choose_first_player();\n        run_game(first);\n\n        if !choose_play_again() {\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "35_Even_Wins/vbnet/EvenWins.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"EvenWins\", \"EvenWins.vbproj\", \"{16D44A7A-9C05-4845-8289-3A65A4D978D0}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "35_Even_Wins/vbnet/EvenWins.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>EvenWins</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "35_Even_Wins/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "36_Flip_Flop/README.md",
    "content": "### Flip Flop\n\nThe object of this game is to change a row of ten X’s\n\n```\nX X X X X X X X X X\n```\n\nto a row of ten 0’s\n\n```\n0 0 0 0 0 0 0 0 0 0\n```\n\nby typing in a number corresponding to the position of an “X” in the line. On some numbers one position will change while on other numbers, two will change. For example, inputting a 3 may reverse the X and 0 in position 3, but it might possibly reverse some of other position too! You ought to be able to change all 10 in 12 or fewer moves. Can you figure out a good winning strategy?\n\nTo reset the line to all X’s (same game), type 0 (zero). To start a new game at any point, type 11.\n\nThe original author of this game was Micheal Kass of New Hyde Park, New York.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=63)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=78)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "36_Flip_Flop/csharp/FlipFlop.cs",
    "content": "﻿// Flip Flop Game\n\nPrintGameInfo();\n\nbool startNewGame = true;\n\nstring[] board = new string[] { \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\" };\n\ndo\n{\n    int stepsCount = 0;\n    int lastMove = -1;\n    int moveIndex;\n    int gameSum;\n    double gameEntropyRate = Rnd();\n    bool toPlay = false;\n    bool setNewBoard = true;\n\n    Print();\n    Print(\"HERE IS THE STARTING LINE OF X'S.\");\n    Print();\n\n    do\n    {\n        bool illegalEntry;\n        bool equalToLastMove;\n\n        if (setNewBoard)\n        {\n            PrintNewBoard();\n            board = new string[] { \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\" };\n            setNewBoard = false;\n            toPlay = true;\n        }\n\n        stepsCount++;\n        gameSum = 0;\n\n        // Read User's move\n        do\n        {\n            Write(\"INPUT THE NUMBER? \");\n            var input = Console.ReadLine();\n            illegalEntry = !int.TryParse(input, out moveIndex);\n\n            if (illegalEntry || moveIndex > 11)\n            {\n                illegalEntry = true;\n                Print(\"ILLEGAL ENTRY--TRY AGAIN.\");\n            }\n        }\n        while (illegalEntry);\n\n        if (moveIndex == 11)\n        {\n            // Run new game, To start a new game at any point\n            toPlay = false;\n            stepsCount = 12;\n            startNewGame = true;\n        }\n\n\n        if (moveIndex == 0)\n        {\n            // To reset the line to all X, same game\n            setNewBoard = true;\n            toPlay = false;\n        }\n\n        if (toPlay)\n        {\n            board[moveIndex - 1] = board[moveIndex - 1] == \"O\" ? \"X\" : \"O\";\n\n            if (lastMove == moveIndex)\n            {\n                equalToLastMove = true;\n            }\n            else\n            {\n                equalToLastMove = false;\n                lastMove = moveIndex;\n            }\n\n            do\n            {\n                moveIndex = equalToLastMove\n                    ? GetMoveIndexWhenEqualeLastMove(moveIndex, gameEntropyRate)\n                    : GetMoveIndex(moveIndex, gameEntropyRate);\n\n                board[moveIndex] = board[moveIndex] == \"O\" ? \"X\" : \"O\";\n            }\n            while (lastMove == moveIndex && board[moveIndex] == \"X\");\n\n            PrintGameBoard(board);\n\n            foreach (var item in board)\n            {\n                if (item == \"O\")\n                {\n                    gameSum++;\n                }\n            }\n        }\n    }\n    while (stepsCount < 12 && gameSum < 10);\n\n    if (toPlay)\n    {\n        PrintGameResult(gameSum, stepsCount);\n\n        Write(\"DO YOU WANT TO TRY ANOTHER PUZZLE \");\n\n        var toContinue = Console.ReadLine();\n\n        if (!string.IsNullOrEmpty(toContinue) && toContinue?.ToUpper()[0] == 'N')\n        {\n            startNewGame = false;\n        }\n\n        Print();\n    }\n}\nwhile (startNewGame);\n\nvoid Print(string str = \"\") => Console.WriteLine(str);\n\nvoid Write(string value) => Console.Write(value);\n\nstring Tab(int pos) => new(' ', pos);\n\ndouble Rnd() => new Random().NextDouble();\n\nint GetMoveIndex(int moveIndex, double gameEntropyRate)\n{\n    double rate = Math.Tan(gameEntropyRate + moveIndex / gameEntropyRate - moveIndex) - Math.Sin(gameEntropyRate / moveIndex) + 336 * Math.Sin(8 * moveIndex);\n    return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate))));\n}\n\nint GetMoveIndexWhenEqualeLastMove(int moveIndex, double gameEntropyRate)\n{\n    double rate = 0.592 * (1 / Math.Tan(gameEntropyRate / moveIndex + gameEntropyRate)) / Math.Sin(moveIndex * 2 + gameEntropyRate) - Math.Cos(moveIndex);\n    return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate))));\n}\n\nvoid PrintNewBoard()\n{\n    Print(\"1 2 3 4 5 6 7 8 9 10\");\n    Print(\"X X X X X X X X X X\");\n    Print();\n}\n\nvoid PrintGameBoard(string[] board)\n{\n    Print(\"1 2 3 4 5 6 7 8 9 10\");\n\n    foreach (var item in board)\n    {\n        Write($\"{item} \");\n    }\n\n    Print();\n    Print();\n}\n\nvoid PrintGameResult(int gameSum, int stepsCount)\n{\n    if (gameSum == 10)\n    {\n        Print($\"VERY GOOD.  YOU GUESSED IT IN ONLY {stepsCount} GUESSES.\");\n    }\n    else\n    {\n        Print($\"TRY HARDER NEXT TIME.  IT TOOK YOU {stepsCount} GUESSES.\");\n    }\n}\n\nvoid PrintGameInfo()\n{\n    Print(Tab(32) + \"FLIPFLOP\");\n    Print(Tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    Print();\n    Print(\"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\");\n    Print();\n\n    Print(\"X X X X X X X X X X\");\n    Print();\n    Print(\"TO THIS:\");\n    Print();\n    Print(\"O O O O O O O O O O\");\n    Print();\n\n    Print(\"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\");\n    Print(\"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\");\n    Print(\"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\");\n    Print(\"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \");\n    Print(\"11 (ELEVEN).\");\n}\n"
  },
  {
    "path": "36_Flip_Flop/csharp/FlipFlop.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "36_Flip_Flop/csharp/FlipFlop.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"FlipFlop\", \"FlipFlop.csproj\", \"{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {108E5099-D7AA-4260-B587-1B1FE1AF6B54}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "36_Flip_Flop/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "36_Flip_Flop/flipflop.bas",
    "content": "2 PRINT TAB(32);\"FLIPFLOP\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT\n10 REM *** CREATED BY MICHAEL CASS\n15 DIM A$(20)\n20 PRINT \"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\"\n30 PRINT\n40 PRINT \"X X X X X X X X X X\"\n50 PRINT\n60 PRINT \"TO THIS:\"\n70 PRINT\n80 PRINT \"O O O O O O O O O O\"\n90 PRINT\n100 PRINT \"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\"\n110 PRINT \"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\"\n120 PRINT \"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\"\n130 PRINT \"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \"\n140 PRINT \"11 (ELEVEN).\"\n170 PRINT\n180 REM\n190 Q=RND(1)\n200 PRINT \"HERE IS THE STARTING LINE OF X'S.\"\n210 PRINT\n220 C=0\n230 PRINT \"1 2 3 4 5 6 7 8 9 10\"\n240 PRINT \"X X X X X X X X X X\"\n250 PRINT\n260 REM\n270 FOR X=1 TO 10\n280 A$(X)=\"X\"\n290 NEXT X\n300 GOTO 320\n310 PRINT \"ILLEGAL ENTRY--TRY AGAIN.\"\n320 PRINT \"INPUT THE NUMBER\";\n330 INPUT N\n340 IF N<>INT(N) THEN 310\n350 IF N=11 THEN 180\n360 IF N>11 THEN 310\n370 IF N=0 THEN 230\n380 IF M=N THEN 510\n390 M=N\n400 IF A$(N)=\"O\" THEN 480\n410 A$(N)=\"O\"\n420 R=TAN(Q+N/Q-N)-SIN(Q/N)+336*SIN(8*N)\n430 N=R-INT(R)\n440 N=INT(10*N)\n450 IF A$(N)=\"O\" THEN 480\n460 A$(N)=\"O\"\n470 GOTO 610\n480 A$(N)=\"X\"\n490 IF M=N THEN 420\n500 GOTO 610\n510 IF A$(N)=\"O\" THEN 590\n520 A$(N)=\"O\"\n530 R=.592*(1/TAN(Q/N+Q))/SIN(N*2+Q)-COS(N)\n540 N=R-INT(R)\n550 N=INT(10*N)\n560 IF A$(N)=\"O\" THEN 590\n570 A$(N)=\"O\"\n580 GOTO 610\n590 A$(N)=\"X\"\n600 IF M=N THEN 530\n610 PRINT \"1 2 3 4 5 6 7 8 9 10\"\n620 FOR Z=1 TO 10: PRINT A$(Z);\" \";: NEXT Z\n630 C=C+1\n640 PRINT\n650 FOR Z=1 TO 10\n660 IF A$(Z)<>\"O\" THEN 320\n670 NEXT Z\n680 IF C>12 THEN 710\n690 PRINT \"VERY GOOD.  YOU GUESSED IT IN ONLY\";C;\"GUESSES.\"\n700 GOTO 720\n710 PRINT \"TRY HARDER NEXT TIME.  IT TOOK YOU\";C;\"GUESSES.\"\n720 PRINT \"DO YOU WANT TO TRY ANOTHER PUZZLE\";\n730 INPUT X$\n740 IF LEFT$(X$,1)=\"N\" THEN 780\n760 PRINT\n770 GOTO 180\n780 END\n"
  },
  {
    "path": "36_Flip_Flop/java/FlipFlop.java",
    "content": "import java.util.Scanner;\nimport java.lang.Math;\n\n/**\n * Game of FlipFlop\n * <p>\n * Based on the BASIC game of FlipFlop here\n * https://github.com/coding-horror/basic-computer-games/blob/main/36%20Flip%20Flop/flipflop.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class FlipFlop {\n\n  private final Scanner scan;  // For user input\n\n  private enum Step {\n    RANDOMIZE, INIT_BOARD, GET_NUMBER, ILLEGAL_ENTRY, FLIP_POSITION, SET_X_FIRST, SET_X_SECOND,\n    GENERATE_R_FIRST, GENERATE_R_SECOND, PRINT_BOARD, QUERY_RETRY\n  }\n\n  public FlipFlop() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor FlipFlop\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(31) + \"FLIPFLOP\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    double mathVal = 0;\n    double randVal = 0;\n    double tmpVal = 0;\n\n    int index = 0;\n    int match = 0;\n    int numFlip = 0;\n    int numGuesses = 0;\n\n    Step nextStep = Step.RANDOMIZE;\n\n    String userResponse = \"\";\n\n    String[] board = new String[21];\n\n    System.out.println(\"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\");\n    System.out.println(\"\");\n    System.out.println(\"X X X X X X X X X X\");\n    System.out.println(\"\");\n    System.out.println(\"TO THIS:\");\n    System.out.println(\"\");\n    System.out.println(\"O O O O O O O O O O\");\n    System.out.println(\"\");\n    System.out.println(\"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\");\n    System.out.println(\"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\");\n    System.out.println(\"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\");\n    System.out.println(\"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \");\n    System.out.println(\"11 (ELEVEN).\");\n    System.out.println(\"\");\n\n    // Begin outer while loop\n    while (true) {\n\n      // Begin switch\n      switch (nextStep) {\n\n        case RANDOMIZE:\n\n          randVal = Math.random();\n\n          System.out.println(\"HERE IS THE STARTING LINE OF X'S.\");\n          System.out.println(\"\");\n\n          numGuesses = 0;\n          nextStep = Step.INIT_BOARD;\n          break;\n\n        case INIT_BOARD:\n\n          System.out.println(\"1 2 3 4 5 6 7 8 9 10\");\n          System.out.println(\"X X X X X X X X X X\");\n          System.out.println(\"\");\n\n          // Avoid out of bounds error by starting at zero\n          for (index = 0; index <= 10; index++) {\n            board[index] = \"X\";\n          }\n\n          nextStep = Step.GET_NUMBER;\n          break;\n\n        case GET_NUMBER:\n\n          System.out.print(\"INPUT THE NUMBER? \");\n          userResponse = scan.nextLine();\n\n          try {\n            numFlip = Integer.parseInt(userResponse);\n          }\n          catch (NumberFormatException ex) {\n            nextStep = Step.ILLEGAL_ENTRY;\n            break;\n          }\n\n          // Command to start a new game\n          if (numFlip == 11) {\n            nextStep = Step.RANDOMIZE;\n            break;\n          }\n\n          if (numFlip > 11) {\n            nextStep = Step.ILLEGAL_ENTRY;\n            break;\n          }\n\n          // Command to reset the board\n          if (numFlip == 0) {\n            nextStep = Step.INIT_BOARD;\n            break;\n          }\n\n          if (match == numFlip) {\n            nextStep = Step.FLIP_POSITION;\n            break;\n          }\n\n          match = numFlip;\n\n          if (board[numFlip].equals(\"O\")) {\n            nextStep = Step.SET_X_FIRST;\n            break;\n          }\n\n          board[numFlip] = \"O\";\n          nextStep = Step.GENERATE_R_FIRST;\n          break;\n\n        case ILLEGAL_ENTRY:\n          System.out.println(\"ILLEGAL ENTRY--TRY AGAIN.\");\n          nextStep = Step.GET_NUMBER;\n          break;\n\n        case GENERATE_R_FIRST:\n\n          mathVal = Math.tan(randVal + numFlip / randVal - numFlip) - Math.sin(randVal / numFlip) + 336\n                    * Math.sin(8 * numFlip);\n\n          tmpVal = mathVal - (int)Math.floor(mathVal);\n\n          numFlip = (int)(10 * tmpVal);\n\n          if (board[numFlip].equals(\"O\")) {\n            nextStep = Step.SET_X_FIRST;\n            break;\n          }\n\n          board[numFlip] = \"O\";\n          nextStep = Step.PRINT_BOARD;\n          break;\n\n        case SET_X_FIRST:\n          board[numFlip] = \"X\";\n\n          if (match == numFlip) {\n            nextStep = Step.GENERATE_R_FIRST;\n          } else {\n            nextStep = Step.PRINT_BOARD;\n          }\n          break;\n\n        case FLIP_POSITION:\n\n          if (board[numFlip].equals(\"O\")) {\n            nextStep = Step.SET_X_SECOND;\n            break;\n          }\n\n          board[numFlip] = \"O\";\n          nextStep = Step.GENERATE_R_SECOND;\n          break;\n\n        case GENERATE_R_SECOND:\n\n          mathVal = 0.592 * (1 / Math.tan(randVal / numFlip + randVal)) / Math.sin(numFlip * 2 + randVal)\n                    - Math.cos(numFlip);\n\n          tmpVal = mathVal - (int)mathVal;\n          numFlip = (int)(10 * tmpVal);\n\n          if (board[numFlip].equals(\"O\")) {\n            nextStep = Step.SET_X_SECOND;\n            break;\n          }\n\n          board[numFlip] = \"O\";\n          nextStep = Step.PRINT_BOARD;\n          break;\n\n        case SET_X_SECOND:\n\n          board[numFlip] = \"X\";\n          if (match == numFlip) {\n            nextStep = Step.GENERATE_R_SECOND;\n            break;\n          }\n\n          nextStep = Step.PRINT_BOARD;\n          break;\n\n        case PRINT_BOARD:\n          System.out.println(\"1 2 3 4 5 6 7 8 9 10\");\n\n          for (index = 1; index <= 10; index++) {\n            System.out.print(board[index] + \" \");\n          }\n\n          numGuesses++;\n\n          System.out.println(\"\");\n\n          for (index = 1; index <= 10; index++) {\n            if (!board[index].equals(\"O\")) {\n              nextStep = Step.GET_NUMBER;\n              break;\n            }\n          }\n\n          if (nextStep == Step.GET_NUMBER) {\n            break;\n          }\n\n          if (numGuesses > 12) {\n            System.out.println(\"TRY HARDER NEXT TIME.  IT TOOK YOU \" + numGuesses + \" GUESSES.\");\n          } else {\n            System.out.println(\"VERY GOOD.  YOU GUESSED IT IN ONLY \" + numGuesses + \" GUESSES.\");\n          }\n          nextStep = Step.QUERY_RETRY;\n          break;\n\n        case QUERY_RETRY:\n\n          System.out.print(\"DO YOU WANT TO TRY ANOTHER PUZZLE? \");\n          userResponse = scan.nextLine();\n\n          if (userResponse.toUpperCase().charAt(0) == 'N') {\n            return;\n          }\n          System.out.println(\"\");\n          nextStep = Step.RANDOMIZE;\n          break;\n\n        default:\n          System.out.println(\"INVALID STEP\");\n          nextStep = Step.QUERY_RETRY;\n          break;\n\n      }  // End of switch\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    FlipFlop game = new FlipFlop();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class FlipFlop\n"
  },
  {
    "path": "36_Flip_Flop/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "36_Flip_Flop/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "36_Flip_Flop/javascript/flipflop.html",
    "content": "<html>\n<head>\n<title>FLIPFLOP</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"flipflop.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "36_Flip_Flop/javascript/flipflop.js",
    "content": "// FLIPFLOP\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar as = [];\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"FLIPFLOP\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    // *** Created by Michael Cass\n    print(\"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\\n\");\n    print(\"\\n\");\n    print(\"X X X X X X X X X X\\n\");\n    print(\"\\n\");\n    print(\"TO THIS:\\n\");\n    print(\"\\n\");\n    print(\"O O O O O O O O O O\\n\");\n    print(\"\\n\");\n    print(\"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\\n\");\n    print(\"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\\n\");\n    print(\"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\\n\");\n    print(\"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \\n\");\n    print(\"11 (ELEVEN).\\n\");\n    print(\"\\n\");\n    while (1) {\n        start = 1;\n        do {\n            z = 1;\n            if (start == 1) {\n                m = 0;\n                q = Math.random();\n                print(\"HERE IS THE STARTING LINE OF X'S.\\n\");\n                print(\"\\n\");\n                c = 0;\n                start = 2;\n            }\n            if (start == 2) {\n                print(\"1 2 3 4 5 6 7 8 9 10\\n\");\n                print(\"X X X X X X X X X X\\n\");\n                print(\"\\n\");\n                for (x = 1; x <= 10; x++)\n                    as[x] = \"X\";\n                start = 0;\n            }\n            print(\"INPUT THE NUMBER\");\n            while (1) {\n                n = parseInt(await input());\n                if (n >= 0 && n <= 11)\n                    break;\n                print(\"ILLEGAL ENTRY--TRY AGAIN.\\n\");\n            }\n            if (n == 11) {\n                start = 1;\n                continue;\n            }\n            if (n == 0) {\n                start = 2;\n                continue;\n            }\n            if (m != n) {\n                m = n;\n                as[n] = (as[n] == \"O\" ? \"X\" : \"O\");\n                do {\n                    r = Math.tan(q + n / q - n) - Math.sin(q / n) + 336 * Math.sin(8 * n);\n                    n = r - Math.floor(r);\n                    n = Math.floor(10 * n);\n                    as[n] = (as[n] == \"O\" ? \"X\" : \"O\");\n                } while (m == n) ;\n            } else {\n                as[n] = (as[n] == \"O\" ? \"X\" : \"O\");\n                do {\n                    r = 0.592 * (1 / Math.tan(q / n + q)) / Math.sin(n * 2 + q) - Math.cos(n);\n                    n = r - Math.floor(r);\n                    n = Math.floor(10 * n);\n                    as[n] = (as[n] == \"O\" ? \"X\" : \"O\");\n                } while (m == n) ;\n            }\n            print(\"1 2 3 4 5 6 7 8 9 10\\n\");\n            for (z = 1; z <= 10; z++)\n                print(as[z] + \" \");\n            c++;\n            print(\"\\n\");\n            for (z = 1; z <= 10; z++) {\n                if (as[z] != \"O\")\n                    break;\n            }\n        } while (z <= 10) ;\n        if (c <= 12) {\n            print(\"VERY GOOD.  YOU GUESSED IT IN ONLY \" + c + \" GUESSES.\\n\");\n        } else {\n            print(\"TRY HARDER NEXT TIME.  IT TOOK YOU \" + c + \" GUESSES.\\n\");\n        }\n        print(\"DO YOU WANT TO TRY ANOTHER PUZZLE\");\n        str = await input();\n        if (str.substr(0, 1) == \"N\")\n            break;\n    }\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "36_Flip_Flop/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "36_Flip_Flop/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "36_Flip_Flop/lua/flipflop-game.lua",
    "content": "--[[\nGame of FlipFlop\n===============\n\nBased on the original BASIC game of FlipFlop from the 1970s.\n\nThis is a faithful recreation of the classic game, maintaining the original gameplay\nwhile modernizing the implementation for Lua. For example, the original's complex\ntrigonometric random number generation has been replaced with Lua's math.random,\nas modern random number generators are more sophisticated than those available\nin 1970s BASIC.\n\nHow to Play:\n-----------\nThe game presents a row of 10 X's. Your goal is to flip all X's to O's.\nEnter a number from 1-10 to flip that position. The computer will also make\nrandom moves in response. Special commands:\n- Enter 0 to see the current board again\n- Enter 11 to quit the game\nTry to complete the puzzle in 12 moves or fewer for the best score!\n\nStrategy Tips:\n------------\n- When you make a move, watch how the computer responds. It will often\n  make a predictable counter-move.\n- If you enter the same position twice, the computer will use a different\n  random pattern for its response.\n- Try to work systematically from one end of the board to the other,\n  rather than making random moves.\n- If you get stuck, sometimes starting over (11) is better than continuing\n  with a poor position.\n\nTechnical Notes:\n--------------\n- Written for Lua 5.1 compatibility\n- Uses tables for game state management\n- Implements original game logic without goto statements\n- Preserves the original game's move counting and win conditions\n- Maintains the classic text-based interface style\n\nOriginal BASIC Version:\n--------------------\nThe original game used complex trigonometric functions for random number\ngeneration, likely due to limitations in BASIC's random number capabilities:\n    R=TAN(Q+N/Q-N)-SIN(Q/N)+336*SIN(8*N)\n    N=R-INT(R)\n    N=INT(10*N)\n\nThis has been simplified to use Lua's built-in random number generator\nwhile maintaining the same gameplay experience.\n\nConverted from BASIC to Lua by Brian Wilkins\nMarch 2025\n]]--\n\nlocal function showInstructions()\n    print(\"                    FLIP FLOP\")\n    print(\"              CREATIVE COMPUTING\")\n    print(\"            MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n    print(\"THE OBJECT OF THIS GAME IS TO FLIP ALL THE X'S TO O'S.\")\n    print(\"WHEN YOU INPUT A NUMBER, THAT NUMBER AND ALL ADJACENT\")\n    print(\"NUMBERS WILL BE FLIPPED.\")\n    print(\"\\n\")\n    print(\"INPUT A NUMBER FROM 1 TO 10 TO START THE GAME. TO QUIT\")\n    print(\"THE GAME AT ANY TIME, TYPE A 0 (ZERO). TO START OVER WITH\")\n    print(\"A NEW PUZZLE IN THE MIDDLE OF A GAME, TYPE A 11 (ELEVEN).\")\n    print(\"\\n\\n\")\nend\n\nlocal function printUpdatedBoard(board)\n    print(\"1 2 3 4 5 6 7 8 9 10\")\n    print(table.concat(board, \" \"))\n    print(\"\\n\\n\")\nend\n\nlocal function processMove(gameState, position)\n    -- Check if current position is O\n    if gameState.board[position] == \"O\" then\n        gameState.board[position] = \"X\"\n        if position == gameState[\"lastMove\"] then\n            -- Generate random position using simplified random logic\n            local R = math.random()  -- between 0 and 1\n            local N = math.floor(R * 10) + 1\n            if gameState.board[N] == \"O\" then\n                gameState.board[N] = \"X\"\n            else\n                gameState.board[N] = \"O\"\n            end\n        end\n    else\n        gameState.board[position] = \"O\"\n        -- Generate another random position\n        local R = math.random()\n        local N = math.floor(R * 10) + 1\n        if gameState.board[N] == \"O\" then\n            gameState.board[N] = \"X\"\n        else\n            gameState.board[N] = \"O\"\n        end\n    end\nend\n\nlocal function checkWin(gameState)\n    -- Check if all positions are O's\n    for i = 1, 10 do\n        if gameState.board[i] ~= \"O\" then\n            return false\n        end\n    end\n    return true\nend\n\nlocal function initializeGame()\n    local gameState = {\n        board = {},\n        lastMove = nil,\n        moves = 0\n    }\n    \n    -- Initialize board\n    for i = 1, 10 do\n        gameState.board[i] = \"X\"\n    end\n    return gameState\nend\n\nlocal function playGame()\n    showInstructions()\n    \n    local gameState = initializeGame()\n    local playing = true\n    \n    print(\"HERE IS THE STARTING LINE OF X'S.\")\n    print(\"\\n\\n\")\n    printUpdatedBoard(gameState.board)\n    \n    while playing do\n        print(\"INPUT THE NUMBER\")\n        local N = tonumber(io.read())\n        \n        -- Check if input is valid\n        if not N or N ~= math.floor(N) then\n            print(\"ILLEGAL ENTRY--TRY AGAIN.\")\n        elseif N == 11 then\n            playing = false\n        elseif N > 11 then\n            print(\"ILLEGAL ENTRY--TRY AGAIN.\")\n        elseif N == 0 then\n            printUpdatedBoard(gameState.board)\n        else\n            -- Process the move\n            processMove(gameState, N)\n            gameState[\"lastMove\"] = N\n            gameState.moves = gameState.moves + 1\n            \n            -- Show the updated board\n            printUpdatedBoard(gameState.board)\n            \n            -- Check for win\n            if checkWin(gameState) then\n                if gameState.moves <= 12 then\n                    print(string.format(\"VERY GOOD. YOU GUESSED IT IN ONLY %d GUESSES.\", gameState.moves))\n                else\n                    print(string.format(\"TRY HARDER NEXT TIME. IT TOOK YOU %d GUESSES.\", gameState.moves))\n                end\n                \n                print(\"DO YOU WANT TO TRY ANOTHER PUZZLE? (Y/N)\")\n                local answer = io.read():upper()\n                if answer:sub(1,1) == \"Y\" then\n                    gameState = initializeGame()\n                    print(\"HERE IS THE STARTING LINE OF X'S.\")\n                    print(\"\\n\\n\")\n                    printUpdatedBoard(gameState.board)\n                else\n                    playing = false\n                end\n            end\n        end\n    end\nend\n\nplayGame()\n"
  },
  {
    "path": "36_Flip_Flop/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "36_Flip_Flop/perl/flipflop.pl",
    "content": "#!/usr/bin/perl\n\n# Flip Flop program in Perl\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\nuse Math::Trig;\n\nprint \"\\n\";\nprint \" \" x 32, \"FLIPFLOP\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n# *** CREATED BY MICHAEL CASS\n\nprint \"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\\n\\n\";\nprint \"X X X X X X X X X X\\n\\n\";\nprint \"TO THIS:\\n\\n\";\nprint \"O O O O O O O O O O\\n\\n\";\nprint \"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\\n\";\nprint \"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\\n\";\nprint \"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\\n\";\nprint \"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \\n\";\nprint \"11 (ELEVEN).\\n\\n\";\n\nsub initialize\n{\n    my @a;\n    print \"1 2 3 4 5 6 7 8 9 10\\n\";\n    print \"X X X X X X X X X X\\n\";\n    for my $i (0 .. 10) { $a[$i] = \"X\"; } # make sure [0] has a value just in case\n    return @a;\n}\n\nwhile (1)\n{\n    my $Q = rand(1);\n    my $C = 0;\n    print \"HERE IS THE STARTING LINE OF X'S.\\n\\n\";\n    my @A = initialize();\n\n    while (1)\n    {\n        my $M = 0;\n        my $N;\n        while (1)\n        {\n            print \"\\nINPUT THE NUMBER: \";\n            chomp($N = <>);\n            if ($N != int($N) || $N < 0 ||  $N > 11)\n            {\n                print \"ILLEGAL ENTRY--TRY AGAIN.\\n\";\n                next;\n            }\n            last;\n        }\n        if ($N == 11) # start a new game\n        {\n            print \"\\n\\n\";\n            last;\n        }\n        if ($N == 0) # reset line\n        {\n            @A = initialize();\n            next;\n        }\n\n        if ($M != $N)\n        {\n            $M = $N;\n            $A[$N] = ($A[$N] eq \"O\") ? \"X\" : \"O\";\n            while ($M == $N)\n            {\n                my $R = tan($Q + $N / $Q - $N) - sin($Q / $N) + 336 * sin(8 * $N);\n                $N = $R - int($R);\n                $N = int(10 * $N);\n                if ($A[$N] eq \"O\")\n                {\n                    $A[$N] = \"X\";\n                    next;\n                }\n                $A[$N] = \"O\";\n                last; # GOTO 610\n\n                $A[$N] = \"X\";\n            }\n        }\n        else\n        {\n            if ($A[$N] ne \"O\") { $A[$N] = \"O\"; }\n            while ($M == $N)\n            {\n                my $R = .592 * (1 / tan($Q / $N + $Q)) / sin( $N * 2 + $Q) - cos($N);\n                $N = $R - int($R);\n                $N = int(10 * $N);\n                if ($A[$N] eq \"O\")\n                {\n                    $A[$N] = \"X\";\n                    next;\n                }\n                $A[$N] = \"O\";\n                last;\n            }\n        }\n\n        print \"1 2 3 4 5 6 7 8 9 10\\n\";\n        for my $i (1 .. 10) { print \"$A[$i] \"; }\n        print \"\\n\";\n        $C++;\n        my $i;\n        for ($i=1 ; $i <= 10 ; $i++) {\n            last if ($A[$i] ne \"O\");\n        }\n        if ($i == 11)\n        {\n            if ($C <= 12) { print \"VERY GOOD.  YOU GUESSED IT IN ONLY $C GUESSES.\\n\"; }\n            else          { print \"TRY HARDER NEXT TIME.  IT TOOK YOU $C GUESSES.\\n\"; }\n            last;\n        }\n    }\n    print \"DO YOU WANT TO TRY ANOTHER PUZZLE (Y/N): \";\n    $_ = <>;\n    print \"\\n\";\n    last if (m/^n/i);\n}\n"
  },
  {
    "path": "36_Flip_Flop/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "36_Flip_Flop/python/flipflop.py",
    "content": "# Flip Flop\n#\n# The object of this game is to change a row of ten X's\n# X X X X X X X X X X\n# to a row of ten O's:\n# O O O O O O O O O O\n# by typing in a number corresponding\n# to the position of an \"X\" in the line. On\n# some numbers one position will\n# change while on other numbers, two\n# will change. For example, inputting a 3\n# may reverse the X and O in position 3,\n# but it might possibly reverse some\n# other position too! You ought to be able\n# to change all 10 in 12 or fewer\n# moves. Can you figure out a good win-\n# ning strategy?\n# To reset the line to all X's (same\n# game), type 0 (zero). To start a new\n# game at any point, type 11.\n# The original author of this game was\n# Michael Kass of New Hyde Park, New\n# York.\nimport math\nimport random\nfrom typing import Callable, List, Tuple\n\nflip_dict = {\"X\": \"O\", \"O\": \"X\"}\n\n\ndef flip_bits(\n    row: List[str], m: int, n: int, r_function: Callable[[int], float]\n) -> Tuple[List[str], int]:\n    \"\"\"\n    Function that flips the positions at the computed steps\n    \"\"\"\n    while m == n:\n        r = r_function(n)\n        n_tmp = r - int(math.floor(r))\n        n = int(10 * n_tmp)\n        if row[n] == \"X\":\n            row[n] = \"O\"\n            break\n        elif row[n] == \"O\":\n            row[n] = \"X\"\n    return row, n\n\n\ndef print_instructions() -> None:\n    print(\" \" * 32 + \"FLIPFLOP\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\" * 2)\n    print(\"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\\n\")\n    print(\"X X X X X X X X X X\\n\")\n    print(\"TO THIS:\\n\")\n    print(\"O O O O O O O O O O\\n\")\n    print(\"BY TYPING TH NUMBER CORRESPONDING TO THE POSITION OF THE\")\n    print(\"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\")\n    print(\"OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0\")\n    print(\"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \")\n    print(\"11 (ELEVEN).\\n\")\n\n\ndef main() -> None:\n    q = random.random()\n\n    print(\"HERE IS THE STARTING LINE OF X'S.\\n\")\n    # We add an extra 0-th item because this sometimes is set to something\n    # but we never check what it is for completion of the puzzle\n    row = [\"\"] + [\"X\"] * 10\n    counter_turns = 0\n    n = -1\n    legal_move = True\n    while row[1:] != [\"O\"] * 10:\n        if legal_move:\n            print(\" \".join([str(i) for i in range(1, 11)]))\n            print(\" \".join(row[1:]) + \"\\n\")\n        m_str = input(\"INPUT THE NUMBER\\n\")\n        try:\n            m = int(m_str)\n            if m > 11 or m < 0:\n                raise ValueError()\n        except ValueError:\n            print(\"ILLEGAL ENTRY--TRY AGAIN\")\n            legal_move = False\n            continue\n        legal_move = True\n        if m == 11:\n            # completely reset the puzzle\n            counter_turns = 0\n            row = [\"\"] + [\"X\"] * 10\n            q = random.random()\n            continue\n        elif m == 0:\n            # reset the board, but not the counter or the random number\n            row = [\"\"] + [\"X\"] * 10\n        elif m == n:\n            row[n] = flip_dict[row[n]]\n            r_function = lambda n_t: 0.592 * (1 / math.tan(q / n_t + q)) / math.sin(\n                n_t * 2 + q\n            ) - math.cos(n_t)\n            row, n = flip_bits(row, m, n, r_function)\n        else:\n            n = m\n            row[n] = flip_dict[row[n]]\n            r_function = lambda n_t: (\n                math.tan(q + n_t / q - n_t)\n                - math.sin(n_t * 2 + q)\n                + 336 * math.sin(8 * n_t)\n            )\n            row, n = flip_bits(row, m, n, r_function)\n\n        counter_turns += 1\n        print()\n\n    if counter_turns <= 12:\n        print(f\"VERY GOOD. YOU GUESSED IT IN ONLY {counter_turns} GUESSES.\")\n    else:\n        print(f\"TRY HARDER NEXT TIME. IT TOOK YOU {counter_turns} GUESSES.\")\n    return\n\n\nif __name__ == \"__main__\":\n    print_instructions()\n\n    another = \"\"\n    while another != \"NO\":\n        main()\n        another = input(\"DO YOU WANT TO TRY ANOTHER PUZZLE\\n\")\n"
  },
  {
    "path": "36_Flip_Flop/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "36_Flip_Flop/ruby/flipflop.rb",
    "content": "#A class representing the internal state of a single game of flip flop\n# state represents the list of X's (A in the original code)\n# guesses represents the number of guesses the user has made (C in the original code)\n# seed represents the random seed for an instance of the game (Q in the original code)\nGame = Struct.new(:state, :guesses, :seed) do\n\n  #The original BASIC program used 1 indexed arrays while Ruby has 0-indexed arrays.\n  #We can't use 0 indexed arrays for the flip functions or we'll get divide by zero errors.\n  #These convenience functions allow us to modify and access internal game state in a 1-indexed fashion\n  def flip_letter(letter_number)\n    index = letter_number -1\n    if self.state[index] == 'X'\n      self.state[index] = 'O'\n    else\n      self.state[index] = 'X'\n    end\n  end\n\n  def letter_at(letter_number)\n    self.state[letter_number - 1]\n  end\nend\n\ndef print_welcome\n  puts 'FLIPFLOP'.center(72)\n  puts 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY'.center(72)\n  puts <<~EOS\n\n    THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n\n    X X X X X X X X X X\n\n    TO THIS:\n\n    O O O O O O O O O O\n\n    BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\n    LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\n    OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\n    (ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE\n    11 (ELEVEN).\n  EOS\nend\n\ndef print_starting_message\n  puts <<~EOS\n\n  HERE IS THE STARTING LINE OF X'S.\n\n  1 2 3 4 5 6 7 8 9 10\n  X X X X X X X X X X\n\n  EOS\nend\n\n#Create a new game with [X,X,X,X,X,X,X,X,X,X] as the state\n#0 as the number of guesses and a random seed between 0 and 1\ndef generate_new_game\n  Game.new(Array.new(10, 'X'), 0, rand())\nend\n\n#Given a game, an index, and a shuffle function, flip one or more letters\ndef shuffle_board(game, index, shuffle_function)\n  n = method(shuffle_function).call(game, index)\n\n  if game.letter_at(n) == \"O\"\n    game.flip_letter(n)\n    if index == n\n      n = shuffle_board(game, index, shuffle_function)\n    end\n  else\n    game.flip_letter(n)\n  end\n  return n\nend\n\n#Shuffle logic copied from original BASIC code\ndef shuffle_function1(game, index)\n  r = Math.tan(game.seed + index / game.seed - index) - Math.sin(game.seed / index) + 336 * Math.sin(8 * index)\n  n = r - r.floor\n  (10 * n).floor\nend\n\ndef shuffle_function2(game, index)\n  r = 0.592 * (1/ Math.tan(game.seed / index + game.seed)) / Math.sin(index * 2 + game.seed) - Math.cos(index)\n  n = r - r.floor\n  (10 * n)\nend\n\ndef play_game\n  print_starting_message\n  game = generate_new_game\n  working_index = nil\n\n  loop do\n    puts \"INPUT THE NUMBER\"\n    input = gets.chomp.downcase\n\n    #See if the user input a valid integer, fail otherwise\n    if numeric_input = Integer(input, exception: false)\n\n      #If 11 is entered, we're done with this version of the game\n      if numeric_input == 11\n        return :restart\n      end\n\n      if numeric_input > 11\n        puts 'ILLEGAL ENTRY--TRY AGAIN.'\n        next #illegal entries don't count towards your guesses\n      end\n\n      if working_index == numeric_input\n        game.flip_letter(numeric_input)\n        working_index = shuffle_board(game, numeric_input, :shuffle_function2)\n      #If 0 is entered, we want to reset the state, but not the random seed or number of guesses and keep playing\n      elsif numeric_input == 0\n        game.state = Array.new(10, 'X')\n      elsif game.letter_at(numeric_input) == \"O\"\n        game.flip_letter(numeric_input)\n        if numeric_input == working_index\n          working_index = shuffle_board(game, numeric_input, :shuffle_function1)\n        end\n      else\n        game.flip_letter(numeric_input)\n        working_index = shuffle_board(game, numeric_input, :shuffle_function1)\n      end\n    else\n      puts 'ILLEGAL ENTRY--TRY AGAIN.'\n      next #illegal entries don't count towards your guesses\n    end\n\n    game.guesses += 1\n    puts '1 2 3 4 5 6 7 8 9 10'\n    puts game.state.join(' ')\n\n    if game.state.all? { |x| x == 'O' }\n      if game.guesses > 12\n        puts \"TRY HARDER NEXT TIME. IT TOOK YOU #{game.guesses} GUESSES.\"\n      else\n        puts \"VERY GOOD.  YOU GUESSED IT IN ONLY #{game.guesses} GUESSES.\"\n      end\n      #game is complete\n      return\n    end\n  end\nend\n\n\n\n#Execution starts\nprint_welcome\nloop do\n  result = play_game\n  if result == :restart\n    next\n  end\n\n  puts 'DO YOU WANT TO TRY ANOTHER PUZZLE'\n  if gets.chomp.downcase[0] == 'n'\n    break\n  end\nend\n"
  },
  {
    "path": "36_Flip_Flop/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\nmorristown = \"0.1.3\"\n"
  },
  {
    "path": "36_Flip_Flop/rust/src/game.rs",
    "content": "pub struct Game {\n    board: [char; 10],\n    last_move: u8,\n    entropy: f32,\n    tries: u8,\n}\n\nimpl Game {\n    pub fn new() -> Self {\n        Game {\n            board: ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'],\n            last_move: 0,\n            entropy: 0.,\n            tries: 0,\n        }\n    }\n\n    pub fn play(&mut self) -> bool {\n        self.reset_game();\n\n        println!(\"\\nHERE IS THE STARTING LINE OF X'S.\\n\");\n        println!(\"1 2 3 4 5 6 7 8 9 10\");\n        println!(\"X X X X X X X X X X\\n\");\n\n        let mut reset = false;\n\n        loop {\n            self.tries += 1;\n\n            match Game::get_number() {\n                0 => self.reset_board(),\n                11 => {\n                    reset = true;\n                    break;\n                }\n                n => {\n                    self.flip(n);\n\n                    let other = self.get_other(n, n == self.last_move);\n                    if other != n {\n                        self.flip(other);\n                    }\n\n                    println!(\"other: {}\", other);\n                    self.last_move = n;\n                }\n            }\n            self.draw();\n\n            if !self.board.iter().any(|c| *c == 'X') {\n                break;\n            }\n        }\n\n        if !reset {\n            let t = self.tries;\n\n            if t > 12 {\n                println!(\"TRY HARDER NEXT TIME. IT TOOK YOU {t} GUESSES.\");\n            } else {\n                println!(\"VERY GOOD. IT TOOK YOU ONLY {t} GUESSES.\");\n            }\n\n            return morristown::prompt_bool(\"DO YOU WANT TO TRY ANOTHER PUZZLE?\", false);\n        }\n\n        true\n    }\n\n    fn flip(&mut self, i: u8) {\n        if (1..=10).contains(&i) {\n            let i = (i - 1) as usize;\n            let char = &mut self.board[i];\n\n            match char {\n                'X' => *char = '0',\n                '0' => *char = 'X',\n                _ => println!(\"INVALID BOARD CHARACTER!\"),\n            }\n        }\n    }\n\n    fn get_other(&self, m: u8, equals_last_move: bool) -> u8 {\n        let e = self.entropy;\n        let m = m as f32;\n\n        let rate = if equals_last_move {\n            0.592 * (1. / (e / m + e).tan()) / (m * 2. + e).sin() - m.cos()\n        } else {\n            (e + m / e - m).tan() - (e / m).sin() + 336. * (8. * m).sin()\n        };\n\n        (10. * (rate - rate.floor())).floor() as u8\n    }\n\n    fn draw(&self) {\n        println!(\"1 2 3 4 5 6 7 8 9 10\");\n        for c in self.board {\n            print!(\"{c} \");\n        }\n        println!();\n    }\n\n    fn get_number() -> u8 {\n        loop {\n            let n = morristown::prompt_number::<u8>(\"INPUT THE NUMBER?\");\n            if n > 11 {\n                println!(\"ILLEGAL ENTRY--TRY AGAIN.\");\n            } else {\n                return n;\n            }\n        }\n    }\n\n    fn reset_board(&mut self) {\n        self.board = ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'];\n    }\n\n    fn reset_game(&mut self) {\n        self.reset_board();\n        self.last_move = 0;\n        self.entropy = rand::random();\n        self.tries = 0;\n    }\n}\n"
  },
  {
    "path": "36_Flip_Flop/rust/src/main.rs",
    "content": "mod game;\nuse crate::game::Game;\n\nfn main() {\n    morristown::print_intro(\"FLIPFLOP\");\n\n    println!(\"THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\\n\");\n    println!(\"X X X X X X X X X X\\n\");\n    println!(\"TO THIS:\\n\");\n    println!(\"O O O O O O O O O O\\n\");\n    println!(\"BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\");\n    println!(\"LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\");\n    println!(\"OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\");\n    println!(\"(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \");\n    println!(\"11 (ELEVEN).\");\n\n    let mut game = Game::new();\n\n    loop {\n        if !game.play() {\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "36_Flip_Flop/vbnet/FlipFlop.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"FlipFlop\", \"FlipFlop.vbproj\", \"{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "36_Flip_Flop/vbnet/FlipFlop.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>FlipFlop</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "36_Flip_Flop/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "37_Football/README.md",
    "content": "### Football\n\nFootball is probably the most popular simulated sports game. I have seen some people play to elect to play computerized football in preference to watching a football game on television.\n\nTwo versions of football are presented. The first is somewhat “traditional” in that you, the player, are playing against the computer. You have a choice of seven offensive plays. On defense the computer seems to play a zone defence, but you have no choice of plays. The computer program presents the necessary rules as you play, and it is also the referee and determines penalties when an infraction is committed. FTBALL was written by John Kemeny at Dartmouth.\n\nIN the second version of football, the computer referees a game played between two human players. Each player gets a list of twenty plays with a code value for each one. This list should be kept confidential from your opponent. The codes can be changes in data. All twenty plays are offensive; a defensive play is specified by defending against a type of offensive play. A defense is good for other similar types of plays, for example, a defense against a flare pass is very good against a screen pass but much less good against a half-back option.\n\nThis game was originally written by Raymond Miseyka of Butler, Pennsylvania.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=64)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=79)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "37_Football/csharp/Football.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "37_Football/csharp/Football.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Football\", \"Football.csproj\", \"{092442FA-EA04-4A80-AB12-138E18CD480A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{092442FA-EA04-4A80-AB12-138E18CD480A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{092442FA-EA04-4A80-AB12-138E18CD480A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{092442FA-EA04-4A80-AB12-138E18CD480A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{092442FA-EA04-4A80-AB12-138E18CD480A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "37_Football/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "37_Football/football.bas",
    "content": "1 PRINT TAB(32);\"FOOTBALL\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n100 REM\n120 DIM A(20),B(20),C(40),H(2),T(2),W(2),X(2),Y(2),Z(2)\n130 DIM M$(2),D(2),P$(20)\n140 PRINT \"PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\"\n145 PRINT:PRINT\n150 INPUT \"DO YOU WANT INSTRUCTIONS\";A$\n160 IF A$=\"NO\" THEN 290\n165 IF A$<>\"YES\" THEN 150\n170 PRINT \"THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST\"\n180 PRINT \"PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,\"\n190 PRINT \"1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20\"\n195 PRINT \"THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS.\"\n200 PRINT\"A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH\"\n210 PRINT \"BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE\"\n220 PRINT \"PLAYS THE LESS YARDAGE GAINED.  SCORES ARE GIVEN\"\n223 PRINT \"WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED\"\n225 PRINT \"BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A\"\n227 PRINT \"FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE\"\n230 PRINT \"ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER\"\n240 PRINT \"YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO\"\n250 PRINT \"BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO\"\n260 PRINT \"TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO.\"\n270 PRINT \"THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C).\"\n280 PRINT \"PLEASE PREPARE A TAPE AND RUN.\": STOP\n290 PRINT:PRINT \"PLEASE INPUT SCORE LIMIT ON GAME\";:INPUT E\n300 FOR I=1 TO 40: READ N: IF I>20 THEN 350\n330 A(N)=I: GOTO 360\n350 B(N)=I-20\n360 C(I)=N: NEXT I\n370 FOR I=1 TO 20: READ P$(I): NEXT I\n380 L=0: T=1\n410 PRINT \"TEAM\";T;\"PLAY CHART\"\n420 PRINT \"NO.      PLAY\"\n430 FOR I=1 TO 20\n440 REM\n450 PRINT C(I+L);TAB(6);P$(I)\n460 NEXT I\n630 L=L+20:T=2\n640 PRINT\n650 PRINT \"TEAR OFF HERE----------------------------------------------\"\n660 FOR X=1 TO 11: PRINT: NEXT X\n670 FOR Z=1 TO 3000: NEXT Z\n680 IF L=20 THEN 410\n690 D(1)=0: D(2)=3: M$(1)=\"--->\": M$(2)=\"<---\"\n700 H(1)=0: H(2)=0: T(1)=2: T(2)=1\n710 W(1)=-1: W(2)=1: X(1)=100: X(2)=0\n720 Y(1)=1: Y(2)=-1: Z(1)=0: Z(2)=100\n725 GOSUB 1910\n730 PRINT \"TEAM 1 DEFENDS 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.\"\n740 T=INT(2*RND(1)+1)\n760 PRINT: PRINT \"THE COIN IS FLIPPED\"\n765 P=X(T)-Y(T)*40\n770 GOSUB 1860: PRINT : PRINT \"TEAM\";T;\"RECEIVES KICK-OFF\"\n780 K=INT(26*RND(1)+40)\n790 P=P-Y(T)*K\n794 IF W(T)*P<Z(T)+10 THEN 810\n795 PRINT: PRINT \"BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--\"\n796 GOTO 870\n810 PRINT \"BALL WENT\";K;\"YARDS.  NOW ON\";P:GOSUB 1900\n830 PRINT \"TEAM\";T;\"DO YOU WANT TO RUNBACK\";:INPUT A$\n840 IF A$=\"YES\" THEN 1430\n845 IF A$<>\"NO\" THEN 830\n850 IF W(T)*P<Z(T) THEN 880\n870 P=Z(T)-W(T)*20\n880 D=1: S=P\n885 FOR I=1 TO 72: PRINT \"=\";: NEXT I\n890 PRINT: PRINT \"TEAM\";T;\"DOWN\";D;\"ON\";P\n893 IF D<>1 THEN 900\n895 IF Y(T)*(P+Y(T)*10)>=X(T) THEN 898\n897 C=4: GOTO 900\n898 C=8\n900 IF C=8 THEN 904\n901 PRINT TAB(27);10-(Y(T)*P-Y(T)*S);\"YARDS TO 1ST DOWN\"\n902 GOTO 910\n904 PRINT TAB(27);X(T)-Y(T)*P;\"YARDS\"\n910 GOSUB 1900: IF D=4 THEN 1180\n920 REM\n930 U=INT(3*RND(0)-1): GOTO 940\n936 PRINT \"ILLEGAL PLAY NUMBER, CHECK AND\"\n940 PRINT \"INPUT OFFENSIVE PLAY, DEFENSIVE PLAY\";\n950 IF T=2 THEN 970\n960 INPUT P1,P2: GOTO 975\n970 INPUT P2,P1\n975 IF P1=77 THEN 1180\n980 IF P1>20 THEN 1800\n985 IF P1<1 THEN 1800\n990 IF P2>20 THEN 1800\n992 IF P2<1 THEN 1800\n995 P1=INT(P1): P2=INT(P2)\n1000 Y=INT(ABS(A(P1)-B(P2))/19*((X(T)-Y(T)*P+25)*RND(1)-15))\n1005 PRINT: IF T=2 THEN 1015\n1010 IF A(P1)<11 THEN 1048\n1012 GOTO 1020\n1015 IF B(P2)<11 THEN 1048\n1020 IF U<>0 THEN 1035\n1025 PRINT \"PASS INCOMPLETE TEAM\";T\n1030 Y=0: GOTO 1050\n1035 G=RND(1): IF G>.025 THEN 1040\n1037 IF Y>2 THEN 1045\n1040 PRINT \"QUARTERBACK SCRAMBLED\": GOTO 1050\n1045 PRINT \"PASS COMPLETED\": GOTO 1050\n1048 PRINT \"THE BALL WAS RUN\"\n1050 P=P-W(T)*Y\n1060 PRINT: PRINT \"NET YARDS GAINED ON DOWN\";D;\"ARE \";Y\n1070 G=RND(1): IF G>.025 THEN 1110\n1080 PRINT: PRINT \"** LOSS OF POSSESSION FROM TEAM\";T;\"TO TEAM\";T(T)\n1100 GOSUB 1850: PRINT: T=T(T): GOTO 830\n1110 IF Y(T)*P>=X(T) THEN 1320\n1120 IF W(T)*P>=Z(T) THEN 1230\n1130 IF Y(T)*P-Y(T)*S>=10 THEN 880\n1140 D=D+1: IF D<>5 THEN 885\n1160 PRINT: PRINT \"CONVERSION UNSUCCESSFUL TEAM\";T:T=T(T)\n1170 GOSUB 1850: GOTO 880\n1180 PRINT \"DOES TEAM\";T;\"WANT TO PUNT\";: INPUT A$\n1185 IF A$=\"NO\" THEN 1200\n1187 IF A$<>\"YES\" THEN 1180\n1190 PRINT:PRINT \"TEAM\";T;\"WILL PUNT\": G=RND(1): IF G<.025 THEN 1080\n1195 GOSUB 1850: K=INT(25*RND(1)+35): T=T(T): GOTO 790\n1200 PRINT \"DOES TEAM\";T;\"WANT TO ATTEMPT A FIELD GOAL\";: INPUT A$\n1210 IF A$=\"YES\" THEN 1640\n1215 IF A$<>\"NO\" THEN 1200\n1217 GOTO 920\n1230 PRINT: PRINT \"SAFETY AGAINST TEAM\";T;\"**********************OH-OH\"\n1240 H(T(T))=H(T(T))+2: GOSUB 1810\n1280 PRINT\"TEAM\";T;\"DO YOU WANT TO PUNT INSTEAD OF A KICKOFF\";:INPUT A$\n1290 P=Z(T)-W(T)*20: IF A$=\"YES\" THEN 1190\n1320 PRINT: PRINT \"TOUCHDOWN BY TEAM\";T;\"*********************YEA TEAM\"\n1340 Q=7: G=RND(1): IF G>.1 THEN 1380\n1360 Q=6: PRINT \"EXTRA POINT NO GOOD\": GOTO 1390\n1380 PRINT \"EXTRA POINT GOOD\"\n1390 H(T)=H(T)+Q: GOSUB 1810\n1420 T=T(T): GOTO 765\n1430 K=INT(9*RND(0)+1)\n1440 R=INT(((X(T)-Y(T)*P+25)*RND(1)-15)/K)\n1460 P=P-W(T)*R\n1480 PRINT:PRINT \"RUNBACK TEAM\";T;R;\"YARDS\"\n1485 G=RND(1): IF G<.025 THEN 1080\n1490 IF Y(T)*P>=X(T) THEN 1320\n1500 IF W(T)*P>=Z(T) THEN 1230\n1510 GOTO 880\n1640 PRINT: PRINT \"TEAM\";T;\"WILL ATTEMPT A FIELD GOAL\"\n1645 G=RND(1): IF G<.025 THEN 1080\n1650 F=INT(35*RND(1)+20)\n1660 PRINT: PRINT \"KICK IS\";F;\"YARDS LONG\"\n1680 P=P-W(T)*F: G=RND(1)\n1690 IF G<.35 THEN 1735\n1700 IF Y(T)*P<X(T) THEN 1740\n1710 PRINT \"FIELD GOAL GOOD FOR TEAM\";T;\"*********************YEA\"\n1720 Q=3: GOTO 1390\n1735 PRINT \"BALL WENT WIDE\"\n1740 PRINT \"FIELD GOAL UNSUCCESFUL TEAM\";T;\"-----------------TOO BAD\"\n1742 GOSUB 1850: IF Y(T)*P<X(T)+10 THEN 1745\n1744 T=T(T): GOTO 794\n1745 PRINT: PRINT \"BALL NOW ON\";P\n1750 T=T(T): GOSUB 1900: GOTO 830\n1770 DATA 17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6\n1780 DATA 20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3\n1790 DATA \"PITCHOUT\",\"TRIPLE REVERSE\",\"DRAW\",\"QB SNEAK\",\"END AROUND\"\n1792 DATA \"DOUBLE REVERSE\",\"LEFT SWEEP\",\"RIGHT SWEEP\",\"OFF TACKLE\"\n1794 DATA \"WISHBONE OPTION\",\"FLARE PASS\",\"SCREEN PASS\"\n1796 DATA \"ROLL OUT OPTION\",\"RIGHT CURL\",\"LEFT CURL\",\"WISHBONE OPTION\"\n1798 DATA \"SIDELINE PASS\",\"HALF-BACK OPTION\",\"RAZZLE-DAZZLE\",\"BOMB!!!!\"\n1800 IF P1<>99 THEN 936\n1810 PRINT: PRINT \"TEAM 1 SCORE IS\";H(1)\n1820 PRINT \"TEAM 2 SCORE IS\";H(2): PRINT\n1825 IF H(T)<E THEN 1830\n1827 PRINT \"TEAM\";T;\"WINS*******************\": GOTO 2000\n1830 IF P1=99 THEN 940\n1835 RETURN\n1850 PRINT\n1860 FOR X=1 TO 72: PRINT \"+\";: NEXT X: PRINT\n1870 RETURN\n1900 PRINT TAB(D(T)+5+P/2);M$(T)\n1910 PRINT \"TEAM 1 [0   10   20   30   40   50   60   70   80   90\";\n1915 PRINT \"   100] TEAM 2\"\n1920 PRINT\n1930 RETURN\n2000 END\n"
  },
  {
    "path": "37_Football/ftball.bas",
    "content": "10 PRINT TAB(33);\"FTBALL\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT\n220 PRINT \"THIS IS DARTMOUTH CHAMPIONSHIP FOOTBALL.\":PRINT\n230 PRINT \"YOU WILL QUARTERBACK DARTMOUTH. CALL PLAYS AS FOLLOWS:\"\n240 PRINT \"1= SIMPLE RUN; 2= TRICKY RUN; 3= SHORT PASS;\"\n250 PRINT \"4= LONG PASS; 5= PUNT; 6= QUICK KICK; 7= PLACE KICK.\"\n260 PRINT\n270 PRINT \"CHOOSE YOUR OPPONENT\";\n280 INPUT O$(1)\n290 O$(0)=\"DARTMOUTH\"\n300 PRINT\n310 LET S(0)=0: LET S(1)=0\n320 REM\n330 DIM L$(20)\n340 FOR I=1 TO 20: READ L$(I): NEXT I\n350 DATA \"KICK\",\"RECEIVE\",\" YARD \",\"RUN BACK FOR \",\"BALL ON \"\n360 DATA \"YARD LINE\",\" SIMPLE RUN\",\" TRICKY RUN\",\" SHORT PASS\"\n370 DATA \" LONG PASS\",\"PUNT\",\" QUICK KICK \",\" PLACE KICK\",\" LOSS \"\n380 DATA \" NO GAIN\",\"GAIN \",\" TOUCHDOWN \",\" TOUCHBACK \",\"SAFETY***\"\n385 DATA \"JUNK\"\n390 LET P=INT(RND(1)*2)\n400 PRINT O$(P);\" WON THE TOSS\"\n410 DEF FNF(X)=1-2*P\n420 DEF FNG(Z)=P*(X1-X)+(1-P)*(X-X1)\n430 IF P=0 THEN 470\n440 PRINT O$(1);\" ELECTS TO RECEIVE.\"\n450 PRINT\n460 GOTO 580\n470 PRINT \"DO YOU ELECT TO KICK OR RECEIVE\";\n480 INPUT A$\n490 PRINT\n500 FOR E=1 TO 2\n510 IF A$=L$(E) THEN 550\n520 NEXT E\n530 PRINT \"INCORRECT ANSWER.  PLEASE TYPE 'KICK' OR 'RECEIVE'\";\n540 GOTO 480\n550 IF E=2 THEN 580\n560 LET P=1\n580 LET X=40+(1-P)*20\n590 LET Y=INT(200*(RND(1)-.5)^3+55)\n600 PRINT Y;L$(3);\" KICKOFF\"\n610 LET X=X-FNF(1)*Y\n620 IF ABS(X-50)>=50 THEN 700\n630 LET Y=INT(50*RND(1)^2)+(1-P)*INT(50*RND(1)^4)\n640 LET X=X+FNF(1)*Y\n650 IF ABS(X-50)>=50 THEN 655\n651 PRINT Y;L$(3);\" RUNBACK\"\n652 GOTO 720\n655 PRINT L$(4);\n660 GOTO 2600\n700 PRINT \"TOUCHBACK FOR \";O$(P);\".\"\n710 LET X=20+P*60\n720 REM FIRST DOWN\n730 GOSUB 800\n740 LET X1=X\n750 LET D=1\n760 PRINT:PRINT \"FIRST DOWN \";O$(P);\"***\"\n770 PRINT\n780 PRINT\n790 GOTO 860\n800 REM PRINT POSITION\n810 IF X>50 THEN 840\n820 PRINT L$(5);O$(0);X;L$(6)\n830 GOTO 850\n840 PRINT L$(5);O$(1);100-X;L$(6)\n850 RETURN\n860 REM NEW PLAY\n870 LET T=T+1\n880 IF T=30 THEN 1060\n890 IF T<50 THEN 940\n900 IF RND(1)>.2 THEN 940\n910 PRINT \"END OF GAME  ***\"\n920 PRINT \"FINAL SCORE:  \";O$(0);\": \";S(0);\"  \";O$(1);\": \";S(1)\n930 STOP\n940 IF P=1 THEN 1870\n950 PRINT \"NEXT PLAY\";\n960 INPUT Z\n970 IF Z<>INT(Z) THEN 990\n980 IF ABS(Z-4)<=3 THEN 1010\n990 PRINT \"ILLEGAL PLAY NUMBER, RETYPE\";\n1000 GOTO 960\n1010 LET F=0\n1020 PRINT L$(Z+6);\".  \";\n1030 LET R=RND(1)*(.98+FNF(1)*.02)\n1040 LET R1=RND(1)\n1050 ON Z GOTO 1110,1150,1260,1480,1570,1570,1680\n1060 REM  JEAN'S SPECIAL\n1070 IF RND(1)> 1/3 THEN 940\n1080 PRINT \"GAME DELAYED.  DOG ON FIELD.\"\n1090 PRINT\n1100 GOTO 940\n1110 REM  SIMPLE RUN\n1120 LET Y=INT(24*(R-.5)^3+3)\n1130 IF RND(1)<.05 THEN 1180\n1140 GOTO 2190\n1150 REM  TRICKY RUN\n1160 LET Y=INT(20*R-5)\n1170 IF RND(1)>.1 THEN 2190\n1180 LET F=-1\n1190 LET X3=X\n1200 LET X=X+FNF(1)*Y\n1210 IF ABS(X-50)>=50 THEN 1240\n1220 PRINT \"***  FUMBLE AFTER \";\n1230 GOTO 2230\n1240 PRINT \"***  FUMBLE.\"\n1250 GOTO 2450\n1260 REM  SHORT PASS\n1270 LET Y=INT(60*(R1-.5)^3+10)\n1280 IF R<.05 THEN 1330\n1290 IF R<.15 THEN 1390\n1300 IF R<.55 THEN 1420\n1310 PRINT \"COMPLETE.  \";\n1320 GOTO 2190\n1330 IF D=4 THEN 1420\n1340 PRINT \"INTERCEPTED.\"\n1350 LET F=-1\n1360 LET X=X+FNF(1)*Y\n1370 IF ABS(X-50)>=50 THEN 2450\n1380 GOTO 2300\n1390 PRINT \"PASSER TACKLED.  \";\n1400 LET Y=-INT(10*R1)\n1410 GOTO 2190\n1420 LET Y=0\n1430 IF RND(1)<.3 THEN 1460\n1440 PRINT \"INCOMPLETE.  \";\n1450 GOTO 2190\n1460 PRINT \"BATTED DOWN.  \";\n1470 GOTO 2190\n1480 REM  LONG PASS\n1490 LET Y=INT(160*(R1-.5)^3+30)\n1500 IF R<.1 THEN 1330\n1510 IF R<.3 THEN 1540\n1520 IF R<.75 THEN 1420\n1530 GOTO 1310\n1540 PRINT \"PASSER TACKLED.  \";\n1550 LET Y=-INT(15*R1+3)\n1560 GOTO 2190\n1570 REM  PUNT OR KICK\n1580 LET Y=INT(100*(R-.5)^3+35)\n1590 IF D=4 THEN 1610\n1600 LET Y=INT(Y*1.3)\n1610 PRINT Y;L$(3);\" PUNT\"\n1620 IF ABS(X+Y*FNF(1)-50)>=50 THEN 1670\n1630 IF D<4 THEN 1670\n1640 LET Y1=INT(R1^2*20)\n1650 PRINT Y1;L$(3);\" RUN BACK\"\n1660 LET Y=Y-Y1\n1670 GOTO 1350\n1680 REM  PLACE KICK\n1690 LET Y=INT(100*(R-.5)^3+35)\n1700 IF R1>.15 THEN 1750\n1710 PRINT \"KICK IS BLOCKED  ***\"\n1720 LET X=X-5*FNF(1)\n1730 LET P=1-P\n1740 GOTO 720\n1750 LET X=X+FNF(1)*Y\n1760 IF ABS(X-50)>=60 THEN 1810\n1770 PRINT \"KICK IS SHORT.\"\n1780 IF ABS(X-50)>=50 THEN 2710\n1790 P=1-P\n1800 GOTO 630\n1810 IF R1>.5 THEN 1840\n1820 PRINT \"KICK IS OFF TO THE SIDE.\"\n1830 GOTO 2710\n1840 PRINT \"FIELD GOAL ***\"\n1850 LET S(P)=S(P)+3\n1860 GOTO 2640\n1870 REM  OPPONENT'S PLAY\n1880 IF D>1 THEN 1940\n1890 IF RND(1)>1/3 THEN 1920\n1900 LET Z=3\n1910 GOTO 1010\n1920 LET Z=1\n1930 GOTO 1010\n1940 IF D=4 THEN 2090\n1950 IF 10+X-X1<5 THEN 1890\n1960 IF X<5 THEN 1890\n1970 IF X<=10 THEN 2160\n1980 IF X>X1 THEN 2020\n1990 LET A=INT(2*RND(1))\n2000 LET Z=2+A*2\n2010 GOTO 1010\n2020 IF D<3 THEN 1990\n2030 IF X<45 THEN 1990\n2040 IF RND(1)>1/4 THEN 2070\n2050 LET Z=6\n2060 GOTO 1010\n2070 LET Z=4\n2080 GOTO 1010\n2090 IF X>30 THEN 2140\n2100 IF 10+X-X1<3 THEN 1890\n2110 IF X<3 THEN 1890\n2120 LET Z=7\n2130 GOTO 1010\n2140 LET Z=5\n2150 GOTO 1010\n2160 LET A=INT(2*RND(1))\n2170 LET Z=2+A\n2180 GOTO 1010\n2190 REM GAIN OR LOSS\n2200 LET X3=X\n2210 LET X=X+FNF(1)*Y\n2220 IF ABS(X-50)>=50 THEN 2450\n2230 IF Y=0 THEN 2250\n2240 PRINT ABS(Y);L$(3);\n2250 PRINT L$(15+SGN(Y))\n2280 IF ABS(X3-50)>40 THEN 2300\n2290 IF RND(1)<.1 THEN 2860\n2300 GOSUB 800\n2310 IF F=0 THEN 2340\n2320 LET P=1-P\n2330 GOTO 740\n2340 IF FNG(1)>=10 THEN 740\n2350 IF D=4 THEN 2320\n2360 LET D=D+1\n2370 PRINT \"DOWN: \";D;\"     \";\n2380 IF (X1-50)*FNF(1)<40 THEN 2410\n2390 PRINT \"GOAL TO GO\"\n2400 GOTO 2420\n2410 PRINT \"YARDS TO GO: \";10-FNG(1)\n2420 PRINT\n2430 PRINT\n2440 GOTO 860\n2450 REM BALL IN END-ZONE\n2460 IF X>=100 THEN 2490\n2470 LET E=0\n2480 GOTO 2500\n2490 LET E=1\n2500 ON 1+E-F*2+P*4 GOTO 2510,2590,2760,2710,2590,2510,2710,2760\n2510 REM SAFETY\n2520 LET S(1-P)=S(1-P)+2\n2530 PRINT L$(19)\n2540 GOSUB 2800\n2550 PRINT O$(P);\" KICKS OFF FROM ITS 20 YARD LINE.\"\n2560 LET X=20+P*60\n2570 LET P=1-P\n2580 GOTO 590\n2590 REM OFFENSIVE TD\n2600 PRINT L$(17);\"***\"\n2610 IF RND(1)>.8 THEN 2680\n2620 LET S(P)=S(P)+7\n2630 PRINT \"KICK IS GOOD.\"\n2640 GOSUB 2800\n2650 PRINT O$(P);\" KICKS OFF\"\n2660 LET P=1-P\n2670 GOTO 580\n2680 PRINT \"KICK IS OFF TO THE SIDE\"\n2690 LET S(P)=S(P)+6\n2700 GOTO 2640\n2710 REM TOUCHBACK\n2720 PRINT L$(18)\n2730 LET P=1-P\n2740 LET X=20+P*60\n2750 GOTO 720\n2760 REM DEFENSIVE TD\n2770 PRINT L$(17);\"FOR \";O$(1-P);\"***\"\n2780 LET P=1-P\n2790 GOTO 2600\n2800 REM SCORE\n2810 PRINT\n2820 PRINT \"SCORE:  \";S(0);\" TO \";S(1)\n2830 PRINT\n2840 PRINT\n2850 RETURN\n2860 REM PENALTY\n2870 LET P3=INT(2*RND(1))\n2880 PRINT O$(P3);\" OFFSIDES -- PENALTY OF 5 YARDS.\"\n2890 PRINT\n2900 PRINT\n2910 IF P3=0 THEN 2980\n2920 PRINT \"DO YOU ACCEPT THE PENALTY\";\n2930 INPUT A$\n2940 IF A$=\"NO\" THEN 2300\n2950 IF A$=\"YES\" THEN 3110\n2960 PRINT \"TYPE 'YES' OR 'NO'\";\n2970 GOTO 2930\n2980 REM OPPONENT'S STRATEGY ON PENALTY\n2990 IF P=1 THEN 3040\n3000 IF Y<=0 THEN 3080\n3010 IF F<0 THEN 3080\n3020 IF FNG(1)<3*D-2 THEN 3080\n3030 GOTO 3100\n3040 IF Y<=5 THEN 3100\n3050 IF F<0 THEN 3100\n3060 IF D<4 THEN 3080\n3070 IF FNG(1)<10 THEN 3100\n3080 PRINT \"PENALTY REFUSED.\"\n3090 GOTO 2300\n3100 PRINT \"PENALTY ACCEPTED.\"\n3110 LET F=0\n3120 LET D=D-1\n3130 IF P<>P3 THEN 3160\n3140 LET X=X3-FNF(1)*5\n3150 GOTO 2300\n3160 LET X=X3+FNF(1)*5\n3170 GOTO 2300\n3180 END\n"
  },
  {
    "path": "37_Football/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "37_Football/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "37_Football/javascript/football.html",
    "content": "<html>\n<head>\n<title>FOOTBALL</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"football.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "37_Football/javascript/football.js",
    "content": "// FOOTBALL\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar player_data = [17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6,\n                   20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3];\nvar aa = [];\nvar ba = [];\nvar ca = [];\nvar ha = [];\nvar ta = [];\nvar wa = [];\nvar xa = [];\nvar ya = [];\nvar za = [];\nvar ms = [];\nvar da = [];\nvar ps = [, \"PITCHOUT\",\"TRIPLE REVERSE\",\"DRAW\",\"QB SNEAK\",\"END AROUND\",\n          \"DOUBLE REVERSE\",\"LEFT SWEEP\",\"RIGHT SWEEP\",\"OFF TACKLE\",\n          \"WISHBONE OPTION\",\"FLARE PASS\",\"SCREEN PASS\",\n          \"ROLL OUT OPTION\",\"RIGHT CURL\",\"LEFT CURL\",\"WISHBONE OPTION\",\n          \"SIDELINE PASS\",\"HALF-BACK OPTION\",\"RAZZLE-DAZZLE\",\"BOMB!!!!\"];\nvar p;\nvar t;\n\nfunction field_headers()\n{\n    print(\"TEAM 1 [0   10   20   30   40   50   60   70   80   90\");\n    print(\"   100] TEAM 2\\n\");\n    print(\"\\n\");\n}\n\nfunction separator()\n{\n    str = \"\";\n    for (x = 1; x <= 72; x++)\n        str += \"+\";\n    print(str + \"\\n\");\n}\n\nfunction show_ball()\n{\n    print(tab(da[t] + 5 + p / 2) + ms[t] + \"\\n\");\n    field_headers();\n}\n\nfunction show_scores()\n{\n    print(\"\\n\");\n    print(\"TEAM 1 SCORE IS \" + ha[1] + \"\\n\");\n    print(\"TEAM 2 SCORE IS \" + ha[2] + \"\\n\");\n    print(\"\\n\");\n    if (ha[t] >= e) {\n        print(\"TEAM \" + t + \" WINS*******************\");\n        return true;\n    }\n    return false;\n}\n\nfunction loss_posession() {\n    print(\"\\n\");\n    print(\"** LOSS OF POSSESSION FROM TEAM \" + t + \" TO TEAM \" + ta[t] + \"\\n\");\n    print(\"\\n\");\n    separator();\n    print(\"\\n\");\n    t = ta[t];\n}\n\nfunction touchdown() {\n    print(\"\\n\");\n    print(\"TOUCHDOWN BY TEAM \" + t + \" *********************YEA TEAM\\n\");\n    q = 7;\n    g = Math.random();\n    if (g <= 0.1) {\n        q = 6;\n        print(\"EXTRA POINT NO GOOD\\n\");\n    } else {\n        print(\"EXTRA POINT GOOD\\n\");\n    }\n    ha[t] = ha[t] + q;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"FOOTBALL\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"DO YOU WANT INSTRUCTIONS\");\n        str = await input();\n        if (str == \"YES\" || str == \"NO\")\n            break;\n    }\n    if (str == \"YES\") {\n        print(\"THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST\\n\");\n        print(\"PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,\\n\");\n        print( \"1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20\\n\");\n        print(\"THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS.\\n\");\n        print(\"A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH\\n\");\n        print(\"BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE\\n\");\n        print(\"PLAYS THE LESS YARDAGE GAINED.  SCORES ARE GIVEN\\n\");\n        print(\"WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED\\n\");\n        print(\"BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A\\n\");\n        print(\"FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE\\n\");\n        print(\"ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER\\n\");\n        print(\"YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO\\n\");\n        print(\"BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO\\n\");\n        print(\"TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO.\\n\");\n        print(\"THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C).\\n\");\n        print(\"PLEASE PREPARE A TAPE AND RUN.\\n\");\n    }\n    print(\"\\n\");\n    print(\"PLEASE INPUT SCORE LIMIT ON GAME\");\n    e = parseInt(await input());\n    for (i = 1; i <= 40; i++) {\n        if (i <= 20) {\n            aa[player_data[i - 1]] = i;\n        } else {\n            ba[player_data[i - 1]] = i - 20;\n        }\n        ca[i] = player_data[i - 1];\n    }\n    l = 0;\n    t = 1;\n    do {\n        print(\"TEAM \" + t + \" PLAY CHART\\n\");\n        print(\"NO.      PLAY\\n\");\n        for (i = 1; i <= 20; i++) {\n            str = \"\" + ca[i + l];\n            while (str.length < 6)\n                str += \" \";\n            str += ps[i];\n            print(str + \"\\n\");\n        }\n        l += 20;\n        t = 2;\n        print(\"\\n\");\n        print(\"TEAR OFF HERE----------------------------------------------\\n\");\n        for (x = 1; x <= 11; x++)\n            print(\"\\n\");\n    } while (l == 20) ;\n    da[1] = 0;\n    da[2] = 3;\n    ms[1] = \"--->\";\n    ms[2] = \"<---\";\n    ha[1] = 0;\n    ha[2] = 0;\n    ta[1] = 2;\n    ta[2] = 1;\n    wa[1] = -1;\n    wa[2] = 1;\n    xa[1] = 100;\n    xa[2] = 0;\n    ya[1] = 1;\n    ya[2] = -1;\n    za[1] = 0;\n    za[2] = 100;\n    p = 0;\n    field_headers();\n    print(\"TEAM 1 DEFEND 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.\\n\");\n    t = Math.floor(2 * Math.random() + 1);\n    print(\"\\n\");\n    print(\"THE COIN IS FLIPPED\\n\");\n    routine = 1;\n    while (1) {\n        if (routine <= 1) {\n            p = xa[t] - ya[t] * 40;\n            separator();\n            print(\"\\n\");\n            print(\"TEAM \" + t + \" RECEIVES KICK-OFF\\n\");\n            k = Math.floor(26 * Math.random() + 40);\n        }\n        if (routine <= 2) {\n            p = p - ya[t] * k;\n        }\n        if (routine <= 3) {\n            if (wa[t] * p >= za[t] + 10) {\n                print(\"\\n\");\n                print(\"BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--\\n\");\n                p = za[t] - wa[t] * 20;\n                if (routine <= 4)\n                    routine = 5;\n            } else {\n                print(\"BALL WENT \" + k + \" YARDS.  NOW ON \" + p + \"\\n\");\n                show_ball();\n            }\n        }\n        if (routine <= 4) {\n            while (1) {\n                print(\"TEAM \" + t + \" DO YOU WANT TO RUNBACK\");\n                str = await input();\n                if (str == \"YES\" || str == \"NO\")\n                    break;\n            }\n            if (str == \"YES\") {\n                k = Math.floor(9 * Math.random() + 1);\n                r = Math.floor(((xa[t] - ya[t] * p + 25) * Math.random() - 15) / k);\n                p = p - wa[t] * r;\n                print(\"\\n\");\n                print(\"RUNBACK TEAM \" + t + \" \" + r + \" YARDS\\n\");\n                g = Math.random();\n                if (g < 0.25) {\n                    loss_posession();\n                    routine = 4;\n                    continue;\n                } else if (ya[t] * p >= xa[t]) {\n                    touchdown();\n                    if (show_scores())\n                        return;\n                    t = ta[t];\n                    routine = 1;\n                    continue;\n                } else if (wa[t] * p >= za[t]) {\n                    print(\"\\n\");\n                    print(\"SAFETY AGAINST TEAM \" + t + \" **********************OH-OH\\n\");\n                    ha[ta[t]] = ha[ta[t]] + 2;\n                    if (show_scores())\n                        return;\n                    print(\"TEAM \" + t + \" DO YOU WANT TO PUNT INSTEAD OF A KICKOFF\");\n                    str = await input();\n                    p = za[t] - wa[t] * 20;\n                    if (str == \"YES\") {\n                        print(\"\\n\");\n                        print(\"TEAM \" + t + \" WILL PUNT\\n\");\n                        g = Math.random();\n                        if (g < 0.25) {\n                            loss_posession();\n                            routine = 4;\n                            continue;\n                        }\n                        print(\"\\n\");\n                        separator();\n                        k = Math.floor(25 * Math.random() + 35);\n                        t = ta[t];\n                        routine = 2;\n                        continue;\n                    }\n                    touchdown();\n                    if (show_scores())\n                        return;\n                    t = ta[t];\n                    routine = 1;\n                    continue;\n                } else {\n                    routine = 5;\n                    continue;\n                }\n            } else if (str == \"NO\") {\n                if (wa[t] * p >= za[t])\n                    p = za[t] - wa[t] * 20;\n            }\n        }\n        if (routine <= 5) {\n            d = 1;\n            s = p;\n        }\n        if (routine <= 6) {\n            str = \"\";\n            for (i = 1; i <= 72; i++)\n                str += \"=\";\n            print(str + \"\\n\");\n            print(\"TEAM \" + t + \" DOWN \" + d + \" ON \" + p + \"\\n\");\n            if (d == 1) {\n                if (ya[t] * (p + ya[t] * 10) >= xa[t])\n                    c = 8;\n                else\n                    c = 4;\n            }\n            if (c != 8) {\n                print(tab(27) + (10 - (ya[t] * p - ya[t] * s)) + \" YARDS TO 1ST DOWN\\n\");\n            } else {\n                print(tab(27) + (xa[t] - ya[t] * p) + \" YARDS\\n\");\n            }\n            show_ball();\n            if (d == 4)\n                routine = 8;\n        }\n        if (routine <= 7) {\n            u = Math.floor(3 * Math.random() - 1);\n            while (1) {\n                print(\"INPUT OFFENSIVE PLAY, DEFENSIVE PLAY\");\n                str = await input();\n                if (t == 1) {\n                    p1 = parseInt(str);\n                    p2 = parseInt(str.substr(str.indexOf(\",\") + 1));\n                } else {\n                    p2 = parseInt(str);\n                    p1 = parseInt(str.substr(str.indexOf(\",\") + 1));\n                }\n                if (p1 == 99) {\n                    if (show_scores())\n                        return;\n                    if (p1 == 99)\n                        continue;\n                }\n                if (p1 < 1 || p1 > 20 || p2 < 1 || p2 > 20) {\n                    print(\"ILLEGAL PLAY NUMBER, CHECK AND\\n\");\n                    continue;\n                }\n                break;\n            }\n        }\n        if (d == 4 || p1 == 77) {\n            while (1) {\n                print(\"DOES TEAM \" + t + \" WANT TO PUNT\");\n                str = await input();\n                if (str == \"YES\" || str == \"NO\")\n                    break;\n            }\n            if (str == \"YES\") {\n                print(\"\\n\");\n                print(\"TEAM \" + t + \" WILL PUNT\\n\");\n                g = Math.random();\n                if (g < 0.25) {\n                    loss_posession();\n                    routine = 4;\n                    continue;\n                }\n                print(\"\\n\");\n                separator();\n                k = Math.floor(25 * Math.random() + 35);\n                t = ta[t];\n                routine = 2;\n                continue;\n            }\n            while (1) {\n                print(\"DOES TEAM \" + t + \" WANT TO ATTEMPT A FIELD GOAL\");\n                str = await input();\n                if (str == \"YES\" || str == \"NO\")\n                    break;\n            }\n            if (str == \"YES\") {\n                print(\"\\n\");\n                print(\"TEAM \" + t + \" WILL ATTEMPT A FIELD GOAL\\n\");\n                g = Math.random();\n                if (g < 0.025) {\n                    loss_posession();\n                    routine = 4;\n                    continue;\n                } else {\n                    f = Math.floor(35 * Math.random() + 20);\n                    print(\"\\n\");\n                    print(\"KICK IS \" + f + \" YARDS LONG\\n\");\n                    p = p - wa[t] * f;\n                    g = Math.random();\n                    if (g < 0.35) {\n                        print(\"BALL WENT WIDE\\n\");\n                    } else if (ya[t] * p >= xa[t]) {\n                        print(\"FIELD GOLD GOOD FOR TEAM \" + t + \" *********************YEA\");\n                        q = 3;\n                        ha[t] = ha[t] + q;\n                        if (show_scores())\n                            return;\n                        t = ta[t];\n                        routine = 1;\n                        continue;\n                    }\n                    print(\"FIELD GOAL UNSUCCESFUL TEAM \" + t + \"-----------------TOO BAD\\n\");\n                    print(\"\\n\");\n                    separator();\n                    if (ya[t] * p < xa[t] + 10) {\n                        print(\"\\n\");\n                        print(\"BALL NOW ON \" + p + \"\\n\");\n                        t = ta[t];\n                        show_ball();\n                        routine = 4;\n                        continue;\n                    } else {\n                        t = ta[t];\n                        routine = 3;\n                        continue;\n                    }\n                }\n            } else {\n                routine = 7;\n                continue;\n            }\n        }\n        y = Math.floor(Math.abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * Math.random() - 15));\n        print(\"\\n\");\n        if (t == 1 && aa[p1] < 11 || t == 2 && ba[p2] < 11) {\n            print(\"THE BALL WAS RUN\\n\");\n        } else if (u == 0) {\n            print(\"PASS INCOMPLETE TEAM \" + t + \"\\n\");\n            y = 0;\n        } else {\n            g = Math.random();\n            if (g <= 0.025 && y > 2) {\n                print(\"PASS COMPLETED\\n\");\n            } else {\n                print(\"QUARTERBACK SCRAMBLED\\n\");\n            }\n        }\n        p = p - wa[t] * y;\n        print(\"\\n\");\n        print(\"NET YARDS GAINED ON DOWN \" + d + \" ARE \" + y + \"\\n\");\n\n        g = Math.random();\n        if (g <= 0.025) {\n            loss_posession();\n            routine = 4;\n            continue;\n        } else if (ya[t] * p >= xa[t]) {\n            touchdown();\n            if (show_scores())\n                return;\n            t = ta[t];\n            routine = 1;\n            continue;\n        } else if (wa[t] * p >= za[t]) {\n            print(\"\\n\");\n            print(\"SAFETY AGAINST TEAM \" + t + \" **********************OH-OH\\n\");\n            ha[ta[t]] = ha[ta[t]] + 2;\n            if (show_scores())\n                return;\n            print(\"TEAM \" + t + \" DO YOU WANT TO PUNT INSTEAD OF A KICKOFF\");\n            str = await input();\n            p = za[t] - wa[t] * 20;\n            if (str == \"YES\") {\n                print(\"\\n\");\n                print(\"TEAM \" + t + \" WILL PUNT\\n\");\n                g = Math.random();\n                if (g < 0.25) {\n                    loss_posession();\n                    routine = 4;\n                    continue;\n                }\n                print(\"\\n\");\n                separator();\n                k = Math.floor(25 * Math.random() + 35);\n                t = ta[t];\n                routine = 2;\n                continue;\n            }\n            touchdown();\n            if (show_scores())\n                return;\n            t = ta[t];\n            routine = 1;\n        } else if (ya[t] * p - ya[t] * s >= 10) {\n            routine = 5;\n        } else {\n            d++;\n            if (d != 5) {\n                routine = 6;\n            } else {\n                print(\"\\n\");\n                print(\"CONVERSION UNSUCCESSFUL TEAM \" + t + \"\\n\");\n                t = ta[t];\n                print(\"\\n\");\n                separator();\n                routine = 5;\n            }\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "37_Football/javascript/ftball.html",
    "content": "<html>\n<head>\n<title>FTBALL</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"ftball.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "37_Football/javascript/ftball.js",
    "content": "// FTBALL\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar os = [];\nvar sa = [];\nvar ls = [, \"KICK\",\"RECEIVE\",\" YARD \",\"RUN BACK FOR \",\"BALL ON \",\n          \"YARD LINE\",\" SIMPLE RUN\",\" TRICKY RUN\",\" SHORT PASS\",\n          \" LONG PASS\",\"PUNT\",\" QUICK KICK \",\" PLACE KICK\",\" LOSS \",\n          \" NO GAIN\",\"GAIN \",\" TOUCHDOWN \",\" TOUCHBACK \",\"SAFETY***\",\n          \"JUNK\"];\nvar p;\nvar x;\nvar x1;\n\nfunction fnf(x)\n{\n    return 1 - 2 * p;\n}\n\nfunction fng(z)\n{\n    return p * (x1 - x) + (1 - p) * (x - x1);\n}\n\nfunction show_score()\n{\n    print(\"\\n\");\n    print(\"SCORE:  \" + sa[0] + \" TO \" + sa[1] + \"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nfunction show_position()\n{\n    if (x <= 50) {\n        print(ls[5] + os[0] + \" \" + x + \" \" + ls[6] + \"\\n\");\n    } else {\n        print(ls[5] + os[1] + \" \" + (100 - x) + \" \" + ls[6] + \"\\n\");\n    }\n}\n\nfunction offensive_td()\n{\n    print(ls[17] + \"***\\n\");\n    if (Math.random() <= 0.8) {\n        sa[p] = sa[p] + 7;\n        print(\"KICK IS GOOD.\\n\");\n    } else {\n        print(\"KICK IS OFF TO THE SIDE\\n\");\n        sa[p] = sa[p] + 6;\n    }\n    show_score();\n    print(os[p] + \" KICKS OFF\\n\");\n    p = 1 - p;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"FTBALL\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS DARTMOUTH CHAMPIONSHIP FOOTBALL.\\n\");\n    print(\"\\n\");\n    print(\"YOU WILL QUARTERBACK DARTMOUTH. CALL PLAYS AS FOLLOWS:\\n\");\n    print(\"1= SIMPLE RUN; 2= TRICKY RUN; 3= SHORT PASS;\\n\");\n    print(\"4= LONG PASS; 5= PUNT; 6= QUICK KICK; 7= PLACE KICK.\\n\");\n    print(\"\\n\");\n    print(\"CHOOSE YOUR OPPONENT\");\n    os[1] = await input();\n    os[0] = \"DARMOUTH\";\n    print(\"\\n\");\n    sa[0] = 0;\n    sa[1] = 0;\n    p = Math.floor(Math.random() * 2);\n    print(os[p] + \" WON THE TOSS\\n\");\n    if (p != 0) {\n        print(os[1] + \" ELECTS TO RECEIVE.\\n\");\n        print(\"\\n\");\n    } else {\n        print(\"DO YOU ELECT TO KICK OR RECEIVE\");\n        while (1) {\n            str = await input();\n            print(\"\\n\");\n            if (str == ls[1] || str == ls[2])\n                break;\n            print(\"INCORRECT ANSWER.  PLEASE TYPE 'KICK' OR 'RECEIVE'\");\n        }\n        e = (str == ls[1]) ? 1 : 2;\n        if (e == 1)\n            p = 1;\n    }\n    t = 0;\n    start = 1;\n    while (1) {\n        if (start <= 1) {\n            x = 40 + (1 - p) * 20;\n        }\n        if (start <= 2) {\n            y = Math.floor(200 * Math.pow((Math.random() - 0.5), 3) + 55);\n            print(\" \" + y + \" \" + ls[3] + \" KICKOFF\\n\");\n            x = x - fnf(1) * y;\n            if (Math.abs(x - 50) >= 50) {\n                print(\"TOUCHBACK FOR \" + os[p] + \".\\n\");\n                x = 20 + p * 60;\n                start = 4;\n            } else {\n                start = 3;\n            }\n        }\n        if (start <= 3) {\n            y = Math.floor(50 * Math.pow(Math.random(), 2)) + (1 - p) * Math.floor(50 * Math.pow(Math.random(), 4));\n            x = x + fnf(1) * y;\n            if (Math.abs(x - 50) < 50) {\n                print(\" \" + y + \" \" + ls[3] + \" RUNBACK\\n\");\n            } else {\n                print(ls[4]);\n                offensive_td();\n                start = 1;\n                continue;\n            }\n        }\n        if (start <= 4) {\n            // First down\n            show_position();\n        }\n        if (start <= 5) {\n            x1 = x;\n            d = 1;\n            print(\"\\n\");\n            print(\"FIRST DOWN \" + os[p] + \"***\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n        }\n        // New play\n        t++;\n        if (t == 30) {\n            if (Math.random() <= 1.3) {\n                print(\"GAME DELAYED.  DOG ON FIELD.\\n\");\n                print(\"\\n\");\n            }\n        }\n        if (t >= 50 && Math.random() <= 0.2)\n            break;\n        if (p != 1) {\n            // Opponent's play\n            if (d <= 1) {\n                z = Math.random() > 1 / 3 ? 1 : 3;\n            } else if (d != 4) {\n                if (10 + x - x1 < 5 || x < 5) {\n                    z = Math.random() > 1 / 3 ? 1 : 3;\n                } else if (x <= 10) {\n                    a = Math.floor(2 * Math.random());\n                    z = 2 + a;\n                } else if (x <= x1 || d < 3 || x < 45) {\n                    a = Math.floor(2 * Math.random());\n                    z = 2 + a * 2;\n                } else {\n                    if (Math.random() > 1 / 4)\n                        z = 4;\n                    else\n                        z = 6;\n                }\n            } else {\n                if (x <= 30) {\n                    z = 5;\n                } else if (10 + x - x1 < 3 || x < 3) {\n                    z = Math.random() > 1 / 3 ? 1 : 3;\n                } else {\n                    z = 7;\n                }\n            }\n        } else {\n            print(\"NEXT PLAY\");\n            while (1) {\n                z = parseInt(await input());\n                if (Math.abs(z - 4) <= 3)\n                    break;\n                print(\"ILLEGAL PLAY NUMBER, RETYPE\");\n            }\n        }\n        f = 0;\n        print(ls[z + 6] + \".  \");\n        r = Math.random() * (0.98 + fnf(1) * 0.02);\n        r1 = Math.random();\n        switch (z) {\n            case 1: // Simple run\n            case 2: // Tricky run\n                if (z == 1) {\n                    y = Math.floor(24 * Math.pow(r - 0.5, 3) + 3);\n                    if (Math.random() >= 0.05) {\n                        routine = 1;\n                        break;\n                    }\n                } else {\n                    y = Math.floor(20 * r - 5);\n                    if (Math.random() > 0.1) {\n                        routine = 1;\n                        break;\n                    }\n                }\n                f = -1;\n                x3 = x;\n                x = x + fnf(1) * y;\n                if (Math.abs(x - 50) < 50) {\n                    print(\"***  FUMBLE AFTER \");\n                    routine = 2;\n                    break;\n                } else {\n                    print(\"***  FUMBLE.\\n\");\n                    routine = 4;\n                    break;\n                }\n            case 3: // Short pass\n            case 4: // Long pass\n                if (z == 3) {\n                    y = Math.floor(60 * Math.pow(r1 - 0.5, 3) + 10);\n                } else {\n                    y = Math.floor(160 * Math.pow((r1 - 0.5), 3) + 30);\n                }\n                if (z == 3 && r < 0.05 || z == 4 && r < 0.1) {\n                    if (d != 4) {\n                        print(\"INTERCEPTED.\\n\");\n                        f = -1;\n                        x = x + fnf(1) * y;\n                        if (Math.abs(x - 50) >= 50) {\n                            routine = 4;\n                            break;\n                        }\n                        routine = 3;\n                        break;\n                    } else {\n                        y = 0;\n                        if (Math.random() < 0.3) {\n                            print(\"BATTED DOWN.  \");\n                        } else {\n                            print(\"INCOMPLETE.  \");\n                        }\n                        routine = 1;\n                        break;\n                    }\n                } else if (z == 4 && r < 0.3) {\n                    print(\"PASSER TACKLED.  \");\n                    y = -Math.floor(15 * r1 + 3);\n                    routine = 1;\n                    break;\n                } else if (z == 3 && r < 0.15) {\n                    print(\"PASSER TACLKED.  \");\n                    y = -Math.floor(10 * r1);\n                    routine = 1;\n                    break;\n                } else if (z == 3 && r < 0.55 || z == 4 && r < 0.75) {\n                    y = 0;\n                    if (Math.random() < 0.3) {\n                        print(\"BATTED DOWN.  \");\n                    } else {\n                        print(\"INCOMPLETE.  \");\n                    }\n                    routine = 1;\n                    break;\n                } else {\n                    print(\"COMPLETE.  \");\n                    routine = 1;\n                    break;\n                }\n            case 5:  // Punt\n            case 6:  // Quick kick\n                y = Math.floor(100 * Math.pow((r - 0.5), 3) + 35);\n                if (d != 4)\n                    y = Math.floor(y * 1.3);\n                print(\" \" + y + \" \" + ls[3] + \" PUNT\\n\");\n                if (Math.abs(x + y * fnf(1) - 50) < 50 && d >= 4) {\n                    y1 = Math.floor(Math.pow(r1, 2) * 20);\n                    print(\" \" + y1 + \" \" + ls[3] + \" RUN BACK\\n\");\n                    y = y - y1;\n                }\n                f = -1;\n                x = x + fnf(1) * y;\n                if (Math.abs(x - 50) >= 50) {\n                    routine = 4;\n                    break;\n                }\n                routine = 3;\n                break;\n            case 7: // Place kick\n                y = Math.floor(100 * Math.pow((r - 0.5), 3) + 35);\n                if (r1 <= 0.15) {\n                    print(\"KICK IS BLOCKED  ***\\n\");\n                    x = x - 5 * fnf(1);\n                    p = 1 - p;\n                    start = 4;\n                    continue;\n                }\n                x = x + fnf(1) * y;\n                if (Math.abs(x - 50) >= 60) {\n                    if (r1 <= 0.5) {\n                        print(\"KICK IS OFF TO THE SIDE.\\n\");\n                        print(ls[18] + \"\\n\");\n                        p = 1 - p;\n                        x = 20 + p * 60;\n                        start = 4;\n                        continue;\n                    } else {\n                        print(\"FIELD GOAL ***\\n\");\n                        sa[p] = sa[p] + 3;\n                        show_score();\n                        print(os[p] + \" KICKS OFF\\n\");\n                        p = 1 - p;\n                        start = 1;\n                        continue;\n                    }\n                } else {\n                    print(\"KICK IS SHORT.\\n\");\n                    if (Math.abs(x - 50) >= 50) {\n                        // Touchback\n                        print(ls[18] + \"\\n\");\n                        p = 1 - p;\n                        x = 20 + p * 60;\n                        start = 4;\n                        continue;\n                    }\n                    p = 1 - p;\n                    start = 3;\n                    continue;\n                }\n\n        }\n        // Gain or loss\n        if (routine <= 1) {\n            x3 = x;\n            x = x + fnf(1) * y;\n            if (Math.abs(x - 50) >= 50) {\n                routine = 4;\n            }\n        }\n        if (routine <= 2) {\n            if (y != 0) {\n                print(\" \" + Math.abs(y) + \" \" + ls[3]);\n                if (y < 0)\n                    yt = -1;\n                else if (y > 0)\n                    yt = 1;\n                else\n                    yt = 0;\n                print(ls[15 + yt]);\n                if (Math.abs(x3 - 50) <= 40 && Math.random() < 0.1) {\n                    // Penalty\n                    p3 = Math.floor(2 * Math.random());\n                    print(os[p3] + \" OFFSIDES -- PENALTY OF 5 YARDS.\\n\");\n                    print(\"\\n\");\n                    print(\"\\n\");\n                    if (p3 != 0) {\n                        print(\"DO YOU ACCEPT THE PENALTY\");\n                        while (1) {\n                            str = await input();\n                            if (str == \"YES\" || str == \"NO\")\n                                break;\n                            print(\"TYPE 'YES' OR 'NO'\");\n                        }\n                        if (str == \"YES\") {\n                            f = 0;\n                            d = d - 1;\n                            if (p != p3)\n                                x = x3 + fnf(1) * 5;\n                            else\n                                x = x3 - fnf(1) * 5;\n                        }\n                    } else {\n                        // Opponent's strategy on penalty\n                        if ((p != 1 && (y <= 0 || f < 0 || fng(1) < 3 * d - 2))\n                            || (p == 1 && ((y > 5 && f >= 0) || d < 4 || fng(1) >= 10))) {\n                            print(\"PENALTY REFUSED.\\n\");\n                        } else {\n                            print(\"PENALTY ACCEPTED.\\n\");\n                            f = 0;\n                            d = d - 1;\n                            if (p != p3)\n                                x = x3 + fnf(1) * 5;\n                            else\n                                x = x3 - fnf(1) * 5;\n                        }\n                    }\n                    routine = 3;\n                }\n            }\n        }\n        if (routine <= 3) {\n            show_position();\n            if (f != 0) {\n                p = 1 - p;\n                start = 5;\n                continue;\n            } else if (fng(1) >= 10) {\n                start = 5;\n                continue;\n            } else if (d == 4) {\n                p = 1 - p;\n                start = 5;\n                continue;\n            } else {\n                d++;\n                print(\"DOWN: \" + d + \"     \");\n                if ((x1 - 50) * fnf(1) >= 40) {\n                    print(\"GOAL TO GO\\n\");\n                } else {\n                    print(\"YARDS TO GO: \" + (10 - fng(1)) + \"\\n\");\n                }\n                print(\"\\n\");\n                print(\"\\n\");\n                start = 6;\n                continue;\n            }\n        }\n        if (routine <= 4) {\n            // Ball in end-zone\n            e = (x >= 100) ? 1 : 0;\n            switch (1 + e - f * 2 + p * 4) {\n                case 1:\n                case 5:\n                    // Safety\n                    sa[1 - p] = sa[1 - p] + 2;\n                    print(ls[19] + \"\\n\");\n                    show_score();\n                    print(os[p] + \" KICKS OFF FROM ITS 20 YARD LINE.\\n\");\n                    x = 20 + p * 60;\n                    p = 1 - p;\n                    start = 2;\n                    continue;\n                case 3:\n                case 6:\n                    // Defensive TD\n                    print(ls[17] + \"FOR \" + os[1 - p] + \"***\\n\");\n                    p = 1 - p;\n                    // Fall-thru\n                case 2:\n                case 8:\n                    // Offensive TD\n                    print(ls[17] + \"***\\n\");\n                    if (Math.random() <= 0.8) {\n                        sa[p] = sa[p] + 7;\n                        print(\"KICK IS GOOD.\\n\");\n                    } else {\n                        print(\"KICK IS OFF TO THE SIDE\\n\");\n                        sa[p] = sa[p] + 6;\n                    }\n                    show_score();\n                    print(os[p] + \" KICKS OFF\\n\");\n                    p = 1 - p;\n                    start = 1;\n                    continue;\n                case 4:\n                case 7:\n                    // Touchback\n                    print(ls[18] + \"\\n\");\n                    p = 1 - p;\n                    x = 20 + p * 60;\n                    start = 4;\n                    continue;\n            }\n        }\n    }\n    print(\"END OF GAME  ***\\n\");\n    print(\"FINAL SCORE:  \" + os[0] + \": \" + sa[0] + \"  \" + os[1] + \": \" + sa[1] + \"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "37_Football/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "37_Football/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "37_Football/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "37_Football/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n\n\n## Porting notes\n\nVariables:\n\n* E: score_limit\n* H(2): Scores\n* T(2): Team toggle\n* T: team who currently possesses the ball\n* L: Offset\n* P: Who has the ball\n* K: yards\n* R: Runback current team in yards\n* P$(20): Actions (see data.json)\n\nFunctions:\n\n* `P$(I)`: Access index `I` of the `P` array\n* ABS: abs (absolute value)\n* RND(1): random()\n* GOSUB: Execute a function - will jump back to this\n* GOTO: Just jump\n\nPatterns:\n\n* `T=T(T)`: Toggle the team who currently has the ball\n"
  },
  {
    "path": "37_Football/python/data.json",
    "content": "{\n    \"players\": [17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6,\n        20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3],\n    \"actions\": [\"PITCHOUT\",\"TRIPLE REVERSE\",\"DRAW\",\"QB SNEAK\",\"END AROUND\",\n        \"DOUBLE REVERSE\",\"LEFT SWEEP\",\"RIGHT SWEEP\",\"OFF TACKLE\",\n        \"WISHBONE OPTION\",\"FLARE PASS\",\"SCREEN PASS\",\n        \"ROLL OUT OPTION\",\"RIGHT CURL\",\"LEFT CURL\",\"WISHBONE OPTION\",\n        \"SIDELINE PASS\",\"HALF-BACK OPTION\",\"RAZZLE-DAZZLE\",\"BOMB!!!!\"]\n}\n"
  },
  {
    "path": "37_Football/python/football.py",
    "content": "\"\"\"\nFOOTBALL\n\nA game.\n\nPorted to Python by Martin Thoma in 2022.\nThe JavaScript version by Oscar Toledo G. (nanochess) was used\n\"\"\"\n# NOTE: The newlines might be wrong\n\nimport json\nfrom math import floor\nfrom pathlib import Path\nfrom random import randint, random\nfrom typing import List, Tuple\n\nwith open(Path(__file__).parent / \"data.json\") as f:\n    data = json.load(f)\n\nplayer_data = [num - 1 for num in data[\"players\"]]\nactions = data[\"actions\"]\n\n\naa: List[int] = [-100 for _ in range(20)]\nba: List[int] = [-100 for _ in range(20)]\nca: List[int] = [-100 for _ in range(40)]\nscore: List[int] = [0, 0]\nta: Tuple[int, int] = (1, 0)\nwa: Tuple[int, int] = (-1, 1)\nxa: Tuple[int, int] = (100, 0)\nya: Tuple[int, int] = (1, -1)\nza: Tuple[int, int] = (0, 100)\nmarker: Tuple[str, str] = (\"--->\", \"<---\")\nt: int = 0\np: int = 0\nwinning_score: int\n\n\ndef ask_bool(prompt: str) -> bool:\n    while True:\n        answer = input(prompt).lower()\n        if answer in [\"yes\", \"y\"]:\n            return True\n        elif answer in [\"no\", \"n\"]:\n            return False\n\n\ndef ask_int(prompt: str) -> int:\n    while True:\n        answer = input(prompt)\n        try:\n            return int(answer)\n        except Exception:\n            pass\n\n\ndef get_offense_defense() -> Tuple[int, int]:\n    while True:\n        input_str = input(\"INPUT OFFENSIVE PLAY, DEFENSIVE PLAY: \")\n        try:\n            p1, p2 = (int(n) for n in input_str.split(\",\"))\n            return p1, p2\n        except Exception:\n            pass\n\n\ndef field_headers() -> None:\n    print(\"TEAM 1 [0   10   20   30   40   50   60   70   80   90   100] TEAM 2\")\n    print(\"\\n\\n\")\n\n\ndef separator() -> None:\n    print(\"+\" * 72 + \"\\n\")\n\n\ndef show_ball() -> None:\n    da: Tuple[int, int] = (0, 3)\n    print(\" \" * (da[t] + 5 + int(p / 2)) + marker[t] + \"\\n\")\n    field_headers()\n\n\ndef show_scores() -> bool:\n    print()\n    print(f\"TEAM 1 SCORE IS {score[0]}\")\n    print(f\"TEAM 2 SCORE IS {score[1]}\")\n    print()\n    if score[t] >= winning_score:\n        print(f\"TEAM {t+1} WINS*******************\")\n        return True\n    return False\n\n\ndef loss_posession() -> None:\n    global t\n    print()\n    print(f\"** LOSS OF POSSESSION FROM TEAM {t+1} TO TEAM {ta[t]+1}\")\n    print()\n    separator()\n    print()\n    t = ta[t]\n\n\ndef touchdown() -> None:\n    print()\n    print(f\"TOUCHDOWN BY TEAM {t+1} *********************YEA TEAM\")\n    q = 7\n    g = random()\n    if g <= 0.1:\n        q = 6\n        print(\"EXTRA POINT NO GOOD\")\n    else:\n        print(\"EXTRA POINT GOOD\")\n    score[t] = score[t] + q\n\n\ndef print_header() -> None:\n    print(\" \" * 32 + \"FOOTBALL\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\\n\\n\")\n\n\ndef print_instructions() -> None:\n    print(\n        \"\"\"THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST\nPREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,\n1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20\nTHESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS.\nA LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH\nBOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE\nPLAYS THE LESS YARDAGE GAINED.  SCORES ARE GIVEN\nWHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED\nBY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A\nFIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE\nASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER\nYOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO\nBOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO\nTRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO.\nTHE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C).\nPLEASE PREPARE A TAPE AND RUN.\n\"\"\"\n    )\n\n\ndef main() -> None:\n    global winning_score\n    print_header()\n    want_instructions = ask_bool(\"DO YOU WANT INSTRUCTIONS? \")\n    if want_instructions:\n        print_instructions()\n    print()\n    winning_score = ask_int(\"PLEASE INPUT SCORE LIMIT ON GAME: \")\n    for i in range(40):\n        index = player_data[i - 1]\n        if i < 20:\n            aa[index] = i\n        else:\n            ba[index] = i - 20\n        ca[i] = index\n    offset = 0\n    for t in [0, 1]:\n        print(f\"TEAM {t+1} PLAY CHART\")\n        print(\"NO.      PLAY\")\n        for i in range(20):\n            input_str = f\"{ca[i + offset]}\"\n            while len(input_str) < 6:\n                input_str += \" \"\n            input_str += actions[i]\n            print(input_str)\n        offset += 20\n        t = 1\n        print()\n        print(\"TEAR OFF HERE----------------------------------------------\")\n        print(\"\\n\" * 10)\n\n    field_headers()\n    print(\"TEAM 1 DEFEND 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.\")\n    t = randint(0, 1)\n    print()\n    print(\"THE COIN IS FLIPPED\")\n    routine = 1\n    while True:\n        if routine <= 1:\n            p = xa[t] - ya[t] * 40\n            separator()\n            print(f\"TEAM {t+1} RECEIVES KICK-OFF\")\n            k = floor(26 * random() + 40)\n        if routine <= 2:\n            p = p - ya[t] * k\n        if routine <= 3:\n            if wa[t] * p >= za[t] + 10:\n                print(\"BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--\")\n                p = za[t] - wa[t] * 20\n                if routine <= 4:\n                    routine = 5\n            else:\n                print(f\"BALL WENT {k} YARDS.  NOW ON {p}\")\n                show_ball()\n\n        if routine <= 4:\n            want_runback = ask_bool(f\"TEAM {t+1} DO YOU WANT TO RUNBACK? \")\n\n            if want_runback:\n                k = floor(9 * random() + 1)\n                r = floor(((xa[t] - ya[t] * p + 25) * random() - 15) / k)\n                p = p - wa[t] * r\n                print(f\"RUNBACK TEAM {t+1} {r} YARDS\")\n                g = random()\n                if g < 0.25:\n                    loss_posession()\n                    routine = 4\n                    continue\n                elif ya[t] * p >= xa[t]:\n                    touchdown()\n                    if show_scores():\n                        return\n                    t = ta[t]\n                    routine = 1\n                    continue\n                elif wa[t] * p >= za[t]:\n                    print(f\"SAFETY AGAINST TEAM {t+1} **********************OH-OH\")\n                    score[ta[t]] = score[ta[t]] + 2\n                    if show_scores():\n                        return\n\n                    p = za[t] - wa[t] * 20\n                    want_punt = ask_bool(\n                        f\"TEAM {t+1} DO YOU WANT TO PUNT INSTEAD OF A KICKOFF? \"\n                    )\n                    if want_punt:\n                        print(f\"TEAM {t+1} WILL PUNT\")\n                        g = random()\n                        if g < 0.25:\n                            loss_posession()\n                            routine = 4\n                            continue\n\n                        print()\n                        separator()\n                        k = floor(25 * random() + 35)\n                        t = ta[t]\n                        routine = 2\n                        continue\n\n                    touchdown()\n                    if show_scores():\n                        return\n                    t = ta[t]\n                    routine = 1\n                    continue\n                else:\n                    routine = 5\n                    continue\n\n            else:\n                if wa[t] * p >= za[t]:\n                    p = za[t] - wa[t] * 20\n\n        if routine <= 5:\n            d = 1\n            s = p\n\n        if routine <= 6:\n            print(\"=\" * 72 + \"\\n\")\n            print(f\"TEAM {t+1} DOWN {d} ON {p}\")\n            if d == 1:\n                if ya[t] * (p + ya[t] * 10) >= xa[t]:\n                    c = 8\n                else:\n                    c = 4\n\n            if c != 8:\n                yards = 10 - (ya[t] * p - ya[t] * s)\n                print(\" \" * 27 + f\"{yards} YARDS TO 1ST DOWN\")\n            else:\n                yards = xa[t] - ya[t] * p\n                print(\" \" * 27 + f\"{yards} YARDS\")\n\n            show_ball()\n            if d == 4:\n                routine = 8\n\n        if routine <= 7:\n            u = floor(3 * random() - 1)\n            while True:\n                p1, p2 = get_offense_defense()\n                if t != 1:\n                    p2, p1 = p1, p2\n\n                if p1 == 99:\n                    if show_scores():\n                        return\n                    if p1 == 99:\n                        continue\n\n                if p1 < 1 or p1 > 20 or p2 < 1 or p2 > 20:\n                    print(\"ILLEGAL PLAY NUMBER, CHECK AND \", end=\"\")\n                    continue\n\n                break\n            p1 -= 1\n            p2 -= 1\n\n        if d == 4 or p1 == 77:\n            want_punt = ask_bool(f\"DOES TEAM {t+1} WANT TO PUNT? \")\n\n            if want_punt:\n                print()\n                print(f\"TEAM {t+1} WILL PUNT\")\n                g = random()\n                if g < 0.25:\n                    loss_posession()\n                    routine = 4\n                    continue\n\n                print()\n                separator()\n                k = floor(25 * random() + 35)\n                t = ta[t]\n                routine = 2\n                continue\n\n            attempt_field_goal = ask_bool(\n                f\"DOES TEAM {t+1} WANT TO ATTEMPT A FIELD GOAL? \"\n            )\n\n            if attempt_field_goal:\n                print()\n                print(f\"TEAM {t+1} WILL ATTEMPT A FIELD GOAL\")\n                g = random()\n                if g < 0.025:\n                    loss_posession()\n                    routine = 4\n                    continue\n                else:\n                    f = floor(35 * random() + 20)\n                    print()\n                    print(f\"KICK IS {f} YARDS LONG\")\n                    p = p - wa[t] * f\n                    g = random()\n                    if g < 0.35:\n                        print(\"BALL WENT WIDE\")\n                    elif ya[t] * p >= xa[t]:\n                        print(\n                            f\"FIELD GOLD GOOD FOR TEAM {t+1} *********************YEA\"\n                        )\n                        q = 3\n                        score[t] = score[t] + q\n                        if show_scores():\n                            return\n                        t = ta[t]\n                        routine = 1\n                        continue\n\n                    print(f\"FIELD GOAL UNSUCCESFUL TEAM {t+1}-----------------TOO BAD\")\n                    print()\n                    separator()\n                    if ya[t] * p < xa[t] + 10:\n                        print()\n                        print(f\"BALL NOW ON {p}\")\n                        t = ta[t]\n                        show_ball()\n                        routine = 4\n                        continue\n                    else:\n                        t = ta[t]\n                        routine = 3\n                        continue\n\n            else:\n                routine = 7\n                continue\n\n        y = floor(\n            abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * random() - 15)\n        )\n        print()\n        if t == 1 and aa[p1] < 11 or t == 2 and ba[p2] < 11:\n            print(\"THE BALL WAS RUN\")\n        elif u == 0:\n            print(f\"PASS INCOMPLETE TEAM {t+1}\")\n            y = 0\n        else:\n            g = random()\n            if g <= 0.025 and y > 2:\n                print(\"PASS COMPLETED\")\n            else:\n                print(\"QUARTERBACK SCRAMBLED\")\n\n        p = p - wa[t] * y\n        print()\n        print(f\"NET YARDS GAINED ON DOWN {d} ARE {y}\")\n\n        g = random()\n        if g <= 0.025:\n            loss_posession()\n            routine = 4\n            continue\n        elif ya[t] * p >= xa[t]:\n            touchdown()\n            if show_scores():\n                return\n            t = ta[t]\n            routine = 1\n            continue\n        elif wa[t] * p >= za[t]:\n            print()\n            print(f\"SAFETY AGAINST TEAM {t+1} **********************OH-OH\")\n            score[ta[t]] = score[ta[t]] + 2\n            if show_scores():\n                return\n            p = za[t] - wa[t] * 20\n            want_punt = ask_bool(\n                f\"TEAM {t+1} DO YOU WANT TO PUNT INSTEAD OF A KICKOFF? \"\n            )\n            if want_punt:\n                print()\n                print(f\"TEAM {t+1} WILL PUNT\")\n                g = random()\n                if g < 0.25:\n                    loss_posession()\n                    routine = 4\n                    continue\n\n                print()\n                separator()\n                k = floor(25 * random() + 35)\n                t = ta[t]\n                routine = 2\n                continue\n\n            touchdown()\n            if show_scores():\n                return\n            t = ta[t]\n            routine = 1\n        elif ya[t] * p - ya[t] * s >= 10:\n            routine = 5\n        else:\n            d += 1\n            if d != 5:\n                routine = 6\n            else:\n                print()\n                print(f\"CONVERSION UNSUCCESSFUL TEAM {t+1}\")\n                t = ta[t]\n                print()\n                separator()\n                routine = 5\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "37_Football/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "37_Football/vbnet/Football.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Football\", \"Football.vbproj\", \"{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "37_Football/vbnet/Football.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Football</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "37_Football/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "38_Fur_Trader/README.md",
    "content": "### Fur Trader\n\nYou are the leader of a French fur trading expedition in 1776 leaving the Ontario area to sell furs and get supplies for the next year. You have a choice of three forts at which you may trade. The cost of supplies and the amount you recieve for your furs will depend upon the fort you choose. You also specify what types of furs that you have to trade.\n\nThe game goes on and on until you elect to trade no longer.\n\nAuthor of the program is Dan Bachor, University of Calgary, Alberta, Canada.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=69)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=84)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The value of some furs are not changed from the previous fort when you select fort 2 or 3.  As a result, you will get a different value for your firs depending on whether you have previously visited a different fort.  (All fur values are set when you visit Fort 1.)\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "38_Fur_Trader/c/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [ANSI-C](https://en.wikipedia.org/wiki/ANSI_C)\n\n##### Translator Notes:\nI tried to preserve as much of the original layout and flow of the code\nas possible.  However I did use enumerated types for the Fort numbers\nand Fur types.  I think this was certainly a change for the better, and\nmakes the code much easier to read.\n\nI also tried to minimise the use of pointers, and stuck with old-school\nC formatting, because you never know how old the compiler is.\n\nInterestingly the code seems to have a bug around the prices of Fox Furs.\nThe commodity-rate for these is stored in the variable `D1`, however some\npaths through the code do not set this price.  So there was a chance of\nusing this uninitialised, or whatever the previous loop set.  I don't\nthink this was the original authors intent.  So I preserved the original flow\nof the code (using the previous `D1` value), but also catching the\nuninitialised path, and assigning a \"best guess\" value.\n\nkrt@krt.com.au 2020-10-10\n"
  },
  {
    "path": "38_Fur_Trader/c/furtrader.c",
    "content": "\n/*\n * Ported from furtrader.bas to ANSI C (C99) by krt@krt.com.au\n *\n * compile with:\n *    gcc -g -Wall -Werror furtrader.c -o furtrader\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n\n/* Constants */\n#define FUR_TYPE_COUNT    4\n#define FUR_MINK          0\n#define FUR_BEAVER        1\n#define FUR_ERMINE        2\n#define FUR_FOX           3\n#define MAX_FURS        190\nconst char *FUR_NAMES[FUR_TYPE_COUNT] = { \"MINK\", \"BEAVER\", \"ERMINE\", \"FOX\" };\n\n#define FORT_TYPE_COUNT 3\n#define FORT_MONTREAL   1\n#define FORT_QUEBEC     2\n#define FORT_NEWYORK    3\nconst char *FORT_NAMES[FORT_TYPE_COUNT] = { \"HOCHELAGA (MONTREAL)\", \"STADACONA (QUEBEC)\", \"NEW YORK\" };\n\n\n\n/* Print the words at the specified column */\nvoid printAtColumn( int column, const char *words )\n{\n    int i;\n    for ( i=0; i<column; i++ )\n        printf( \" \" );\n    printf( \"%s\\n\", words );\n}\n\n/* trivial function to output a line with a \\n */\nvoid print( const char *words )\n{\n    printf( \"%s\\n\", words );\n}\n\n/* Show the player the introductory message */\nvoid showIntroduction()\n{\n    print( \"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \" );\n    print( \"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\" );\n    print( \"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\" );\n    print( \"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\" );\n    print( \"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\" );\n    print( \"ON THE FORT THAT YOU CHOOSE.\" );\n    print( \"\" );\n}\n\n\n/*\n * Prompt the user for input.\n * When input is given, try to conver it to an integer\n * return the integer converted value or 0 on error\n */\nint getNumericInput()\n{\n    int  result = -1;\n    char buffer[64];   /* somewhere to store user input */\n    char *endstr;\n\n    while ( result == -1 )\n    {\n        printf( \">> \" );                                 /* prompt the user */\n        fgets( buffer, sizeof( buffer ), stdin );        /* read from the console into the buffer */\n        result = (int)strtol( buffer, &endstr, 10 );     /* only simple error checking */\n\n        if ( endstr == buffer )                          /* was the string -> integer ok? */\n            result = -1;\n    }\n\n    return result;\n}\n\n\n/*\n * Prompt the user for YES/NO input.\n * When input is given, try to work out if it's YES, Yes, yes, Y, etc.\n * And convert to a single upper-case letter\n * Returns a character of 'Y' or 'N'.\n */\nchar getYesOrNo()\n{\n    char result = '!';\n    char buffer[64];   /* somewhere to store user input */\n\n    while ( !( result == 'Y' || result == 'N' ) )       /* While the answer was not Yes or No */\n    {\n        print( \"ANSWER YES OR NO\" );\n        printf( \">> \" );\n\n        fgets( buffer, sizeof( buffer ), stdin );            /* read from the console into the buffer */\n        if ( buffer[0] == 'Y' || buffer[0] == 'y' )\n            result = 'Y';\n        else if ( buffer[0] == 'N' || buffer[0] == 'n' )\n            result = 'N';\n    }\n\n    return result;\n}\n\n\n\n/*\n * Show the player the choices of Fort, get their input, if the\n * input is a valid choice (1,2,3) return it, otherwise keep\n * prompting the user.\n */\nint getFortChoice()\n{\n    int result = 0;\n\n    while ( result == 0 )\n    {\n        print( \"\" );\n        print( \"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\" );\n        print( \"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\" );\n        print( \"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\" );\n        print( \"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\" );\n        print( \"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\" );\n        print( \"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\" );\n        print( \"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\" );\n        print( \"YOU MUST CROSS THROUGH IROQUOIS LAND.\" );\n        print( \"ANSWER 1, 2, OR 3.\" );\n\n        result = getNumericInput();   /* get input from the player */\n    }\n\n    return result;\n}\n\n\n/*\n * Print the description for the fort\n */\nvoid showFortComment( int which_fort )\n{\n    print( \"\" );\n    if ( which_fort == FORT_MONTREAL )\n    {\n        print( \"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\" );\n        print( \"IS FAR FROM ANY SEAPORT.  THE VALUE\" );\n        print( \"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\" );\n        print( \"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\" );\n    }\n    else if ( which_fort == FORT_QUEBEC )\n    {\n        print( \"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\" );\n        print( \"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\" );\n        print( \"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\" );\n        print( \"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\" );\n    }\n    else if ( which_fort == FORT_NEWYORK )\n    {\n        print( \"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\" );\n        print( \"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\" );\n        print( \"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\" );\n        print( \"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\" );\n    }\n    else\n    {\n        printf( \"Internal error #1, fort %d does not exist\\n\", which_fort );\n        exit( 1 );  /* you have a bug */\n    }\n    print( \"\" );\n}\n\n\n/*\n * Prompt the player for how many of each fur type they want.\n * Accept numeric inputs, re-prompting on incorrect input values\n */\nvoid getFursPurchase( int *furs )\n{\n    int i;\n\n    printf( \"YOUR %d FURS ARE DISTRIBUTED AMONG THE FOLLOWING\\n\", FUR_TYPE_COUNT );\n    print( \"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\" );\n    print( \"\" );\n\n    for ( i=0; i<FUR_TYPE_COUNT; i++ )\n    {\n        printf( \"HOW MANY %s DO YOU HAVE\\n\", FUR_NAMES[i] );\n        furs[i] = getNumericInput();\n    }\n}\n\n\n/*\n * (Re)Set the player's inventory to zero\n */\nvoid zeroInventory( int *player_fur_count )\n{\n    int i;\n    for ( i=0; i<FUR_TYPE_COUNT; i++ )\n    {\n        player_fur_count[i] = 0;\n    }\n}\n\n\n/*\n * Tally the player's inventory\n */\nint sumInventory( int *player_fur_count )\n{\n    int result = 0;\n    int i;\n    for ( i=0; i<FUR_TYPE_COUNT; i++ )\n    {\n        result += player_fur_count[i];\n    }\n\n    return result;\n}\n\n\n/*\n * Return a random number between a & b\n * Ref: https://stackoverflow.com/a/686376/1730895\n */\nfloat randomAB(float a, float b)\n{\n    return ((b - a) * ((float)rand() / (float)RAND_MAX)) + a;\n}\n/* Random floating point number between 0 and 1 */\nfloat randFloat()\n{\n    return randomAB( 0, 1 );\n}\n\n\n/* States to allow switching in main game-loop */\n#define STATE_STARTING      1\n#define STATE_CHOOSING_FORT 2\n#define STATE_TRAVELLING    3\n#define STATE_TRADING       4\n\nint main( void )\n{\n    /* variables for storing player's status */\n    float player_funds = 0;                              /* no money */\n    int   player_furs[FUR_TYPE_COUNT]  = { 0, 0, 0, 0 }; /* no furs */\n\n    /* player input holders */\n    char  yes_or_no;\n    int   event_picker;\n    int   which_fort;\n\n    /* what part of the game is in play */\n    int   game_state = STATE_STARTING;\n\n    /* commodity prices */\n    float mink_price   = -1;\n    float beaver_price = -1;\n    float ermine_price = -1;\n    float fox_price    = -1;  /* sometimes this takes the \"last\" price (probably this was a bug) */\n\n    float mink_value;\n    float beaver_value;\n    float ermine_value;\n    float fox_value;      /* for calculating sales results */\n\n\n    srand( time( NULL ) );  /* seed the random number generator */\n\n    printAtColumn( 31, \"FUR TRADER\" );\n    printAtColumn( 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\" );\n    printAtColumn( 15, \"(Ported to ANSI-C Oct 2012 krt@krt.com.au)\" );\n    print( \"\\n\\n\\n\" );\n\n    /* Loop forever until the player asks to quit */\n    while ( 1 )\n    {\n        if ( game_state == STATE_STARTING )\n        {\n            showIntroduction();\n\n            player_funds = 600;            /* Initial player start money */\n            zeroInventory( player_furs );  /* Player fur inventory */\n\n            print( \"DO YOU WISH TO TRADE FURS?\" );\n            yes_or_no = getYesOrNo();\n            if ( yes_or_no == 'N' )\n                exit( 0 );                 /* STOP */\n            game_state = STATE_TRADING;\n        }\n\n        else if ( game_state == STATE_TRADING )\n        {\n            print( \"\" );\n            printf( \"YOU HAVE $ %1.2f IN SAVINGS\\n\", player_funds );\n            printf( \"AND %d FURS TO BEGIN THE EXPEDITION\\n\", MAX_FURS );\n            getFursPurchase( player_furs );\n\n            if ( sumInventory( player_furs ) > MAX_FURS )\n            {\n                print( \"\" );\n                print( \"YOU MAY NOT HAVE THAT MANY FURS.\" );\n                print( \"DO NOT TRY TO CHEAT.  I CAN ADD.\" );\n                print( \"YOU MUST START AGAIN.\" );\n                print( \"\" );\n                game_state = STATE_STARTING;   /* T/N: Wow, harsh. */\n            }\n            else\n            {\n                game_state = STATE_CHOOSING_FORT;\n            }\n        }\n\n        else if ( game_state == STATE_CHOOSING_FORT )\n        {\n            which_fort = getFortChoice();\n            showFortComment( which_fort );\n            print( \"DO YOU WANT TO TRADE AT ANOTHER FORT?\" );\n            yes_or_no = getYesOrNo();\n            if ( yes_or_no == 'N' )\n                game_state = STATE_TRAVELLING;\n        }\n\n        else if ( game_state == STATE_TRAVELLING )\n        {\n            print( \"\" );\n            if ( which_fort == FORT_MONTREAL )\n            {\n                mink_price   = ( ( 0.2 * randFloat() + 0.70 ) * 100 + 0.5 ) / 100;\n                ermine_price = ( ( 0.2 * randFloat() + 0.65 ) * 100 + 0.5 ) / 100;\n                beaver_price = ( ( 0.2 * randFloat() + 0.75 ) * 100 + 0.5 ) / 100;\n                fox_price    = ( ( 0.2 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;\n\n                print( \"SUPPLIES AT FORT HOCHELAGA COST $150.00.\" );\n                print( \"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\" );\n                player_funds -= 160;\n            }\n\n            else if ( which_fort == FORT_QUEBEC )\n            {\n                mink_price   = ( ( 0.30 * randFloat() + 0.85 ) * 100 + 0.5 ) / 100;\n                ermine_price = ( ( 0.15 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;\n                beaver_price = ( ( 0.20 * randFloat() + 0.90 ) * 100 + 0.5 ) / 100;\n                fox_price    = ( ( 0.25 * randFloat() + 1.10 ) * 100 + 0.5 ) / 100;\n                event_picker = ( 10 * randFloat() ) + 1;\n\n                if ( event_picker <= 2 )\n                {\n                    print( \"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\" );\n                    print( \"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\" );\n                    print( \"THEM STOLEN WHEN YOU RETURNED.\" );\n                    player_furs[ FUR_BEAVER ] = 0;\n                }\n                else if ( event_picker <= 6 )\n                {\n                    print( \"YOU ARRIVED SAFELY AT FORT STADACONA.\" );\n                }\n                else if ( event_picker <= 8 )\n                {\n                    print( \"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\" );\n                    print( \"LOST ALL YOUR FURS.\" );\n                    zeroInventory( player_furs );\n                }\n                else if ( event_picker <= 10 )\n                {\n                    print( \"YOUR FOX PELTS WERE NOT CURED PROPERLY.\" );\n                    print( \"NO ONE WILL BUY THEM.\" );\n                    player_furs[ FUR_FOX ] = 0;\n                }\n                else\n                {\n                    printf( \"Internal Error #3, Out-of-bounds event_picker %d\\n\", event_picker );\n                    exit( 1 );  /* you have a bug */\n                }\n\n                print( \"\" );\n                print( \"SUPPLIES AT FORT STADACONA COST $125.00.\" );\n                print( \"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\" );\n                player_funds -= 140;\n            }\n\n            else if ( which_fort == FORT_NEWYORK )\n            {\n                mink_price   = ( ( 0.15 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100;\n                ermine_price = ( ( 0.15 * randFloat() + 0.95 ) * 100 + 0.5 ) / 100;\n                beaver_price = ( ( 0.25 * randFloat() + 1.00 ) * 100 + 0.5 ) / 100;\n                if ( fox_price < 0 )\n                {\n                    /* Original Bug?  There is no Fox price generated for New York,\n                       it will use any previous \"D1\" price.\n                       So if there was no previous value, make one up */\n                    fox_price = ( ( 0.25 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100; /* not in orginal code */\n                }\n                event_picker = ( 10 * randFloat() ) + 1;\n\n                if ( event_picker <= 2 )\n                {\n                    print( \"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\" );\n                    print( \"ALL PEOPLE IN YOUR TRADING GROUP WERE\" );\n                    print( \"KILLED.  THIS ENDS THE GAME.\" );\n                    exit( 0 );\n                }\n                else if ( event_picker <= 6 )\n                {\n                    print( \"YOU WERE LUCKY.  YOU ARRIVED SAFELY\" );\n                    print( \"AT FORT NEW YORK.\" );\n                }\n                else if ( event_picker <= 8 )\n                {\n                    print( \"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\" );\n                    print( \"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\" );\n                    zeroInventory( player_furs );\n                }\n                else if ( event_picker <= 10 )\n                {\n                    mink_price /= 2;\n                    fox_price  /= 2;\n                    print( \"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\" );\n                    print( \"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\" );\n                }\n                else\n                {\n                    print( \"Internal Error #4, Out-of-bounds event_picker %d\\n\" );\n                    exit( 1 );  /* you have a bug */\n                }\n\n                print( \"\" );\n                print( \"SUPPLIES AT NEW YORK COST $85.00.\" );\n                print( \"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\" );\n                player_funds -= 105;\n            }\n\n            else\n            {\n                printf( \"Internal error #2, fort %d does not exist\\n\", which_fort );\n                exit( 1 );  /* you have a bug */\n            }\n\n            /* Calculate sales */\n            beaver_value = beaver_price * player_furs[ FUR_BEAVER ];\n            fox_value    = fox_price    * player_furs[ FUR_FOX ];\n            ermine_value = ermine_price * player_furs[ FUR_ERMINE ];\n            mink_value   = mink_price   * player_furs[ FUR_MINK ];\n\n            print( \"\" );\n            printf( \"YOUR BEAVER SOLD FOR $%6.2f\\n\", beaver_value );\n            printf( \"YOUR FOX SOLD FOR    $%6.2f\\n\", fox_value );\n            printf( \"YOUR ERMINE SOLD FOR $%6.2f\\n\", ermine_value );\n            printf( \"YOUR MINK SOLD FOR   $%6.2f\\n\", mink_value );\n\n            player_funds += beaver_value + fox_value + ermine_value + mink_value;\n\n            print( \"\" );\n            printf( \"YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS\\n\", player_funds );\n\n            print( \"\" );\n            print( \"DO YOU WANT TO TRADE FURS NEXT YEAR?\" );\n            yes_or_no = getYesOrNo();\n            if ( yes_or_no == 'N' )\n                exit( 0 );             /* STOP */\n            else\n                game_state = STATE_TRADING;\n\n        }\n    }\n\n    return 0; /* exit OK */\n}\n"
  },
  {
    "path": "38_Fur_Trader/csharp/FurTrader.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "38_Fur_Trader/csharp/FurTrader.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30804.86\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"FurTrader\", \"FurTrader.csproj\", \"{1FB826B9-8794-4DB7-B676-B51F177B7B87}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {DDB24448-50EB-47C6-BDB9-465896A81779}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "38_Fur_Trader/csharp/Game.cs",
    "content": "﻿using System;\n\nnamespace FurTrader\n{\n    public class Game\n    {\n        /// <summary>\n        /// random number generator; no seed to be faithful to original implementation\n        /// </summary>\n        private Random Rnd { get; } = new Random();\n\n        /// <summary>\n        /// Generate a price for pelts based off a factor and baseline value\n        /// </summary>\n        /// <param name=\"factor\">Multiplier for the price</param>\n        /// <param name=\"baseline\">The baseline price</param>\n        /// <returns>A randomised price for pelts</returns>\n        internal double RandomPriceGenerator(double factor, double baseline)\n        {\n            var price = (Convert.ToInt32((factor * Rnd.NextDouble() + baseline) * 100d) + 5) / 100d;\n            return price;\n        }\n\n        /// <summary>\n        /// Main game loop function. This will play the game endlessly until the player chooses to quit or a GameOver event occurs\n        /// </summary>\n        /// <remarks>\n        /// General structure followed from Adam Dawes (@AdamDawes575) implementation of Acey Ducey.\");\n        /// </remarks>\n        internal void GameLoop()\n        {\n            // display instructions to the player\n            DisplayIntroText();\n\n            var state = new GameState();\n\n            // loop for each turn until the player decides not to continue (or has a Game Over event)\n            while ((!state.GameOver) && ContinueGame())\n            {\n                // clear display at start of each turn\n                Console.Clear();\n\n                // play the next turn; pass game state for details and updates from the turn\n                PlayTurn(state);\n            }\n\n            // end screen; show some statistics to the player\n            Console.Clear();\n            Console.WriteLine(\"Thanks for playing!\");\n            Console.WriteLine(\"\");\n            Console.WriteLine($\"Total Expeditions: {state.ExpeditionCount}\");\n            Console.WriteLine($\"Final Amount:      {state.Savings.ToString(\"c\")}\");\n        }\n\n        /// <summary>\n        /// Display instructions on how to play the game and wait for the player to press a key.\n        /// </summary>\n        private void DisplayIntroText()\n        {\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"Fur Trader.\");\n            Console.WriteLine(\"Creating Computing, Morristown, New Jersey.\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.DarkGreen;\n            Console.WriteLine(\"Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.Gray;\n            Console.WriteLine(\"You are the leader of a French fur trading expedition in 1776 leaving the Lake Ontario area to sell furs and get supplies for the next year.\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"You have a choice of three forts at which you may trade. The cost of supplies and the amount you receive for your furs will depend on the fort that you choose.\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"Press any key start the game.\");\n            Console.ReadKey(true);\n\n        }\n\n        /// <summary>\n        /// Prompt the player to try again, and wait for them to press Y or N.\n        /// </summary>\n        /// <returns>Returns true if the player wants to try again, false if they have finished playing.</returns>\n        private bool ContinueGame()\n        {\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"Do you wish to trade furs? \");\n            Console.Write(\"Answer (Y)es or (N)o \");\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.Write(\"> \");\n\n            char pressedKey;\n            // Keep looping until we get a recognised input\n            do\n            {\n                // Read a key, don't display it on screen\n                ConsoleKeyInfo key = Console.ReadKey(true);\n                // Convert to upper-case so we don't need to care about capitalisation\n                pressedKey = Char.ToUpper(key.KeyChar);\n                // Is this a key we recognise? If not, keep looping\n            } while (pressedKey != 'Y' && pressedKey != 'N');\n\n            // Display the result on the screen\n            Console.WriteLine(pressedKey);\n\n            // Return true if the player pressed 'Y', false for anything else.\n            return (pressedKey == 'Y');\n        }\n\n        /// <summary>\n        /// Play a turn\n        /// </summary>\n        /// <param name=\"state\">The current game state</param>\n        private void PlayTurn(GameState state)\n        {\n            state.UnasignedFurCount = 190;      /// start with 190 furs each turn\n\n            // provide current status to user\n            Console.WriteLine(new string('_', 70));\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n            Console.WriteLine($\"You have {state.Savings.ToString(\"c\")} savings and {state.UnasignedFurCount} furs to begin the expedition.\");\n            Console.WriteLine(\"\");\n            Console.WriteLine($\"Your {state.UnasignedFurCount} furs are distributed among the following kinds of pelts: Mink, Beaver, Ermine, and Fox\");\n            Console.WriteLine(\"\");\n\n            // get input on number of pelts\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write(\"How many Mink pelts do you have? \");\n            state.MinkPelts = GetPelts(state.UnasignedFurCount);\n            state.UnasignedFurCount -= state.MinkPelts;\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine($\"You have {state.UnasignedFurCount} furs remaining for distribution\");\n            Console.Write(\"How many Beaver pelts do you have? \");\n            state.BeaverPelts = GetPelts(state.UnasignedFurCount);\n            state.UnasignedFurCount -= state.BeaverPelts;\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine($\"You have {state.UnasignedFurCount} furs remaining for distribution\");\n            Console.Write(\"How many Ermine pelts do you have? \");\n            state.ErminePelts = GetPelts(state.UnasignedFurCount);\n            state.UnasignedFurCount -= state.ErminePelts;\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine($\"You have {state.UnasignedFurCount} furs remaining for distribution\");\n            Console.Write(\"How many Fox pelts do you have? \");\n            state.FoxPelts = GetPelts(state.UnasignedFurCount);\n            state.UnasignedFurCount -= state.FoxPelts;\n\n            // get input on which fort to trade with; user gets an opportunity to evaluate and re-select fort after selection until user confirms selection\n            do\n            {\n                Console.ForegroundColor = ConsoleColor.White;\n                Console.WriteLine(\"\");\n                Console.WriteLine(\"Do you want to trade your furs at Fort 1, Fort 2, or Fort 3\");\n                Console.WriteLine(\"Fort 1 is Fort Hochelaga (Montreal) and is under the protection of the French army.\");\n                Console.WriteLine(\"Fort 2 is Fort Stadacona (Quebec) and is under the protection of the French army. However, you must make a portage and cross the Lachine rapids.\");\n                Console.WriteLine(\"Fort 3 is Fort New York and is under Dutch control. You must cross through Iroquois land.\");\n                Console.WriteLine(\"\");\n                state.SelectedFort = GetSelectedFort();\n\n                DisplaySelectedFortInformation(state.SelectedFort);\n\n            } while (TradeAtAnotherFort());\n\n            // process the travel to the fort\n            ProcessExpeditionOutcome(state);\n\n            // display results of expedition (savings change) to the user\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write(\"You now have \");\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.Write($\"{state.Savings.ToString(\"c\")}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\" including your previous savings.\");\n\n            // update the turn count now that another turn has been played\n            state.ExpeditionCount += 1;\n        }\n\n        /// <summary>\n        /// Method to show the expedition costs to the player with some standard formatting\n        /// </summary>\n        /// <param name=\"fortname\">The name of the fort traded with</param>\n        /// <param name=\"supplies\">The cost of the supplies at the fort</param>\n        /// <param name=\"expenses\">The travel expenses for the expedition</param>\n        internal void DisplayCosts(string fortname, double supplies, double expenses)\n        {\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write($\"Supplies at {fortname} cost\".PadLeft(55));\n            Console.ForegroundColor = ConsoleColor.Red;\n            Console.WriteLine($\"{supplies.ToString(\"c\").PadLeft(10)}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write($\"Your travel expenses to {fortname} were\".PadLeft(55));\n            Console.ForegroundColor = ConsoleColor.Red;\n            Console.WriteLine($\"{expenses.ToString(\"c\").PadLeft(10)}\");\n            Console.ForegroundColor = ConsoleColor.White;\n        }\n\n        /// <summary>\n        /// Process the results of the expedition\n        /// </summary>\n        /// <param name=\"state\">the game state</param>\n        private void ProcessExpeditionOutcome(GameState state)\n        {\n            var beaverPrice = RandomPriceGenerator(0.25d, 1.00d);\n            var foxPrice =    RandomPriceGenerator(0.2d , 0.80d);\n            var erminePrice = RandomPriceGenerator(0.15d, 0.95d);\n            var minkPrice =   RandomPriceGenerator(0.2d , 0.70d);\n\n            var fortname = String.Empty;\n            var suppliesCost = 0.0d;\n            var travelExpenses = 0.0d;\n\n            // create a random value 1 to 10 for the different outcomes at each fort\n            var p = ((int)(10 * Rnd.NextDouble())) + 1;\n            Console.WriteLine(\"\");\n\n            switch (state.SelectedFort)\n            {\n                case 1:     // outcome for expedition to Fort Hochelaga\n                    beaverPrice = RandomPriceGenerator(0.2d, 0.75d);\n                    foxPrice =    RandomPriceGenerator(0.2d, 0.80d);\n                    erminePrice = RandomPriceGenerator(0.2d, 0.65d);\n                    minkPrice =   RandomPriceGenerator(0.2d, 0.70d);\n                    fortname = \"Fort Hochelaga\";\n                    suppliesCost = 150.0d;\n                    travelExpenses = 10.0d;\n                    break;\n                case 2:     // outcome for expedition to Fort Stadacona\n                    beaverPrice = RandomPriceGenerator(0.2d , 0.90d);\n                    foxPrice =    RandomPriceGenerator(0.2d , 0.80d);\n                    erminePrice = RandomPriceGenerator(0.15d, 0.80d);\n                    minkPrice =   RandomPriceGenerator(0.3d , 0.85d);\n                    fortname = \"Fort Stadacona\";\n                    suppliesCost = 125.0d;\n                    travelExpenses = 15.0d;\n                    if (p <= 2)\n                    {\n                        state.BeaverPelts = 0;\n                        Console.WriteLine(\"Your beaver were to heavy to carry across the portage.\");\n                        Console.WriteLine(\"You had to leave the pelts but found them stolen when you returned\");\n                    }\n                    else if (p <= 6)\n                    {\n                        Console.WriteLine(\"You arrived safely at Fort Stadacona\");\n                    }\n                    else if (p <= 8)\n                    {\n                        state.BeaverPelts = 0;\n                        state.FoxPelts = 0;\n                        state.ErminePelts = 0;\n                        state.MinkPelts = 0;\n                        Console.WriteLine(\"Your canoe upset in the Lachine Rapids.\");\n                        Console.WriteLine(\"Your lost all your furs\");\n                    }\n                    else if (p <= 10)\n                    {\n                        state.FoxPelts = 0;\n                        Console.WriteLine(\"Your fox pelts were not cured properly.\");\n                        Console.WriteLine(\"No one will buy them.\");\n                    }\n                    else\n                    {\n                        throw new Exception($\"Unexpected Outcome p = {p}\");\n                    }\n                    break;\n                case 3:     // outcome for expedition to Fort New York\n                    beaverPrice = RandomPriceGenerator(0.2d , 1.00d);\n                    foxPrice =    RandomPriceGenerator(0.25d, 1.10d);\n                    erminePrice = RandomPriceGenerator(0.2d , 0.95d);\n                    minkPrice =   RandomPriceGenerator(0.15d, 1.05d);\n                    fortname = \"Fort New York\";\n                    suppliesCost = 80.0d;\n                    travelExpenses = 25.0d;\n                    if (p <= 2)\n                    {\n                        state.BeaverPelts = 0;\n                        state.FoxPelts = 0;\n                        state.ErminePelts = 0;\n                        state.MinkPelts = 0;\n                        suppliesCost = 0.0d;\n                        travelExpenses = 0.0d;\n                        Console.WriteLine(\"You were attacked by a party of Iroquois.\");\n                        Console.WriteLine(\"All people in your trading group were killed.\");\n                        Console.WriteLine(\"This ends the game (press any key).\");\n                        Console.ReadKey(true);\n                        state.GameOver = true;\n                    }\n                    else if (p <= 6)\n                    {\n                        Console.WriteLine(\"You were lucky. You arrived safely at Fort New York.\");\n                    }\n                    else if (p <= 8)\n                    {\n                        state.BeaverPelts = 0;\n                        state.FoxPelts = 0;\n                        state.ErminePelts = 0;\n                        state.MinkPelts = 0;\n                        Console.WriteLine(\"You narrowly escaped an Iroquois raiding party.\");\n                        Console.WriteLine(\"However, you had to leave all your furs behind.\");\n                    }\n                    else if (p <= 10)\n                    {\n                        beaverPrice = beaverPrice / 2;\n                        minkPrice = minkPrice / 2;\n                        Console.WriteLine(\"Your mink and beaver were damaged on your trip.\");\n                        Console.WriteLine(\"You receive only half the current price for these furs.\");\n                    }\n                    else\n                    {\n                        throw new Exception($\"Unexpected Outcome p = {p}\");\n                    }\n                    break;\n                default:\n                    break;\n            }\n\n            var beaverSale = state.BeaverPelts * beaverPrice;\n            var foxSale = state.FoxPelts * foxPrice;\n            var ermineSale = state.ErminePelts * erminePrice;\n            var minkSale = state.MinkPelts * minkPrice;\n            var profit = beaverSale + foxSale + ermineSale + minkSale - suppliesCost - travelExpenses;\n            state.Savings += profit;\n\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write($\"Your {state.BeaverPelts.ToString().PadLeft(3, ' ')} beaver pelts sold @ {beaverPrice.ToString(\"c\")} per pelt for a total\");\n            Console.ForegroundColor = ConsoleColor.Green;\n            Console.WriteLine($\"{beaverSale.ToString(\"c\").PadLeft(10)}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write($\"Your {state.FoxPelts.ToString().PadLeft(3, ' ')} fox    pelts sold @ {foxPrice.ToString(\"c\")} per pelt for a total\");\n            Console.ForegroundColor = ConsoleColor.Green;\n            Console.WriteLine($\"{foxSale.ToString(\"c\").PadLeft(10)}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write($\"Your {state.ErminePelts.ToString().PadLeft(3, ' ')} ermine pelts sold @ {erminePrice.ToString(\"c\")} per pelt for a total\");\n            Console.ForegroundColor = ConsoleColor.Green;\n            Console.WriteLine($\"{ermineSale.ToString(\"c\").PadLeft(10)}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.Write($\"Your {state.MinkPelts.ToString().PadLeft(3, ' ')} mink   pelts sold @ {minkPrice.ToString(\"c\")} per pelt for a total\");\n            Console.ForegroundColor = ConsoleColor.Green;\n            Console.WriteLine($\"{minkSale.ToString(\"c\").PadLeft(10)}\");\n            Console.WriteLine(\"\");\n            DisplayCosts(fortname, suppliesCost, travelExpenses);\n            Console.WriteLine(\"\");\n            Console.Write($\"Profit / Loss\".PadLeft(55));\n            Console.ForegroundColor = profit >= 0.0d ? ConsoleColor.Green : ConsoleColor.Red;\n            Console.WriteLine($\"{profit.ToString(\"c\").PadLeft(10)}\");\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n        }\n\n        private void DisplaySelectedFortInformation(int selectedFort)\n        {\n            Console.WriteLine(\"\");\n            Console.ForegroundColor = ConsoleColor.White;\n\n            switch (selectedFort)\n            {\n                case 1:    // selected fort details for Fort Hochelaga\n                    Console.WriteLine(\"You have chosen the easiest route.\");\n                    Console.WriteLine(\"However, the fort is far from any seaport.\");\n                    Console.WriteLine(\"The value you receive for your furs will be low.\");\n                    Console.WriteLine(\"The cost of supplies will be higher than at Forts Stadacona or New York\");\n                    break;\n                case 2:    // selected fort details for Fort Stadacona\n                    Console.WriteLine(\"You have chosen a hard route.\");\n                    Console.WriteLine(\"It is, in comparsion, harder than the route to Hochelaga but easier than the route to New York.\");\n                    Console.WriteLine(\"You will receive an average value for your furs.\");\n                    Console.WriteLine(\"The cost of your supplies will be average.\");\n                    break;\n                case 3:    // selected fort details for Fort New York\n                    Console.WriteLine(\"You have chosen the most difficult route.\");\n                    Console.WriteLine(\"At Fort New York you will receive the higest value for your furs.\");\n                    Console.WriteLine(\"The cost of your supplies will be lower than at all the other forts.\");\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        private bool TradeAtAnotherFort()\n        {\n            Console.ForegroundColor = ConsoleColor.White;\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"Do you want to trade at another fort?\");\n            Console.Write(\"Answer (Y)es or (N)o \");\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.Write(\"> \");\n\n            char pressedKey;\n            // Keep looping until we get a recognised input\n            do\n            {\n                // Read a key, don't display it on screen\n                ConsoleKeyInfo key = Console.ReadKey(true);\n                // Convert to upper-case so we don't need to care about capitalisation\n                pressedKey = Char.ToUpper(key.KeyChar);\n                // Is this a key we recognise? If not, keep looping\n            } while (pressedKey != 'Y' && pressedKey != 'N');\n\n            // Display the result on the screen\n            Console.WriteLine(pressedKey);\n\n            // Return true if the player pressed 'Y', false for anything else.\n            return (pressedKey == 'Y');\n        }\n\n        /// <summary>\n        /// Get an amount of pelts from the user\n        /// </summary>\n        /// <param name=\"currentMoney\">The total pelts available</param>\n        /// <returns>Returns the amount the player selects</returns>\n        private int GetPelts(int furCount)\n        {\n            int peltCount;\n\n            // loop until the user enters a valid value\n            do\n            {\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.Write(\"> \");\n                string input = Console.ReadLine();\n\n                // parse user information to check if it is a valid entry\n                if (!int.TryParse(input, out peltCount))\n                {\n                    // invalid entry; message back to user\n                    Console.ForegroundColor = ConsoleColor.Red;\n                    Console.WriteLine(\"Sorry, I didn't understand. Please enter the number of pelts.\");\n\n                    // continue looping\n                    continue;\n                }\n\n                // check if plet amount is more than the available pelts\n                if (peltCount > furCount)\n                {\n                    // too many pelts selected\n                    Console.ForegroundColor = ConsoleColor.Red;\n                    Console.WriteLine($\"You may not have that many furs. Do not try to cheat. I can add.\");\n\n                    // continue looping\n                    continue;\n                }\n\n                // valid pelt amount entered\n                break;\n            } while (true);\n\n            // return pelt count to the user\n            return peltCount;\n        }\n\n        /// <summary>\n        /// Prompt the user for their selected fort\n        /// </summary>\n        /// <returns>returns the fort the user has selected</returns>\n        private int GetSelectedFort()\n        {\n            int selectedFort;\n\n            // loop until the user enters a valid value\n            do\n            {\n                Console.ForegroundColor = ConsoleColor.White;\n                Console.Write(\"Answer 1, 2, or 3 \");\n                Console.ForegroundColor = ConsoleColor.Yellow;\n                Console.Write(\"> \");\n                string input = Console.ReadLine();\n\n                // is the user entry valid\n                if (!int.TryParse(input, out selectedFort))\n                {\n                    // no, invalid data\n                    Console.ForegroundColor = ConsoleColor.Red;\n                    Console.WriteLine(\"Sorry, I didn't understand. Please answer 1, 2, or 3.\");\n\n                    // continue looping\n                    continue;\n                }\n\n                // is the selected fort an option (one, two or three only)\n                if (selectedFort != 1 && selectedFort != 2 && selectedFort != 3)\n                {\n                    // no, invalid for selected\n                    Console.ForegroundColor = ConsoleColor.Red;\n                    Console.WriteLine($\"Please answer 1, 2, or 3.\");\n\n                    // continue looping\n                    continue;\n                }\n\n                // valid fort selected, stop looping\n                break;\n            } while (true);\n\n            // return the players selected fort\n            return selectedFort;\n        }\n    }\n}\n"
  },
  {
    "path": "38_Fur_Trader/csharp/GameState.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FurTrader\n{\n    internal class GameState\n    {\n        internal bool GameOver { get; set; }\n\n        internal double Savings { get; set; }\n\n        internal int ExpeditionCount { get; set; }\n\n        internal int UnasignedFurCount { get; set; }\n\n        internal int[] Pelts { get; private set; }\n\n        internal int MinkPelts { get { return this.Pelts[0]; } set { this.Pelts[0] = value; } }\n        internal int BeaverPelts { get { return this.Pelts[1]; } set { this.Pelts[1] = value; } }\n        internal int ErminePelts { get { return this.Pelts[2]; } set { this.Pelts[2] = value; } }\n        internal int FoxPelts { get { return this.Pelts[3]; } set { this.Pelts[3] = value; } }\n\n        internal int SelectedFort { get; set; }\n\n        internal GameState()\n        {\n            this.Savings = 600;\n            this.ExpeditionCount = 0;\n            this.UnasignedFurCount = 190;\n            this.Pelts = new int[4];\n            this.SelectedFort = 0;\n        }\n\n        internal void StartTurn()\n        {\n            this.SelectedFort = 0;              // reset to a default value\n            this.UnasignedFurCount = 190;       // each turn starts with 190 furs\n            this.Pelts = new int[4];            // reset pelts on each turn\n        }\n    }\n}\n"
  },
  {
    "path": "38_Fur_Trader/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace FurTrader\n{\n    public class Program\n    {\n        /// <summary>\n        /// This function will be called automatically when the application begins\n        /// </summary>\n        /// <param name=\"args\"></param>\n        public static void Main(string[] args)\n        {\n            // Create an instance of our main Game class\n            var game = new Game();\n\n            // Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.\n            game.GameLoop();\n        }\n    }\n}\n"
  },
  {
    "path": "38_Fur_Trader/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "38_Fur_Trader/furtrader.bas",
    "content": "1 DIM F(4)\n2 PRINT TAB(31);\"FUR TRADER\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n15 GOSUB 1091\n16 LET I=600\n17 PRINT \"DO YOU WISH TO TRADE FURS?\"\n18 GOSUB 1402\n19 IF B$=\"YES\" THEN 100\n20 IF B$=\"YES \" THEN 100\n21 STOP\n100 PRINT\n101 PRINT \"YOU HAVE $\";I \" SAVINGS.\"\n102 PRINT \"AND 190 FURS TO BEGIN THE EXPEDITION.\"\n261 LET E1=INT((.15*RND(1)+.95)*10^2+.5)/10^2\n262 LET B1=INT((.25*RND(1)+1.00)*10^2+.5)/10^2\n300 PRINT\n301 PRINT \"YOUR 190 FURS ARE DISTRIBUTED AMONG THE FOLLOWING\"\n302 PRINT \"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\"\n310 GOSUB 1430\n315 RESTORE\n330 FOR J=1 TO 4\n332 READ B$\n333 PRINT\n335 PRINT \"HOW MANY \";B$;\" PELTS DO YOU HAVE\";\n338 INPUT F(J)\n340 LET F(0)=F(1)+F(2)+F(3)+F(4)\n342 IF F(0)=190 THEN 1100\n344 IF F(0)>190 THEN 500\n348 NEXT J\n350 GOTO 1100\n500 PRINT\n501 PRINT \"YOU MAY NOT HAVE THAT MANY FURS.\"\n502 PRINT \"DO NOT TRY TO CHEAT.  I CAN ADD.\"\n503 PRINT \"YOU MUST START AGAIN.\"\n504 GOTO 15\n508 PRINT\n511 PRINT \"DO YOU WANT TO TRADE FURS NEXT YEAR?\"\n513 GOTO 18\n1091 PRINT \"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \"\n1092 PRINT \"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\"\n1093 PRINT \"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\"\n1094 PRINT \"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\"\n1095 PRINT \"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\"\n1096 PRINT \"ON THE FORT THAT YOU CHOOSE.\"\n1099 RETURN\n1100 PRINT \"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\"\n1102 PRINT \"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\"\n1103 PRINT \"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\"\n1104 PRINT \"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\"\n1105 PRINT \"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\"\n1106 PRINT \"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\"\n1108 PRINT \"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\"\n1109 PRINT \"YOU MUST CROSS THROUGH IROQUOIS LAND.\"\n1110 PRINT \"ANSWER 1, 2, OR 3.\"\n1111 INPUT B\n1112 IF B=1 THEN 1120\n1113 IF B=2 THEN 1135\n1115 IF B=3 THEN 1147\n1116 GOTO 1110\n1120 PRINT \"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\"\n1121 PRINT \"IS FAR FROM ANY SEAPORT.  THE VALUE\"\n1122 PRINT \"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\"\n1123 PRINT \"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\"\n1125 GOSUB 1400\n1129 IF B$=\"YES\" THEN 1110\n1130 GOTO 1160\n1135 PRINT \"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\"\n1136 PRINT \"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\"\n1137 PRINT \"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\"\n1138 PRINT \"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\"\n1141 GOSUB 1400\n1144 IF B$=\"YES\" THEN 1110\n1145 GOTO 1198\n1147 PRINT \"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\"\n1148 PRINT \"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\"\n1149 PRINT \"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\"\n1150 PRINT \"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\"\n1152 GOSUB 1400\n1155 IF B$=\"YES\" THEN 1110\n1156 GOTO 1250\n1160 LET I=I-160\n1169 PRINT\n1174 LET M1=INT((.2*RND(1)+.7)*10^2+.5)/10^2\n1175 LET E1=INT((.2*RND(1)+.65)*10^2+.5)/10^2\n1176 LET B1=INT((.2*RND(1)+.75)*10^2+.5)/10^2\n1177 LET D1=INT((.2*RND(1)+.8)*10^2+.5)/10^2\n1180 PRINT \"SUPPLIES AT FORT HOCHELAGA COST $150.00.\"\n1181 PRINT \"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\"\n1190 GOTO 1410\n1198 LET I=I-140\n1201 PRINT\n1205 LET M1=INT((.3*RND(1)+.85)*10^2+.5)/10^2\n1206 LET E1=INT((.15*RND(1)+.8)*10^2+.5)/10^2\n1207 LET B1=INT((.2*RND(1)+.9)*10^2+.5)/10^2\n1209 LET P=INT(10*RND(1))+1\n1210 IF P<=2 THEN 1216\n1212 IF P<=6 THEN 1224\n1213 IF P<=8 THEN 1226\n1215 IF P<=10 THEN 1235\n1216 LET F(2)=0\n1218 PRINT \"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\"\n1219 PRINT \"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\"\n1220 PRINT \"THEM STOLEN WHEN YOU RETURNED.\"\n1221 GOSUB 1244\n1222 GOTO 1414\n1224 PRINT \"YOU ARRIVED SAFELY AT FORT STADACONA.\"\n1225 GOTO 1239\n1226 GOSUB 1430\n1230 PRINT \"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\"\n1231 PRINT \"LOST ALL YOUR FURS.\"\n1232 GOSUB 1244\n1233 GOTO 1418\n1235 LET F(4)=0\n1237 PRINT \"YOUR FOX PELTS WERE NOT CURED PROPERLY.\"\n1238 PRINT \"NO ONE WILL BUY THEM.\"\n1239 GOSUB 1244\n1240 GOTO 1410\n1244 PRINT \"SUPPLIES AT FORT STADACONA COST $125.00.\"\n1246 PRINT \"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\"\n1248 RETURN\n1250 LET I=I-105\n1254 PRINT\n1260 LET M1=INT((.15*RND(1)+1.05)*10^2+.5)/10^2\n1263 LET D1=INT((.25*RND(1)+1.1)*10^2+.5)/10^2\n1270 LET P=INT(10*RND(1))+1\n1271 IF P<=2 THEN 1281\n1272 IF P<=6 THEN 1291\n1273 IF P<=8 THEN 1295\n1274 IF P<=10 THEN 1306\n1281 PRINT \"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\"\n1282 PRINT \"ALL PEOPLE IN YOUR TRADING GROUP WERE\"\n1283 PRINT \"KILLED.  THIS ENDS THE GAME.\"\n1284 STOP\n1291 PRINT \"YOU WERE LUCKY.  YOU ARRIVED SAFELY\"\n1292 PRINT \"AT FORT NEW YORK.\"\n1293 GOTO 1311\n1295 GOSUB 1430\n1300 PRINT \"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\"\n1301 PRINT \"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\"\n1303 GOSUB 1320\n1304 GOTO 1418\n1306 LET B1=B1/2\n1307 LET M1=M1/2\n1308 PRINT \"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\"\n1309 PRINT \"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\"\n1311 GOSUB 1320\n1312 GOTO 1410\n1320 PRINT \"SUPPLIES AT NEW YORK COST $80.00.\"\n1321 PRINT \"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\"\n1322 RETURN\n1400 PRINT \"DO YOU WANT TO TRADE AT ANOTHER FORT?\"\n1402 PRINT \"ANSWER YES OR NO\",\n1403 INPUT B$\n1404 RETURN\n1410 PRINT\n1412 PRINT \"YOUR BEAVER SOLD FOR $\";B1*F(2);\n1414 PRINT \"YOUR FOX SOLD FOR $\";D1*F(4)\n1416 PRINT \"YOUR ERMINE SOLD FOR $\";E1*F(3);\n1417 PRINT \"YOUR MINK SOLD FOR $\";M1*F(1)\n1418 LET I=M1*F(1)+B1*F(2)+E1*F(3)+D1*F(4)+I\n1420 PRINT\n1422 PRINT \"YOU NOW HAVE $\";I;\" INCLUDING YOUR PREVIOUS SAVINGS\"\n1425 GOTO 508\n1430 FOR J=1 TO 4\n1432 LET F(J)=0\n1434 NEXT J\n1436 RETURN\n2000 DATA \"MINK\",\"BEAVER\",\"ERMINE\",\"FOX\"\n2046 END\n"
  },
  {
    "path": "38_Fur_Trader/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "38_Fur_Trader/java/src/FurTrader.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Fur Trader\n * <p>\n * Based on the Basic game of Fur Trader here\n * https://github.com/coding-horror/basic-computer-games/blob/main/38%20Fur%20Trader/furtrader.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class FurTrader {\n\n    public static final double START_SAVINGS_AMOUNT = 600.0;\n    public static final int STARTING_FURS = 190;\n\n    public static final int FORT_HOCHELAGA_MONTREAL = 1;\n    public static final int FORT_STADACONA_QUEBEC = 2;\n    public static final int FORT_NEW_YORK = 3;\n\n    public static final String MINK = \"MINK\";\n    public static final int MINK_ENTRY = 0;\n    public static final String BEAVER = \"BEAVER\";\n    public static final int BEAVER_ENTRY = 1;\n    public static final String ERMINE = \"ERMINE\";\n    public static final int ERMINE_ENTRY = 2;\n    public static final String FOX = \"FOX\";\n    public static final int FOX_ENTRY = 3;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        STARTUP,\n        INIT,\n        TRADE_AT_FORT,\n        TRADE_SUMMARY,\n        TRADE_AGAIN,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private double savings;\n    private double minkPrice;\n    private double beaverPrice;\n    private double erminePrice;\n    private double foxPrice;\n\n    private ArrayList<Pelt> pelts;\n\n    private boolean playedOnce;\n\n    public FurTrader() {\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.INIT;\n        playedOnce = false;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case INIT:\n                    savings = START_SAVINGS_AMOUNT;\n\n                    // Only display initial game heading once\n                    if (!playedOnce) {\n                        playedOnce = true;\n                        gameStartupMessage();\n                    }\n\n                    intro();\n                    if (yesEntered(displayTextAndGetInput(\"DO YOU WISH TO TRADE FURS? \"))) {\n                        System.out.println(\"YOU HAVE $\" + formatNumber(savings) + \" SAVINGS.\");\n                        System.out.println(\"AND \" + STARTING_FURS + \" FURS TO BEGIN THE EXPEDITION.\");\n\n                        // Create a new array of Pelts.\n                        pelts = initPelts();\n                        gameState = GAME_STATE.STARTUP;\n                    } else {\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n\n                    break;\n\n                case STARTUP:\n\n                    // Reset count of pelts (all types)\n                    resetPelts();\n\n                    // This is where we will go to after processing all pelts.\n                    gameState = GAME_STATE.TRADE_AT_FORT;\n\n                    int totalPelts = 0;\n                    // Cycle through all types of pelts\n                    for (int i = 0; i < pelts.size(); i++) {\n                        Pelt pelt = pelts.get(i);\n                        int number = getPeltCount(pelt.getName());\n                        totalPelts += number;\n                        if (totalPelts > STARTING_FURS) {\n                            System.out.println(\"YOU MAY NOT HAVE THAT MANY FURS.\");\n                            System.out.println(\"DO NOT TRY TO CHEAT.  I CAN ADD.\");\n                            System.out.println(\"YOU MUST START AGAIN.\");\n                            System.out.println();\n                            // Restart the game\n                            gameState = GAME_STATE.INIT;\n                            break;\n                        } else {\n                            // update count entered by player and save back to ArrayList.\n                            pelt.setPeltCount(number);\n                            pelts.set(i, pelt);\n                            // Its possible for the player to put all their pelt allocation\n                            // into one or more different pelts.  They don't have to use all four types.\n                            // If we have an exact count of pelts matching the MAX\n                            // don't bother continuing to ask for more.\n                            if (totalPelts == STARTING_FURS) {\n                                break;\n                            }\n                        }\n                    }\n\n                    // Only move onto the trading part of the game if the player didn't add too many pelts\n                    if (gameState != GAME_STATE.STARTUP) {\n                        // Set ermine and beaver default prices here, depending on where you trade these\n                        // defaults will either be used or overwritten with other values.\n                        // check out the tradeAt??? methods for more info.\n                        erminePrice = ((.15 * Math.random() + .95) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n                        beaverPrice = ((.25 * Math.random() + 1.00) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n                        System.out.println();\n                    }\n                    break;\n\n                case TRADE_AT_FORT:\n\n                    extendedTradingInfo();\n                    int answer = displayTextAndGetNumber(\"ANSWER 1, 2, OR 3. \");\n\n                    System.out.println();\n\n                    // Now show the details of the fort they are about to trade\n                    // and give the player the chance to NOT proceed.\n                    // A \"No\" or false means they do not want to change to another fort\n                    if (!confirmFort(answer)) {\n                        switch (answer) {\n                            case 1:\n                                tradeAtFortHochelagaMontreal();\n                                gameState = GAME_STATE.TRADE_SUMMARY;\n                                break;\n\n                            case 2:\n                                tradeAtFortStadaconaQuebec();\n                                gameState = GAME_STATE.TRADE_SUMMARY;\n                                break;\n                            case 3:\n                                // Did the player and party all die?\n                                if (!tradeAtFortNewYork()) {\n                                    gameState = GAME_STATE.GAME_OVER;\n                                } else {\n                                    gameState = GAME_STATE.TRADE_SUMMARY;\n                                }\n                                break;\n                        }\n\n                        break;\n                    }\n\n                case TRADE_SUMMARY:\n\n                    System.out.println();\n                    double beaverTotal = beaverPrice * pelts.get(BEAVER_ENTRY).getNumber();\n                    System.out.print(\"YOUR BEAVER SOLD FOR $ \" + formatNumber(beaverTotal));\n\n                    double foxTotal = foxPrice * pelts.get(FOX_ENTRY).getNumber();\n                    System.out.println(simulateTabs(5) + \"YOUR FOX SOLD FOR $ \" + formatNumber(foxTotal));\n\n                    double erMineTotal = erminePrice * pelts.get(ERMINE_ENTRY).getNumber();\n                    System.out.print(\"YOUR ERMINE SOLD FOR $ \" + formatNumber(erMineTotal));\n\n                    double minkTotal = minkPrice * pelts.get(MINK_ENTRY).getNumber();\n                    System.out.println(simulateTabs(5) + \"YOUR MINK SOLD FOR $ \" + formatNumber(minkTotal));\n\n                    savings += beaverTotal + foxTotal + erMineTotal + minkTotal;\n                    System.out.println();\n                    System.out.println(\"YOU NOW HAVE $\" + formatNumber(savings) + \" INCLUDING YOUR PREVIOUS SAVINGS\");\n\n                    gameState = GAME_STATE.TRADE_AGAIN;\n                    break;\n\n                case TRADE_AGAIN:\n                    if (yesEntered(displayTextAndGetInput(\"DO YOU WANT TO TRADE FURS NEXT YEAR? \"))) {\n                        gameState = GAME_STATE.STARTUP;\n                    } else {\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Create all pelt types with a count of zero\n     *\n     * @return Arraylist of initialised Pelt objects.\n     */\n    private ArrayList<Pelt> initPelts() {\n\n        ArrayList<Pelt> tempPelts = new ArrayList<>();\n        tempPelts.add(new Pelt(MINK, 0));\n        tempPelts.add(new Pelt(BEAVER, 0));\n        tempPelts.add(new Pelt(ERMINE, 0));\n        tempPelts.add(new Pelt(FOX, 0));\n        return tempPelts;\n    }\n\n    /**\n     * Display a message about trading at each fort and confirm if the player wants to trade\n     * at ANOTHER fort\n     *\n     * @param fort the fort in question\n     * @return true if YES was typed by player\n     */\n    private boolean confirmFort(int fort) {\n        switch (fort) {\n            case FORT_HOCHELAGA_MONTREAL:\n                System.out.println(\"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\");\n                System.out.println(\"IS FAR FROM ANY SEAPORT.  THE VALUE\");\n                System.out.println(\"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\");\n                System.out.println(\"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\");\n                break;\n            case FORT_STADACONA_QUEBEC:\n                System.out.println(\"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\");\n                System.out.println(\"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\");\n                System.out.println(\"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\");\n                System.out.println(\"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\");\n                break;\n            case FORT_NEW_YORK:\n                System.out.println(\"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\");\n                System.out.println(\"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\");\n                System.out.println(\"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\");\n                System.out.println(\"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\");\n                break;\n        }\n\n        System.out.println(\"DO YOU WANT TO TRADE AT ANOTHER FORT?\");\n        return yesEntered(displayTextAndGetInput(\"ANSWER YES OR NO \"));\n\n    }\n\n    /**\n     * Trade at the safest fort - Fort Hochelaga\n     * No chance of anything bad happening, so just calculate amount per pelt\n     * and return\n     */\n    private void tradeAtFortHochelagaMontreal() {\n        savings -= 160.0;\n        System.out.println();\n        System.out.println(\"SUPPLIES AT FORT HOCHELAGA COST $150.00.\");\n        System.out.println(\"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\");\n        minkPrice = ((.2 * Math.random() + .7) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n        erminePrice = ((.2 * Math.random() + .65) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n        beaverPrice = ((.2 * Math.random() + .75) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n        foxPrice = ((.2 * Math.random() + .8) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n    }\n\n\n    private void tradeAtFortStadaconaQuebec() {\n        savings -= 140.0;\n        System.out.println();\n        minkPrice = ((.2 * Math.random() + .85) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n        erminePrice = ((.2 * Math.random() + .8) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n        beaverPrice = ((.2 * Math.random() + .9) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n\n        // What happened during the trip to the fort?\n        int tripResult = (int) (Math.random() * 10) + 1;\n        if (tripResult <= 2) {\n            // Find the Beaver pelt in our Arraylist\n            Pelt beaverPelt = pelts.get(BEAVER_ENTRY);\n            // Pelts got stolen, so update to a count of zero\n            beaverPelt.lostPelts();\n            // Update it back in the ArrayList\n            pelts.set(BEAVER_ENTRY, beaverPelt);\n            System.out.println(\"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\");\n            System.out.println(\"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\");\n            System.out.println(\"THEM STOLEN WHEN YOU RETURNED.\");\n        } else if (tripResult <= 6) {\n            System.out.println(\"YOU ARRIVED SAFELY AT FORT STADACONA.\");\n        } else if (tripResult <= 8) {\n            System.out.println(\"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\");\n            System.out.println(\"LOST ALL YOUR FURS.\");\n            // Clear out all pelts.\n            resetPelts();\n        } else if (tripResult <= 10) {\n            // Fox pelts not cured\n            System.out.println(\"YOUR FOX PELTS WERE NOT CURED PROPERLY.\");\n            System.out.println(\"NO ONE WILL BUY THEM.\");\n            // Bug because Fox furs were not calculated above in original basic program\n            // Find the Beaver pelt in our Arraylist\n            Pelt foxPelt = pelts.get(FOX_ENTRY);\n            // Pelts got stolen, so update to a count of zero\n            foxPelt.lostPelts();\n            // Update it back in the ArrayList\n            pelts.set(FOX_ENTRY, foxPelt);\n        }\n\n        System.out.println(\"SUPPLIES AT FORT STADACONA COST $125.00.\");\n        System.out.println(\"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\");\n    }\n\n    private boolean tradeAtFortNewYork() {\n\n        boolean playerAlive = true;\n        savings -= 105.0;\n        System.out.println();\n        minkPrice = ((.2 * Math.random() + 1.05) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n        foxPrice = ((.2 * Math.random() + 1.1) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2);\n\n        // What happened during the trip to the fort?\n        int tripResult = (int) (Math.random() * 10) + 1;\n        if (tripResult <= 2) {\n            System.out.println(\"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\");\n            System.out.println(\"ALL PEOPLE IN YOUR TRADING GROUP WERE\");\n            System.out.println(\"KILLED.  THIS ENDS THE GAME.\");\n            playerAlive = false;\n        } else if (tripResult <= 6) {\n            System.out.println(\"YOU WERE LUCKY.  YOU ARRIVED SAFELY\");\n            System.out.println(\"AT FORT NEW YORK.\");\n        } else if (tripResult <= 8) {\n            System.out.println(\"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\");\n            System.out.println(\"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\");\n            // Clear out all pelts.\n            resetPelts();\n        } else if (tripResult <= 10) {\n            beaverPrice /= 2;\n            minkPrice /= 2;\n            System.out.println(\"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\");\n            System.out.println(\"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\");\n        }\n\n        if (playerAlive) {\n            System.out.println(\"SUPPLIES AT NEW YORK COST $80.00.\");\n            System.out.println(\"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\");\n        }\n\n        return playerAlive;\n    }\n\n    /**\n     * Reset pelt count for all Pelt types to zero.\n     */\n    private void resetPelts() {\n        for (int i = 0; i < pelts.size(); i++) {\n            Pelt pelt = pelts.get(i);\n            pelt.lostPelts();\n            pelts.set(i, pelt);\n        }\n    }\n\n    /**\n     * Return a pelt object containing the user entered number of pelts.\n     *\n     * @param peltName Name of pelt (Type)\n     * @return number of pelts assigned by player\n     */\n    private int getPeltCount(String peltName) {\n        return displayTextAndGetNumber(\"HOW MANY \" + peltName + \" PELTS DO YOU HAVE? \");\n    }\n\n    private void extendedTradingInfo() {\n        System.out.println(\"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\");\n        System.out.println(\"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\");\n        System.out.println(\"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\");\n        System.out.println(\"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\");\n        System.out.println(\"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\");\n        System.out.println(\"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\");\n        System.out.println(\"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\");\n        System.out.println(\"YOU MUST CROSS THROUGH IROQUOIS LAND.\");\n        System.out.println();\n\n    }\n\n    private void gameStartupMessage() {\n        System.out.println(simulateTabs(31) + \"FUR TRADER\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n    }\n\n    private void intro() {\n        System.out.println(\"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \");\n        System.out.println(\"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\");\n        System.out.println(\"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\");\n        System.out.println(\"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\");\n        System.out.println(\"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\");\n        System.out.println(\"ON THE FORT THAT YOU CHOOSE.\");\n        System.out.println();\n    }\n\n    /**\n     * Format a double number to two decimal points for output.\n     *\n     * @param number double number\n     * @return formatted number as a string\n     */\n    private String formatNumber(double number) {\n        return String.format(\"%.2f\", number);\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text));\n    }\n}\n"
  },
  {
    "path": "38_Fur_Trader/java/src/FurTraderGame.java",
    "content": "public class FurTraderGame {\n    public static void main(String[] args) {\n\n        FurTrader furTrader = new FurTrader();\n        furTrader.play();\n    }\n}\n"
  },
  {
    "path": "38_Fur_Trader/java/src/Pelt.java",
    "content": "/**\n * Pelt object - tracks the name and number of pelts the player has for this pelt type\n */\npublic class Pelt {\n\n    private final String name;\n    private int number;\n\n    public Pelt(String name, int number) {\n        this.name = name;\n        this.number = number;\n    }\n\n    public void setPeltCount(int pelts) {\n        this.number = pelts;\n    }\n\n    public int getNumber() {\n        return this.number;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void lostPelts() {\n        this.number = 0;\n    }\n}\n"
  },
  {
    "path": "38_Fur_Trader/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "38_Fur_Trader/javascript/furtrader.html",
    "content": "<html>\n<head>\n<title>FUR TRADER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"furtrader.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "38_Fur_Trader/javascript/furtrader.js",
    "content": "// FUR TRADER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar f = [];\nvar bs = [, \"MINK\", \"BEAVER\", \"ERMINE\", \"FOX\"];\n\nfunction reset_stats()\n{\n    for (var j = 1; j <= 4; j++)\n        f[j] = 0;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(31) + \"FUR TRADER\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    first_time = true;\n    while (1) {\n        if (first_time) {\n            print(\"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \\n\");\n            print(\"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\\n\");\n            print(\"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\\n\");\n            print(\"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\\n\");\n            print(\"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\\n\");\n            print(\"ON THE FORT THAT YOU CHOOSE.\\n\");\n            i = 600;\n            print(\"DO YOU WISH TO TRADE FURS?\\n\");\n            first_time = false;\n        }\n        print(\"ANSWER YES OR NO\\t\");\n        str = await input();\n        if (str == \"NO\")\n            break;\n        print(\"\\n\");\n        print(\"YOU HAVE $\" + i + \" SAVINGS.\\n\");\n        print(\"AND 190 FURS TO BEGIN THE EXPEDITION.\\n\");\n        e1 = Math.floor((0.15 * Math.random() + 0.95) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n        b1 = Math.floor((0.25 * Math.random() + 1.00) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n        print(\"\\n\");\n        print(\"YOUR 190 FURS ARE DISTRIBUTED AMONG THE FOLLOWING\\n\");\n        print(\"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\\n\");\n        reset_stats();\n        for (j = 1; j <= 4; j++) {\n            print(\"\\n\");\n            print(\"HOW MANY \" + bs[j] + \" PELTS DO YOU HAVE\\n\");\n            f[j] = parseInt(await input());\n            f[0] = f[1] + f[2] + f[3] + f[4];\n            if (f[0] == 190)\n                break;\n            if (f[0] > 190) {\n                print(\"\\n\");\n                print(\"YOU MAY NOT HAVE THAT MANY FURS.\\n\");\n                print(\"DO NOT TRY TO CHEAT.  I CAN ADD.\\n\");\n                print(\"YOU MUST START AGAIN.\\n\");\n                break;\n            }\n        }\n        if (f[0] > 190) {\n            first_time = true;\n            continue;\n        }\n        print(\"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\\n\");\n        print(\"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\\n\");\n        print(\"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\\n\");\n        print(\"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\\n\");\n        print(\"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\\n\");\n        print(\"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\\n\");\n        print(\"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\\n\");\n        print(\"YOU MUST CROSS THROUGH IROQUOIS LAND.\\n\");\n        do {\n            print(\"ANSWER 1, 2, OR 3.\\n\");\n            b = parseInt(await input());\n            if (b == 1) {\n                print(\"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\\n\");\n                print(\"IS FAR FROM ANY SEAPORT.  THE VALUE\\n\");\n                print(\"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\\n\");\n                print(\"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\\n\");\n            } else if (b == 2) {\n                print(\"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\\n\");\n                print(\"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\\n\");\n                print(\"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\\n\");\n                print(\"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\\n\");\n            } else {\n                print(\"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\\n\");\n                print(\"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\\n\");\n                print(\"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\\n\");\n                print(\"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\\n\");\n            }\n            if (b >= 1 && b <= 3) {\n                print(\"DO YOU WANT TO TRADE AT ANOTHER FORT?\\n\");\n                print(\"ANSWER YES OR NO\\t\");\n                str = await input();\n                if (str == \"YES\") {\n                    b = 0;\n                }\n            }\n        } while (b < 1 || b > 3) ;\n        show_beaver = true;\n        show_all = true;\n        if (b == 1) {\n            i -= 160;\n            print(\"\\n\");\n            m1 = Math.floor((0.2 * Math.random() + 0.7) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            e1 = Math.floor((0.2 * Math.random() + 0.65) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            b1 = Math.floor((0.2 * Math.random() + 0.75) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            d1 = Math.floor((0.2 * Math.random() + 0.8) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            print(\"SUPPLIES AT FORT HOCHELAGA COST $150.00.\\n\");\n            print(\"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\\n\");\n        } else if (b == 2) {\n            i -= 140;\n            print(\"\\n\");\n            m1 = Math.floor((0.3 * Math.random() + 0.85) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            e1 = Math.floor((0.15 * Math.random() + 0.8) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            b1 = Math.floor((0.2 * Math.random() + 0.9) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            p = Math.floor(10 * Math.random()) + 1;\n            if (p <= 2) {\n                f[2] = 0;\n                print(\"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\\n\");\n                print(\"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\\n\");\n                print(\"THEM STOLEN WHEN YOU RETURNED.\\n\");\n                show_beaver = false;\n            } else if (p <= 6) {\n                print(\"YOU ARRIVED SAFELY AT FORT STADACONA.\\n\");\n            } else if (p <= 8) {\n                reset_stats();\n                print(\"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\\n\");\n                print(\"LOST ALL YOUR FURS.\\n\");\n                show_all = false;\n            } else if (p <= 10) {\n                f[4] = 0;\n                print(\"YOUR FOX PELTS WERE NOT CURED PROPERLY.\\n\");\n                print(\"NO ONE WILL BUY THEM.\\n\");\n            }\n            print(\"SUPPLIES AT FORT STADACONA COST $125.00.\\n\");\n            print(\"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\\n\");\n\n            d1 = Math.floor((0.2 * Math.random() + 0.8) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n        } else if (b == 3) {\n            i -= 105;\n            print(\"\\n\");\n            m1 = Math.floor((0.15 * Math.random() + 1.05) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            d1 = Math.floor((0.25 * Math.random() + 1.1) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);\n            p = Math.floor(10 * Math.random()) + 1;\n            if (p <= 2) {\n                print(\"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\\n\");\n                print(\"ALL PEOPLE IN YOUR TRADING GROUP WERE\\n\");\n                print(\"KILLED.  THIS ENDS THE GAME.\\n\");\n                break;\n            } else if (p <= 6) {\n                print(\"YOU WERE LUCKY.  YOU ARRIVED SAFELY\\n\");\n                print(\"AT FORT NEW YORK.\\n\");\n            } else if (p <= 8) {\n                reset_stats();\n                print(\"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\\n\");\n                print(\"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\\n\");\n                show_all = false;\n            } else if (p <= 10) {\n                b1 /= 2;\n                m1 /= 2;\n                print(\"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\\n\");\n                print(\"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\\n\");\n            }\n            print(\"SUPPLIES AT NEW YORK COST $80.00.\\n\");\n            print(\"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\\n\");\n        }\n        print(\"\\n\");\n        if (show_all) {\n            if (show_beaver)\n                print(\"YOUR BEAVER SOLD FOR $\" + b1 * f[2] + \" \");\n            print(\"YOUR FOX SOLD FOR $\" + d1 * f[4] + \"\\n\");\n            print(\"YOUR ERMINE SOLD FOR $\" + e1 * f[3] + \" \");\n            print(\"YOUR MINK SOLD FOR $\" + m1 * f[1] + \"\\n\");\n        }\n        i += m1 * f[1] + b1 * f[2] + e1 * f[3] + d1 * f[4];\n        print(\"\\n\");\n        print(\"YOU NOW HAVE $\" + i + \" INCLUDING YOUR PREVIOUS SAVINGS\\n\");\n        print(\"\\n\");\n        print(\"DO YOU WANT TO TRADE FURS NEXT YEAR?\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "38_Fur_Trader/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "38_Fur_Trader/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "38_Fur_Trader/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nYou can answer yes/no questions in lower case if desired.\n"
  },
  {
    "path": "38_Fur_Trader/perl/furtrader.pl",
    "content": "#!/usr/bin/perl\n\n# Fur Trader program in Perl\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy @Pelts = (qw(0 MINK BEAVER ERMINE FOX ));\nmy $Num_pelts = 4;\nmy @Quantity; # how many of each fur\nmy $Money;\nmy $Max_pelts = 190;\nmy $Ermine_price;  # like we have @Pelts and @Quantity we could have @Prices\nmy $Beaver_price;  # then have 4 constants as index into the arrays to avoid\nmy $Fox_price;     # the magic numbers 1-4, or better have a array of objects (really a hash)\nmy $Mink_price;    # with the 3 keys (name, number, price), but well keep it\n                   # with 4 vars like the basic program did\n\nprint \"\\n\";\nprint \" \" x 31, \"FUR TRADER\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\ninit();\nwhile (1)\n{\n    my $ans = get_yesno();\n    last if ($ans ne \"YES\");\n\n    $Ermine_price = new_price(.15, 0.95);\n    $Beaver_price = new_price(.25, 1.00);\n\n    print \"\\nYOU HAVE \\$$Money SAVINGS.\\n\";\n    print \"AND $Max_pelts FURS TO BEGIN THE EXPEDITION.\\n\";\n    print \"\\nYOUR $Max_pelts FURS ARE DISTRIBUTED AMONG THE FOLLOWING\\n\";\n    print \"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\\n\";\n    reset_furs();\n\n    my $total = 0;\n    for my $j ( 1 .. $Num_pelts)\n    {\n        print \"\\nHOW MANY $Pelts[$j] PELTS DO YOU HAVE? \";\n        chomp(my $ans = <>);\n        $Quantity[$j] = int($ans);\n        $total += $Quantity[$j];\n    }\n    if ($total > $Max_pelts)\n    {\n        print \"\\nYOU MAY NOT HAVE THAT MANY FURS.\\n\";\n        print \"DO NOT TRY TO CHEAT.  I CAN ADD.\\n\";\n        print \"YOU MUST START AGAIN.\\n\";\n        init();\n        next;\n    }\n\n    print \"\\nYOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\\n\";\n    print \"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\\n\";\n    print \"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\\n\";\n    print \"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\\n\";\n    print \"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\\n\";\n    print \"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\\n\";\n    print \"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\\n\";\n    print \"YOU MUST CROSS THROUGH IROQUOIS LAND.\\n\";\n    my $done = 0;\n    while (!$done)\n    {\n        $ans = 0;\n        while ($ans < 1 || $ans > 3)\n        {\n            no warnings; # in case user enters alpha chars, then int() will return 0 with no warnings\n            print \"ANSWER 1, 2, OR 3: \";\n            $ans = int(<>);\n        }\n        # returns 0 if they want to go somewhere else;\n        # or returns the old basic line number to show what to do\n        if ($ans == 1)    { $done = fort1(); }\n        elsif ($ans == 2) { $done = fort2(); }\n        elsif ($ans == 3) { $done = fort3(); }\n    }\n\n    if ($done == 1410)\n    {\n        print \"YOUR BEAVER SOLD FOR \\$\", $Beaver_price * $Quantity[2], \"\\t\";\n    }\n\n    if ($done <= 1414)\n    {\n        print \"YOUR FOX SOLD FOR \\$\", $Fox_price * $Quantity[4], \"\\n\";\n        print \"YOUR ERMINE SOLD FOR \\$\", $Ermine_price * $Quantity[3], \"\\t\";\n        print \"YOUR MINK SOLD FOR \\$\", $Mink_price * $Quantity[1], \"\\n\";\n    }\n\n    # 1418 is always done\n    $Money += $Mink_price * $Quantity[1] + $Beaver_price * $Quantity[2] + $Ermine_price * $Quantity[3] + $Fox_price * $Quantity[4];\n    print \"\\nYOU NOW HAVE \\$$Money INCLUDING YOUR PREVIOUS SAVINGS\\n\";\n    print \"\\nDO YOU WANT TO TRADE FURS NEXT YEAR? \";\n}\nexit(0);\n\n###############################################################\n\nsub init\n{\n    print \"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN\\n\";\n    print \"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\\n\";\n    print \"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\\n\";\n    print \"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\\n\";\n    print \"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\\n\";\n    print \"ON THE FORT THAT YOU CHOOSE.\\n\";\n\n    $Money = 600;\n    print \"DO YOU WISH TO TRADE FURS?\\n\";\n}\n\nsub new_price\n{\n    my ($base, $factor) = @_;\n    return int(($base * rand(1) + $factor) * 100 + .5) / 100;\n}\n\nsub supplies_fs\n{\n    print \"SUPPLIES AT FORT STADACONA COST \\$125.00.\\n\";\n    print \"YOUR TRAVEL EXPENSES TO STADACONA WERE \\$15.00.\\n\";\n}\n\nsub supplies_ny\n{\n    print \"SUPPLIES AT NEW YORK COST \\$80.00.\\n\";\n    print \"YOUR TRAVEL EXPENSES TO NEW YORK WERE \\$25.00.\\n\";\n}\n\nsub reset_furs\n{\n    for my $j (1 .. $Num_pelts) { $Quantity[$j] = 0; }\n}\n\nsub get_yesno\n{\n    my $ans;\n    print \"ANSWER YES OR NO: \";\n    chomp($ans = uc(<>));\n    return $ans;\n}\n\nsub trade_elsewhere\n{\n    print \"DO YOU WANT TO TRADE AT ANOTHER FORT? \";\n    my $ans = get_yesno();\n    return $ans;\n}\n\nsub fort1\n{\n    print \"\\nYOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\\n\";\n    print \"IS FAR FROM ANY SEAPORT.  THE VALUE\\n\";\n    print \"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\\n\";\n    print \"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\\n\";\n    my $ans = trade_elsewhere();\n    if ($ans eq \"YES\") { return 0; }\n    \n    $Money -= 160;\n    $Mink_price = new_price(.2, .7 );\n    $Ermine_price = new_price(.2, .65);\n    $Beaver_price = new_price(.2, .75);\n    $Fox_price = new_price(.2, .8 );\n    print \"\\nSUPPLIES AT FORT HOCHELAGA COST \\$150.00.\\n\";\n    print \"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE \\$10.00.\\n\";\n    return 1410;\n}\n\nsub fort2\n{\n    print \"\\nYOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\\n\";\n    print \"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\\n\";\n    print \"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\\n\";\n    print \"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\\n\";\n    my $ans = trade_elsewhere();\n    if ($ans eq \"YES\") { return 0; }\n\n    $Money -= 140;\n    print \"\\n\";\n    $Mink_price = new_price(.3,  .85);\n    $Ermine_price = new_price(.15, .8);\n    $Beaver_price = new_price(.2,  .9);\n    my $P = int(10 * rand(1)) + 1;\n    if ($P <= 2)\n    {\n        $Quantity[2] = 0;\n        print \"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\\n\";\n        print \"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\\n\";\n        print \"THEM STOLEN WHEN YOU RETURNED.\\n\";\n        supplies_fs();\n        return 1414;\n    }\n    elsif ($P <= 6)\n    {\n        print \"YOU ARRIVED SAFELY AT FORT STADACONA.\\n\";\n        supplies_fs();\n    }\n    elsif ($P <= 8)\n    {\n        reset_furs();\n        print \"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\\n\";\n        print \"LOST ALL YOUR FURS.\\n\";\n        supplies_fs();\n        return 1418;\n    }\n    elsif ($P <= 10)\n    {\n        $Quantity[4] = 0;\n        print \"YOUR FOX PELTS WERE NOT CURED PROPERLY.\\n\";\n        print \"NO ONE WILL BUY THEM.\\n\";\n        supplies_fs();\n    }\n    return 1410;\n}\n\nsub fort3\n{\n    print \"\\nYOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\\n\";\n    print \"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\\n\";\n    print \"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\\n\";\n    print \"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\\n\";\n    my $ans = trade_elsewhere();\n    if ($ans eq \"YES\") { return 0; }\n\n    $Money -= 105;\n    print \"\\n\";\n    $Mink_price = new_price(.15, 1.05);\n    $Fox_price = new_price(.25, 1.1);\n    $Fox_price = new_price(.25, 1.1);\n    my $P = int(10 * rand(1)) + 1;\n    if ($P <= 2)\n    {\n        print \"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\\n\";\n        print \"ALL PEOPLE IN YOUR TRADING GROUP WERE\\n\";\n        print \"KILLED.  THIS ENDS THE GAME.\\n\";\n        exit(0);\n    }\n    elsif ($P <= 6)\n    {\n        print \"YOU WERE LUCKY.  YOU ARRIVED SAFELY\\n\";\n        print \"AT FORT NEW YORK.\\n\";\n        supplies_ny();\n    }\n    elsif ($P <= 8)\n    {\n        reset_furs();\n        print \"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\\n\";\n        print \"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\\n\";\n        supplies_ny();\n        return 1418;\n    }\n    elsif ($P <= 10)\n    {\n        $Beaver_price /= 2;\n        $Mink_price /= 2;\n        print \"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\\n\";\n        print \"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\\n\";\n        supplies_ny();\n    }\n    return 1410;\n}\n"
  },
  {
    "path": "38_Fur_Trader/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n\n##### Translator Notes:\nI tried to preserve as much of the original layout and flow of the code\nas possible.  However I did use quasi enumerated types for the Fort numbers\nand Fur types.  I think this was certainly a change for the better, and\nmakes the code much easier to read.\n\nI program in many different languages on a daily basis.  Most languages\nrequire brackets around expressions, so I just cannot bring myself to\nwrite an expression without brackets.  IMHO it makes the code easier to study,\nbut it does contravene the Python PEP-8 Style guide.\n\nInterestingly the code seems to have a bug around the prices of Fox Furs.\nThe commodity-rate for these is stored in the variable `D1`, however some\npaths through the code do not set this price.  So there was a chance of\nusing this uninitialised, or whatever the previous loop set.  I don't\nthink this was the original authors intent.  So I preserved the original flow\nof the code (using the previous `D1` value), but also catching the\nuninitialised path, and assigning a \"best guess\" value.\n\nkrt@krt.com.au 2020-10-10\n"
  },
  {
    "path": "38_Fur_Trader/python/furtrader.py",
    "content": "#!/usr/bin/env python3\n\nimport random  # for generating random numbers\nimport sys  # for system function, like exit()\nfrom typing import List\n\n# global variables for storing player's status\nplayer_funds: float = 0  # no money\nplayer_furs = [0, 0, 0, 0]  # no furs\n\n\n# Constants\nFUR_MINK = 0\nFUR_BEAVER = 1\nFUR_ERMINE = 2\nFUR_FOX = 3\nMAX_FURS = 190\nFUR_NAMES = [\"MINK\", \"BEAVER\", \"ERMINE\", \"FOX\"]\n\nFORT_MONTREAL = 1\nFORT_QUEBEC = 2\nFORT_NEWYORK = 3\nFORT_NAMES = [\"HOCHELAGA (MONTREAL)\", \"STADACONA (QUEBEC)\", \"NEW YORK\"]\n\n\ndef show_introduction() -> None:\n    \"\"\"Show the player the introductory message\"\"\"\n    print(\"YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \")\n    print(\"1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\")\n    print(\"SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\")\n    print(\"FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\")\n    print(\"AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\")\n    print(\"ON THE FORT THAT YOU CHOOSE.\")\n    print()\n\n\ndef get_fort_choice() -> int:\n    \"\"\"Show the player the choices of Fort, get their input, if the\n    input is a valid choice (1,2,3) return it, otherwise keep\n    prompting the user.\"\"\"\n    result = 0\n    while result == 0:\n        print()\n        print(\"YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\")\n        print(\"OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\")\n        print(\"AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\")\n        print(\"FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\")\n        print(\"PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\")\n        print(\"MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\")\n        print(\"FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\")\n        print(\"YOU MUST CROSS THROUGH IROQUOIS LAND.\")\n        print(\"ANSWER 1, 2, OR 3.\")\n\n        player_choice = input(\">> \")  # get input from the player\n\n        # try to convert the player's string input into an integer\n        try:\n            result = int(player_choice)  # string to integer\n        except Exception:\n            # Whatever the player typed, it could not be interpreted as a number\n            pass\n\n    return result\n\n\ndef show_fort_comment(which_fort) -> None:\n    \"\"\"Print the description for the fort\"\"\"\n    print()\n    if which_fort == FORT_MONTREAL:\n        print(\"YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\")\n        print(\"IS FAR FROM ANY SEAPORT.  THE VALUE\")\n        print(\"YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\")\n        print(\"OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\")\n    elif which_fort == FORT_QUEBEC:\n        print(\"YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\")\n        print(\"HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\")\n        print(\"THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\")\n        print(\"FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\")\n    elif which_fort == FORT_NEWYORK:\n        print(\"YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\")\n        print(\"FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\")\n        print(\"FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\")\n        print(\"WILL BE LOWER THAN AT ALL THE OTHER FORTS.\")\n    else:\n        print(f\"Internal error #1, fort {str(which_fort)} does not exist\")\n        sys.exit(1)  # you have a bug\n    print()\n\n\ndef get_yes_or_no() -> str:\n    \"\"\"Prompt the player to enter 'YES' or 'NO'. Keep prompting until\n    valid input is entered.  Accept various spellings by only\n    checking the first letter of input.\n    Return a single letter 'Y' or 'N'\"\"\"\n    result = \"\"\n    while result not in (\"Y\", \"N\"):\n        print(\"ANSWER YES OR NO\")\n        player_choice = input(\">> \")\n        player_choice = player_choice.strip().upper()  # trim spaces, make upper-case\n        if player_choice.startswith(\"Y\"):\n            result = \"Y\"\n        elif player_choice.startswith(\"N\"):\n            result = \"N\"\n    return result\n\n\ndef get_furs_purchase() -> List[int]:\n    \"\"\"Prompt the player for how many of each fur type they want.\n    Accept numeric inputs, re-prompting on incorrect input values\"\"\"\n    results: List[int] = []\n\n    print(f\"YOUR {str(MAX_FURS)} FURS ARE DISTRIBUTED AMONG THE FOLLOWING\")\n    print(\"KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\")\n    print()\n\n    while len(results) < len(FUR_NAMES):\n        print(f\"HOW MANY {FUR_NAMES[len(results)]} DO YOU HAVE\")\n        count_str = input(\">> \")\n        try:\n            count = int(count_str)\n            results.append(count)\n        except Exception:  # invalid input, prompt again by re-looping\n            pass\n    return results\n\n\ndef main() -> None:\n    print(\" \" * 31 + \"FUR TRADER\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\" \" * 15 + \"(Ported to Python Oct 2012 krt@krt.com.au)\")\n    print(\"\\n\\n\\n\")\n\n    fox_price = None  # sometimes this takes the \"last\" price (probably this was a bug)\n\n    game_state = \"starting\"\n    while True:\n\n        if game_state == \"starting\":\n            show_introduction()\n\n            player_funds: float = 600  # Initial player start money\n            player_furs = [0, 0, 0, 0]  # Player fur inventory\n\n            print(\"DO YOU WISH TO TRADE FURS?\")\n            should_trade = get_yes_or_no()\n            if should_trade == \"N\":\n                sys.exit(0)  # STOP\n            game_state = \"trading\"\n\n        elif game_state == \"trading\":\n            print()\n            print(\"YOU HAVE $ %1.2f IN SAVINGS\" % (player_funds))\n            print(f\"AND {str(MAX_FURS)} FURS TO BEGIN THE EXPEDITION\")\n            player_furs = get_furs_purchase()\n\n            if sum(player_furs) > MAX_FURS:\n                print()\n                print(\"YOU MAY NOT HAVE THAT MANY FURS.\")\n                print(\"DO NOT TRY TO CHEAT.  I CAN ADD.\")\n                print(\"YOU MUST START AGAIN.\")\n                game_state = \"starting\"  # T/N: Wow, harsh.\n            else:\n                game_state = \"choosing fort\"\n\n        elif game_state == \"choosing fort\":\n            which_fort = get_fort_choice()\n            show_fort_comment(which_fort)\n            print(\"DO YOU WANT TO TRADE AT ANOTHER FORT?\")\n            change_fort = get_yes_or_no()\n            if change_fort == \"N\":\n                game_state = \"travelling\"\n\n        elif game_state == \"travelling\":\n            print()\n            if which_fort == FORT_MONTREAL:\n                mink_price = (\n                    int((0.2 * random.random() + 0.70) * 100 + 0.5) / 100\n                )  # INT((.2*RND(1)+.7)*10^2+.5)/10^2\n                ermine_price = (\n                    int((0.2 * random.random() + 0.65) * 100 + 0.5) / 100\n                )  # INT((.2*RND(1)+.65)*10^2+.5)/10^2\n                beaver_price = (\n                    int((0.2 * random.random() + 0.75) * 100 + 0.5) / 100\n                )  # INT((.2*RND(1)+.75)*10^2+.5)/10^2\n                fox_price = (\n                    int((0.2 * random.random() + 0.80) * 100 + 0.5) / 100\n                )  # INT((.2*RND(1)+.8)*10^2+.5)/10^2\n\n                print(\"SUPPLIES AT FORT HOCHELAGA COST $150.00.\")\n                print(\"YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\")\n                player_funds -= 160\n\n            elif which_fort == FORT_QUEBEC:\n                mink_price = (\n                    int((0.30 * random.random() + 0.85) * 100 + 0.5) / 100\n                )  # INT((.3*RND(1)+.85)*10^2+.5)/10^2\n                ermine_price = (\n                    int((0.15 * random.random() + 0.80) * 100 + 0.5) / 100\n                )  # INT((.15*RND(1)+.8)*10^2+.5)/10^2\n                beaver_price = (\n                    int((0.20 * random.random() + 0.90) * 100 + 0.5) / 100\n                )  # INT((.2*RND(1)+.9)*10^2+.5)/10^2\n                fox_price = (\n                    int((0.25 * random.random() + 1.10) * 100 + 0.5) / 100\n                )  # INT((.25*RND(1)+1.1)*10^2+.5)/10^2\n                event_picker = int(10 * random.random()) + 1\n\n                if event_picker <= 2:\n                    print(\"YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\")\n                    print(\"THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\")\n                    print(\"THEM STOLEN WHEN YOU RETURNED.\")\n                    player_furs[FUR_BEAVER] = 0\n                elif event_picker <= 6:\n                    print(\"YOU ARRIVED SAFELY AT FORT STADACONA.\")\n                elif event_picker <= 8:\n                    print(\"YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\")\n                    print(\"LOST ALL YOUR FURS.\")\n                    player_furs = [0, 0, 0, 0]\n                elif event_picker <= 10:\n                    print(\"YOUR FOX PELTS WERE NOT CURED PROPERLY.\")\n                    print(\"NO ONE WILL BUY THEM.\")\n                    player_furs[FUR_FOX] = 0\n                else:\n                    print(f\"Internal Error #3, Out-of-bounds event_picker{str(event_picker)}\")\n                    sys.exit(1)  # you have a bug\n\n                print()\n                print(\"SUPPLIES AT FORT STADACONA COST $125.00.\")\n                print(\"YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\")\n                player_funds -= 140\n\n            elif which_fort == FORT_NEWYORK:\n                mink_price = (\n                    int((0.15 * random.random() + 1.05) * 100 + 0.5) / 100\n                )  # INT((.15*RND(1)+1.05)*10^2+.5)/10^2\n                ermine_price = (\n                    int((0.15 * random.random() + 0.95) * 100 + 0.5) / 100\n                )  # INT((.15*RND(1)+.95)*10^2+.5)/10^2\n                beaver_price = (\n                    int((0.25 * random.random() + 1.00) * 100 + 0.5) / 100\n                )  # INT((.25*RND(1)+1.00)*10^2+.5)/10^2\n                if fox_price is None:\n                    # Original Bug?  There is no Fox price generated for New York, it will use any previous \"D1\" price\n                    # So if there was no previous value, make one up\n                    fox_price = (\n                        int((0.25 * random.random() + 1.05) * 100 + 0.5) / 100\n                    )  # not in orginal code\n                event_picker = int(10 * random.random()) + 1\n\n                if event_picker <= 2:\n                    print(\"YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\")\n                    print(\"ALL PEOPLE IN YOUR TRADING GROUP WERE\")\n                    print(\"KILLED.  THIS ENDS THE GAME.\")\n                    sys.exit(0)\n                elif event_picker <= 6:\n                    print(\"YOU WERE LUCKY.  YOU ARRIVED SAFELY\")\n                    print(\"AT FORT NEW YORK.\")\n                elif event_picker <= 8:\n                    print(\"YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\")\n                    print(\"HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\")\n                    player_furs = [0, 0, 0, 0]\n                elif event_picker <= 10:\n                    mink_price /= 2\n                    fox_price /= 2\n                    print(\"YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\")\n                    print(\"YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\")\n                else:\n                    print(f\"Internal Error #4, Out-of-bounds event_picker{str(event_picker)}\")\n                    sys.exit(1)  # you have a bug\n\n                print()\n                print(\"SUPPLIES AT NEW YORK COST $85.00.\")\n                print(\"YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\")\n                player_funds -= 105\n\n            else:\n                print(f\"Internal error #2, fort {str(which_fort)} does not exist\")\n                sys.exit(1)  # you have a bug\n\n            # Calculate sales\n            beaver_value = beaver_price * player_furs[FUR_BEAVER]\n            fox_value = fox_price * player_furs[FUR_FOX]\n            ermine_value = ermine_price * player_furs[FUR_ERMINE]\n            mink_value = mink_price * player_furs[FUR_MINK]\n\n            print()\n            print(\"YOUR BEAVER SOLD FOR $%6.2f\" % (beaver_value))\n            print(\"YOUR FOX SOLD FOR    $%6.2f\" % (fox_value))\n            print(\"YOUR ERMINE SOLD FOR $%6.2f\" % (ermine_value))\n            print(\"YOUR MINK SOLD FOR   $%6.2f\" % (mink_value))\n\n            player_funds += beaver_value + fox_value + ermine_value + mink_value\n\n            print()\n            print(\n                \"YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS\" % (player_funds)\n            )\n\n            print()\n            print(\"DO YOU WANT TO TRADE FURS NEXT YEAR?\")\n            should_trade = get_yes_or_no()\n            if should_trade == \"N\":\n                sys.exit(0)  # STOP\n            else:\n                game_state = \"trading\"\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "38_Fur_Trader/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "38_Fur_Trader/vbnet/FurTrader.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"FurTrader\", \"FurTrader.vbproj\", \"{D8310FB8-132A-4D43-A654-17E5A267DDBD}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "38_Fur_Trader/vbnet/FurTrader.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>FurTrader</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "38_Fur_Trader/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "39_Golf/README.md",
    "content": "### Golf\n\nThis is a single player golf game. In other words it’s you against the golf course (the computer). The program asks for your handicap (maximum of 30) and your area of difficulty. You have a bag of 29 clubs plus a putter. On the course you have to contend with rough, trees, on and off fairway, sand traps, and water hazards. In addition, you can hook, slice, go out of bounds, or hit too far. On putting, you determine the potency factor (or percent of swing). Until you get the swing of the game (no pun intended), you’ll probably was to use a fairly high handicap.\n\nSteve North of Creative Computing modified the original version of this game, the author of which is unknown.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=71)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=86)\n\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The weakness numbers printed in the original BASIC program are wrong.  It says 4=TRAP SHOTS, 5=PUTTING, but in the code, trap shots and putting are 3 and 4, respectively.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "39_Golf/csharp/Golf.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "39_Golf/csharp/Golf.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Golf\", \"Golf.csproj\", \"{0D91BC87-BADF-445F-876F-38F3A66A3B83}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "39_Golf/csharp/Program.cs",
    "content": "﻿//\r\n//          8\"\"\"\"8 8\"\"\"88 8     8\"\"\"\"\r\n//          8    \" 8    8 8     8\r\n//          8e     8    8 8e    8eeee\r\n//          88  ee 8    8 88    88\r\n//          88   8 8    8 88    88\r\n//          88eee8 8eeee8 88eee 88\r\n//\r\n// GOLF\r\n//\r\n// C#\r\n// .NET Core\r\n// TargetFramework: netcoreapp 3.1\r\n//\r\n// Run source:\r\n// dotnet run\r\n//\r\n// Linux compile:\r\n// dotnet publish --self-contained -c Release -r linux-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true\r\n//\r\n// Windows compile:\r\n// dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true\r\n//\r\n//\r\n// INDEX\r\n// ----------------- methods\r\n// constructor\r\n// NewHole\r\n// TeeUp\r\n// Stroke\r\n// PlotBall\r\n// InterpretResults\r\n// ReportCurrentScore\r\n// FindBall\r\n// IsOnFairway\r\n// IsOnGreen\r\n// IsInHazard\r\n// IsInRough\r\n// IsOutOfBounds\r\n// ScoreCardNewHole\r\n// ScoreCardRecordStroke\r\n// ScoreCardGetPreviousStroke\r\n// ScoreCardGetTotal\r\n// Ask\r\n// Wait\r\n// ReviewBag\r\n// Quit\r\n// GameOver\r\n// ----------------- DATA\r\n// Clubs\r\n// CourseInfo\r\n// ----------------- classes\r\n// HoleInfo\r\n// CircleGameObj\r\n// RectGameObj\r\n// HoleGeometry\r\n// Plot\r\n// ----------------- helper methods\r\n// GetDistance\r\n// IsInRectangle\r\n// ToRadians\r\n// ToDegrees360\r\n// Odds\r\n//\r\n//  Despite being a text based game, the code uses simple geometry to simulate a course.\r\n//  Fairways are 40 yard wide rectangles, surrounded by 5 yards of rough around the perimeter.\r\n//  The green is a circle of 10 yards radius around the cup.\r\n//  The cup is always at point (0,0).\r\n//\r\n//  Using basic trigonometry we can plot the ball's location using the distance of the stroke and\r\n//  and the angle of deviation (hook/slice).\r\n//\r\n//  The stroke distances are based on real world averages of different club types.\r\n//  Lots of randomization, \"business rules\", and luck influence the game play.\r\n//  Probabilities are commented in the code.\r\n//\r\n//  note: 'courseInfo', 'clubs', & 'scoreCard' arrays each include an empty object so indexing\r\n//  can begin at 1. Like all good programmers we count from zero, but in this context,\r\n//  it's more natural when hole number one is at index one\r\n//\r\n//\r\n//     |-----------------------------|\r\n//     |            rough            |\r\n//     |   ----------------------    |\r\n//     |   |                     |   |\r\n//     | r |        =  =         | r |\r\n//     | o |     =        =      | o |\r\n//     | u |    =    .     =     | u |\r\n//     | g |    =   green  =     | g |\r\n//     | h |     =        =      | h |\r\n//     |   |        =  =         |   |\r\n//     |   |                     |   |\r\n//     |   |                     |   |\r\n//     |   |      Fairway        |   |\r\n//     |   |                     |   |\r\n//     |   |               ------    |\r\n//     |   |            --        -- |\r\n//     |   |           --  hazard  --|\r\n//     |   |            --        -- |\r\n//     |   |               ------    |\r\n//     |   |                     |   |\r\n//     |   |                     |   |   out\r\n//     |   |                     |   |   of\r\n//     |   |                     |   |   bounds\r\n//     |   |                     |   |\r\n//     |   |                     |   |\r\n//     |            tee              |\r\n//\r\n//\r\n//  Typical green size: 20-30 yards\r\n//  Typical golf course fairways are 35 to 45 yards wide\r\n//  Our fairway extends 5 yards past green\r\n//  Our rough is a 5 yard perimeter around fairway\r\n//\r\n//  We calculate the new position of the ball given the ball's point, the distance\r\n//  of the stroke, and degrees off line (hook or slice).\r\n//\r\n//  Degrees off (for a right handed golfer):\r\n//  Slice: positive degrees = ball goes right\r\n//  Hook: negative degrees = left goes left\r\n//\r\n//  The cup is always at point: 0,0.\r\n//  We use atan2 to compute the angle between the cup and the ball.\r\n//  Setting the cup's vector to 0,-1 on a 360 circle is equivalent to:\r\n//  0 deg = 12 o'clock;  90 deg = 3 o'clock;  180 deg = 6 o'clock;  270 = 9 o'clock\r\n//  The reverse angle between the cup and the ball is a difference of PI (using radians).\r\n//\r\n//  Given the angle and stroke distance (hypotenuse), we use cosine to compute\r\n//  the opposite and adjacent sides of the triangle, which, is the ball's new position.\r\n//\r\n//           0\r\n//           |\r\n//    270 - cup - 90\r\n//           |\r\n//          180\r\n//\r\n//\r\n//          cup\r\n//           |\r\n//           |\r\n//           | opp\r\n//           |-----* new position\r\n//           |    /\r\n//           |   /\r\n//      adj  |  /\r\n//           | /  hyp\r\n//           |/\r\n//          tee\r\n//\r\n//    <- hook    slice ->\r\n//\r\n//\r\n//  Given the large number of combinations needed to describe a particular stroke / ball location,\r\n//  we use the technique of \"bitwise masking\" to describe stroke results.\r\n//  With bit masking, multiple flags (bits) are combined into a single binary number that can be\r\n//  tested by applying a mask. A mask is another binary number that isolates a particular bit that\r\n//  you are interested in. You can then apply your language's bitwise opeartors to test or\r\n//  set a flag.\r\n//\r\n//  Game design by Jason Bonthron, 2021\r\n//  www.bonthron.com\r\n//  for my father, Raymond Bonthron, an avid golfer\r\n//\r\n//  Inspired by the 1978 \"Golf\" from \"Basic Computer Games\"\r\n//  by Steve North, who modified an existing golf game by an unknown author\r\n//\r\n//\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Drawing;\r\nusing System.Threading;\r\n\r\n\r\nnamespace Golf\r\n{\r\n    using Ball = Golf.CircleGameObj;\r\n    using Hazard = Golf.CircleGameObj;\r\n\r\n    // --------------------------------------------------------------------------- Program\r\n    class Program\r\n    {\r\n        static void Main(string[] args)\r\n        {\r\n            Golf g = new Golf();\r\n        }\r\n    }\r\n\r\n\r\n    // --------------------------------------------------------------------------- Golf\r\n    public class Golf\r\n    {\r\n        Ball BALL;\r\n        int HOLE_NUM = 0;\r\n        int STROKE_NUM = 0;\r\n        int Handicap = 0;\r\n        int PlayerDifficulty = 0;\r\n        HoleGeometry holeGeometry;\r\n\r\n        // all fairways are 40 yards wide, extend 5 yards beyond the cup, and\r\n        // have 5 yards of rough around the perimeter\r\n        const int FairwayWidth = 40;\r\n        const int FairwayExtension = 5;\r\n        const int RoughAmt = 5;\r\n\r\n        // ScoreCard records the ball position after each stroke\r\n        // a new list for each hole\r\n        // include a blank list so index 1 == hole 1\r\n\r\n        List<List<Ball>> ScoreCard = new List<List<Ball>> { new List<Ball>() };\r\n\r\n        static void w(string s) { Console.WriteLine(s); } // WRITE\r\n        Random RANDOM = new Random();\r\n\r\n\r\n        // --------------------------------------------------------------- constructor\r\n        public Golf()\r\n        {\r\n            Console.Clear();\r\n            w(\" \");\r\n            w(\"          8\\\"\\\"\\\"\\\"8 8\\\"\\\"\\\"88 8     8\\\"\\\"\\\"\\\" \");\r\n            w(\"          8    \\\" 8    8 8     8     \");\r\n            w(\"          8e     8    8 8e    8eeee \");\r\n            w(\"          88  ee 8    8 88    88    \");\r\n            w(\"          88   8 8    8 88    88    \");\r\n            w(\"          88eee8 8eeee8 88eee 88    \");\r\n            w(\" \");\r\n            w(\"Welcome to the Creative Computing Country Club,\");\r\n            w(\"an eighteen hole championship layout located a short\");\r\n            w(\"distance from scenic downtown Lambertville, New Jersey.\");\r\n            w(\"The game will be explained as you play.\");\r\n            w(\"Enjoy your game! See you at the 19th hole...\");\r\n            w(\" \");\r\n            w(\"Type QUIT at any time to leave the game.\");\r\n            w(\"Type BAG at any time to review the clubs in your bag.\");\r\n            w(\" \");\r\n\r\n            Wait((z) =>\r\n            {\r\n                w(\" \");\r\n                w(\"              YOUR BAG\");\r\n                ReviewBag();\r\n                w(\"Type BAG at any time to review the clubs in your bag.\");\r\n                w(\" \");\r\n\r\n                Wait((zz) =>\r\n                {\r\n                    w(\" \");\r\n\r\n                    Ask(\"PGA handicaps range from 0 to 30.\\nWhat is your handicap?\", 0, 30, (i) =>\r\n                    {\r\n                        Handicap = i;\r\n                        w(\" \");\r\n\r\n                        Ask(\"Common difficulties at golf include:\\n1=Hook, 2=Slice, 3=Poor Distance, 4=Trap Shots, 5=Putting\\nWhich one is your worst?\", 1, 5, (j) =>\r\n                        {\r\n                            PlayerDifficulty = j;\r\n                            Console.Clear();\r\n                            NewHole();\r\n                        });\r\n                    });\r\n                });\r\n            });\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- NewHole\r\n        void NewHole()\r\n        {\r\n            HOLE_NUM++;\r\n            STROKE_NUM = 0;\r\n\r\n            HoleInfo info = CourseInfo[HOLE_NUM];\r\n\r\n            int yards = info.Yards;  // from tee to cup\r\n            int par = info.Par;\r\n            var cup = new CircleGameObj(0, 0, 0, GameObjType.CUP);\r\n            var green = new CircleGameObj(0, 0, 10, GameObjType.GREEN);\r\n\r\n            var fairway = new RectGameObj(0 - (FairwayWidth / 2),\r\n                                          0 - (green.Radius + FairwayExtension),\r\n                                          FairwayWidth,\r\n                                          yards + (green.Radius + FairwayExtension) + 1,\r\n                                          GameObjType.FAIRWAY);\r\n\r\n            var rough = new RectGameObj(fairway.X - RoughAmt,\r\n                                        fairway.Y - RoughAmt,\r\n                                        fairway.Width + (2 * RoughAmt),\r\n                                        fairway.Length + (2 * RoughAmt),\r\n                                        GameObjType.ROUGH);\r\n\r\n            BALL = new Ball(0, yards, 0, GameObjType.BALL);\r\n\r\n            ScoreCardStartNewHole();\r\n\r\n            holeGeometry = new HoleGeometry(cup, green, fairway, rough, info.Hazard);\r\n\r\n            w(\"                |> \" + HOLE_NUM);\r\n            w(\"                |        \");\r\n            w(\"                |        \");\r\n            w(\"          ^^^^^^^^^^^^^^^\");\r\n\r\n            Console.WriteLine(\"Hole #{0}. You are at the tee. Distance {1} yards, par {2}.\", HOLE_NUM, info.Yards, info.Par);\r\n            w(info.Description);\r\n\r\n            TeeUp();\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- TeeUp\r\n        // on the green? automatically select putter\r\n        // otherwise Ask club and swing strength\r\n\r\n        void TeeUp()\r\n        {\r\n            if (IsOnGreen(BALL) && !IsInHazard(BALL, GameObjType.SAND))\r\n            {\r\n                var putt = 10;\r\n                w(\"[PUTTER: average 10 yards]\");\r\n                var msg = Odds(20) ? \"Keep your head down.\\n\" : \"\";\r\n\r\n                Ask(msg + \"Choose your putt potency. (1-10)\", 1, 10, (strength) =>\r\n                {\r\n                    var putter = Clubs[putt];\r\n                    Stroke(Convert.ToDouble((double)putter.Item2 * ((double)strength / 10.0)), putt);\r\n                });\r\n            }\r\n            else\r\n            {\r\n                Ask(\"What club do you choose? (1-10)\", 1, 10, (c) =>\r\n                {\r\n                    var club = Clubs[c];\r\n\r\n                    w(\" \");\r\n                    Console.WriteLine(\"[{0}: average {1} yards]\", club.Item1.ToUpper(), club.Item2);\r\n\r\n                    Ask(\"Now gauge your distance by a percentage of a full swing. (1-10)\", 1, 10, (strength) =>\r\n                    {\r\n                        Stroke(Convert.ToDouble((double)club.Item2 * ((double)strength / 10.0)), c);\r\n                    });\r\n                });\r\n            };\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- bitwise Flags\r\n        int dub         = 0b00000000000001;\r\n        int hook        = 0b00000000000010;\r\n        int slice       = 0b00000000000100;\r\n        int passedCup   = 0b00000000001000;\r\n        int inCup       = 0b00000000010000;\r\n        int onFairway   = 0b00000000100000;\r\n        int onGreen     = 0b00000001000000;\r\n        int inRough     = 0b00000010000000;\r\n        int inSand      = 0b00000100000000;\r\n        int inTrees     = 0b00001000000000;\r\n        int inWater     = 0b00010000000000;\r\n        int outOfBounds = 0b00100000000000;\r\n        int luck        = 0b01000000000000;\r\n        int ace         = 0b10000000000000;\r\n\r\n\r\n        // --------------------------------------------------------------- Stroke\r\n        void Stroke(double clubAmt, int clubIndex)\r\n        {\r\n            STROKE_NUM++;\r\n\r\n            var flags = 0b000000000000;\r\n\r\n            // fore! only when driving\r\n            if ((STROKE_NUM == 1) && (clubAmt > 210) && Odds(30)) { w(\"\\\"...Fore !\\\"\"); };\r\n\r\n            // dub\r\n            if (Odds(5)) { flags |= dub; }; // there's always a 5% chance of dubbing it\r\n\r\n            // if you're in the rough, or sand, you really should be using a wedge\r\n            if ((IsInRough(BALL) || IsInHazard(BALL, GameObjType.SAND)) &&\r\n                !(clubIndex == 8 || clubIndex == 9))\r\n            {\r\n                if (Odds(40)) { flags |= dub; };\r\n            };\r\n\r\n            // trap difficulty\r\n            if (IsInHazard(BALL, GameObjType.SAND) && PlayerDifficulty == 4)\r\n            {\r\n                if (Odds(20)) { flags |= dub; };\r\n            }\r\n\r\n            // hook/slice\r\n            // There's 10% chance of a hook or slice\r\n            // if it's a known playerDifficulty then increase chance to 30%\r\n            // if it's a putt & putting is a playerDifficulty increase to 30%\r\n\r\n            bool randHookSlice = (PlayerDifficulty == 1 ||\r\n                                  PlayerDifficulty == 2 ||\r\n                                  (PlayerDifficulty == 5 && IsOnGreen(BALL))) ? Odds(30) : Odds(10);\r\n\r\n            if (randHookSlice)\r\n            {\r\n                if (PlayerDifficulty == 1)\r\n                {\r\n                    if (Odds(80)) { flags |= hook; } else { flags |= slice; };\r\n                }\r\n                else if (PlayerDifficulty == 2)\r\n                {\r\n                    if (Odds(80)) { flags |= slice; } else { flags |= hook; };\r\n                }\r\n                else\r\n                {\r\n                    if (Odds(50)) { flags |= hook; } else { flags |= slice; };\r\n                };\r\n            };\r\n\r\n            // beginner's luck !\r\n            // If handicap is greater than 15, there's a 10% chance of avoiding all errors\r\n            if ((Handicap > 15) && (Odds(10))) { flags |= luck; };\r\n\r\n            // ace\r\n            // there's a 10% chance of an Ace on a par 3\r\n            if (CourseInfo[HOLE_NUM].Par == 3 && Odds(10) && STROKE_NUM == 1) { flags |= ace; };\r\n\r\n            // distance:\r\n            // If handicap is < 15, there a 50% chance of reaching club average,\r\n            // a 25% of exceeding it, and a 25% of falling short\r\n            // If handicap is > 15, there's a 25% chance of reaching club average,\r\n            // and 75% chance of falling short\r\n            // The greater the handicap, the more the ball falls short\r\n            // If poor distance is a known playerDifficulty, then reduce distance by 10%\r\n\r\n            double distance;\r\n            int rnd = RANDOM.Next(1, 101);\r\n\r\n            if (Handicap < 15)\r\n            {\r\n                if (rnd <= 25)\r\n                {\r\n                    distance = clubAmt - (clubAmt * ((double)Handicap / 100.0));\r\n                }\r\n                else if (rnd > 25 && rnd <= 75)\r\n                {\r\n                    distance = clubAmt;\r\n                }\r\n                else\r\n                {\r\n                    distance = clubAmt + (clubAmt * 0.10);\r\n                };\r\n            }\r\n            else\r\n            {\r\n                if (rnd <= 75)\r\n                {\r\n                    distance = clubAmt - (clubAmt * ((double)Handicap / 100.0));\r\n                }\r\n                else\r\n                {\r\n                    distance = clubAmt;\r\n                };\r\n            };\r\n\r\n            if (PlayerDifficulty == 3)  // poor distance\r\n            {\r\n                if (Odds(80)) { distance = (distance * 0.80); };\r\n            };\r\n\r\n            if ((flags & luck) == luck) { distance = clubAmt; }\r\n\r\n            // angle\r\n            // For all strokes, there's a possible \"drift\" of 4 degrees\r\n            // a hooks or slice increases the angle between 5-10 degrees, hook uses negative degrees\r\n            int angle = RANDOM.Next(0, 5);\r\n            if ((flags & slice) == slice) { angle = RANDOM.Next(5, 11); };\r\n            if ((flags & hook) == hook) { angle = 0 - RANDOM.Next(5, 11); };\r\n            if ((flags & luck) == luck) { angle = 0; };\r\n\r\n            var plot = PlotBall(BALL, distance, Convert.ToDouble(angle));  // calculate a new location\r\n            if ((flags & luck) == luck) { if(plot.Y > 0){ plot.Y = 2; }; };\r\n\r\n            flags = FindBall(new Ball(plot.X, plot.Y, plot.Offline, GameObjType.BALL), flags);\r\n\r\n            InterpretResults(plot, flags);\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- plotBall\r\n        Plot PlotBall(Ball ball, double strokeDistance, double degreesOff)\r\n        {\r\n            var cupVector = new Point(0, -1);\r\n            double radFromCup = Math.Atan2((double)ball.Y, (double)ball.X) - Math.Atan2((double)cupVector.Y, (double)cupVector.X);\r\n            double radFromBall = radFromCup - Math.PI;\r\n\r\n            var hypotenuse = strokeDistance;\r\n            var adjacent = Math.Cos(radFromBall + ToRadians(degreesOff)) * hypotenuse;\r\n            var opposite = Math.Sqrt(Math.Pow(hypotenuse, 2) - Math.Pow(adjacent, 2));\r\n\r\n            Point newPos;\r\n            if (ToDegrees360(radFromBall + ToRadians(degreesOff)) > 180)\r\n            {\r\n                newPos = new Point(Convert.ToInt32(ball.X - opposite),\r\n                                   Convert.ToInt32(ball.Y - adjacent));\r\n            }\r\n            else\r\n            {\r\n                newPos = new Point(Convert.ToInt32(ball.X + opposite),\r\n                                   Convert.ToInt32(ball.Y - adjacent));\r\n            }\r\n\r\n            return new Plot(newPos.X, newPos.Y, Convert.ToInt32(opposite));\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- InterpretResults\r\n        void InterpretResults(Plot plot, int flags)\r\n        {\r\n            int cupDistance = Convert.ToInt32(GetDistance(new Point(plot.X, plot.Y),\r\n                                                          new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y)));\r\n            int travelDistance = Convert.ToInt32(GetDistance(new Point(plot.X, plot.Y),\r\n                                                             new Point(BALL.X, BALL.Y)));\r\n\r\n            w(\" \");\r\n\r\n            if ((flags & ace) == ace)\r\n            {\r\n                w(\"Hole in One! You aced it.\");\r\n                ScoreCardRecordStroke(new Ball(0, 0, 0, GameObjType.BALL));\r\n                ReportCurrentScore();\r\n                return;\r\n            };\r\n\r\n            if ((flags & inTrees) == inTrees)\r\n            {\r\n                w(\"Your ball is lost in the trees. Take a penalty stroke.\");\r\n                ScoreCardRecordStroke(BALL);\r\n                TeeUp();\r\n                return;\r\n            };\r\n\r\n            if ((flags & inWater) == inWater)\r\n            {\r\n                var msg = Odds(50) ? \"Your ball has gone to a watery grave.\" : \"Your ball is lost in the water.\";\r\n                w(msg + \" Take a penalty stroke.\");\r\n                ScoreCardRecordStroke(BALL);\r\n                TeeUp();\r\n                return;\r\n            };\r\n\r\n            if ((flags & outOfBounds) == outOfBounds)\r\n            {\r\n                w(\"Out of bounds. Take a penalty stroke.\");\r\n                ScoreCardRecordStroke(BALL);\r\n                TeeUp();\r\n                return;\r\n            };\r\n\r\n            if ((flags & dub) == dub)\r\n            {\r\n                w(\"You dubbed it.\");\r\n                ScoreCardRecordStroke(BALL);\r\n                TeeUp();\r\n                return;\r\n            };\r\n\r\n            if ((flags & inCup) == inCup)\r\n            {\r\n                var msg = Odds(50) ? \"You holed it.\" : \"It's in!\";\r\n                w(msg);\r\n                ScoreCardRecordStroke(new Ball(plot.X, plot.Y, 0, GameObjType.BALL));\r\n                ReportCurrentScore();\r\n                return;\r\n            };\r\n\r\n            if (((flags & slice) == slice) &&\r\n                !((flags & onGreen) == onGreen))\r\n            {\r\n                var bad = ((flags & outOfBounds) == outOfBounds) ? \" badly\" : \"\";\r\n                Console.WriteLine(\"You sliced{0}: {1} yards offline.\", bad, plot.Offline);\r\n            };\r\n\r\n            if (((flags & hook) == hook) &&\r\n                !((flags & onGreen) == onGreen))\r\n            {\r\n                var bad = ((flags & outOfBounds) == outOfBounds) ? \" badly\" : \"\";\r\n                Console.WriteLine(\"You hooked{0}: {1} yards offline.\", bad, plot.Offline);\r\n            };\r\n\r\n            if (STROKE_NUM > 1)\r\n            {\r\n                var prevBall = ScoreCardGetPreviousStroke();\r\n                var d1 = GetDistance(new Point(prevBall.X, prevBall.Y),\r\n                                     new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y));\r\n                var d2 = cupDistance;\r\n                if (d2 > d1) { w(\"Too much club.\"); };\r\n            };\r\n\r\n            if ((flags & inRough) == inRough) { w(\"You're in the rough.\"); };\r\n\r\n            if ((flags & inSand) == inSand) { w(\"You're in a sand trap.\"); };\r\n\r\n            if ((flags & onGreen) == onGreen)\r\n            {\r\n                var pd = (cupDistance < 4) ? ((cupDistance * 3) + \" feet\") : (cupDistance + \" yards\");\r\n                Console.WriteLine(\"You're on the green. It's {0} from the pin.\", pd);\r\n            };\r\n\r\n            if (((flags & onFairway) == onFairway) ||\r\n                ((flags & inRough) == inRough))\r\n            {\r\n                Console.WriteLine(\"Shot went {0} yards. It's {1} yards from the cup.\", travelDistance, cupDistance);\r\n            };\r\n\r\n            ScoreCardRecordStroke(new Ball(plot.X, plot.Y, 0, GameObjType.BALL));\r\n\r\n            BALL = new Ball(plot.X, plot.Y, 0, GameObjType.BALL);\r\n\r\n            TeeUp();\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- ReportCurrentScore\r\n        void ReportCurrentScore()\r\n        {\r\n            var par = CourseInfo[HOLE_NUM].Par;\r\n            if (ScoreCard[HOLE_NUM].Count == par + 1) { w(\"A bogey. One above par.\"); };\r\n            if (ScoreCard[HOLE_NUM].Count == par) { w(\"Par. Nice.\"); };\r\n            if (ScoreCard[HOLE_NUM].Count == (par - 1)) { w(\"A birdie! One below par.\"); };\r\n            if (ScoreCard[HOLE_NUM].Count == (par - 2)) { w(\"An Eagle! Two below par.\"); };\r\n            if (ScoreCard[HOLE_NUM].Count == (par - 3)) { w(\"Double Eagle! Unbelievable.\"); };\r\n\r\n            int totalPar = 0;\r\n            for (var i = 1; i <= HOLE_NUM; i++) { totalPar += CourseInfo[i].Par; };\r\n\r\n            w(\" \");\r\n            w(\"-----------------------------------------------------\");\r\n            Console.WriteLine(\" Total par for {0} hole{1} is: {2}. Your total is: {3}.\",\r\n                              HOLE_NUM,\r\n                              ((HOLE_NUM > 1) ? \"s\" : \"\"), //plural\r\n                              totalPar,\r\n                              ScoreCardGetTotal());\r\n            w(\"-----------------------------------------------------\");\r\n            w(\" \");\r\n\r\n            if (HOLE_NUM == 18)\r\n            {\r\n                GameOver();\r\n            }\r\n            else\r\n            {\r\n                Thread.Sleep(2000);\r\n                NewHole();\r\n            };\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- FindBall\r\n        int FindBall(Ball ball, int flags)\r\n        {\r\n            if (IsOnFairway(ball) && !IsOnGreen(ball)) { flags |= onFairway; }\r\n            if (IsOnGreen(ball)) { flags |= onGreen; }\r\n            if (IsInRough(ball)) { flags |= inRough; }\r\n            if (IsOutOfBounds(ball)) { flags |= outOfBounds; }\r\n            if (IsInHazard(ball, GameObjType.WATER)) { flags |= inWater; }\r\n            if (IsInHazard(ball, GameObjType.TREES)) { flags |= inTrees; }\r\n            if (IsInHazard(ball, GameObjType.SAND))  { flags |= inSand;  }\r\n\r\n            if (ball.Y < 0) { flags |= passedCup; }\r\n\r\n            // less than 2, it's in the cup\r\n            var d = GetDistance(new Point(ball.X, ball.Y),\r\n                                new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y));\r\n            if (d < 2) { flags |= inCup; };\r\n\r\n            return flags;\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- IsOnFairway\r\n        bool IsOnFairway(Ball ball)\r\n        {\r\n            return IsInRectangle(ball, holeGeometry.Fairway);\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- IsOngreen\r\n        bool IsOnGreen(Ball ball)\r\n        {\r\n            var d = GetDistance(new Point(ball.X, ball.Y),\r\n                                new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y));\r\n            return d < holeGeometry.Green.Radius;\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- IsInHazard\r\n        bool IsInHazard(Ball ball, GameObjType hazard)\r\n        {\r\n            bool result = false;\r\n            Array.ForEach(holeGeometry.Hazards, (Hazard h) =>\r\n            {\r\n                var d = GetDistance(new Point(ball.X, ball.Y), new Point(h.X, h.Y));\r\n                if ((d < h.Radius) && h.Type == hazard) { result = true; };\r\n            });\r\n            return result;\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- IsInRough\r\n        bool IsInRough(Ball ball)\r\n        {\r\n            return IsInRectangle(ball, holeGeometry.Rough) &&\r\n                (IsInRectangle(ball, holeGeometry.Fairway) == false);\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- IsOutOfBounds\r\n        bool IsOutOfBounds(Ball ball)\r\n        {\r\n            return (IsOnFairway(ball) == false) && (IsInRough(ball) == false);\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- ScoreCardNewHole\r\n        void ScoreCardStartNewHole()\r\n        {\r\n            ScoreCard.Add(new List<Ball>());\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- ScoreCardRecordStroke\r\n        void ScoreCardRecordStroke(Ball ball)\r\n        {\r\n            var clone = new Ball(ball.X, ball.Y, 0, GameObjType.BALL);\r\n            ScoreCard[HOLE_NUM].Add(clone);\r\n        }\r\n\r\n\r\n        // ------------------------------------------------------------ ScoreCardGetPreviousStroke\r\n        Ball ScoreCardGetPreviousStroke()\r\n        {\r\n            return ScoreCard[HOLE_NUM][ScoreCard[HOLE_NUM].Count - 1];\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- ScoreCardGetTotal\r\n        int ScoreCardGetTotal()\r\n        {\r\n            int total = 0;\r\n            ScoreCard.ForEach((h) => { total += h.Count; });\r\n            return total;\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- Ask\r\n        // input from console is always an integer passed to a callback\r\n        // or \"quit\" to end game\r\n\r\n        void Ask(string question, int min, int max, Action<int> callback)\r\n        {\r\n            w(question);\r\n            string i = Console.ReadLine().Trim().ToLower();\r\n            if (i == \"quit\") { Quit(); return; };\r\n            if (i == \"bag\") { ReviewBag(); };\r\n\r\n            int n;\r\n            bool success = Int32.TryParse(i, out n);\r\n\r\n            if (success)\r\n            {\r\n                if (n >= min && n <= max)\r\n                {\r\n                    callback(n);\r\n                }\r\n                else\r\n                {\r\n                    Ask(question, min, max, callback);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                Ask(question, min, max, callback);\r\n            };\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- Wait\r\n        void Wait(Action<int> callback)\r\n        {\r\n            w(\"Press any key to continue.\");\r\n\r\n            ConsoleKeyInfo keyinfo;\r\n            do { keyinfo = Console.ReadKey(true); }\r\n            while (keyinfo.KeyChar < 0);\r\n            Console.Clear();\r\n            callback(0);\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- ReviewBag\r\n        void ReviewBag()\r\n        {\r\n            w(\" \");\r\n            w(\"  #     Club      Average Yardage\");\r\n            w(\"-----------------------------------\");\r\n            w(\"  1    Driver           250\");\r\n            w(\"  2    3 Wood           225\");\r\n            w(\"  3    5 Wood           200\");\r\n            w(\"  4    Hybrid           190\");\r\n            w(\"  5    4 Iron           170\");\r\n            w(\"  6    7 Iron           150\");\r\n            w(\"  7    9 Iron           125\");\r\n            w(\"  8    Pitching wedge   110\");\r\n            w(\"  9    Sand wedge        75\");\r\n            w(\" 10    Putter            10\");\r\n            w(\" \");\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- Quit\r\n        void Quit()\r\n        {\r\n            w(\"\");\r\n            w(\"Looks like rain. Goodbye!\");\r\n            w(\"\");\r\n            Wait((z) => { });\r\n            return;\r\n        }\r\n\r\n\r\n        // --------------------------------------------------------------- GameOver\r\n        void GameOver()\r\n        {\r\n            var net = ScoreCardGetTotal() - Handicap;\r\n            w(\"Good game!\");\r\n            w(\"Your net score is: \" + net);\r\n            w(\"Let's visit the pro shop...\");\r\n            w(\" \");\r\n            Wait((z) => { });\r\n            return;\r\n        }\r\n\r\n\r\n        // YOUR BAG\r\n        // ======================================================== Clubs\r\n        (string, int)[] Clubs = new (string, int)[] {\r\n            (\"\",0),\r\n\r\n                // name, average yardage\r\n                (\"Driver\", 250),\r\n                (\"3 Wood\", 225),\r\n                (\"5 Wood\", 200),\r\n                (\"Hybrid\", 190),\r\n                (\"4 Iron\", 170),\r\n                (\"7 Iron\", 150),\r\n                (\"9 Iron\", 125),\r\n                (\"Pitching wedge\", 110),\r\n                (\"Sand wedge\", 75),\r\n                (\"Putter\", 10)\r\n                };\r\n\r\n\r\n        // THE COURSE\r\n        // ======================================================== CourseInfo\r\n\r\n        HoleInfo[] CourseInfo = new HoleInfo[]{\r\n            new HoleInfo(0, 0, 0, new Hazard[]{}, \"\"), // include a blank so index 1 == hole 1\r\n\r\n\r\n            // -------------------------------------------------------- front 9\r\n            // hole, yards, par, hazards, (description)\r\n\r\n            new HoleInfo(1, 361, 4,\r\n                         new Hazard[]{\r\n                             new Hazard( 20, 100, 10, GameObjType.TREES),\r\n                             new Hazard(-20,  80, 10, GameObjType.TREES),\r\n                             new Hazard(-20, 100, 10, GameObjType.TREES)\r\n                         },\r\n                         \"There are a couple of trees on the left and right.\"),\r\n\r\n            new HoleInfo(2, 389, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(0, 160, 20, GameObjType.WATER)\r\n                         },\r\n                         \"There is a large water hazard across the fairway about 150 yards.\"),\r\n\r\n            new HoleInfo(3, 206, 3,\r\n                         new Hazard[]{\r\n                             new Hazard( 20,  20,  5, GameObjType.WATER),\r\n                             new Hazard(-20, 160, 10, GameObjType.WATER),\r\n                             new Hazard( 10,  12,  5, GameObjType.SAND)\r\n                         },\r\n                         \"There is some sand and water near the green.\"),\r\n\r\n            new HoleInfo(4, 500, 5,\r\n                         new Hazard[]{\r\n                             new Hazard(-14, 12, 12, GameObjType.SAND)\r\n                         },\r\n                         \"There's a bunker to the left of the green.\"),\r\n\r\n            new HoleInfo(5, 408, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(20, 120, 20, GameObjType.TREES),\r\n                             new Hazard(20, 160, 20, GameObjType.TREES),\r\n                             new Hazard(10,  20,  5, GameObjType.SAND)\r\n                         },\r\n                         \"There are some trees to your right.\"),\r\n\r\n            new HoleInfo(6, 359, 4,\r\n                         new Hazard[]{\r\n                             new Hazard( 14, 0, 4, GameObjType.SAND),\r\n                             new Hazard(-14, 0, 4, GameObjType.SAND)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(7, 424, 5,\r\n                         new Hazard[]{\r\n                             new Hazard(20, 200, 10, GameObjType.SAND),\r\n                             new Hazard(10, 180, 10, GameObjType.SAND),\r\n                             new Hazard(20, 160, 10, GameObjType.SAND)\r\n                         },\r\n                         \"There are several sand traps along your right.\"),\r\n\r\n            new HoleInfo(8, 388, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(-20, 340, 10, GameObjType.TREES)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(9, 196, 3,\r\n                         new Hazard[]{\r\n                             new Hazard(-30, 180, 20, GameObjType.TREES),\r\n                             new Hazard( 14,  -8,  5, GameObjType.SAND)\r\n                         },\r\n                         \"\"),\r\n\r\n            // -------------------------------------------------------- back 9\r\n            // hole, yards, par, hazards, (description)\r\n\r\n            new HoleInfo(10, 400, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(-14, -8, 5, GameObjType.SAND),\r\n                             new Hazard( 14, -8, 5, GameObjType.SAND)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(11, 560, 5,\r\n                         new Hazard[]{\r\n                             new Hazard(-20, 400, 10, GameObjType.TREES),\r\n                             new Hazard(-10, 380, 10, GameObjType.TREES),\r\n                             new Hazard(-20, 260, 10, GameObjType.TREES),\r\n                             new Hazard(-20, 200, 10, GameObjType.TREES),\r\n                             new Hazard(-10, 180, 10, GameObjType.TREES),\r\n                             new Hazard(-20, 160, 10, GameObjType.TREES)\r\n                         },\r\n                         \"Lots of trees along the left of the fairway.\"),\r\n\r\n            new HoleInfo(12, 132, 3,\r\n                         new Hazard[]{\r\n                             new Hazard(-10, 120, 10, GameObjType.WATER),\r\n                             new Hazard( -5, 100, 10, GameObjType.SAND)\r\n                         },\r\n                         \"There is water and sand directly in front of you. A good drive should clear both.\"),\r\n\r\n            new HoleInfo(13, 357, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(-20, 200, 10, GameObjType.TREES),\r\n                             new Hazard(-10, 180, 10, GameObjType.TREES),\r\n                             new Hazard(-20, 160, 10, GameObjType.TREES),\r\n                             new Hazard( 14,  12,  8, GameObjType.SAND)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(14, 294, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(0, 20, 10, GameObjType.SAND)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(15, 475, 5,\r\n                         new Hazard[]{\r\n                             new Hazard(-20, 20, 10, GameObjType.WATER),\r\n                             new Hazard( 10, 20, 10, GameObjType.SAND)\r\n                         },\r\n                         \"Some sand and water near the green.\"),\r\n\r\n            new HoleInfo(16, 375, 4,\r\n                         new Hazard[]{\r\n                             new Hazard(-14, -8, 5, GameObjType.SAND)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(17, 180, 3,\r\n                         new Hazard[]{\r\n                             new Hazard( 20, 100, 10, GameObjType.TREES),\r\n                             new Hazard(-20,  80, 10, GameObjType.TREES)\r\n                         },\r\n                         \"\"),\r\n\r\n            new HoleInfo(18, 550, 5,\r\n                         new Hazard[]{\r\n                             new Hazard(20, 30, 15, GameObjType.WATER)\r\n                         },\r\n                         \"There is a water hazard near the green.\")\r\n        };\r\n\r\n\r\n        // -------------------------------------------------------- HoleInfo\r\n        class HoleInfo\r\n        {\r\n            public int Hole { get; }\r\n            public int Yards { get; }\r\n            public int Par { get; }\r\n            public Hazard[] Hazard { get; }\r\n            public string Description { get; }\r\n\r\n            public HoleInfo(int hole, int yards, int par, Hazard[] hazard, string description)\r\n            {\r\n                Hole = hole;\r\n                Yards = yards;\r\n                Par = par;\r\n                Hazard = hazard;\r\n                Description = description;\r\n            }\r\n        }\r\n\r\n\r\n        public enum GameObjType { BALL, CUP, GREEN, FAIRWAY, ROUGH, TREES, WATER, SAND }\r\n\r\n\r\n        // -------------------------------------------------------- CircleGameObj\r\n        public class CircleGameObj\r\n        {\r\n            public GameObjType Type { get; }\r\n            public int X { get; }\r\n            public int Y { get; }\r\n            public int Radius { get; }\r\n\r\n            public CircleGameObj(int x, int y, int r, GameObjType type)\r\n            {\r\n                Type = type;\r\n                X = x;\r\n                Y = y;\r\n                Radius = r;\r\n            }\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- RectGameObj\r\n        public class RectGameObj\r\n        {\r\n            public GameObjType Type { get; }\r\n            public int X { get; }\r\n            public int Y { get; }\r\n            public int Width { get; }\r\n            public int Length { get; }\r\n\r\n            public RectGameObj(int x, int y, int w, int l, GameObjType type)\r\n            {\r\n                Type = type;\r\n                X = x;\r\n                Y = y;\r\n                Width = w;\r\n                Length = l;\r\n            }\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- HoleGeometry\r\n        public class HoleGeometry\r\n        {\r\n            public CircleGameObj Cup { get; }\r\n            public CircleGameObj Green { get; }\r\n            public RectGameObj Fairway { get; }\r\n            public RectGameObj Rough { get; }\r\n            public Hazard[] Hazards { get; }\r\n\r\n            public HoleGeometry(CircleGameObj cup, CircleGameObj green, RectGameObj fairway, RectGameObj rough, Hazard[] haz)\r\n            {\r\n                Cup = cup;\r\n                Green = green;\r\n                Fairway = fairway;\r\n                Rough = rough;\r\n                Hazards = haz;\r\n            }\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- Plot\r\n        public class Plot\r\n        {\r\n            public int X { get; }\r\n            public int Y { get; set; }\r\n            public int Offline { get; }\r\n\r\n            public Plot(int x, int y, int offline)\r\n            {\r\n                X = x;\r\n                Y = y;\r\n                Offline = offline;\r\n            }\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- GetDistance\r\n        // distance between 2 points\r\n        double GetDistance(Point pt1, Point pt2)\r\n        {\r\n            return Math.Sqrt(Math.Pow((pt2.X - pt1.X), 2) + Math.Pow((pt2.Y - pt1.Y), 2));\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- IsInRectangle\r\n        bool IsInRectangle(CircleGameObj pt, RectGameObj rect)\r\n        {\r\n            return ((pt.X > rect.X) &&\r\n                    (pt.X < rect.X + rect.Width) &&\r\n                    (pt.Y > rect.Y) &&\r\n                    (pt.Y < rect.Y + rect.Length));\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- ToRadians\r\n        double ToRadians(double angle) { return angle * (Math.PI / 180.0); }\r\n\r\n\r\n        // -------------------------------------------------------- ToDegrees360\r\n        // radians to 360 degrees\r\n        double ToDegrees360(double angle)\r\n        {\r\n            double deg = angle * (180.0 / Math.PI);\r\n            if (deg < 0.0) { deg += 360.0; }\r\n            return deg;\r\n        }\r\n\r\n\r\n        // -------------------------------------------------------- Odds\r\n        // chance an integer is <= the given argument\r\n        // between 1-100\r\n        Random RND = new Random();\r\n\r\n        bool Odds(int x)\r\n        {\r\n            return RND.Next(1, 101) <= x;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "39_Golf/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\nThere are 2 compiled executables in the compiled/ directory (windows and linux) that you can play right away!\n\nProgram.cs contains the C# source code.\nIt has been written for .NET Core 3.1\n\nThe source code is well documented.\n"
  },
  {
    "path": "39_Golf/golf.bas",
    "content": "1 PRINT TAB(34);\"GOLF\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,\"\n5 PRINT \"AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT\"\n6 PRINT \"DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN.  THE\"\n7 PRINT \"COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY.\"\n8 PRINT \"ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE...\"\n9 PRINT:PRINT: DIM L(10)\n10 G1=18\n20 G2=0\n30 G3=0\n40 A=0\n50 N=.8\n60 S2=0\n70 F=1\n80 PRINT \"WHAT IS YOUR HANDICAP\";\n90 INPUT H:PRINT\n100 IF H>30 THEN 470\n110 IF H<0 THEN 470\n120 PRINT \"DIFFICULTIES AT GOLF INCLUDE:\"\n130 PRINT \"0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING\"\n140 PRINT \"WHICH ONE (ONLY ONE) IS YOUR WORST\";\n150 INPUT T:PRINT\n160 IF T>5 THEN 120\n170 S1=0\n210 REM\n230 L(0)=0\n240 J=0\n245 Q=0\n250 S2=S2+1\n260 K=0\n270 IF F=1 THEN 310\n290 PRINT \"YOUR SCORE ON HOLE\";F-1;\"WAS\";S1\n291 GOTO 1750\n292 IF S1>P+2 THEN 297\n293 IF S1=P THEN 299\n294 IF S1=P-1 THEN 301\n295 IF S1=P-2 THEN 303\n296 GOTO 310\n297 PRINT \"KEEP YOUR HEAD DOWN.\"\n298 GOTO 310\n299 PRINT \"A PAR.  NICE GOING.\"\n300 GOTO 310\n301 PRINT \"A BIRDIE.\"\n302 GOTO 310\n303 IF P=3 THEN 306\n304 PRINT \"A GREAT BIG EAGLE.\"\n305 GOTO 310\n306 PRINT \"A HOLE IN ONE.\"\n310 IF F=19 THEN 1710\n315 S1=0\n316 PRINT\n320 IF S1=0 THEN 1590\n330 IF L(0)<1 THEN 1150\n340 X=0\n350 IF L(0)>5 THEN 1190\n360 PRINT \"SHOT WENT\";D1;\"YARDS.  IT'S\";D2;\"YARDS FROM THE CUP.\"\n362 PRINT \"BALL IS\";INT(O);\"YARDS OFF LINE... IN \";\n380 GOSUB 400\n390 GOTO 620\n400 IF L(X)=1 THEN 480\n410 IF L(X)=2 THEN 500\n420 IF L(X)=3 THEN 520\n430 IF L(X)=4 THEN 540\n440 IF L(X)=5 THEN 560\n450 IF L(X)=6 THEN 580\n460 PRINT \"OUT OF BOUNDS.\"\n465 GOTO 1690\n470 PRINT \"PGA HANDICAPS RANGE FROM 0 TO 30.\"\n472 GOTO 80\n480 PRINT \"FAIRWAY.\"\n490 GOTO 1690\n500 PRINT \"ROUGH.\"\n510 GOTO 1690\n520 PRINT \"TREES.\"\n530 GOTO 1690\n540 PRINT \"ADJACENT FAIRWAY.\"\n550 GOTO 1690\n560 PRINT \"TRAP.\"\n570 GOTO 1690\n580 PRINT \"WATER.\"\n590 GOTO 1690\n620 IF A=1 THEN 629\n621 PRINT \"SELECTION OF CLUBS\"\n622 PRINT \"YARDAGE DESIRED                       SUGGESTED CLUBS\"\n623 PRINT \"200 TO 280 YARDS                           1 TO 4\"\n624 PRINT \"100 TO 200 YARDS                          19 TO 13\"\n625 PRINT \"  0 TO 100 YARDS                          29 TO 23\"\n626 A=1\n629 PRINT \"WHAT CLUB DO YOU CHOOSE\";\n630 INPUT C\n632 PRINT\n635 IF C<1 THEN 690\n637 IF C>29 THEN 690\n640 IF C>4 THEN 710\n650 IF L(0)<=5 THEN 740\n660 IF C=14 THEN 740\n665 IF C=23 THEN 740\n670 GOTO 690\n680 S1=S1-1\n690 PRINT \"THAT CLUB IS NOT IN THE BAG.\"\n693 PRINT\n700 GOTO 620\n710 IF C<12 THEN 690\n720 C=C-6\n730 GOTO 650\n740 S1=S1+1\n741 W=1\n742 IF C>13 THEN 960\n746 IF INT(F/3)=F/3 THEN 952\n752 IF C<4 THEN 756\n754 GOTO 760\n756 IF L(0)=2 THEN 862\n760 IF S1>7 THEN 867\n770 D1=INT(((30-H)*2.5+187-((30-H)*.25+15)*C/2)+25*RND(1))\n780 D1=INT(D1*W)\n800 IF T=2 THEN 1170\n830 O=(RND(1)/.8)*(2*H+16)*ABS(TAN(D1*.0035))\n840 D2=INT(SQR(O^2+ABS(D-D1)^2))\n850 IF D-D1<0 THEN 870\n860 GOTO 890\n862 PRINT \"YOU DUBBED IT.\"\n864 D1=35\n866 GOTO 830\n867 IF D<200 THEN 1300\n868 GOTO 770\n870 IF D2<20 THEN 890\n880 PRINT \"TOO MUCH CLUB. YOU'RE PAST THE HOLE.\"\n890 B=D\n900 D=D2\n910 IF D2>27 THEN 1020\n920 IF D2>20 THEN 1100\n930 IF D2>.5 THEN 1120\n940 L(0)=9\n950 GOTO 1470\n952 IF S2+Q+(10*(F-1)/18)<(F-1)*(72+((H+1)/.85))/18 THEN 956\n954 GOTO 752\n956 Q=Q+1\n957 IF S1/2<>INT(S1/2) THEN 1011\n958 GOTO 862\n960 PRINT \"NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)\"\n961 PRINT \"OF A FULL SWING\";\n970 INPUT W: W=W/100\n972 PRINT\n980 IF W>1 THEN 680\n985 IF L(0)=5 THEN 1280\n990 IF C=14 THEN 760\n1000 C=C-10\n1010 GOTO 760\n1011 IF D<95 THEN 862\n1012 PRINT \"BALL HIT TREE - BOUNCED INTO ROUGH\";D-75;\"YARDS FROM HOLE.\"\n1014 D=D-75\n1018 GOTO 620\n1020 IF O<30 THEN 1150\n1022 IF J>0 THEN 1150\n1030 IF T>0 THEN 1070\n1035 S9=(S2+1)/15\n1036 IF INT(S9)=S9 THEN 1075\n1040 PRINT \"YOU HOOKED- \";\n1050 L(0)=L(2)\n1055 IF O>45 THEN 1092\n1060 GOTO 320\n1070 S9=(S2+1)/15\n1071 IF INT(S9)=S9 THEN 1040\n1075 PRINT \"YOU SLICED- \";\n1080 L(0)=L(1)\n1090 GOTO 1055\n1092 PRINT \"BADLY.\"\n1094 GOTO 320\n1100 L(0)=5\n1110 GOTO 320\n1120 L(0)=8\n1130 D2=INT(D2*3)\n1140 GOTO 1380\n1150 L(0)=1\n1160 GOTO 320\n1170 D1=INT(.85*D1)\n1180 GOTO 830\n1190 IF L(0)>6 THEN 1260\n1200 PRINT \"YOUR SHOT WENT INTO THE WATER.\"\n1210 S1=S1+1\n1220 PRINT \"PENALTY STROKE ASSESSED.  HIT FROM PREVIOUS LOCATION.\"\n1230 J=J+1\n1240 L(0)=1\n1242 D=B\n1250 GOTO 620\n1260 PRINT \"YOUR SHOT WENT OUT OF BOUNDS.\"\n1270 GOTO 1210\n1280 IF T=3 THEN 1320\n1300 D2=1+(3*INT((80/(40-H))*RND(1)))\n1310 GOTO 1380\n1320 IF RND(1)>N THEN 1360\n1330 N=N*.2\n1340 PRINT \"SHOT DUBBED, STILL IN TRAP.\"\n1350 GOTO 620\n1360 N=.8\n1370 GOTO 1300\n1380 PRINT \"ON GREEN,\";D2;\"FEET FROM THE PIN.\"\n1381 PRINT \"CHOOSE YOUR PUTT POTENCY (1 TO 13):\";\n1400 INPUT I\n1410 S1=S1+1\n1420 IF S1+1-P>(H*.072)+2 THEN 1470\n1425 IF K>2 THEN 1470\n1428 K=K+1\n1430 IF T=4 THEN 1530\n1440 D2=D2-I*(4+2*RND(1))+1.5\n1450 IF D2<-2 THEN 1560\n1460 IF D2>2 THEN 1500\n1470 PRINT \"YOU HOLED IT.\"\n1472 PRINT\n1480 F=F+1\n1490 GOTO 230\n1500 PRINT \"PUTT SHORT.\"\n1505 D2=INT(D2)\n1510 GOTO 1380\n1530 D2=D2-I*(4+1*RND(1))+1\n1550 GOTO 1450\n1560 PRINT \"PASSED BY CUP.\"\n1570 D2=-D2\n1580 GOTO 1505\n1590 READ D,P,L(1),L(2)\n1595 PRINT\n1600 PRINT \"YOU ARE AT THE TEE OFF HOLE\";F;\"DISTANCE\";D;\"YARDS, PAR\";P\n1605 G3=G3+P\n1620 PRINT \"ON YOUR RIGHT IS \";\n1630 X=1\n1640 GOSUB 400\n1650 PRINT \"ON YOUR LEFT IS \";\n1660 X=2\n1670 GOSUB 400\n1680 GOTO 620\n1690 RETURN\n1700 DATA 361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2\n1702 DATA 408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4\n1704 DATA 196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2\n1706 DATA 357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2\n1708 DATA 180,3,6,2,550,5,6,6\n1710 PRINT\n1750 G2=G2+S1\n1760 PRINT \"TOTAL PAR FOR\";F-1;\"HOLES IS\";G3;\"  YOUR TOTAL IS\";G2\n1761 IF G1=F-1 THEN 1770\n1765 GOTO 292\n1770 END\n"
  },
  {
    "path": "39_Golf/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "39_Golf/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "39_Golf/javascript/golf.html",
    "content": "<html>\n<head>\n<title>GOLF</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"golf.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "39_Golf/javascript/golf.js",
    "content": "// GOLF\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar la = [];\nvar f;\nvar s1;\nvar g2;\nvar g3;\nvar x;\n\nvar hole_data = [\n    361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2,\n    408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4,\n    196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2,\n    357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2,\n    180,3,6,2,550,5,6,6,\n];\n\nfunction show_obstacle()\n{\n    switch (la[x]) {\n        case 1:\n            print(\"FAIRWAY.\\n\");\n            break;\n        case 2:\n            print(\"ROUGH.\\n\");\n            break;\n        case 3:\n            print(\"TREES.\\n\");\n            break;\n        case 4:\n            print(\"ADJACENT FAIRWAY.\\n\");\n            break;\n        case 5:\n            print(\"TRAP.\\n\");\n            break;\n        case 6:\n            print(\"WATER.\\n\");\n            break;\n    }\n}\n\nfunction show_score()\n{\n    g2 += s1;\n    print(\"TOTAL PAR FOR \" + (f - 1) + \" HOLES IS \" + g3 + \"  YOUR TOTAL IS \" + g2 + \"\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"GOLF\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,\\n\");\n    print(\"AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT\\n\");\n    print(\"DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN.  THE\\n\");\n    print(\"COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY.\\n\");\n    print(\"ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE...\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    next_hole = 0;\n    g1 = 18;\n    g2 = 0;\n    g3 = 0;\n    a = 0;\n    n = 0.8;\n    s2 = 0;\n    f = 1;\n    while (1) {\n        print(\"WHAT IS YOUR HANDICAP\");\n        h = parseInt(await input());\n        print(\"\\n\");\n        if (h < 0 || h > 30) {\n            print(\"PGA HANDICAPS RANGE FROM 0 TO 30.\\n\");\n        } else {\n            break;\n        }\n    }\n    do {\n        print(\"DIFFICULTIES AT GOLF INCLUDE:\\n\");\n        print(\"0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING\\n\");\n        print(\"WHICH ONE (ONLY ONE) IS YOUR WORST\");\n        t = parseInt(await input());\n        print(\"\\n\");\n    } while (t > 5) ;\n    s1 = 0;\n    first_routine = true;\n    while (1) {\n        if (first_routine) {\n            la[0] = 0;\n            j = 0;\n            q = 0;\n            s2++;\n            k = 0;\n            if (f != 1) {\n                print(\"YOUR SCORE ON HOLE \" + (f - 1) + \" WAS \" + s1 + \"\\n\");\n                show_score();\n                if (g1 == f - 1)    // Completed all holes?\n                    return;         // Exit game\n                if (s1 > p + 2) {\n                    print(\"KEEP YOUR HEAD DOWN.\\n\");\n                } else if (s1 == p) {\n                    print(\"A PAR.  NICE GOING.\\n\");\n                } else if (s1 == p - 1) {\n                    print(\"A BIRDIE.\\n\");\n                } else if (s1 == p - 2) {\n                    if (p != 3)\n                        print(\"A GREAT BIG EAGLE.\\n\");\n                    else\n                        print(\"A HOLE IN ONE.\\n\");\n                }\n            }\n            if (f == 19) {\n                print(\"\\n\");\n                show_score();\n                if (g1 == f - 1)\n                    return;\n            }\n            s1 = 0;\n            print(\"\\n\");\n            if (s1 != 0 && la[0] < 1)\n                la[0] = 1;\n        }\n        if (s1 == 0) {\n            d = hole_data[next_hole++];\n            p = hole_data[next_hole++];\n            la[1] = hole_data[next_hole++];\n            la[2] = hole_data[next_hole++];\n            print(\"\\n\");\n            print(\"YOU ARE AT THE TEE OFF HOLE \" + f + \" DISTANCE \" + d + \" YARDS, PAR \" + p + \"\\n\");\n            g3 += p;\n            print(\"ON YOUR RIGHT IS \");\n            x = 1;\n            show_obstacle();\n            print(\"ON YOUR LEFT IS \");\n            x = 2\n            show_obstacle();\n        } else {\n            x = 0;\n            if (la[0] > 5) {\n                if (la[0] > 6) {\n                    print(\"YOUR SHOT WENT OUT OF BOUNDS.\\n\");\n                } else {\n                    print(\"YOUR SHOT WENT INTO THE WATER.\\n\");\n                }\n                s1++;\n                print(\"PENALTY STROKE ASSESSED.  HIT FROM PREVIOUS LOCATION.\\n\");\n                j++;\n                la[0] = 1;\n                d = b;\n            } else {\n                print(\"SHOT WENT \" + d1 + \" YARDS.  IT'S \" + d2 + \" YARDS FROM THE CUP.\\n\");\n                print(\"BALL IS \" + Math.floor(o) + \" YARDS OFF LINE... IN \");\n                show_obstacle();\n            }\n        }\n\n        while (1) {\n            if (a != 1) {\n                print(\"SELECTION OF CLUBS\\n\");\n                print(\"YARDAGE DESIRED                       SUGGESTED CLUBS\\n\");\n                print(\"200 TO 280 YARDS                           1 TO 4\\n\");\n                print(\"100 TO 200 YARDS                          19 TO 13\\n\");\n                print(\"  0 TO 100 YARDS                          29 TO 23\\n\");\n                a = 1;\n            }\n            print(\"WHAT CLUB DO YOU CHOOSE\");\n            c = parseInt(await input());\n            print(\"\\n\");\n            if (c >= 1 && c <= 29 && (c < 5 || c >= 12)) {\n                if (c > 4)\n                    c -= 6;\n                if (la[0] <= 5 || c == 14 || c == 23) {\n                    s1++;\n                    w = 1;\n                    if (c <= 13) {\n                        if (f % 3 == 0 && s2 + q + (10 * (f - 1) / 18) < (f - 1) * (72 + ((h + 1) / 0.85)) / 18) {\n                            q++;\n                            if (s1 % 2 != 0 && d >= 95) {\n                                print(\"BALL HIT TREE - BOUNCED INTO ROUGH \" + (d - 75) + \" YARDS FROM HOLE.\\n\");\n                                d -= 75;\n                                continue;\n                            }\n                            print(\"YOU DUBBED IT.\\n\");\n                            d1 = 35;\n                            second_routine = 1;\n                            break;\n                        } else if (c < 4 && la[0] == 2) {\n                            print(\"YOU DUBBED IT.\\n\");\n                            d1 = 35;\n                            second_routine = 1;\n                            break;\n                        } else {\n                            second_routine = 0;\n                            break;\n                        }\n                    } else {\n                        print(\"NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)\\n\");\n                        print(\"OF A FULL SWING\");\n                        w = parseInt(await input());\n                        w /= 100;\n                        print(\"\\n\");\n                        if (w <= 1) {\n                            if (la[0] == 5) {\n                                if (t == 3) {\n                                    if (Math.random() <= n) {\n                                        n *= 0.2;\n                                        print(\"SHOT DUBBED, STILL IN TRAP.\\n\");\n                                        continue;\n                                    }\n                                    n = 0.8;\n                                }\n                                d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));\n                                second_routine = 2;\n                                break;\n                            }\n                            if (c != 14)\n                                c -= 10;\n                            second_routine = 0;\n                            break;\n                        }\n                        s1--;\n                        // Fall through to THAT CLUB IS NOT IN THE BAG.\n                    }\n                }\n            }\n            print(\"THAT CLUB IS NOT IN THE BAG.\\n\");\n            print(\"\\n\");\n        }\n        if (second_routine == 0) {\n            if (s1 > 7 && d < 200) {\n                d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));\n                second_routine = 2;\n            } else {\n                d1 = Math.floor(((30 - h) * 2.5 + 187 - ((30 - h) * 0.25 + 15) * c / 2) + 25 * Math.random());\n                d1 = Math.floor(d1 * w);\n                if (t == 2)\n                    d1 = Math.floor(d1 * 0.85);\n            }\n        }\n        if (second_routine <= 1) {\n            o = (Math.random() / 0.8) * (2 * h + 16) * Math.abs(Math.tan(d1 * 0.0035));\n            d2 = Math.floor(Math.sqrt(Math.pow(o, 2) + Math.pow(Math.abs(d - d1), 2)));\n            if (d - d1 < 0) {\n                if (d2 >= 20)\n                    print(\"TOO MUCH CLUB, YOU'RE PAST THE HOLE.\\n\");\n            }\n            b = d;\n            d = d2;\n            if (d2 > 27) {\n                if (o < 30 || j > 0) {\n                    la[0] = 1;\n                } else {\n                    if (t <= 0) {\n                        s9 = (s2 + 1) / 15;\n                        if (Math.floor(s9) == s9) {\n                            print(\"YOU SLICED- \");\n                            la[0] = la[1];\n                        } else {\n                            print(\"YOU HOOKED- \");\n                            la[0] = la[2];\n                        }\n                    } else {\n                        s9 = (s2 + 1) / 15;\n                        if (Math.floor(s9) == s9) {\n                            print(\"YOU HOOKED- \");\n                            la[0] = la[2];\n                        } else {\n                            print(\"YOU SLICED- \");\n                            la[0] = la[1];\n                        }\n                    }\n                    if (o > 45)\n                        print(\"BADLY.\\n\");\n                }\n                first_routine = false;\n            } else if (d2 > 20) {\n                la[0] = 5;\n                first_routine = false;\n            } else if (d2 > 0.5) {\n                la[0] = 8;\n                d2 = Math.floor(d2 * 3);\n                second_routine = 2;\n            } else {\n                la[0] = 9;\n                print(\"YOU HOLED IT.\\n\");\n                print(\"\\n\");\n                f++;\n                first_routine = true;\n            }\n        }\n        if (second_routine == 2) {\n            while (1) {\n                print(\"ON GREEN, \" + d2 + \" FEET FROM THE PIN.\\n\");\n                print(\"CHOOSE YOUR PUTT POTENCY (1 TO 13):\");\n                i = parseInt(await input());\n                s1++;\n                if (s1 + 1 - p <= (h * 0.072) + 2 && k <= 2) {\n                    k++;\n                    if (t == 4)\n                        d2 -= i * (4 + 1 * Math.random()) + 1;\n                    else\n                        d2 -= i * (4 + 2 * Math.random()) + 1.5;\n                    if (d2 < -2) {\n                        print(\"PASSED BY CUP.\\n\");\n                        d2 = Math.floor(-d2);\n                        continue;\n                    }\n                    if (d2 > 2) {\n                        print(\"PUTT SHORT.\\n\");\n                        d2 = Math.floor(d2);\n                        continue;\n                    }\n                }\n                print(\"YOU HOLED IT.\\n\");\n                print(\"\\n\");\n                f++;\n                break;\n            }\n            first_routine = true;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "39_Golf/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "39_Golf/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "39_Golf/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "39_Golf/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "39_Golf/python/golf.py",
    "content": "'''\n        8\"\"\"\"8 8\"\"\"88 8     8\"\"\"\"\n        8    \" 8    8 8     8\n        8e     8    8 8e    8eeee\n        88  ee 8    8 88    88\n        88   8 8    8 88    88\n        88eee8 8eeee8 88eee 88\n\nGOLF\n\n\nDespite being a text based game, the code uses simple geometry to simulate a course.\nFairways are 40 yard wide rectangles, surrounded by 5 yards of rough around the perimeter.\nThe green is a circle of 10 yards radius around the cup.\nThe cup is always at point (0,0).\n\nUsing basic trigonometry we can plot the ball's location using the distance of the stroke and\nand the angle of deviation (hook/slice).\n\nThe stroke distances are based on real world averages of different club types.\nLots of randomization, \"business rules\", and luck influence the game play.\nProbabilities are commented in the code.\n\nnote: 'courseInfo', 'clubs', & 'scoreCard' arrays each include an empty object so indexing\ncan begin at 1. Like all good programmers we count from zero, but in this context,\nit's more natural when hole number one is at index one\n\n\n    |-----------------------------|\n    |            rough            |\n    |   ----------------------    |\n    |   |                     |   |\n    | r |        =  =         | r |\n    | o |     =        =      | o |\n    | u |    =    .     =     | u |\n    | g |    =   green  =     | g |\n    | h |     =        =      | h |\n    |   |        =  =         |   |\n    |   |                     |   |\n    |   |                     |   |\n    |   |      Fairway        |   |\n    |   |                     |   |\n    |   |               ------    |\n    |   |            --        -- |\n    |   |           --  hazard  --|\n    |   |            --        -- |\n    |   |               ------    |\n    |   |                     |   |\n    |   |                     |   |   out\n    |   |                     |   |   of\n    |   |                     |   |   bounds\n    |   |                     |   |\n    |   |                     |   |\n    |            tee              |\n\n\nTypical green size: 20-30 yards\nTypical golf course fairways are 35 to 45 yards wide\nOur fairway extends 5 yards past green\nOur rough is a 5 yard perimeter around fairway\n\nWe calculate the new position of the ball given the ball's point, the distance\nof the stroke, and degrees off line (hook or slice).\n\nDegrees off (for a right handed golfer):\nSlice: positive degrees = ball goes right\nHook: negative degrees = left goes left\n\nThe cup is always at point: 0,0.\nWe use atan2 to compute the angle between the cup and the ball.\nSetting the cup's vector to 0,-1 on a 360 circle is equivalent to:\n0 deg = 12 o'clock;  90 deg = 3 o'clock;  180 deg = 6 o'clock;  270 = 9 o'clock\nThe reverse angle between the cup and the ball is a difference of PI (using radians).\n\nGiven the angle and stroke distance (hypotenuse), we use cosine to compute\nthe opposite and adjacent sides of the triangle, which, is the ball's new position.\n\n        0\n        |\n270 - cup - 90\n        |\n        180\n\n\n        cup\n        |\n        |\n        | opp\n        |-----* new position\n        |    /\n        |   /\n    adj  |  /\n        | /  hyp\n        |/\n        tee\n\n<- hook    slice ->\n\n\nGiven the large number of combinations needed to describe a particular stroke / ball location,\nwe use the technique of \"bitwise masking\" to describe stroke results.\nWith bit masking, multiple flags (bits) are combined into a single binary number that can be\ntested by applying a mask. A mask is another binary number that isolates a particular bit that\nyou are interested in. You can then apply your language's bitwise opeartors to test or\nset a flag.\n\nGame design by Jason Bonthron, 2021\nwww.bonthron.com\nfor my father, Raymond Bonthron, an avid golfer\n\nInspired by the 1978 \"Golf\" from \"Basic Computer Games\"\nby Steve North, who modified an existing golf game by an unknown author\n\nPorted in 2022 to Python by Martin Thoma\n'''\n\n\nimport enum\nimport math\nimport random\nimport time\nfrom dataclasses import dataclass\nfrom functools import partial\nfrom typing import Any, Callable, List, NamedTuple, Tuple\n\n\ndef clear_console() -> None:\n    print(\"\\033[H\\033[J\", end=\"\")\n\n\nclass Point(NamedTuple):\n    x: int\n    y: int\n\n\nclass GameObjType(enum.Enum):\n    BALL = enum.auto()\n    CUP = enum.auto()\n    GREEN = enum.auto()\n    FAIRWAY = enum.auto()\n    ROUGH = enum.auto()\n    TREES = enum.auto()\n    WATER = enum.auto()\n    SAND = enum.auto()\n\n\nclass CircleGameObj(NamedTuple):\n    # center point\n    X: int\n    Y: int\n    Radius: int\n    Type: GameObjType\n\n\nclass RectGameObj(NamedTuple):\n    # Upper left corner\n    X: int\n    Y: int\n    Width: int\n    Length: int\n    Type: GameObjType\n\n\nBall = CircleGameObj\nHazard = CircleGameObj\n\n\nclass HoleInfo(NamedTuple):\n    hole: int\n    yards: int\n    par: int\n    hazards: List[Hazard]\n    description: str\n\n\nclass HoleGeometry(NamedTuple):\n    cup: CircleGameObj\n    green: CircleGameObj\n    fairway: RectGameObj\n    rough: RectGameObj\n    hazards: List[Hazard]\n\n\n@dataclass\nclass Plot:\n    x: int\n    y: int\n    offline: int\n\n\ndef get_distance(pt1: Point, pt2: Point) -> float:\n    \"\"\"distance between 2 points\"\"\"\n    return math.sqrt(math.pow((pt2.x - pt1.x), 2) + math.pow((pt2.y - pt1.y), 2))\n\n\ndef is_in_rectangle(pt: CircleGameObj, rect: RectGameObj) -> bool:\n    # only true if its completely inside\n    return (\n        (pt.X > rect.X)\n        and (pt.X < rect.X + rect.Width)\n        and (pt.Y > rect.Y)\n        and (pt.Y < rect.Y + rect.Length)\n    )\n\n\ndef to_radians(angle: float) -> float:\n    return angle * (math.pi / 180.0)\n\n\ndef to_degrees_360(angle: float) -> float:\n    \"\"\"radians to 360 degrees\"\"\"\n    deg = angle * (180.0 / math.pi)\n    if deg < 0.0:\n        deg += 360.0\n    return deg\n\n\ndef odds(x: int) -> bool:\n    # chance an integer is <= the given argument\n    # between 1-100\n    return random.randint(1, 101) <= x\n\n\n# THE COURSE\nCourseInfo = [\n    HoleInfo(0, 0, 0, [], \"\"),  # include a blank so index 1 == hole 1\n    # -------------------------------------------------------- front 9\n    HoleInfo(\n        1,\n        361,\n        4,\n        [\n            Hazard(20, 100, 10, GameObjType.TREES),\n            Hazard(-20, 80, 10, GameObjType.TREES),\n            Hazard(-20, 100, 10, GameObjType.TREES),\n        ],\n        \"There are a couple of trees on the left and right.\",\n    ),\n    HoleInfo(\n        2,\n        389,\n        4,\n        [Hazard(0, 160, 20, GameObjType.WATER)],\n        \"There is a large water hazard across the fairway about 150 yards.\",\n    ),\n    HoleInfo(\n        3,\n        206,\n        3,\n        [\n            Hazard(20, 20, 5, GameObjType.WATER),\n            Hazard(-20, 160, 10, GameObjType.WATER),\n            Hazard(10, 12, 5, GameObjType.SAND),\n        ],\n        \"There is some sand and water near the green.\",\n    ),\n    HoleInfo(\n        4,\n        500,\n        5,\n        [Hazard(-14, 12, 12, GameObjType.SAND)],\n        \"There's a bunker to the left of the green.\",\n    ),\n    HoleInfo(\n        5,\n        408,\n        4,\n        [\n            Hazard(20, 120, 20, GameObjType.TREES),\n            Hazard(20, 160, 20, GameObjType.TREES),\n            Hazard(10, 20, 5, GameObjType.SAND),\n        ],\n        \"There are some trees to your right.\",\n    ),\n    HoleInfo(\n        6,\n        359,\n        4,\n        [Hazard(14, 0, 4, GameObjType.SAND), Hazard(-14, 0, 4, GameObjType.SAND)],\n        \"\",\n    ),\n    HoleInfo(\n        7,\n        424,\n        5,\n        [\n            Hazard(20, 200, 10, GameObjType.SAND),\n            Hazard(10, 180, 10, GameObjType.SAND),\n            Hazard(20, 160, 10, GameObjType.SAND),\n        ],\n        \"There are several sand traps along your right.\",\n    ),\n    HoleInfo(8, 388, 4, [Hazard(-20, 340, 10, GameObjType.TREES)], \"\"),\n    HoleInfo(\n        9,\n        196,\n        3,\n        [Hazard(-30, 180, 20, GameObjType.TREES), Hazard(14, -8, 5, GameObjType.SAND)],\n        \"\",\n    ),\n    # -------------------------------------------------------- back 9\n    HoleInfo(\n        hole=10,\n        yards=400,\n        par=4,\n        hazards=[\n            Hazard(-14, -8, 5, GameObjType.SAND),\n            Hazard(14, -8, 5, GameObjType.SAND),\n        ],\n        description=\"\",\n    ),\n    HoleInfo(\n        11,\n        560,\n        5,\n        [\n            Hazard(-20, 400, 10, GameObjType.TREES),\n            Hazard(-10, 380, 10, GameObjType.TREES),\n            Hazard(-20, 260, 10, GameObjType.TREES),\n            Hazard(-20, 200, 10, GameObjType.TREES),\n            Hazard(-10, 180, 10, GameObjType.TREES),\n            Hazard(-20, 160, 10, GameObjType.TREES),\n        ],\n        \"Lots of trees along the left of the fairway.\",\n    ),\n    HoleInfo(\n        12,\n        132,\n        3,\n        [\n            Hazard(-10, 120, 10, GameObjType.WATER),\n            Hazard(-5, 100, 10, GameObjType.SAND),\n        ],\n        \"There is water and sand directly in front of you. A good drive should clear both.\",\n    ),\n    HoleInfo(\n        13,\n        357,\n        4,\n        [\n            Hazard(-20, 200, 10, GameObjType.TREES),\n            Hazard(-10, 180, 10, GameObjType.TREES),\n            Hazard(-20, 160, 10, GameObjType.TREES),\n            Hazard(14, 12, 8, GameObjType.SAND),\n        ],\n        \"\",\n    ),\n    HoleInfo(14, 294, 4, [Hazard(0, 20, 10, GameObjType.SAND)], \"\"),\n    HoleInfo(\n        15,\n        475,\n        5,\n        [Hazard(-20, 20, 10, GameObjType.WATER), Hazard(10, 20, 10, GameObjType.SAND)],\n        \"Some sand and water near the green.\",\n    ),\n    HoleInfo(16, 375, 4, [Hazard(-14, -8, 5, GameObjType.SAND)], \"\"),\n    HoleInfo(\n        17,\n        180,\n        3,\n        [\n            Hazard(20, 100, 10, GameObjType.TREES),\n            Hazard(-20, 80, 10, GameObjType.TREES),\n        ],\n        \"\",\n    ),\n    HoleInfo(\n        18,\n        550,\n        5,\n        [Hazard(20, 30, 15, GameObjType.WATER)],\n        \"There is a water hazard near the green.\",\n    ),\n]\n\n\n# -------------------------------------------------------- bitwise Flags\ndub = 0b00000000000001\nhook = 0b00000000000010\nslice_ = 0b00000000000100\npassed_cup = 0b00000000001000\nin_cup = 0b00000000010000\non_fairway = 0b00000000100000\non_green = 0b00000001000000\nin_rough = 0b00000010000000\nin_sand = 0b00000100000000\nin_trees = 0b00001000000000\nin_water = 0b00010000000000\nout_of_bounds = 0b00100000000000\nluck = 0b01000000000000\nace = 0b10000000000000\n\n\nclass Golf:\n    ball: Ball\n    hole_num: int = 0\n    stroke_num: int = 0\n    handicap: int = 0\n    player_difficulty: int = 0\n    hole_geometry: HoleGeometry\n\n    # all fairways are 40 yards wide, extend 5 yards beyond the cup, and\n    # have 5 yards of rough around the perimeter\n    fairway_width: int = 40\n    fairway_extension: int = 5\n    rough_amt: int = 5\n\n    # ScoreCard records the ball position after each stroke\n    # a new list for each hole\n    # include a blank list so index 1 == hole 1\n    score_card: List[List[Ball]] = [[]]\n\n    # YOUR BAG\n    clubs: List[Tuple[str, int]] = [\n        (\"\", 0),\n        # name, average yardage\n        (\"Driver\", 250),\n        (\"3 Wood\", 225),\n        (\"5 Wood\", 200),\n        (\"Hybrid\", 190),\n        (\"4 Iron\", 170),\n        (\"7 Iron\", 150),\n        (\"9 Iron\", 125),\n        (\"Pitching wedge\", 110),\n        (\"Sand wedge\", 75),\n        (\"Putter\", 10),\n    ]\n\n    def __init__(self) -> None:\n        print(\" \")\n        print('          8\"\"\"\"8 8\"\"\"88 8     8\"\"\"\" ')\n        print('          8    \" 8    8 8     8     ')\n        print(\"          8e     8    8 8e    8eeee \")\n        print(\"          88  ee 8    8 88    88    \")\n        print(\"          88   8 8    8 88    88    \")\n        print(\"          88eee8 8eeee8 88eee 88    \")\n        print(\" \")\n        print(\"Welcome to the Creative Computing Country Club,\")\n        print(\"an eighteen hole championship layout located a short\")\n        print(\"distance from scenic downtown Lambertville, New Jersey.\")\n        print(\"The game will be explained as you play.\")\n        print(\"Enjoy your game! See you at the 19th hole...\")\n        print(\" \")\n        print(\"Type QUIT at any time to leave the game.\")\n        print(\"Type BAG at any time to review the clubs in your bag.\")\n        print(\" \")\n\n        input(\"Press any key to continue.\")\n        clear_console()\n        self.start_game()\n\n    def start_game(self) -> None:\n        print(\" \")\n        print(\"              YOUR BAG\")\n        self.review_bag()\n        print(\"Type BAG at any time to review the clubs in your bag.\")\n        print(\" \")\n\n        input(\"Press any key to continue.\")\n        clear_console()\n        self.ask_handicap()\n\n    def ask_handicap(self) -> None:\n        print(\" \")\n\n        self.ask(\n            \"PGA handicaps range from 0 to 30.\\nWhat is your handicap?\",\n            0,\n            30,\n            self.set_handicap_ask_difficulty,\n        )\n\n    def set_handicap_ask_difficulty(self, i: int) -> None:\n        self.handicap = i\n        print(\" \")\n\n        self.ask(\n            (\n                \"Common difficulties at golf include:\\n\"\n                \"1=Hook, 2=Slice, 3=Poor Distance, 4=Trap Shots, 5=Putting\\n\"\n                \"Which one is your worst?\"\n            ),\n            1,\n            5,\n            self.set_difficulty_and_hole,\n        )\n\n    def set_difficulty_and_hole(self, j: int) -> None:\n        self.player_difficulty = j\n        clear_console()\n        self.new_hole()\n\n    def new_hole(self) -> None:\n        self.hole_num += 1\n        self.stroke_num = 0\n\n        info: HoleInfo = CourseInfo[self.hole_num]\n\n        yards: int = info.yards\n        # from tee to cup\n        cup = CircleGameObj(0, 0, 0, GameObjType.CUP)\n        green = CircleGameObj(0, 0, 10, GameObjType.GREEN)\n\n        fairway = RectGameObj(\n            0 - int(self.fairway_width / 2),\n            0 - (green.Radius + self.fairway_extension),\n            self.fairway_width,\n            yards + (green.Radius + self.fairway_extension) + 1,\n            GameObjType.FAIRWAY,\n        )\n\n        rough = RectGameObj(\n            fairway.X - self.rough_amt,\n            fairway.Y - self.rough_amt,\n            fairway.Width + (2 * self.rough_amt),\n            fairway.Length + (2 * self.rough_amt),\n            GameObjType.ROUGH,\n        )\n\n        self.ball = Ball(0, yards, 0, GameObjType.BALL)\n\n        self.score_card_start_new_hole()\n\n        self.hole_geometry = HoleGeometry(cup, green, fairway, rough, info.hazards)\n\n        print(f\"                |> {self.hole_num}\")\n        print(\"                |        \")\n        print(\"                |        \")\n        print(\"          ^^^^^^^^^^^^^^^\")\n\n        print(\n            f\"Hole #{self.hole_num}. You are at the tee. Distance {info.yards} yards, par {info.par}.\"\n        )\n        print(info.description)\n\n        self.tee_up()\n\n    def set_putter_and_stroke(self, strength: float) -> None:\n        putter = self.clubs[self.putt]\n        self.stroke((putter[1] * (strength / 10.0)), self.putt)\n\n    def ask_gauge(self, c: int) -> None:\n        self.club = self.clubs[c]\n\n        print(\" \")\n        print(f\"[{self.club[0].upper()}: average {self.club[1]} yards]\")\n\n        foo = partial(self.make_stroke, c=c)\n\n        self.ask(\n            \"Now gauge your distance by a percentage of a full swing. (1-10)\",\n            1,\n            10,\n            foo,\n        )\n\n    def make_stroke(self, strength: float, c: int) -> None:\n        self.stroke((self.club[1] * (strength / 10.0)), c)\n\n    def tee_up(self) -> None:\n        # on the green? automatically select putter\n        # otherwise Ask club and swing strength\n        if self.is_on_green(self.ball) and not self.is_in_hazard(\n            self.ball, GameObjType.SAND\n        ):\n            self.putt = 10\n            print(\"[PUTTER: average 10 yards]\")\n            msg = \"Keep your head down.\\n\" if odds(20) else \"\"\n            self.ask(\n                f\"{msg}Choose your putt potency. (1-10)\",\n                1,\n                10,\n                self.set_putter_and_stroke,\n            )\n        else:\n            self.ask(\"What club do you choose? (1-10)\", 1, 10, self.ask_gauge)\n\n    def stroke(self, club_amt: float, club_index: int) -> None:\n        self.stroke_num += 1\n\n        flags = 0b000000000000\n\n        # fore! only when driving\n        if (self.stroke_num == 1) and (club_amt > 210) and odds(30):\n            print('\"...Fore !\"')\n\n        # dub\n        if odds(5):\n            # there's always a 5% chance of dubbing it\n            flags |= dub\n\n        # if you're in the rough, or sand, you really should be using a wedge\n        if (\n            (\n                self.is_in_rough(self.ball)\n                or self.is_in_hazard(self.ball, GameObjType.SAND)\n            )\n            and club_index not in {8, 9}\n            and odds(40)\n        ):\n            flags |= dub\n\n        # trap difficulty\n        if (\n            self.is_in_hazard(self.ball, GameObjType.SAND)\n            and self.player_difficulty == 4\n        ) and odds(20):\n            flags |= dub\n\n        # hook/slice\n        # There's 10% chance of a hook or slice\n        # if it's a known player_difficulty then increase chance to 30%\n        # if it's a putt & putting is a player_difficulty increase to 30%\n\n        rand_hook_slice: bool\n        if (\n            self.player_difficulty == 1\n            or self.player_difficulty == 2\n            or (self.player_difficulty == 5 and self.is_on_green(self.ball))\n        ):\n            rand_hook_slice = odds(30)\n        else:\n            rand_hook_slice = odds(10)\n\n        if rand_hook_slice:\n            if self.player_difficulty == 1:\n                if odds(80):\n                    flags |= hook\n                else:\n                    flags |= slice_\n            elif self.player_difficulty == 2:\n                if odds(80):\n                    flags |= slice_\n                else:\n                    flags |= hook\n            elif odds(50):\n                flags |= hook\n            else:\n                flags |= slice_\n\n        # beginner's luck !\n        # If handicap is greater than 15, there's a 10% chance of avoiding all errors\n        if (self.handicap > 15) and (odds(10)):\n            flags |= luck\n\n        # ace\n        # there's a 10% chance of an Ace on a par 3\n        if CourseInfo[self.hole_num].par == 3 and odds(10) and self.stroke_num == 1:\n            flags |= ace\n\n        # distance:\n        # If handicap is < 15, there a 50% chance of reaching club average,\n        # a 25% of exceeding it, and a 25% of falling short\n        # If handicap is > 15, there's a 25% chance of reaching club average,\n        # and 75% chance of falling short\n        # The greater the handicap, the more the ball falls short\n        # If poor distance is a known player_difficulty, then reduce distance by 10%\n\n        distance: float\n        rnd = random.randint(1, 101)\n\n        if self.handicap < 15 and rnd <= 25 or self.handicap >= 15 and rnd <= 75:\n            distance = club_amt - (club_amt * (self.handicap / 100.0))\n        elif self.handicap < 15 and rnd <= 75 or self.handicap >= 15:\n            distance = club_amt\n        else:\n            distance = club_amt + (club_amt * 0.10)\n        if self.player_difficulty == 3 and odds(80):  # poor distance\n            distance *= 0.80\n\n        if (flags & luck) == luck:\n            distance = club_amt\n\n        # angle\n        # For all strokes, there's a possible \"drift\" of 4 degrees\n        # a hooks or slice increases the angle between 5-10 degrees,\n        # hook uses negative degrees\n        angle = random.randint(0, 5)\n        if (flags & slice_) == slice_:\n            angle = random.randint(5, 11)\n        if (flags & hook) == hook:\n            angle = 0 - random.randint(5, 11)\n        if (flags & luck) == luck:\n            angle = 0\n\n        plot = self.plot_ball(self.ball, distance, angle)\n        # calculate a new location\n        if (flags & luck) == luck and plot.y > 0:\n            plot.y = 2\n\n        flags = self.find_ball(\n            Ball(plot.x, plot.y, plot.offline, GameObjType.BALL), flags\n        )\n\n        self.interpret_results(plot, flags)\n\n    def plot_ball(self, ball: Ball, stroke_distance: float, degrees_off: float) -> Plot:\n        cup_vector = Point(0, -1)\n        rad_from_cup = math.atan2(ball.Y, ball.X) - math.atan2(\n            cup_vector.y, cup_vector.x\n        )\n        rad_from_ball = rad_from_cup - math.pi\n\n        hypotenuse = stroke_distance\n        adjacent = math.cos(rad_from_ball + to_radians(degrees_off)) * hypotenuse\n        opposite = math.sqrt(math.pow(hypotenuse, 2) - math.pow(adjacent, 2))\n\n        new_pos: Point\n        if to_degrees_360(rad_from_ball + to_radians(degrees_off)) > 180:\n            new_pos = Point(int(ball.X - opposite), int(ball.Y - adjacent))\n        else:\n            new_pos = Point(int(ball.X + opposite), int(ball.Y - adjacent))\n\n        return Plot(new_pos.x, new_pos.y, int(opposite))\n\n    def interpret_results(self, plot: Plot, flags: int) -> None:\n        cup_distance: int = int(\n            get_distance(\n                Point(plot.x, plot.y),\n                Point(self.hole_geometry.cup.X, self.hole_geometry.cup.Y),\n            )\n        )\n        travel_distance: int = int(\n            get_distance(Point(plot.x, plot.y), Point(self.ball.X, self.ball.Y))\n        )\n\n        print(\" \")\n\n        if (flags & ace) == ace:\n            print(\"Hole in One! You aced it.\")\n            self.score_card_record_stroke(Ball(0, 0, 0, GameObjType.BALL))\n            self.report_current_score()\n            return\n\n        if (flags & in_trees) == in_trees:\n            print(\"Your ball is lost in the trees. Take a penalty stroke.\")\n            self.score_card_record_stroke(self.ball)\n            self.tee_up()\n            return\n\n        if (flags & in_water) == in_water:\n            if odds(50):\n                msg = \"Your ball has gone to a watery grave.\"\n            else:\n                msg = \"Your ball is lost in the water.\"\n            print(f\"{msg} Take a penalty stroke.\")\n            self.score_card_record_stroke(self.ball)\n            self.tee_up()\n            return\n\n        if (flags & out_of_bounds) == out_of_bounds:\n            print(\"Out of bounds. Take a penalty stroke.\")\n            self.score_card_record_stroke(self.ball)\n            self.tee_up()\n            return\n\n        if (flags & dub) == dub:\n            print(\"You dubbed it.\")\n            self.score_card_record_stroke(self.ball)\n            self.tee_up()\n            return\n\n        if (flags & in_cup) == in_cup:\n            msg = \"You holed it.\" if odds(50) else \"It's in!\"\n            print(msg)\n            self.score_card_record_stroke(Ball(plot.x, plot.y, 0, GameObjType.BALL))\n            self.report_current_score()\n            return\n\n        if (flags & slice_) == slice_ and flags & on_green != on_green:\n            bad = \"badly\" if (flags & out_of_bounds) == out_of_bounds else \"\"\n            print(f\"You sliced{bad}: {plot.offline} yards offline.\")\n\n        if (flags & hook) == hook and flags & on_green != on_green:\n            bad = \"badly\" if (flags & out_of_bounds) == out_of_bounds else \"\"\n            print(f\"You hooked{bad}: {plot.offline} yards offline.\")\n\n        if self.stroke_num > 1:\n            prev_ball = self.score_card_get_previous_stroke()\n            d1 = get_distance(\n                Point(prev_ball.X, prev_ball.Y),\n                Point(self.hole_geometry.cup.X, self.hole_geometry.cup.Y),\n            )\n            d2 = cup_distance\n            if d2 > d1:\n                print(\"Too much club.\")\n\n        if (flags & in_rough) == in_rough:\n            print(\"You're in the rough.\")\n\n        if (flags & in_sand) == in_sand:\n            print(\"You're in a sand trap.\")\n\n        if (flags & on_green) == on_green:\n            if cup_distance < 4:\n                pd = f\"{str(cup_distance * 3)} feet\"\n            else:\n                pd = f\"{cup_distance} yards\"\n            print(f\"You're on the green. It's {pd} from the pin.\")\n\n        if ((flags & on_fairway) == on_fairway) or ((flags & in_rough) == in_rough):\n            print(\n                f\"Shot went {travel_distance} yards. \"\n                f\"It's {cup_distance} yards from the cup.\"\n            )\n\n        self.score_card_record_stroke(Ball(plot.x, plot.y, 0, GameObjType.BALL))\n\n        self.ball = Ball(plot.x, plot.y, 0, GameObjType.BALL)\n\n        self.tee_up()\n\n    def report_current_score(self) -> None:\n        par = CourseInfo[self.hole_num].par\n        if len(self.score_card[self.hole_num]) == par + 1:\n            print(\"A bogey. One above par.\")\n        if len(self.score_card[self.hole_num]) == par:\n            print(\"Par. Nice.\")\n        if len(self.score_card[self.hole_num]) == (par - 1):\n            print(\"A birdie! One below par.\")\n        if len(self.score_card[self.hole_num]) == (par - 2):\n            print(\"An Eagle! Two below par.\")\n        if len(self.score_card[self.hole_num]) == (par - 3):\n            print(\"Double Eagle! Unbelievable.\")\n\n        total_par: int = sum(CourseInfo[i].par for i in range(1, self.hole_num + 1))\n        print(\" \")\n        print(\"-----------------------------------------------------\")\n        hole_str = \"holes\" if self.hole_num > 1 else \"hole\"\n        print(\n            f\" Total par for {self.hole_num} {hole_str} is: {total_par}. \"\n            f\"Your total is: {self.score_card_get_total()}.\"\n        )\n        print(\"-----------------------------------------------------\")\n        print(\" \")\n\n        if self.hole_num == 18:\n            self.game_over()\n        else:\n            time.sleep(2)\n            self.new_hole()\n\n    def find_ball(self, ball: Ball, flags: int) -> int:\n        if self.is_on_fairway(ball) and not self.is_on_green(ball):\n            flags |= on_fairway\n        if self.is_on_green(ball):\n            flags |= on_green\n        if self.is_in_rough(ball):\n            flags |= in_rough\n        if self.is_out_of_bounds(ball):\n            flags |= out_of_bounds\n        if self.is_in_hazard(ball, GameObjType.WATER):\n            flags |= in_water\n        if self.is_in_hazard(ball, GameObjType.TREES):\n            flags |= in_trees\n        if self.is_in_hazard(ball, GameObjType.SAND):\n            flags |= in_sand\n\n        if ball.Y < 0:\n            flags |= passed_cup\n\n        # less than 2, it's in the cup\n        d = get_distance(\n            Point(ball.X, ball.Y),\n            Point(self.hole_geometry.cup.X, self.hole_geometry.cup.Y),\n        )\n        if d < 2:\n            flags |= in_cup\n\n        return flags\n\n    def is_on_fairway(self, ball: Ball) -> bool:\n        return is_in_rectangle(ball, self.hole_geometry.fairway)\n\n    def is_on_green(self, ball: Ball) -> bool:\n        d = get_distance(\n            Point(ball.X, ball.Y),\n            Point(self.hole_geometry.cup.X, self.hole_geometry.cup.Y),\n        )\n        return d < self.hole_geometry.green.Radius\n\n    def hazard_hit(self, h: Hazard, ball: Ball, hazard: GameObjType) -> bool:\n        d = get_distance(Point(ball.X, ball.Y), Point(h.X, h.Y))\n        return d < h.Radius and h.Type == hazard\n\n    def is_in_hazard(self, ball: Ball, hazard: GameObjType) -> bool:\n        result: bool = False\n        for h in self.hole_geometry.hazards:\n            result = result and self.hazard_hit(h, ball, hazard)\n        return result\n\n    def is_in_rough(self, ball: Ball) -> bool:\n        return is_in_rectangle(ball, self.hole_geometry.rough) and (\n            not is_in_rectangle(ball, self.hole_geometry.fairway)\n        )\n\n    def is_out_of_bounds(self, ball: Ball) -> bool:\n        return (not self.is_on_fairway(ball)) and (not self.is_in_rough(ball))\n\n    def score_card_start_new_hole(self) -> None:\n        self.score_card.append([])\n\n    def score_card_record_stroke(self, ball: Ball) -> None:\n        clone = Ball(ball.X, ball.Y, 0, GameObjType.BALL)\n        self.score_card[self.hole_num].append(clone)\n\n    def score_card_get_previous_stroke(self) -> Ball:\n        return self.score_card[self.hole_num][len(self.score_card[self.hole_num]) - 1]\n\n    def score_card_get_total(self) -> int:\n        total: int = sum(len(h) for h in self.score_card)\n        return total\n\n    def ask(\n        self, question: str, min_: int, max_: int, callback: Callable[[int], Any]\n    ) -> None:\n        # input from console is always an integer passed to a callback\n        # or \"quit\" to end game\n        print(question)\n        i = input().strip().lower()\n        if i == \"quit\":\n            self.quit_game()\n            return\n        if i == \"bag\":\n            self.review_bag()\n\n        try:\n            n = int(i)\n            success = True\n        except Exception:\n            success = False\n            n = 0\n\n        if success and n >= min_ and n <= max_:\n            callback(n)\n        else:\n            self.ask(question, min_, max_, callback)\n\n    def review_bag(self) -> None:\n        print(\" \")\n        print(\"  #     Club      Average Yardage\")\n        print(\"-----------------------------------\")\n        print(\"  1    Driver           250\")\n        print(\"  2    3 Wood           225\")\n        print(\"  3    5 Wood           200\")\n        print(\"  4    Hybrid           190\")\n        print(\"  5    4 Iron           170\")\n        print(\"  6    7 Iron           150\")\n        print(\"  7    9 Iron           125\")\n        print(\"  8    Pitching wedge   110\")\n        print(\"  9    Sand wedge        75\")\n        print(\" 10    Putter            10\")\n        print(\" \")\n\n    def quit_game(self) -> None:\n        print(\"\\nLooks like rain. Goodbye!\\n\")\n        return\n\n    def game_over(self) -> None:\n        net = self.score_card_get_total() - self.handicap\n        print(\"Good game!\")\n        print(f\"Your net score is: {net}\")\n        print(\"Let's visit the pro shop...\")\n        print(\" \")\n        return\n\n\nif __name__ == \"__main__\":\n    Golf()\n"
  },
  {
    "path": "39_Golf/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "39_Golf/vbnet/Golf.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Golf\", \"Golf.vbproj\", \"{65A2E065-6541-4E6E-B6F0-9881080B5FFF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "39_Golf/vbnet/Golf.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Golf</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "39_Golf/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "40_Gomoko/README.md",
    "content": "### Gomoko\n\nGOMOKO or GOMOKU is a traditional game of the Orient. It is played by two people on a board of intersecting lines (19 left-to-right lines, 19 top-to-bottom lines, 361 intersections in all). Players take turns. During his turn, a player may cover one intersection with a marker; (one player uses white markers; the other player uses black markers). The object of the game is to get five adjacent markers in a row, horizontally, vertically or along either diagonal.\n\nUnfortunately, this program does not make the computer a very good player. It does not know when you are about to win or even who has won. But some of its moves may surprise you.\n\nThe original author of this program is Peter Sessions of People’s Computer Company.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=74)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=89)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "40_Gomoko/csharp/Gomoko.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "40_Gomoko/csharp/Gomoko.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Gomoko\", \"Gomoko.csproj\", \"{558B84AB-2010-436E-B191-00980C6CBA61}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{558B84AB-2010-436E-B191-00980C6CBA61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{558B84AB-2010-436E-B191-00980C6CBA61}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{558B84AB-2010-436E-B191-00980C6CBA61}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{558B84AB-2010-436E-B191-00980C6CBA61}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "40_Gomoko/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "40_Gomoko/gomoko.bas",
    "content": "2 PRINT TAB(33);\"GOMOKO\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n8 DIM A(19,19)\n10 PRINT \"WELCOME TO THE ORIENTAL GAME OF GOMOKO.\"\n20 PRINT: PRINT \"THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\"\n30 PRINT \"THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID\"\n40 PRINT \"INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\"\n50 PRINT \"5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\"\n60 PRINT \"DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\"\n70 PRINT \"WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\"\n80 PRINT: PRINT \"THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\"\n90 PRINT \"TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\": PRINT\n110 PRINT \"WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)\";: INPUT N\n115 IF N>6 THEN 117\n116 GOTO 120\n117 IF N<20 THEN 210\n120 PRINT \"I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\": GOTO 110\n210 FOR I=1 TO N:FOR J=1 TO N: A(I,J)=0: NEXT J: NEXT I\n300 PRINT: PRINT \"WE ALTERNATE MOVES.  YOU GO FIRST...\": PRINT\n310 PRINT \"YOUR PLAY (I,J)\";: INPUT I,J\n315 PRINT\n320 IF I=-1 THEN 980\n330 X=I: Y=J: GOSUB 910: IF L=1 THEN 410\n340 PRINT \"ILLEGAL MOVE.  TRY AGAIN...\": GOTO 310\n410 IF A(I,J)=0 THEN 440\n420 PRINT \"SQUARE OCCUPIED.  TRY AGAIN...\": GOTO 310\n440 A(I,J)=1\n500 REM *** COMPUTER TRIES AN INTELLIGENT MOVE ***\n510 FOR E=-1 TO 1: FOR F=-1 TO 1: IF E+F-E*F=0 THEN 590\n540 X=I+E: Y=J+F: GOSUB 910\n570 IF L=0 THEN 590\n580 IF A(X,Y)=1 THEN 710\n590 NEXT F: NEXT E\n600 REM *** COMPUTER TRIES A RANDOM MOVE ***\n610 X=INT(N*RND(1)+1): Y=INT(N*RND(1)+1): GOSUB 910: IF L=0 THEN 610\n650 IF A(X,Y)<>0 THEN 610\n660 A(X,Y)=2: GOSUB 810: GOTO 310\n710 X=I-E: Y=J-F: GOSUB 910\n750 IF L=0 THEN 610\n760 GOTO 650\n800 REM *** PRINT THE BOARD ***\n810 FOR I=1 TO N: FOR J=1 TO N: PRINT A(I,J);\n840 NEXT J: PRINT: NEXT I: PRINT: RETURN\n910 L=1: IF X<1 THEN 970\n920 IF X>N THEN 970\n930 IF Y<1 THEN 970\n940 IF Y>N THEN 970\n950 RETURN\n970 L=0: RETURN\n980 PRINT: PRINT \"THANKS FOR THE GAME!!\"\n985 PRINT \"PLAY AGAIN (1 FOR YES, 0 FOR NO)\";: INPUT Q\n990 IF Q=1 THEN 110\n999 END\n"
  },
  {
    "path": "40_Gomoko/java/Gomoko.java",
    "content": "import java.util.Arrays;\nimport java.util.InputMismatchException;\nimport java.util.Scanner;\n\n/**\n * GOMOKO\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class Gomoko {\n\n\tprivate static final int MIN_BOARD_SIZE = 7;\n\tprivate static final int MAX_BOARD_SIZE = 19;\n\n\tpublic static void main(String[] args) {\n\t\tprintIntro();\n\t\tScanner scan = new Scanner(System.in);\n\t\tint boardSize = readBoardSize(scan);\n\n\t\tboolean continuePlay = true;\n\t\twhile (continuePlay) {\n\t\t\tint[][] board = new int[boardSize][boardSize];\n\t\t\t//initialize the board elements to 0\n\t\t\tfor (int[] ints : board) {\n\t\t\t\tArrays.fill(ints, 0);\n\t\t\t}\n\n\t\t\tSystem.out.println(\"\\n\\nWE ALTERNATE MOVES.  YOU GO FIRST...\");\n\n\t\t\tboolean doneRound = false;\n\t\t\twhile (!doneRound) {\n\t\t\t\tMove playerMove = null;\n\t\t\t\tboolean validMove = false;\n\t\t\t\twhile (!validMove) {\n\t\t\t\t\tplayerMove = readMove(scan);\n\t\t\t\t\tif (playerMove.i == -1 || playerMove.j == -1) {\n\t\t\t\t\t\tdoneRound = true;\n\t\t\t\t\t\tSystem.out.println(\"\\nTHANKS FOR THE GAME!!\");\n\t\t\t\t\t\tSystem.out.print(\"PLAY AGAIN (1 FOR YES, 0 FOR NO)? \");\n\t\t\t\t\t\tfinal int playAgain = scan.nextInt();\n\t\t\t\t\t\tscan.nextLine();\n\t\t\t\t\t\tif (playAgain == 1) {\n\t\t\t\t\t\t\tcontinuePlay = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontinuePlay = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!isLegalMove(playerMove, boardSize)) {\n\t\t\t\t\t\tSystem.out.println(\"ILLEGAL MOVE.  TRY AGAIN...\");\n\t\t\t\t\t} else if (board[playerMove.i - 1][playerMove.j - 1] != 0) {\n\t\t\t\t\t\tSystem.out.println(\"SQUARE OCCUPIED.  TRY AGAIN...\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalidMove = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!doneRound) {\n\t\t\t\t\tboard[playerMove.i - 1][playerMove.j - 1] = 1;\n\t\t\t\t\tMove computerMove = getComputerMove(playerMove, board, boardSize);\n\t\t\t\t\tif (computerMove == null) {\n\t\t\t\t\t\tcomputerMove = getRandomMove(board, boardSize);\n\t\t\t\t\t}\n\t\t\t\t\tboard[computerMove.i - 1][computerMove.j - 1] = 2;\n\n\t\t\t\t\tprintBoard(board);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\t//*** COMPUTER TRIES AN INTELLIGENT MOVE ***\n\tprivate static Move getComputerMove(Move playerMove, int[][] board, int boardSize) {\n\t\tfor (int e = -1; e <= 1; e++) {\n\t\t\tfor (int f = -1; f <= 1; f++) {\n\t\t\t\tif ((e + f - e * f) != 0) {\n\t\t\t\t\tvar x = playerMove.i + f;\n\t\t\t\t\tvar y = playerMove.j + f;\n\t\t\t\t\tfinal Move newMove = new Move(x, y);\n\t\t\t\t\tif (isLegalMove(newMove, boardSize)) {\n\t\t\t\t\t\tif (board[newMove.i - 1][newMove.j - 1] != 0) {\n\t\t\t\t\t\t\tnewMove.i = newMove.i - e;\n\t\t\t\t\t\t\tnewMove.i = newMove.j - f;\n\t\t\t\t\t\t\tif (!isLegalMove(newMove, boardSize)) {\n\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (board[newMove.i - 1][newMove.j - 1] == 0) {\n\t\t\t\t\t\t\t\t\treturn newMove;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static void printBoard(int[][] board) {\n\t\tfor (int[] ints : board) {\n\t\t\tfor (int cell : ints) {\n\t\t\t\tSystem.out.printf(\" %s\", cell);\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\n\t//*** COMPUTER TRIES A RANDOM MOVE ***\n\tprivate static Move getRandomMove(int[][] board, int boardSize) {\n\t\tboolean legalMove = false;\n\t\tMove randomMove = null;\n\t\twhile (!legalMove) {\n\t\t\trandomMove = randomMove(boardSize);\n\t\t\tlegalMove = isLegalMove(randomMove, boardSize) && board[randomMove.i - 1][randomMove.j - 1] == 0;\n\n\t\t}\n\t\treturn randomMove;\n\t}\n\n\tprivate static Move randomMove(int boardSize) {\n\t\tint x = (int) (boardSize * Math.random() + 1);\n\t\tint y = (int) (boardSize * Math.random() + 1);\n\t\treturn new Move(x, y);\n\t}\n\n\tprivate static boolean isLegalMove(Move move, int boardSize) {\n\t\treturn (move.i >= 1) && (move.i <= boardSize) && (move.j >= 1) && (move.j <= boardSize);\n\t}\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                GOMOKO\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\");\n\t\tSystem.out.println(\"WELCOME TO THE ORIENTAL GAME OF GOMOKO.\");\n\t\tSystem.out.println(\"\\n\");\n\t\tSystem.out.println(\"THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\");\n\t\tSystem.out.println(\"THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID\");\n\t\tSystem.out.println(\"INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\");\n\t\tSystem.out.println(\"5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\");\n\t\tSystem.out.println(\"DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\");\n\t\tSystem.out.println(\"WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\");\n\t\tSystem.out.println(\"\\nTHE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\");\n\t\tSystem.out.println(\"TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\\n \");\n\t}\n\n\tprivate static int readBoardSize(Scanner scan) {\n\t\tSystem.out.print(\"WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? \");\n\n\t\tboolean validInput = false;\n\t\tint input = 0;\n\t\twhile (!validInput) {\n\t\t\ttry {\n\t\t\t\tinput = scan.nextInt();\n\t\t\t\tif (input < MIN_BOARD_SIZE || input > MAX_BOARD_SIZE) {\n\t\t\t\t\tSystem.out.printf(\"I SAID, THE MINIMUM IS %s, THE MAXIMUM IS %s.\\n\", MIN_BOARD_SIZE, MAX_BOARD_SIZE);\n\t\t\t\t} else {\n\t\t\t\t\tvalidInput = true;\n\t\t\t\t}\n\t\t\t} catch (InputMismatchException ex) {\n\t\t\t\tSystem.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\\n\");\n\t\t\t\tvalidInput = false;\n\t\t\t} finally {\n\t\t\t\tscan.nextLine();\n\t\t\t}\n\t\t}\n\t\treturn input;\n\t}\n\n\tprivate static Move readMove(Scanner scan) {\n\t\tSystem.out.print(\"YOUR PLAY (I,J)? \");\n\t\tboolean validInput = false;\n\t\tMove move = new Move();\n\t\twhile (!validInput) {\n\t\t\tString input = scan.nextLine();\n\t\t\tfinal String[] split = input.split(\",\");\n\t\t\ttry {\n\t\t\t\tmove.i = Integer.parseInt(split[0]);\n\t\t\t\tmove.j = Integer.parseInt(split[1]);\n\t\t\t\tvalidInput = true;\n\t\t\t} catch (NumberFormatException nfe) {\n\t\t\t\tSystem.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\\n? \");\n\t\t\t}\n\n\t\t}\n\t\treturn move;\n\t}\n\n\tprivate static class Move {\n\t\tint i;\n\t\tint j;\n\n\t\tpublic Move() {\n\t\t}\n\n\t\tpublic Move(int i, int j) {\n\t\t\tthis.i = i;\n\t\t\tthis.j = j;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Move{\" +\n\t\t\t\t\t\"i=\" + i +\n\t\t\t\t\t\", j=\" + j +\n\t\t\t\t\t'}';\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "40_Gomoko/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "40_Gomoko/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "40_Gomoko/javascript/gomoko.html",
    "content": "<html>\n<head>\n<title>GOMOKO</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"gomoko.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "40_Gomoko/javascript/gomoko.js",
    "content": "// GOMOKO\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nfunction reset_stats()\n{\n    for (var j = 1; j <= 4; j++)\n        f[j] = 0;\n}\n\nvar a = [];\nvar x;\nvar y;\nvar n;\n\n// *** PRINT THE BOARD ***\nfunction print_board()\n{\n    for (i = 1; i <= n; i++) {\n        for (j = 1; j <= n; j++) {\n            print(\" \" + a[i][j] + \" \");\n        }\n        print(\"\\n\");\n    }\n    print(\"\\n\");\n}\n\n// Is valid the movement\nfunction is_valid()\n{\n    if (x < 1 || x > n || y < 1 || y > n)\n        return false;\n    return true;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"GOMOKO\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 0; i <= 19; i++) {\n        a[i] = [];\n        for (j = 0; j <= 19; j++)\n            a[i][j] = 0;\n    }\n    print(\"WELCOME TO THE ORIENTAL GAME OF GOMOKO.\\n\");\n    print(\"\\n\");\n    print(\"THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\\n\");\n    print(\"THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID\\n\");\n    print(\"INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\\n\");\n    print(\"5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\\n\");\n    print(\"DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\\n\");\n    print(\"WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\\n\");\n    print(\"\\n\");\n    print(\"THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\\n\");\n    print(\"TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)\");\n        while (1) {\n            n = parseInt(await input());\n            if (n >= 7 && n<= 19)\n                break;\n            print(\"I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\\n\");\n        }\n        for (i = 1; i <= n; i++) {\n            for (j = 1; j <= n; j++) {\n                a[i][j] = 0;\n            }\n        }\n        print(\"\\n\");\n        print(\"WE ALTERNATE MOVES.  YOU GO FIRST...\\n\");\n        print(\"\\n\");\n        while (1) {\n            print(\"YOUR PLAY (I,J)\");\n            str = await input();\n            i = parseInt(str);\n            j = parseInt(str.substr(str.indexOf(\",\") + 1));\n            print(\"\\n\");\n            if (i == -1)\n                break;\n            x = i;\n            y = j;\n            if (!is_valid()) {\n                print(\"ILLEGAL MOVE.  TRY AGAIN...\\n\");\n                continue;\n            }\n            if (a[i][j] != 0) {\n                print(\"SQUARE OCCUPIED.  TRY AGAIN...\\n\");\n                continue;\n            }\n            a[i][j] = 1;\n            // *** Computer tries an intelligent move ***\n            found = false;\n            for (e = -1; e <= 1; e++) {\n                for (f = -1; f <= 1; f++) {\n                    if (e + f - e * f == 0)\n                        continue;\n                    x = i + f;\n                    y = j + f;\n                    if (!is_valid())\n                        continue;\n                    if (a[x][y] == 1) {\n                        x = i - e;\n                        y = j - f;\n                        if (is_valid() || a[x][y] == 0)\n                            found = true;\n                        break;\n                    }\n                }\n            }\n            if (!found) {\n                // *** Computer tries a random move ***\n                do {\n                    x = Math.floor(n * Math.random() + 1);\n                    y = Math.floor(n * Math.random() + 1);\n                } while (!is_valid() || a[x][y] != 0) ;\n            }\n            a[x][y] = 2;\n            print_board();\n        }\n        print(\"\\n\");\n        print(\"THANKS FOR THE GAME!!\\n\");\n        print(\"PLAY AGAIN (1 FOR YES, 0 FOR NO)\");\n        q = parseInt(await input());\n        if (q != 1)\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "40_Gomoko/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "40_Gomoko/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "40_Gomoko/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "40_Gomoko/perl/gomoko.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 33 . \"GOMOKO\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\n#my @A;\nprint \"WELCOME TO THE ORIENTAL GAME OF GOMOKO.\\n\";\nprint \"\\n\"; print \"THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\\n\";\nprint \"THAT YOU SPECIFY. DURING YOUR PLAY, YOU MAY COVER ONE GRID\\n\";\nprint \"INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\\n\";\nprint \"5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\\n\";\nprint \"DIAGONALLY. ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\\n\";\nprint \"WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\\n\";\nprint \"\\n\"; print \"THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\\n\";\nprint \"TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\\n\"; print \"\\n\";\n\n\nmy $Ret;\nmy $I;\nmy $J;\n\nmy @Board;\nmy $Size= 0;\n\n\nwhile (1) {\n\n\tdo {\n\t\t$Size= 0;\n\t\tprint \"WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)\"; print \"? \"; chomp($Size = uc(<STDIN>));\n\t\tif ($Size<7 || $Size>19) {\n\t\t\t$Size=0;\n\t\t\tprint \"I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\\n\";\n\t\t\t}\n\t\t} until ($Size);\n\n\t#==> Reset Board to zeroes...\n\tfor (my $I=1; $I<=$Size; $I++) {\n\t\tfor (my $J=1; $J<=$Size; $J++) {\n\t\t\t$Board[$I][$J]= 0;\n\t\t\t}\n\t\t}\n\n\tprint \"\\n\"; print \"WE ALTERNATE MOVES. YOU GO FIRST...\\n\"; print \"\\n\";\n\n\twhile (1) {\n\t\tdo {\n\t\t\tprint \"YOUR PLAY (I,J)\"; print \"? \"; chomp(my $Inp = uc(<STDIN>));\n\t\t\t($I, $J)= split(\",\", $Inp);\n\t\t\tprint \"\\n\";\n\t\t\tif ($I==-1) { last; }\n\t\t\t$Ret= &ValidMove($I, $J, 1);\n\t\t\t} until ($Ret==1);\n\t\tif ($I==-1) { last; }\n\t\t$Board[$I][$J]= 1;\n\n\t\tmy $X;\n\t\tmy $Y;\n\t\tmy $Found=0;\n\t\t# REM *** COMPUTER TRIES AN INTELLIGENT MOVE ***\n\t\t#==> Too complex, original basic code seems only move below user.\n\t\t$Ret= &ValidMove($I+1, $J);\n\t\tif ($Ret==1) {\n\t\t\t$Found=1;\n\t\t\t$X= $I+1;\n\t\t\t$Y= $J;\n\t\t\t}\n\n\t\twhile($Found==0) {\n\t\t# REM *** COMPUTER TRIES A RANDOM MOVE ***\n\t\t\t$X= int($Size*rand(1)+1);\n\t\t\t$Y= int($Size*rand(1)+1);\n\t\t\t$Ret= &ValidMove($X, $Y, 2);\n\t\t\tif ($Ret==1) { $Found= 1; }\n\t\t\t};\n\t\t$Board[$X][$Y]=2;\n\n\t\t&ShowBoard();\n\t\t}\n\n\tprint \"\\n\"; print \"THANKS FOR THE GAME!!\\n\";\n\tprint \"PLAY AGAIN (1 FOR YES, 0 FOR NO)\"; print \"? \"; chomp(my $Q = uc(<STDIN>));\n\tif ($Q==0) { last; }\n\t}\n\n\n\nexit;\n\n\nsub ShowBoard {\n\tfor (my $I=1; $I<=$Size; $I++) {\n\t\tprint \" \";\n\t\tfor (my $J=1; $J<=$Size; $J++) {\n\t\t\tprint \"$Board[$I][$J]  \";\n\t\t\t}\n\t\tprint \"\\n\";\n\t\t}\n\tprint \"\\n\";\n\treturn;\n\t}\n\n\nsub ValidMove {\n\tmy ($X, $Y, $Val)= @_;\n\tif ($X<1 || $X>$Size || $Y<1 || $Y>$Size) {\n\t\tif ($Val==1) { print \"ILLEGAL MOVE. TRY AGAIN...\\n\"; }\n\t\treturn 0;\n\t\t}\n\tif ($Board[$X][$Y]!=0) {\n\t\tif ($Val==1) { print \"SQUARE OCCUPIED. TRY AGAIN...\\n\"; }\n\t\treturn 0;\n\t\t}\n\n\t#$Board[$X][$Y]= $Val;\n\treturn 1;\n\t}\n"
  },
  {
    "path": "40_Gomoko/python/Gomoko.py",
    "content": "import random\nfrom typing import Any, List, Tuple\n\n\ndef print_board(A: List[List[Any]], n: int) -> None:\n    \"\"\"PRINT THE BOARD\"\"\"\n    for i in range(n):\n        print(\" \", end=\"\")\n        for j in range(n):\n            print(A[i][j], end=\"\")\n            print(\" \", end=\"\")\n        print()\n\n\ndef check_move(_I, _J, _N) -> bool:  # 910\n    return _I >= 1 and _I <= _N and _J >= 1 and _J <= _N\n\n\ndef print_banner() -> None:\n    print(\" \" * 33 + \"GOMOKU\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"WELCOME TO THE ORIENTAL GAME OF GOMOKO.\\n\")\n    print(\"THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\")\n    print(\"THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID\")\n    print(\"INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\")\n    print(\"5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\")\n    print(\"DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\")\n    print(\"WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\\n\")\n    print(\"THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\")\n    print(\"TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\\n\")\n\n\ndef get_board_dimensions() -> int:\n    n = 0\n    while True:\n        n = int(input(\"WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? \"))\n        if n >= 7 and n <= 19:\n            break\n        print(\"I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\")\n        print()\n    return n\n\n\ndef get_move() -> Tuple[int, int]:\n    while True:\n        xy = input(\"YOUR PLAY (I,J)? \")\n        print()\n        x_str, y_str = xy.split(\",\")\n        try:\n            x = int(x_str)\n            y = int(y_str)\n        except Exception:\n            print(\"ILLEGAL MOVE.  TRY AGAIN...\")\n            continue\n        return x, y\n\n\ndef initialize_board(n: int) -> List[List[int]]:\n    # Initialize the board\n    board = []\n    for _x in range(n):\n        sub_a = [0 for _y in range(n)]\n        board.append(sub_a)\n    return board\n\n\ndef main() -> None:\n    print_banner()\n\n    while True:\n        n = get_board_dimensions()\n        board = initialize_board(n)\n\n        print()\n        print()\n        print(\"WE ALTERNATE MOVES. YOU GO FIRST...\")\n        print()\n\n        while True:\n            x, y = get_move()\n            if x == -1:\n                break\n            elif not check_move(x, y, n):\n                print(\"ILLEGAL MOVE.  TRY AGAIN...\")\n            elif board[x - 1][y - 1] == 0:\n                board[x - 1][y - 1] = 1\n                # COMPUTER TRIES AN INTELLIGENT MOVE\n                skip_ef_loop = False\n                for E in range(-1, 2):\n                    for F in range(-1, 2):\n                        if E + F - E * F == 0 or skip_ef_loop:\n                            continue\n                        X = x + F\n                        Y = y + F\n                        if not check_move(X, Y, n):\n                            continue\n                        if board[X - 1][Y - 1] == 1:\n                            skip_ef_loop = True\n                            X = x - E\n                            Y = y - F\n                            if not check_move(X, Y, n):  # 750\n                                while True:  # 610\n                                    X = random.randint(1, n)\n                                    Y = random.randint(1, n)\n                                    if (\n                                        check_move(X, Y, n)\n                                        and board[X - 1][Y - 1] == 0\n                                    ):\n                                        board[X - 1][Y - 1] = 2\n                                        print_board(board, n)\n                                        break\n                            elif board[X - 1][Y - 1] == 0:\n                                board[X - 1][Y - 1] = 2\n                                print_board(board, n)\n                            else:\n                                while True:\n                                    X = random.randint(1, n)\n                                    Y = random.randint(1, n)\n                                    if (\n                                        check_move(X, Y, n)\n                                        and board[X - 1][Y - 1] == 0\n                                    ):\n                                        board[X - 1][Y - 1] = 2\n                                        print_board(board, n)\n                                        break\n            else:\n                print(\"SQUARE OCCUPIED.  TRY AGAIN...\")\n        print()\n        print(\"THANKS FOR THE GAME!!\")\n        repeat = int(input(\"PLAY AGAIN (1 FOR YES, 0 FOR NO)? \"))\n        if repeat == 0:\n            break\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "40_Gomoko/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "40_Gomoko/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "40_Gomoko/vbnet/Gomoko.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Gomoko\", \"Gomoko.vbproj\", \"{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "40_Gomoko/vbnet/Gomoko.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Gomoko</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "40_Gomoko/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "41_Guess/README.md",
    "content": "### Guess\n\nIn Program GUESS, the computer chooses a random integer between 0 and any limit you set. You must then try to guess the number the computer has chosen using the clues provided by the computer.\n\nYou should be able to guess the number in one less than the number of digits needed to represent the number in binary notation — i.e., in base 2. This ought to give you a clue as to the optimum search technique.\n\nGUESS converted from the original program in FOCAL which appeared in the book “Computers in the Classroom” by Walt Koetke of Lexington High School, Lexington, Massachusetts.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=75)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=90)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "41_Guess/csharp/Game.cs",
    "content": "namespace Guess;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    public void Play()\n    {\n        while (true)\n        {\n            _io.Write(Streams.Introduction);\n\n            var limit = _io.ReadNumber(Prompts.Limit);\n            _io.WriteLine();\n\n            // There's a bug here that exists in the original code. \n            // If the limit entered is <= 0 then the program will crash.\n            var targetGuessCount = checked((int)Math.Log2(limit) + 1);\n\n            PlayGuessingRounds(limit, targetGuessCount);\n\n            _io.Write(Streams.BlankLines);\n        }\n    }\n\n    private void PlayGuessingRounds(float limit, int targetGuessCount)\n    {\n        while (true)\n        {\n            _io.WriteLine(Formats.Thinking, limit);\n\n            // There's a bug here that exists in the original code. If a non-integer is entered as the limit\n            // then it's possible for the secret number to be the next integer greater than the limit.\n            var secretNumber = (int)_random.NextFloat(limit) + 1;\n\n            var guessCount = 0;\n\n            while (true)\n            {\n                var guess = _io.ReadNumber(\"\");\n                if (guess <= 0) { return; }\n                guessCount++;\n                if (IsGuessCorrect(guess, secretNumber)) { break; }\n            }\n\n            ReportResult(guessCount, targetGuessCount);\n\n            _io.Write(Streams.BlankLines);\n        }\n    }\n\n    private bool IsGuessCorrect(float guess, int secretNumber)\n    {\n        if (guess < secretNumber) { _io.Write(Streams.TooLow); }\n        if (guess > secretNumber) { _io.Write(Streams.TooHigh); }\n\n        return guess == secretNumber;\n    }\n\n    private void ReportResult(int guessCount, int targetGuessCount)\n    {\n        _io.WriteLine(Formats.ThatsIt, guessCount);\n        _io.WriteLine(\n            (guessCount - targetGuessCount) switch\n            {\n                < 0 => Strings.VeryGood,\n                0 => Strings.Good,\n                > 0 => string.Format(Formats.ShouldHave, targetGuessCount)\n            });\n    }\n}"
  },
  {
    "path": "41_Guess/csharp/Guess.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "41_Guess/csharp/Guess.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Guess\", \"Guess.csproj\", \"{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "41_Guess/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using static Guess.Resources.Resource;  \n\nusing Guess;\n\nnew Game(new ConsoleIO(), new RandomNumberGenerator()).Play();\n"
  },
  {
    "path": "41_Guess/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "41_Guess/csharp/Resources/BlankLines.txt",
    "content": "\n\n\n\n\n"
  },
  {
    "path": "41_Guess/csharp/Resources/Good.txt",
    "content": "Good."
  },
  {
    "path": "41_Guess/csharp/Resources/Introduction.txt",
    "content": "                                 Guess\n               Creative Computing  Morristown, New Jersey\n\n\n\nThis is a number guessing game. I'll think\nof a number between 1 and any limit you want.\nThe you have to guess what it is.\n\n"
  },
  {
    "path": "41_Guess/csharp/Resources/Limit.txt",
    "content": "What limit do you want"
  },
  {
    "path": "41_Guess/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Guess.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n        public static Stream TooLow => GetStream();\n        public static Stream TooHigh => GetStream();\n        public static Stream BlankLines => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string Thinking => GetString();\n        public static string ThatsIt => GetString();\n        public static string ShouldHave => GetString();\n    }\n\n    internal static class Prompts\n    {\n        public static string Limit => GetString();\n    }\n\n    internal static class Strings\n    {\n        public static string Good => GetString();\n        public static string VeryGood => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "41_Guess/csharp/Resources/ShouldHave.txt",
    "content": "You should have been able to get it in only {0}"
  },
  {
    "path": "41_Guess/csharp/Resources/ThatsIt.txt",
    "content": "That's it! You got it in {0} tries."
  },
  {
    "path": "41_Guess/csharp/Resources/Thinking.txt",
    "content": "I'm thinking of a number between 1 and {0}\nNow you try to guess what it is."
  },
  {
    "path": "41_Guess/csharp/Resources/TooHigh.txt",
    "content": "Too high. Try a smaller answer."
  },
  {
    "path": "41_Guess/csharp/Resources/TooLow.txt",
    "content": "Too low. Try a bigger answer."
  },
  {
    "path": "41_Guess/csharp/Resources/VeryGood.txt",
    "content": "Very good."
  },
  {
    "path": "41_Guess/guess.bas",
    "content": "1 PRINT TAB(33);\"GUESS\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"THIS IS A NUMBER GUESSING GAME. I'LL THINK\"\n5 PRINT \"OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\"\n6 PRINT \"THEN YOU HAVE TO GUESS WHAT IT IS.\"\n7 PRINT\n8 PRINT \"WHAT LIMIT DO YOU WANT\";\n9 INPUT L\n10 PRINT\n11 L1=INT(LOG(L)/LOG(2))+1\n12 PRINT \"I'M THINKING OF A NUMBER BETWEEN 1 AND\";L\n13 G=1\n14 PRINT \"NOW YOU TRY TO GUESS WHAT IT IS.\"\n15 M=INT(L*RND(1)+1)\n20 INPUT N\n21 IF N>0 THEN 25\n22 GOSUB 70\n23 GOTO 1\n25 IF N=M THEN 50\n30 G=G+1\n31 IF N>M THEN 40\n32 PRINT \"TOO LOW. TRY A BIGGER ANSWER.\"\n33 GOTO 20\n40 PRINT \"TOO HIGH. TRY A SMALLER ANSWER.\"\n42 GOTO 20\n50 PRINT \"THAT'S IT! YOU GOT IT IN\";G;\"TRIES.\"\n52 IF G<L1 THEN 58\n54 IF G=L1 THEN 60\n56 PRINT \"YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY\";L1\n57 GOTO 65\n58 PRINT \"VERY \";\n60 PRINT \"GOOD.\"\n65 GOSUB 70\n66 GOTO 12\n70 FOR H=1 TO 5\n71 PRINT\n72 NEXT H\n73 RETURN\n99 END\n"
  },
  {
    "path": "41_Guess/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "41_Guess/java/src/Guess.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Guess\n * <p>\n * Based on the Basic game of Guess here\n * https://github.com/coding-horror/basic-computer-games/blob/main/41%20Guess/guess.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Guess {\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        STARTUP,\n        INPUT_RANGE,\n        DEFINE_COMPUTERS_NUMBER,\n        GUESS,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // User supplied maximum number to guess\n    private int limit;\n\n    // Computers calculated number for the player to guess\n\n    private int computersNumber;\n\n    // Number of turns the player has had guessing\n    private int tries;\n\n    // Optimal number of turns it should take to guess\n    private int calculatedTurns;\n\n    public Guess() {\n        kbScanner = new Scanner(System.in);\n\n        gameState = GAME_STATE.STARTUP;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case STARTUP:\n                    intro();\n                    gameState = GAME_STATE.INPUT_RANGE;\n                    break;\n\n                case INPUT_RANGE:\n\n                    limit = displayTextAndGetNumber(\"WHAT LIMIT DO YOU WANT? \");\n                    calculatedTurns = (int) (Math.log(limit) / Math.log(2)) + 1;\n                    gameState = GAME_STATE.DEFINE_COMPUTERS_NUMBER;\n                    break;\n\n                case DEFINE_COMPUTERS_NUMBER:\n\n                    tries = 1;\n                    System.out.println(\"I'M THINKING OF A NUMBER BETWEEN 1 AND \" + limit);\n                    computersNumber = (int) (Math.random() * limit + 1);\n\n                    gameState = GAME_STATE.GUESS;\n                    break;\n\n                case GUESS:\n                    int playersGuess = displayTextAndGetNumber(\"NOW YOU TRY TO GUESS WHAT IT IS \");\n\n                    // Allow player to restart game with entry of 0\n                    if (playersGuess == 0) {\n                        linePadding();\n                        gameState = GAME_STATE.STARTUP;\n                        break;\n                    }\n\n                    if (playersGuess == computersNumber) {\n                        System.out.println(\"THAT'S IT! YOU GOT IT IN \" + tries + \" TRIES.\");\n                        if (tries < calculatedTurns) {\n                            System.out.println(\"VERY \");\n                        }\n                        System.out.println(\"GOOD.\");\n                        System.out.println(\"YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY \" + calculatedTurns);\n                        linePadding();\n                        gameState = GAME_STATE.DEFINE_COMPUTERS_NUMBER;\n                        break;\n                    } else if (playersGuess < computersNumber) {\n                        System.out.println(\"TOO LOW. TRY A BIGGER ANSWER.\");\n                    } else {\n                        System.out.println(\"TOO HIGH. TRY A SMALLER ANSWER.\");\n                    }\n                    tries++;\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(33) + \"GUESS\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THIS IS A NUMBER GUESSING GAME. I'LL THINK\");\n        System.out.println(\"OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\");\n        System.out.println(\"THEN YOU HAVE TO GUESS WHAT IT IS.\");\n    }\n\n    /**\n     * Print a predefined number of blank lines\n     *\n     */\n    private void linePadding() {\n        for (int i = 1; i <= 5; i++) {\n            System.out.println();\n        }\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n}\n"
  },
  {
    "path": "41_Guess/java/src/GuessGame.java",
    "content": "public class GuessGame {\n    public static void main(String[] args) {\n        Guess guess = new Guess();\n        guess.play();\n    }\n}\n"
  },
  {
    "path": "41_Guess/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "41_Guess/javascript/guess.html",
    "content": "<html>\n<head>\n<title>GUESS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"guess.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "41_Guess/javascript/guess.js",
    "content": "// GUESS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nfunction make_space()\n{\n    for (h = 1; h <= 5; h++)\n        print(\"\\n\");\n}\n\n// Main control section\nasync function main()\n{\n    while (1) {\n        print(tab(33) + \"GUESS\\n\");\n        print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"THIS IS A NUMBER GUESSING GAME. I'LL THINK\\n\");\n        print(\"OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\\n\");\n        print(\"THEN YOU HAVE TO GUESS WHAT IT IS.\\n\");\n        print(\"\\n\");\n\n        print(\"WHAT LIMIT DO YOU WANT\");\n        l = parseInt(await input());\n        print(\"\\n\");\n        l1 = Math.floor(Math.log(l) / Math.log(2)) + 1;\n        while (1) {\n            print(\"I'M THINKING OF A NUMBER BETWEEN 1 AND \" + l + \"\\n\");\n            g = 1;\n            print(\"NOW YOU TRY TO GUESS WHAT IT IS.\\n\");\n            m = Math.floor(l * Math.random() + 1);\n            while (1) {\n                n = parseInt(await input());\n                if (n <= 0) {\n                    make_space();\n                    break;\n                }\n                if (n == m) {\n                    print(\"THAT'S IT! YOU GOT IT IN \" + g + \" TRIES.\\n\");\n                    if (g == l1) {\n                        print(\"GOOD.\\n\");\n                    } else if (g < l1) {\n                        print(\"VERY GOOD.\\n\");\n                    } else {\n                        print(\"YOU SHOULD HAVE BEEN TO GET IT IN ONLY \" + l1 + \"\\n\");\n                    }\n                    make_space();\n                    break;\n                }\n                g++;\n                if (n > m)\n                    print(\"TOO HIGH. TRY A SMALLER ANSWER.\\n\");\n                else\n                    print(\"TOO LOW. TRY A BIGGER ANSWER.\\n\");\n            }\n            if (n <= 0)\n                break;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "41_Guess/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "41_Guess/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "41_Guess/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "41_Guess/perl/guess.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nmy $L1;\nwhile (1) {\n\tprint ' 'x 33 . \"GUESS\\n\";\n\tprint ' 'x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\n\tprint \"\\n\"; print \"\\n\"; print \"\\n\";\n\tprint \"THIS IS A NUMBER GUESSING GAME. I'LL THINK\\n\";\n\tprint \"OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\\n\";\n\tprint \"THEN YOU HAVE TO GUESS WHAT IT IS.\\n\";\n\tprint \"\\n\";\n\tprint \"WHAT LIMIT DO YOU WANT\";\n\tprint \"? \"; chomp(my $L = <STDIN>);\n\tprint \"\\n\";\n\t$L1= int(log($L)/log(2))+1;\n\n\twhile (1) {\n\t\tprint \"I'M THINKING OF A NUMBER BETWEEN 1 AND $L\\n\";\n\t\tmy $G=0;\n\t\tprint \"NOW YOU TRY TO GUESS WHAT IT IS.\\n\";\n\t\tmy $M=int($L*rand(1)+1);\n\t\tmy $N=0;\n\t\twhile (1) {\n\t\t\twhile (1) {\n\t\t\t\tprint \"? \"; chomp($N = <STDIN>);\n\t\t\t\tif ($N>0) { last; }\n\t\t\t\t}\n\t\t\t$G=$G+1;\n\t\t\tif ($N==$M) { last; }\n\t\t\tif ($N>$M) { print \"TOO HIGH. TRY A SMALLER ANSWER.\\n\"; }\n\t\t\t\telse { print \"TOO LOW. TRY A BIGGER ANSWER.\\n\"; }\n\t\t\t}\n\t\tprint \"THAT'S IT! YOU GOT IT IN $G TRIES.\\n\";\n\t\tif ($G<$L1) { print \"VERY \"; }\n\t\tif ($G<=$L1) { print \"GOOD.\\n\"; }\n\t\tif ($G>$L1) { print \"YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY $L1\\n\"; }\n\t\t&ENTERS();\n\t\t}\n\t}\n\nexit;\n\n\nsub ENTERS { #GOSUB 70\n\tfor (my $H=1; $H<=5; $H++) {\n\t\tprint \"\\n\";\n\t\t}\n\treturn;\n\t}\n"
  },
  {
    "path": "41_Guess/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "41_Guess/python/guess.py",
    "content": "\"\"\"\nGuess\n\nFrom: Basic Computer Games (1978)\n\n \"In program Guess, the computer  chooses a random\n  integer between 0 and any limit and any limit you\n  set. You must then try to guess the number the\n  computer has choosen using the clues provideed by\n  the computer.\n   You should be able to guess the number in one less\n  than the number of digits needed to  represent the\n  number in binary notation - i.e. in base 2. This ought\n  to give you a clue as to the optimum search technique.\n   Guess converted from the original program in FOCAL\n  which appeared in the book \"Computers in the Classroom\"\n  by Walt Koetke of Lexington High School, Lexington,\n  Massaschusetts.\n\"\"\"\n\n# Altough the introduction says that the computer chooses\n# a number between 0 and any limit, it actually chooses\n# a number between 1 and any limit. This due to the fact that\n# for computing the number of digits the limit has in binary\n# representation, it has to use log.\n\nfrom math import log\nfrom random import random\nfrom typing import Tuple\n\n\ndef insert_whitespaces() -> None:\n    print(\"\\n\\n\\n\\n\\n\")\n\n\ndef limit_set() -> Tuple[int, int]:\n    print(\"                   Guess\")\n    print(\"Creative Computing  Morristown, New Jersey\")\n    print(\"\\n\\n\\n\")\n    print(\"This is a number guessing game. I'll think\")\n    print(\"of a number between 1 and any limit you want.\\n\")\n    print(\"Then you have to guess what it is\\n\")\n    print(\"What limit do you want?\")\n\n    limit = int(input())\n\n    while limit <= 0:\n        print(\"Please insert a number greater or equal to 1\")\n        limit = int(input())\n\n    # limit_goal = Number of digits \"limit\" in binary has\n    limit_goal = int((log(limit) / log(2)) + 1)\n\n    return limit, limit_goal\n\n\ndef main() -> None:\n    limit, limit_goal = limit_set()\n    while True:\n        guess_count = 1\n        still_guessing = True\n        won = False\n        my_guess = int(limit * random() + 1)\n\n        print(f\"I'm thinking of a number between 1 and {limit}\")\n        print(\"Now you try to guess what it is.\")\n\n        while still_guessing:\n            n = int(input())\n\n            if n < 0:\n                break\n\n            insert_whitespaces()\n            if n < my_guess:\n                print(\"Too low. Try a bigger answer\")\n                guess_count += 1\n            elif n > my_guess:\n                print(\"Too high. Try a smaller answer\")\n                guess_count += 1\n            else:\n                print(f\"That's it! You got it in {guess_count} tries\")\n                won = True\n                still_guessing = False\n\n        if won:\n            if guess_count < limit_goal:\n                print(\"Very good.\")\n            elif guess_count == limit_goal:\n                print(\"Good.\")\n            else:\n                print(f\"You should have been able to get it in only {limit_goal}\")\n            insert_whitespaces()\n        else:\n            insert_whitespaces()\n            limit, limit_goal = limit_set()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "41_Guess/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "41_Guess/ruby/guess.rb",
    "content": "def print_intro\n  print \" \" * 31 + \"GUESS\\n\"\n  print \" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\"\n  print \"THIS IS A NUMBER GUESSING GAME. I'LL THINK\\nOF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\\nTHEN YOU HAVE TO GUESS WHAT IT IS.\\n\"\nend\n\ndef game_play(limit,choice_limit)\n    random = rand(limit.to_i)+1\n    puts \"I'M THINKING OF A NUMBER BETWEEN 1 and #{limit}\"\n    puts \"NOW YOU TRY TO GUESS WHAT IT IS.\"\n    print \"? \"\n    ans=0\n    guesses=0\n    until ans.to_i == random.to_i\n      ans = gets.chomp\n      guesses += 1\n      if ans.to_i > random.to_i\n        puts \"TOO HIGH. TRY A SMALLER ANSWER.\"\n        print \"? \"\n      elsif ans.to_i < random.to_i\n        puts \"TOO LOW. TRY A BIGGER ANSWER.\"\n        print \"? \"\n      elsif ans.to_i == random.to_i\n        puts \"THAT'S IT! YOU GOT IT IN #{guesses} TRIES.\"\n        if guesses.to_i < choice_limit.to_i\n          puts \"VERY GOOD.\"\n        elsif guesses.to_i == choice_limit.to_i\n          puts \"GOOD.\"\n        else\n          puts \"YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY #{choice_limit}\"\n        end\n        print \"\\n\\n\\n\\n\\n\"\n      end\n    end\nend\n\n\ndef main\n  print_intro\n  puts \"WHAT LIMIT DO YOU WANT\"\n  limit = gets.chomp\n  choice_limit = (Math.log(limit.to_i)/Math.log(2)+1).to_i\n  while 1\n    game_play(limit,choice_limit)\n  end\nend\n\nmain\n"
  },
  {
    "path": "41_Guess/rust/Cargo.toml",
    "content": "[package]\nname = \"guess\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.4\"\n"
  },
  {
    "path": "41_Guess/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "41_Guess/rust/src/main.rs",
    "content": "//#######################################################\n//\n// Guess\n//\n// From: Basic Computer Games (1978)\n//\n// \"In program Guess, the computer  chooses a random\n//  integer between 0 and any limit and any limit you\n//  set. You must then try to guess the number the\n//  computer has choosen using the clues provideed by\n//  the computer.\n//   You should be able to guess the number in one less\n//  than the number of digits needed to  represent the\n//  number in binary notation - i.e. in base 2. This ought\n//  to give you a clue as to the optimum search technique.\n//   Guess converted from the original program in FOCAL\n//  which appeared in the book \"Computers in the Classroom\"\n//  by Walt Koetke of Lexington High School, Lexington,\n//   Massaschusetts.\n//\n//#######################################################\n\n\nuse rand::Rng;\nuse std::io;\nuse std::cmp::Ordering;\n// Rust haven't log2 in the standard library so I added fn log_2\nconst fn num_bits<T>() -> usize { std::mem::size_of::<T>() * 8 }\n\nfn main() {\n\n    let mut rng = rand::thread_rng();\n    let mut still_guessing = true;\n    let limit = set_limit();\n    let limit_goal = 1+(log_2(limit.try_into().unwrap())/log_2(2)) ;\n    loop{\n\n        let mut won = false;\n        let mut guess_count = 1;\n        let my_guess = rng.gen_range(1..limit);\n\n        println!(\"I'm thinking of a number between 1 and {}\",limit);\n        println!(\"Now you try to guess what it is.\");\n\n        while still_guessing {\n            let inp = get_input()\n                .trim()\n                .parse::<i64>().unwrap();\n            println!(\"\\n\\n\\n\");\n            if inp < my_guess {\n                println!(\"Too low. Try a bigger answer\");\n                guess_count+=1;\n            }\n            else if inp > my_guess {\n                println!(\"Too high. Try a smaller answer\");\n                guess_count+=1;\n            }\n            else {\n                println!(\"That's it! You got it in {} tries\", guess_count);\n                won = true;\n                still_guessing = false;\n            }\n        }\n        if won {\n            match guess_count.cmp(&limit_goal) {\n                Ordering::Less => println!(\"Very good.\"),\n                Ordering::Equal => println!(\"Good.\"),\n                Ordering::Greater => println!(\"You should have been able to get it in only {}\", limit_goal),\n            }\n\n            println!(\"\\n\\n\\n\");\n            still_guessing = true;\n        } else {\n            println!(\"\\n\\n\\n\");\n        }\n    }\n}\n\nfn log_2(x:i32) -> u32 {\n    assert!(x > 0);\n    num_bits::<i32>() as u32 - x.leading_zeros() - 1\n}\n\nfn set_limit() -> i64 {\n\n    println!(\"                   Guess\");\n    println!(\"\\n\\n\\n\");\n    println!(\"This is a number guessing game. I'll think\");\n    println!(\"of a number between 1 and any limit you want.\\n\");\n    println!(\"Then you have to guess what it is\\n\");\n    println!(\"What limit do you want?\");\n\n    let inp = get_input().trim().parse::<i64>().unwrap();\n\n    if inp >= 2 {\n        inp\n    }\n    else {\n        set_limit()\n    }\n}\n\nfn get_input() -> String {\n    let mut input = String::new();\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Your input is not correct\");\n    input\n}\n"
  },
  {
    "path": "41_Guess/vbnet/Guess.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Guess\", \"Guess.vbproj\", \"{33AB1024-1609-4163-BEAF-BA02A5D42F8A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "41_Guess/vbnet/Guess.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Guess</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "41_Guess/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "42_Gunner/README.md",
    "content": "### Gunner\n\nGUNNER allows you to adjust the fire of a field artillery weapon to hit a stationary target. You specify the number of degrees of elevation of your weapon; 45 degrees provides maximum range with values under or over 45 degrees providing less range.\n\nYou get up to five shots to destroy the enemy before he destroys you. Gun range varies between 20,000 and 60,000 yards and burst radius is 100 yards. You must specify elevation within approximately 0.2 degrees to get a hit.\n\nTom Kloos of the Oregon Museum of Science and Industry in Portland, Oregon originally wrote GUNNER. Extensive modifications were added by David Ahl.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=77)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=92)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "42_Gunner/csharp/Gunner.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "42_Gunner/csharp/Gunner.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Gunner\", \"Gunner.csproj\", \"{0279F69D-A69A-49B6-867C-78AA4F4DB962}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {09C668DA-38D4-4EF4-9FCA-EB1FF9EF6067}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "42_Gunner/csharp/Program.cs",
    "content": "﻿namespace Gunner\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            PrintIntro();\n\n            string keepPlaying = \"Y\";\n\n            while (keepPlaying == \"Y\") {\n                PlayGame();\n                Console.WriteLine(\"TRY AGAIN (Y OR N)\");\n                keepPlaying = Console.ReadLine();\n            }\n        }\n\n        static void PlayGame()\n        {\n            int totalAttempts = 0;\n            int amountOfGames = 0;\n\n            while (amountOfGames < 4) {\n\n                int maximumRange = new Random().Next(0, 40000) + 20000;\n                Console.WriteLine($\"MAXIMUM RANGE OF YOUR GUN IS {maximumRange} YARDS.\" + Environment.NewLine + Environment.NewLine + Environment.NewLine);\n\n                int distanceToTarget = (int) (maximumRange * (0.1 + 0.8 * new Random().NextDouble()));\n                Console.WriteLine($\"DISTANCE TO THE TARGET IS {distanceToTarget} YARDS.\");\n\n                (bool gameWon, int attempts) = HitTheTarget(maximumRange, distanceToTarget);\n\n                if(!gameWon) {\n                    Console.WriteLine(Environment.NewLine + \"BOOM !!!!   YOU HAVE JUST BEEN DESTROYED\" + Environment.NewLine +\n                        \"BY THE ENEMY.\" + Environment.NewLine + Environment.NewLine + Environment.NewLine\n                    );\n                    PrintReturnToBase();\n                    break;\n                } else {\n                    amountOfGames += 1;\n                    totalAttempts += attempts;\n\n                    Console.WriteLine($\"TOTAL ROUNDS EXPENDED WERE:{totalAttempts}\");\n\n                    if (amountOfGames < 4) {\n                        Console.WriteLine(\"THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\");\n                    } else {\n                        if (totalAttempts > 18) {\n                            PrintReturnToBase();\n                        } else {\n                            Console.WriteLine($\"NICE SHOOTING !!\");\n                        }\n                    }\n                }\n            }\n        }\n\n        static (bool, int) HitTheTarget(int maximumRange, int distanceToTarget)\n        {\n            int attempts = 0;\n\n            while (attempts < 6)\n            {\n                int elevation = GetElevation();\n\n                int differenceBetweenTargetAndImpact = CalculateDifferenceBetweenTargetAndImpact(maximumRange, distanceToTarget, elevation);\n\n                if (Math.Abs(differenceBetweenTargetAndImpact) < 100)\n                {\n                    Console.WriteLine($\"*** TARGET DESTROYED *** {attempts} ROUNDS OF AMMUNITION EXPENDED.\");\n                    return (true, attempts);\n                }\n                else if (differenceBetweenTargetAndImpact > 100)\n                {\n                    Console.WriteLine($\"OVER TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS.\");\n                }\n                else\n                {\n                    Console.WriteLine($\"SHORT OF TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS.\");\n                }\n\n                attempts += 1;\n            }\n            return (false, attempts);\n        }\n\n        static int CalculateDifferenceBetweenTargetAndImpact(int maximumRange, int distanceToTarget, int elevation)\n        {\n            double weirdNumber = 2 * elevation / 57.3;\n            double distanceShot = maximumRange * Math.Sin(weirdNumber);\n            return (int)distanceShot - distanceToTarget;\n        }\n\n        static void PrintReturnToBase()\n        {\n            Console.WriteLine(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\");\n        }\n\n        static int GetElevation()\n        {\n            Console.WriteLine(\"ELEVATION\");\n            int elevation = int.Parse(Console.ReadLine());\n            if (elevation > 89) {\n                Console.WriteLine(\"MAXIMUM ELEVATION IS 89 DEGREES\");\n                return GetElevation();\n            }\n            if (elevation < 1) {\n                Console.WriteLine(\"MINIMUM ELEVATION IS 1 DEGREE\");\n                return GetElevation();\n            }\n            return elevation;\n        }\n\n        static void PrintIntro()\n        {\n            Console.WriteLine(new String(' ', 30) + \"GUNNER\");\n            Console.WriteLine(new String(' ', 15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\" + Environment.NewLine + Environment.NewLine + Environment.NewLine);\n            Console.WriteLine(\"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\");\n            Console.WriteLine(\"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\");\n            Console.WriteLine(\"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\");\n            Console.WriteLine(\"OF THE TARGET WILL DESTROY IT.\" + Environment.NewLine);\n        }\n    }\n}\n"
  },
  {
    "path": "42_Gunner/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "42_Gunner/gunner.bas",
    "content": "10 PRINT TAB(30);\"GUNNER\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n130 PRINT \"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\"\n140 PRINT \"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\"\n150 PRINT \"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\"\n160 PRINT \"OF THE TARGET WILL DESTROY IT.\" : PRINT\n170 R=INT(40000*RND(1)+20000)\n180 PRINT \"MAXIMUM RANGE OF YOUR GUN IS\";R;\" YARDS.\"\n185 Z=0\n190 PRINT\n195 S1=0\n200 T=INT(R*(.1+.8*RND(1)))\n210 S=0\n220 GOTO 370\n230 PRINT \"MINIMUM ELEVATION IS ONE DEGREE.\"\n240 GOTO 390\n250 PRINT \"MAXIMUM ELEVATION IS 89 DEGREES.\"\n260 GOTO 390\n270 PRINT \"OVER TARGET BY \";ABS(E);\"YARDS.\"\n280 GOTO 390\n290 PRINT \"SHORT OF TARGET BY \"ABS(E);\"YARDS.\"\n300 GOTO 390\n320 PRINT \"*** TARGET DESTROYED ***  \";S;\"ROUNDS OF AMMUNITION EXPENDED.\"\n325 S1=S1+S\n330 IF Z=4 THEN 490\n340 Z=Z+1\n345 PRINT\n350 PRINT \"THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\"\n360 GOTO 200\n370 PRINT \"DISTANCE TO THE TARGET IS \"T;\" YARDS.\"\n380 PRINT\n390 PRINT\n400 INPUT \"ELEVATION\";B\n420 IF B>89 THEN 250\n430 IF B<1 THEN 230\n440 S=S+1\n442 IF S<6 THEN 450\n444 PRINT:PRINT \"BOOM !!!!   YOU HAVE JUST BEEN DESTROYED \";\n446 PRINT \"BY THE ENEMY.\" : PRINT : PRINT : PRINT : GOTO 495\n450 B2=2*B/57.3 : I=R*SIN(B2) : X=T-I : E=INT(X)\n460 IF ABS(E)<100 THEN 320\n470 IF E>100 THEN 290\n480 GOTO 270\n490 PRINT : PRINT : PRINT \"TOTAL ROUNDS EXPENDED WERE:\";S1\n492 IF S1>18 THEN 495\n493 PRINT \"NICE SHOOTING !!\" : GOTO 500\n495 PRINT \"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\"\n500 PRINT : INPUT \"TRY AGAIN (Y OR N)\";Z$\n510 IF Z$=\"Y\" THEN 170\n520 PRINT:PRINT \"OK.  RETURN TO BASE CAMP.\"\n999 END\n"
  },
  {
    "path": "42_Gunner/java/Gunner.java",
    "content": "import java.util.Random;\nimport java.util.Scanner;\n\npublic class Gunner {\n\n    public static final int MAX_ROUNDS = 6;\n    public static final int MAX_ENEMIES = 4;\n    public static final int ERROR_DISTANCE = 100;\n\n    private static Scanner scanner = new Scanner(System.in);\n    private static Random random = new Random();\n\n    public static void main(String[] args) {\n        println(\"                              GUNNER\");\n        println(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        println();\n        println();\n        println();\n        println(\"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\");\n        println(\"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\");\n        println(\"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN \" + ERROR_DISTANCE + \" YARDS\");\n        println(\"OF THE TARGET WILL DESTROY IT.\");\n        println();\n        while (true) {\n            int maxRange = random.nextInt(40000) + 20000;\n            int enemyCount = 0;\n            int totalRounds = 0;\n            println(\"MAXIMUM RANGE OF YOUR GUN IS \" + maxRange + \" YARDS.\\n\");\n\n            while (true) {\n                int rounds = fightEnemy(maxRange);\n                totalRounds += rounds;\n\n                if (enemyCount == MAX_ENEMIES || rounds >= MAX_ROUNDS) {\n                    if (rounds < MAX_ROUNDS) {\n                        println(\"\\n\\n\\nTOTAL ROUNDS EXPENDED WERE:\" + totalRounds);\n                    }\n                    if (totalRounds > 18 || rounds >= MAX_ROUNDS) {\n                        println(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\");\n                    } else {\n                        println(\"NICE SHOOTING !!\");\n                    }\n                    println(\"\\nTRY AGAIN (Y OR N)\");\n                    String tryAgainResponse = scanner.nextLine();\n                    if (\"Y\".equals(tryAgainResponse) || \"y\".equals(tryAgainResponse)) {\n                        break;\n                    }\n                    println(\"\\nOK.  RETURN TO BASE CAMP.\");\n                    return;\n                }\n                enemyCount++;\n                println(\"\\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\");\n            }\n        }\n    }\n\n    private static int fightEnemy(int maxRange) {\n        int rounds = 0;\n        long target = Math.round(maxRange * (random.nextDouble() * 0.8 + 0.1));\n        println(\"      DISTANCE TO THE TARGET IS \" + target + \" YARDS.\");\n\n        while (true) {\n            println(\"\\nELEVATION?\");\n            double elevation = Double.parseDouble(scanner.nextLine());\n            if (elevation > 89.0) {\n                println(\"MAXIMUM ELEVATION IS 89 DEGREES.\");\n                continue;\n            }\n            if (elevation < 1.0) {\n                println(\"MINIMUM ELEVATION IS ONE DEGREE.\");\n                continue;\n            }\n            rounds++;\n            if (rounds >= MAX_ROUNDS) {\n                println(\"\\nBOOM !!!!   YOU HAVE JUST BEEN DESTROYED \");\n                println(\"BY THE ENEMY.\\n\\n\\n\");\n                break;\n            }\n\n            long error = calculateError(maxRange, target, elevation);\n            if (Math.abs(error) < ERROR_DISTANCE) {\n                println(\"*** TARGET DESTROYED ***  \" + rounds + \" ROUNDS OF AMMUNITION EXPENDED.\");\n                break;\n            } else if (error > ERROR_DISTANCE) {\n                println(\"SHORT OF TARGET BY \" + Math.abs(error) + \" YARDS.\");\n            } else {\n                println(\"OVER TARGET BY \" + Math.abs(error) + \" YARDS.\");\n            }\n\n        }\n        return rounds;\n    }\n\n    private static long calculateError(int maxRange, long target, double elevationInDegrees) {\n        double elevationInRadians = Math.PI * elevationInDegrees / 90.0; //convert degrees to radians\n        double impact = maxRange * Math.sin(elevationInRadians);\n        double error = target - impact;\n        return Math.round(error);\n    }\n\n    private static void println(String s) {\n        System.out.println(s);\n    }\n\n    private static void println() {\n        System.out.println();\n    }\n}\n"
  },
  {
    "path": "42_Gunner/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "42_Gunner/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "42_Gunner/javascript/gunner.html",
    "content": "<html>\n<head>\n<title>GUNNER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"gunner.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "42_Gunner/javascript/gunner.js",
    "content": "// GUNNER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nprint(tab(30) + \"GUNNER\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\\n\");\nprint(\"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\\n\");\nprint(\"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\\n\");\nprint(\"OF THE TARGET WILL DESTROY IT.\\n\");\nprint(\"\\n\");\n\n// Main control section\nasync function main()\n{\n    while (1) {\n        r = Math.floor(40000 * Math.random() + 20000);\n        print(\"MAXIMUM RANGE OF YOUR GUN IS \" + r + \" YARDS.\\n\");\n        z = 0;\n        print(\"\\n\");\n        s1 = 0;\n        while (1) {\n            t = Math.floor(r * (0.1 + 0.8 * Math.random()));\n            s = 0;\n            print(\"DISTANCE TO THE TARGET IS \" + t + \" YARDS.\\n\");\n            print(\"\\n\");\n\n            while (1) {\n                print(\"\\n\");\n                print(\"ELEVATION\");\n                b = parseFloat(await input());\n                if (b > 89) {\n                    print(\"MAXIMUM ELEVATION IS 89 DEGREES.\\n\");\n                    continue;\n                }\n                if (b < 1) {\n                    print(\"MINIMUM ELEVATION IS ONE DEGREE.\\n\");\n                    continue;\n                }\n                if (++s >= 6) {\n                    print(\"\\n\");\n                    print(\"BOOM !!!!   YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\\n\");\n                    print(\"\\n\");\n                    print(\"\\n\");\n                    print(\"\\n\");\n                    e = 0;\n                    break;\n                }\n                b2 = 2 * b / 57.3;\n                i = r * Math.sin(b2);\n                x = t - i;\n                e = Math.floor(x);\n                if (true) { //Math.abs(e) < 100) {\n                    e = 1;\n                    break;\n                }\n                if (e > 100) {\n                    print(\"SHORT OF TARGET BY \" + Math.abs(e) + \" YARDS.\\n\");\n                } else {\n                    print(\"OVER TARGET BY \" + Math.abs(e) + \" YARDS.\\n\");\n                }\n            }\n            if (e == 1) {\n                print(\"*** TARGET DESTROYED *** \" + s + \" ROUNDS OF AMMUNITION EXPENDED.\\n\");\n                s1 += s;\n                if (z == 4) {\n                    print(\"\\n\");\n                    print(\"\\n\");\n                    print(\"TOTAL ROUND EXPENDED WERE: \" + s1 + \"\\n\");\n                    break;\n                } else {\n                    z++;\n                    print(\"\\n\");\n                    print(\"THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\\n\");\n                }\n            } else {\n                s1 = 19;\n                break;\n            }\n        }\n        if (s1 > 18) {\n            print(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\\n\");\n        } else {\n            print(\"NICE SHOOTING !!\");\n        }\n        print(\"\\n\");\n        print(\"TRY AGAIN (Y OR N)\");\n        str = await input();\n        if (str.substr(0, 1) != \"Y\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"OK.  RETURN TO BASE CAMP.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "42_Gunner/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "42_Gunner/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "42_Gunner/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "42_Gunner/perl/gunner.pl",
    "content": "#!/usr/bin/perl\n\n# Gunner program in Perl\n#   Required extensive restructuring to remove all of the GOTO's.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $Max_range = int(40000*rand(1)+20000);\nmy $Total_shots = 0;\nmy $Games = 0;\n\nprint \"\\n\";\nprint \" \" x 30, \"GUNNER\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\nprint \"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\\n\";\nprint \"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\\n\";\nprint \"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\\n\";\nprint \"OF THE TARGET WILL DESTROY IT.\\n\\n\";\nprint \"MAXIMUM RANGE OF YOUR GUN IS $Max_range YARDS.\\n\\n\";\n\nGAME: while (1)\n{\n    my $target_dist = int($Max_range * (.1 + .8 * rand(1)));\n    my $shots = 0;\n    print \"DISTANCE TO THE TARGET IS $target_dist YARDS.\\n\\n\";\n    while (1)\n    {\n        my $elevation = get_elevation(); # in degrees\n        $shots++;\n        my $dist = int($target_dist - ($Max_range * sin(2 * $elevation / 57.3)));\n        if (abs($dist) < 100)\n        {\n            print \"*** TARGET DESTROYED ***  $shots ROUNDS OF AMMUNITION EXPENDED.\\n\";\n            $Total_shots += $shots;\n            if ($Games++ == 4)\n            {\n                print \"\\n\\nTOTAL ROUNDS EXPENDED WERE: $Total_shots\\n\";\n                if ($Total_shots > 18) { print \"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\\n\"; }\n                else                   { print \"NICE SHOOTING !!\\n\"; }\n                last;\n            }\n            print \"\\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\\n\";\n            next GAME;\n        }\n        if ($dist > 100) { print \"SHORT OF TARGET BY \", abs($dist),\" YARDS.\\n\"; }\n        else             { print \"OVER TARGET BY \", abs($dist), \" YARDS.\\n\"; }\n\n        if ($shots >= 5)\n        {\n            print \"\\nBOOM !!!!   YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\\n\\n\\n\\n\"; \n            print \"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\\n\";\n            last;\n        }\n    }\n\n    print \"\\nTRY AGAIN (Y OR N): \";\n    chomp(my $ans=uc(<>));\n    if ($ans ne \"Y\") { last; }\n    else             { $Games = 0; $Total_shots = 0; }\n}\n\nprint \"\\nOK.  RETURN TO BASE CAMP.\\n\";\n\n####################################\n\nsub get_elevation\n{\n    my $elevation;\n    while (1)\n    {\n        print \"\\nELEVATION: \";\n        chomp($elevation = <>);\n        if    ($elevation > 89) { print \"MAXIMUM ELEVATION IS 89 DEGREES.\\n\"; }\n        elsif ($elevation < 1)  { print \"MINIMUM ELEVATION IS ONE DEGREE.\\n\"; }\n        else                    { return $elevation; }\n    }\n}\n"
  },
  {
    "path": "42_Gunner/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "42_Gunner/python/gunner.py",
    "content": "#!/usr/bin/env python3\n#\n# Ported to Python by @iamtraction\n\nfrom math import sin\nfrom random import random\n\n\ndef gunner() -> None:\n    gun_range = int(40000 * random() + 20000)\n\n    print(\"\\nMAXIMUM RANGE OF YOUR GUN IS\", gun_range, \"YARDS.\")\n\n    killed_enemies = 0\n    S1 = 0\n\n    while True:\n        target_distance = int(gun_range * (0.1 + 0.8 * random()))\n        shots = 0\n\n        print(\"\\nDISTANCE TO THE TARGET IS\", target_distance, \"YARDS.\")\n\n        while True:\n            elevation = float(input(\"\\n\\nELEVATION? \"))\n\n            if elevation > 89:\n                print(\"MAXIMUM ELEVATION IS 89 DEGREES.\")\n                continue\n\n            if elevation < 1:\n                print(\"MINIMUM ELEVATION IS ONE DEGREE.\")\n                continue\n\n            shots += 1\n\n            if shots < 6:\n                B2 = 2 * elevation / 57.3\n                shot_impact = gun_range * sin(B2)\n                shot_proximity = target_distance - shot_impact\n                shot_proximity_int = int(shot_proximity)\n\n                if abs(shot_proximity_int) < 100:\n                    print(\n                        \"*** TARGET DESTROYED *** \",\n                        shots,\n                        \"ROUNDS OF AMMUNITION EXPENDED.\",\n                    )\n                    S1 += shots\n                    if killed_enemies == 4:\n                        print(\"\\n\\nTOTAL ROUNDS EXPENDED WERE: \", S1)\n                        if S1 > 18:\n                            print(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\")\n                        else:\n                            print(\"NICE SHOOTING !!\")\n                        return\n                    else:\n                        killed_enemies += 1\n                        print(\n                            \"\\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\"\n                        )\n                        break\n                elif shot_proximity_int > 100:\n                    print(\"SHORT OF TARGET BY\", abs(shot_proximity_int), \"YARDS.\")\n                else:\n                    print(\"OVER TARGET BY\", abs(shot_proximity_int), \"YARDS.\")\n            else:\n                print(\"\\nBOOM !!!!   YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\\n\\n\\n\")\n                print(\"BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\")\n                return\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"GUNNER\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\\n\")\n    print(\"YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\")\n    print(\"CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\")\n    print(\"WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\")\n    print(\"OF THE TARGET WILL DESTROY IT.\")\n\n    while True:\n        gunner()\n\n        not_again = input(\"TRY AGAIN (Y OR N)? \").upper() != \"Y\"\n        if not_again:\n            print(\"\\nOK.  RETURN TO BASE CAMP.\")\n            break\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "42_Gunner/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "42_Gunner/rust/Cargo.toml",
    "content": "[package]\nname = \"gunner\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n[dependencies]\nrand = \"0.10.0\"\n"
  },
  {
    "path": "42_Gunner/rust/src/main.rs",
    "content": "use rand::{RngExt, rngs::ThreadRng};\nuse std::{\n    convert::Infallible,\n    io::{self, BufRead, Write},\n    str::FromStr,\n};\n\nfn main() {\n    println!(\"{:>30}GUNNER\", \"\");\n    println!(\"{:>15}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", \"\");\n    println!(\"\\n\\n\");\n\n    println!(\"You are the officer-in-charge, giving orders to a gun\");\n    println!(\"crew, telling them the degrees of elevation you estimate\");\n    println!(\"will place a projectile on target.  A hit wihtin 100 yards\");\n    println!(\"of the target will destroy it.\\n\");\n\n    let mut game = GunnerGame::new();\n    while game.run() == PlayAgain::Yes {\n        // do nothing -- just loop around and call game.run() again\n    }\n}\n\nstruct GunnerGame {\n    gun_range: usize, // each game has different range for the gun. \"R\" in the basic code\n    targets_destroyed: isize, // the \"Z\" counter in basic\n    total_rounds: isize, // how many rounds were fired across all targets. \"S1\" in basic\n    rng: ThreadRng,   // our PRNG\n}\n\nimpl GunnerGame {\n    fn new() -> Self {\n        let mut rng = rand::rng();\n        let gun_range = rng.random_range(20_000..=60_000);\n\n        Self {\n            gun_range,\n            rng,\n            targets_destroyed: 0,\n            total_rounds: 0,\n        }\n    }\n\n    fn run(&mut self) -> PlayAgain {\n        println!(\"Maximum range of your gun is {} yards.\\n\", self.gun_range);\n\n        for targets in 0..4 {\n            if targets > 0 {\n                // After the first round, we want to let the user know that there's\n                // another target in sight\n                println!(\"\\nThe forward observer has sighted more enemy activity...\");\n            }\n\n            // let the player try to destroy it\n            let target_destroyed = self.handle_target();\n\n            if !target_destroyed {\n                println!(\"\\nBoom !!!!   You have just been destroyed by the enemy.\\n\\n\\n\");\n                println!(\"Better go back to Fort Sill for refresher training!\");\n\n                println!();\n                break;\n            } else {\n                self.targets_destroyed += 1;\n            }\n        }\n\n        // only display success message if all targets were destroyed\n        if self.targets_destroyed == 4 {\n            println!(\"\\n\\nTotal rounds expended were: {}\", self.total_rounds);\n            if self.total_rounds <= 18 {\n                println!(\"Nice shooting !!\");\n            }\n        }\n\n        println!(\"\\n\");\n        get_input(\"Try again (Y or N)\")\n    }\n\n    fn handle_target(&mut self) -> bool {\n        let target_distance =\n            ((self.gun_range as f32) * (0.1 + 0.8 * self.rng.random::<f32>())) as isize;\n\n        println!(\"Distance to the target is {target_distance} yards.\\n\\n\");\n\n        // The player gets 5 shots. On the 6th shot we still ask for an elevation,\n        // but then report that they've been destroyed.\n        for shots_fired in 1..=6 {\n            let elevation = loop {\n                let elevation: f32 = get_input(\"Elevation\");\n\n                // Let the player know how well they did.\n                if elevation < 1.0 {\n                    println!(\"Miniumum elevation is one degree.\");\n                } else if elevation > 89.0 {\n                    println!(\"Maximum elevation is 89 degrees.\");\n                } else {\n                    break elevation;\n                }\n            };\n\n            // Only allow the player to destroy the target with the first 5 shots. The\n            // sixth is ignored.\n            if shots_fired < 6 {\n                let angle = 2.0 * elevation / 57.3;\n                let intersection = self.gun_range as f32 * angle.sin();\n                let delta = target_distance - (intersection as isize);\n\n                if delta.abs() < 100 {\n                    println!(\n                        \"*** Target Destroyed ***  {shots_fired} rounds of ammunition expended.\"\n                    );\n                    self.total_rounds += shots_fired;\n                    return true;\n                } else if delta > 100 {\n                    println!(\"Short of target by {delta} yards.\");\n                } else {\n                    println!(\"Over target by {} yards.\", delta.abs());\n                }\n            }\n        }\n\n        false\n    }\n}\n\n#[derive(PartialEq, Eq)]\nenum PlayAgain {\n    Yes,\n    No,\n}\n\nimpl FromStr for PlayAgain {\n    type Err = Infallible;\n\n    fn from_str(line: &str) -> Result<Self, Self::Err> {\n        if line.to_uppercase() == \"Y\" {\n            Ok(Self::Yes)\n        } else {\n            Ok(Self::No)\n        }\n    }\n}\n\nfn get_input<R: FromStr, S: AsRef<str>>(prompt: S) -> R {\n    loop {\n        print!(\"{}? \", prompt.as_ref());\n        let mut stdout = io::stdout().lock();\n        let _ = stdout.flush();\n\n        let mut buffer = String::new();\n        let stdin = std::io::stdin();\n        let mut handle = stdin.lock();\n        let _ = handle.read_line(&mut buffer);\n\n        if let Ok(result) = buffer.trim().to_string().parse::<R>() {\n            return result;\n        }\n        println!(\"?Re-enter\");\n    }\n}\n"
  },
  {
    "path": "42_Gunner/vbnet/Gunner.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Gunner\", \"Gunner.vbproj\", \"{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "42_Gunner/vbnet/Gunner.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Gunner</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "42_Gunner/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "43_Hammurabi/README.md",
    "content": "### Hammurabi\n\nIn this game you direct the administrator of Sumeria, Hammurabi, how to manage the city. The city initially has 1,000 acres, 100 people and 3,000 bushels of grain in storage.\n\nYou may buy and sell land with your neighboring city-states for bushels of grain — the price will vary between 17 and 26 bushels per acre. You also must use grain to feed your people and as seed to plant the next year’s crop.\n\nYou will quickly find that a certain number of people can only tend a certain amount of land and that people starve if they are not fed enough. You also have the unexpected to contend with such as a plague, rats destroying stored grain, and variable harvests.\n\nYou will also find that managing just the few resources in this game is not a trivial job over a period of say ten years. The crisis of population density rears its head very rapidly.\n\nThis program was originally written in Focal at DEC; author unknown. David Ahl converted it to BASIC and added the 10-year performance assessment. If you wish to change any of the factors, the extensive remarks in the program should make modification fairly straightforward.\n\nNote for trivia buffs: somewhere along the line an m was dropped out of the spelling of Hammurabi in hte Ahl version of the computer program. This error has spread far and wide until a generation of students now think that Hammurabi is the incorrect spelling.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=78)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=93)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- Though the file name and README both spell \"Hammurabi\" with two M's, the program itself consistently uses only one M.\n\n#### External Links\n - C: https://github.com/beyonddream/hamurabi\n - Rust: https://github.com/beyonddream/hamurabi.rs\n"
  },
  {
    "path": "43_Hammurabi/csharp/ActionResult.cs",
    "content": "﻿namespace Hammurabi\n{\n    /// <summary>\n    /// Enumerates the different possible outcomes of attempting the various\n    /// actions in the game.\n    /// </summary>\n    public enum ActionResult\n    {\n        /// <summary>\n        /// The action was a success.\n        /// </summary>\n        Success,\n\n        /// <summary>\n        /// The action could not be completed because the city does not have\n        /// enough bushels of grain.\n        /// </summary>\n        InsufficientStores,\n\n        /// <summary>\n        /// The action could not be completed because the city does not have\n        /// sufficient acreage.\n        /// </summary>\n        InsufficientLand,\n\n        /// <summary>\n        /// The action could not be completed because the city does not have\n        /// sufficient population.\n        /// </summary>\n        InsufficientPopulation,\n\n        /// <summary>\n        /// The requested action offended the city steward.\n        /// </summary>\n        Offense\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/Controller.cs",
    "content": "﻿using System;\n\nnamespace Hammurabi\n{\n    /// <summary>\n    /// Provides methods for reading input from the user.\n    /// </summary>\n    public static class Controller\n    {\n        /// <summary>\n        /// Continuously prompts the user to enter a number until he or she\n        /// enters a valid number and updates the game state.\n        /// </summary>\n        /// <param name=\"state\">\n        /// The current game state.\n        /// </param>\n        /// <param name=\"prompt\">\n        /// Action that will display the prompt to the user.\n        /// </param>\n        /// <param name=\"rule\">\n        /// The rule to invoke once input is retrieved.\n        /// </param>\n        /// <returns>\n        /// The updated game state.\n        /// </returns>\n        public static GameState UpdateGameState(\n            GameState state,\n            Action prompt,\n            Func<GameState, int, (GameState newState, ActionResult result)> rule)\n        {\n            while (true)\n            {\n                prompt();\n\n                if (!Int32.TryParse(Console.ReadLine(), out var amount))\n                {\n                    View.ShowInvalidNumber();\n                    continue;\n                }\n\n                var (newState, result) = rule(state, amount);\n\n                switch (result)\n                {\n                    case ActionResult.InsufficientLand:\n                        View.ShowInsufficientLand(state);\n                        break;\n                    case ActionResult.InsufficientPopulation:\n                        View.ShowInsufficientPopulation(state);\n                        break;\n                    case ActionResult.InsufficientStores:\n                        View.ShowInsufficientStores(state);\n                        break;\n                    case ActionResult.Offense:\n                        // Not sure why we have to blow up the game here...\n                        // Maybe this made sense in the 70's.\n                        throw new GreatOffence();\n                    default:\n                        return newState;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/GameResult.cs",
    "content": "﻿namespace Hammurabi\n{\n    /// <summary>\n    /// Stores the final game result.\n    /// </summary>\n    public record GameResult\n    {\n        /// <summary>\n        /// Gets the player's performance rating.\n        /// </summary>\n        public PerformanceRating Rating { get; init; }\n\n        /// <summary>\n        /// Gets the number of acres in the city per person.\n        /// </summary>\n        public int AcresPerPerson { get; init; }\n\n        /// <summary>\n        /// Gets the number of people who starved the final year in office.\n        /// </summary>\n        public int FinalStarvation { get; init; }\n\n        /// <summary>\n        /// Gets the total number of people who starved.\n        /// </summary>\n        public int TotalStarvation { get; init; }\n\n        /// <summary>\n        /// Gets the average starvation rate per year (as a percentage\n        /// of population).\n        /// </summary>\n        public int AverageStarvationRate { get; init; }\n\n        /// <summary>\n        /// Gets the number of people who want to assassinate the player.\n        /// </summary>\n        public int Assassins { get; init; }\n\n        /// <summary>\n        /// Gets a flag indicating whether the player was impeached for\n        /// starving too many people.\n        /// </summary>\n        public bool WasPlayerImpeached { get; init; }\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/GameState.cs",
    "content": "﻿namespace Hammurabi\n{\n    /// <summary>\n    /// Stores the state of the game.\n    /// </summary>\n    public record GameState\n    {\n        /// <summary>\n        /// Gets the current game year.\n        /// </summary>\n        public int Year { get; init; }\n\n        /// <summary>\n        /// Gets the city's population.\n        /// </summary>\n        public int Population { get; init; }\n\n        /// <summary>\n        /// Gets the population increase this year.\n        /// </summary>\n        public int PopulationIncrease { get; init; }\n\n        /// <summary>\n        /// Gets the number of people who starved.\n        /// </summary>\n        public int Starvation { get; init; }\n\n        /// <summary>\n        /// Gets the city's size in acres.\n        /// </summary>\n        public int Acres { get; init; }\n\n        /// <summary>\n        /// Gets the price for an acre of land (in bushels).\n        /// </summary>\n        public int LandPrice { get; init; }\n\n        /// <summary>\n        /// Gets the number of bushels of grain in the city stores.\n        /// </summary>\n        public int Stores { get; init; }\n\n        /// <summary>\n        /// Gets the amount of food distributed to the people.\n        /// </summary>\n        public int FoodDistributed { get; init; }\n\n        /// <summary>\n        /// Gets the number of acres that were planted.\n        /// </summary>\n        public int AcresPlanted { get; init; }\n\n        /// <summary>\n        /// Gets the number of bushels produced per acre.\n        /// </summary>\n        public int Productivity { get; init; }\n\n        /// <summary>\n        /// Gets the amount of food lost to rats.\n        /// </summary>\n        public int Spoilage { get; init; }\n\n        /// <summary>\n        /// Gets a flag indicating whether the current year is a plague year.\n        /// </summary>\n        public bool IsPlagueYear { get; init; }\n\n        /// <summary>\n        /// Gets a flag indicating whether the player has been impeached.\n        /// </summary>\n        public bool IsPlayerImpeached { get; init; }\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/GreatOffence.cs",
    "content": "﻿using System;\n\nnamespace Hammurabi\n{\n    /// <summary>\n    /// Indicates that the game cannot continue due to the player's extreme\n    /// incompetance and/or unserious attitude!\n    /// </summary>\n    public class GreatOffence : InvalidOperationException\n    {\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/Hammurabi.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "43_Hammurabi/csharp/Hammurabi.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Hammurabi\", \"Hammurabi.csproj\", \"{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {89DBE213-C0F0-4ABA-BB2D-5D9AAED41FF6}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "43_Hammurabi/csharp/PerformanceRating.cs",
    "content": "﻿namespace Hammurabi\n{\n    /// <summary>\n    /// Enumerates the different performance ratings that the player can\n    /// achieve.\n    /// </summary>\n    public enum PerformanceRating\n    {\n        Disgraceful,\n        Bad,\n        Ok,\n        Terrific\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Immutable;\n\nnamespace Hammurabi\n{\n    public static class Program\n    {\n        public const int GameLength = 10;\n\n        public static void Main(string[] args)\n        {\n            var random  = new Random() ;\n            var state   = Rules.BeginGame();\n            var history = ImmutableList<GameState>.Empty;\n\n            View.ShowBanner();\n\n            try\n            {\n                while (!state.IsPlayerImpeached)\n                {\n                    state = Rules.BeginTurn(state, random);\n                    View.ShowCitySummary(state);\n\n                    if (state.Year > GameLength)\n                        break;\n\n                    View.ShowLandPrice(state);\n                    var newState = Controller.UpdateGameState(state, View.PromptBuyLand, Rules.BuyLand);\n                    state = newState.Acres != state.Acres ?\n                        newState : Controller.UpdateGameState(state, View.PromptSellLand, Rules.SellLand);\n\n                    View.ShowSeparator();\n                    state = Controller.UpdateGameState(state, View.PromptFeedPeople, Rules.FeedPeople);\n\n                    View.ShowSeparator();\n                    state = Controller.UpdateGameState(state, View.PromptPlantCrops, Rules.PlantCrops);\n\n                    state = Rules.EndTurn(state, random);\n                    history = history.Add(state);\n                }\n\n                var result = Rules.GetGameResult(history, random);\n                View.ShowGameResult(result);\n            }\n            catch (GreatOffence)\n            {\n                View.ShowGreatOffence();\n            }\n\n            View.ShowFarewell();\n        }\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "43_Hammurabi/csharp/Rules.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Hammurabi\n{\n    public static class Rules\n    {\n        /// <summary>\n        /// Creates the initial state for a new game.\n        /// </summary>\n        public static GameState BeginGame() =>\n            new GameState\n            {\n                Year                = 0,\n                Population          = 95,\n                PopulationIncrease  = 5,\n                Starvation          = 0,\n                Acres               = 1000,\n                Stores              = 0,\n                AcresPlanted        = 1000,\n                Productivity        = 3,\n                Spoilage            = 200,\n                IsPlagueYear        = false,\n                IsPlayerImpeached   = false\n            };\n\n        /// <summary>\n        /// Updates the game state to start a new turn.\n        /// </summary>\n        public static GameState BeginTurn(GameState state, Random random) =>\n            state with\n            {\n                Year            = state.Year + 1,\n                Population      = (state.Population + state.PopulationIncrease - state.Starvation) / (state.IsPlagueYear ? 2 : 1),\n                LandPrice       = random.Next(10) + 17,\n                Stores          = state.Stores + (state.AcresPlanted * state.Productivity) - state.Spoilage,\n                AcresPlanted    = 0,\n                FoodDistributed = 0\n            };\n\n        /// <summary>\n        /// Attempts to purchase the given number of acres.\n        /// </summary>\n        /// <returns>\n        /// The updated game state and action result.\n        /// </returns>\n        public static (GameState newState, ActionResult result) BuyLand(GameState state, int amount)\n        {\n            var price = state.LandPrice * amount;\n\n            if (price < 0)\n                return (state, ActionResult.Offense);\n            else\n            if (price > state.Stores)\n                return (state, ActionResult.InsufficientStores);\n            else\n                return (state with { Acres = state.Acres + amount, Stores = state.Stores - price }, ActionResult.Success);\n        }\n\n        /// <summary>\n        /// Attempts to sell the given number of acres.\n        /// </summary>\n        /// <returns>\n        /// The updated game state and action result.\n        /// </returns>\n        public static (GameState newState, ActionResult result) SellLand(GameState state, int amount)\n        {\n            var price = state.LandPrice * amount;\n\n            if (price < 0)\n                return (state, ActionResult.Offense);\n            else\n            if (amount >= state.Acres)\n                return (state, ActionResult.InsufficientLand);\n            else\n                return (state with { Acres = state.Acres - amount, Stores = state.Stores + price }, ActionResult.Success);\n        }\n\n        /// <summary>\n        /// Attempts to feed the people the given number of buschels.\n        /// </summary>\n        /// <returns>\n        /// <returns>\n        /// The updated game state and action result.\n        /// </returns>\n        public static (GameState newState, ActionResult result) FeedPeople(GameState state, int amount)\n        {\n            if (amount < 0)\n                return (state, ActionResult.Offense);\n            else\n            if (amount > state.Stores)\n                return (state, ActionResult.InsufficientStores);\n            else\n                return (state with { Stores = state.Stores - amount, FoodDistributed = state.FoodDistributed + amount }, ActionResult.Success);\n        }\n\n        /// <summary>\n        /// Attempts to plant crops on the given number of acres.\n        /// </summary>\n        /// <returns>\n        /// The updated game state and action result.\n        /// </returns>\n        public static (GameState newState, ActionResult result) PlantCrops(GameState state, int amount)\n        {\n            var storesRequired = amount / 2;\n            var maxAcres       = state.Population * 10;\n\n            if (amount < 0)\n                return (state, ActionResult.Offense);\n            else\n            if (amount > state.Acres)\n                return (state, ActionResult.InsufficientLand);\n            else\n            if (storesRequired > state.Stores)\n                return (state, ActionResult.InsufficientStores);\n            else\n            if ((state.AcresPlanted + amount) > maxAcres)\n                return (state, ActionResult.InsufficientPopulation);\n            else\n                return (state with\n                {\n                    AcresPlanted = state.AcresPlanted + amount,\n                    Stores       = state.Stores - storesRequired,\n                }, ActionResult.Success);\n        }\n\n        /// <summary>\n        /// Ends the current turn and returns the updated game state.\n        /// </summary>\n        public static GameState EndTurn(GameState state, Random random)\n        {\n            var productivity = random.Next(1, 6);\n            var harvest = productivity * state.AcresPlanted;\n\n            var spoilage = random.Next(1, 6) switch\n            {\n                2 => state.Stores / 2,\n                4 => state.Stores / 4,\n                _ => 0\n            };\n\n            var populationIncrease= (int)((double)random.Next(1, 6) * (20 * state.Acres + state.Stores + harvest - spoilage) / state.Population / 100 + 1);\n\n            var plagueYear = random.Next(20) < 3;\n\n            var peopleFed  = state.FoodDistributed / 20;\n            var starvation = peopleFed < state.Population ? state.Population - peopleFed : 0;\n            var impeached  = starvation > state.Population * 0.45;\n\n            return state with\n            {\n                Productivity       = productivity,\n                Spoilage           = spoilage,\n                PopulationIncrease = populationIncrease,\n                Starvation         = starvation,\n                IsPlagueYear       = plagueYear,\n                IsPlayerImpeached  = impeached\n            };\n        }\n\n        /// <summary>\n        /// Examines the game's history to arrive at the final result.\n        /// </summary>\n        public static GameResult GetGameResult(IEnumerable<GameState> history, Random random)\n        {\n            var (_, averageStarvationRate, totalStarvation, finalState) = history.Aggregate(\n                (count: 0, starvationRate: 0, totalStarvation: 0, finalState: default(GameState)),\n                (stats, state) =>\n                (\n                    stats.count + 1,\n                    ((stats.starvationRate * stats.count) + (state.Starvation * 100 / state.Population)) / (stats.count + 1),\n                    stats.totalStarvation + state.Starvation,\n                    state\n                ));\n\n            var acresPerPerson = finalState.Acres / finalState.Population;\n\n            var rating = finalState.IsPlayerImpeached ?\n                PerformanceRating.Disgraceful :\n                (averageStarvationRate, acresPerPerson) switch\n                {\n                    (> 33, _) => PerformanceRating.Disgraceful,\n                    (_, < 7)  => PerformanceRating.Disgraceful,\n                    (> 10, _) => PerformanceRating.Bad,\n                    (_, < 9)  => PerformanceRating.Bad,\n                    (> 3, _)  => PerformanceRating.Ok,\n                    (_, < 10) => PerformanceRating.Ok,\n                    _         => PerformanceRating.Terrific\n                };\n\n            var assassins = rating == PerformanceRating.Ok ?\n                random.Next(0, (int)(finalState.Population * 0.8)) : 0;\n\n            return new GameResult\n            {\n                Rating                = rating,\n                AcresPerPerson        = acresPerPerson,\n                FinalStarvation       = finalState.Starvation,\n                TotalStarvation       = totalStarvation,\n                AverageStarvationRate = averageStarvationRate,\n                Assassins             = assassins,\n                WasPlayerImpeached    = finalState.IsPlayerImpeached\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/csharp/View.cs",
    "content": "﻿using System;\n\nnamespace Hammurabi\n{\n    /// <summary>\n    /// Provides various methods for presenting information to the user.\n    /// </summary>\n    public static class View\n    {\n        /// <summary>\n        /// Shows the introductory banner to the player.\n        /// </summary>\n        public static void ShowBanner()\n        {\n            Console.WriteLine(\"                                HAMURABI\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\");\n            Console.WriteLine(\"FOR A TEN-YEAR TERM OF OFFICE.\");\n        }\n\n        /// <summary>\n        /// Shows a summary of the current state of the city.\n        /// </summary>\n        public static void ShowCitySummary(GameState state)\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"HAMURABI:  I BEG TO REPORT TO YOU,\");\n            Console.WriteLine($\"IN YEAR {state.Year}, {state.Starvation} PEOPLE STARVED, {state.PopulationIncrease} CAME TO THE CITY,\");\n\n            if (state.IsPlagueYear)\n            {\n                Console.WriteLine(\"A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\");\n            }\n\n            Console.WriteLine($\"POPULATION IS NOW {state.Population}\");\n            Console.WriteLine($\"THE CITY NOW OWNS {state.Acres} ACRES.\");\n            Console.WriteLine($\"YOU HARVESTED {state.Productivity} BUSHELS PER ACRE.\");\n            Console.WriteLine($\"THE RATS ATE {state.Spoilage} BUSHELS.\");\n            Console.WriteLine($\"YOU NOW HAVE {state.Stores} BUSHELS IN STORE.\");\n            Console.WriteLine();\n        }\n\n        /// <summary>\n        /// Shows the current cost of land.\n        /// </summary>\n        /// <param name=\"state\"></param>\n        public static void ShowLandPrice(GameState state)\n        {\n            Console.WriteLine ($\"LAND IS TRADING AT {state.LandPrice} BUSHELS PER ACRE.\");\n        }\n\n        /// <summary>\n        /// Displays a section separator.\n        /// </summary>\n        public static void ShowSeparator()\n        {\n            Console.WriteLine();\n        }\n\n        /// <summary>\n        /// Inform the player that he or she has entered an invalid number.\n        /// </summary>\n        public static void ShowInvalidNumber()\n        {\n            Console.WriteLine(\"PLEASE ENTER A VALID NUMBER\");\n        }\n\n        /// <summary>\n        /// Inform the player that he or she has insufficient acreage.\n        /// </summary>\n        public static void ShowInsufficientLand(GameState state)\n        {\n            Console.WriteLine($\"HAMURABI:  THINK AGAIN.  YOU OWN ONLY {state.Acres} ACRES.  NOW THEN,\");\n        }\n\n        /// <summary>\n        /// Inform the player that he or she has insufficient population.\n        /// </summary>\n        public static void ShowInsufficientPopulation(GameState state)\n        {\n            Console.WriteLine($\"BUT YOU HAVE ONLY {state.Population} PEOPLE TO TEND THE FIELDS!  NOW THEN,\");\n        }\n\n        /// <summary>\n        /// Inform the player that he or she has insufficient grain stores.\n        /// </summary>\n        public static void ShowInsufficientStores(GameState state)\n        {\n            Console.WriteLine(\"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\");\n            Console.WriteLine($\"{state.Stores} BUSHELS OF GRAIN.  NOW THEN,\");\n        }\n\n        /// <summary>\n        /// Show the player that he or she has caused great offence.\n        /// </summary>\n        public static void ShowGreatOffence()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"HAMURABI:  I CANNOT DO WHAT YOU WISH.\");\n            Console.WriteLine(\"GET YOURSELF ANOTHER STEWARD!!!!!\");\n        }\n\n        /// <summary>\n        /// Shows the game's final result to the user.\n        /// </summary>\n        public static void ShowGameResult(GameResult result)\n        {\n            if (!result.WasPlayerImpeached)\n            {\n                Console.WriteLine($\"IN YOUR 10-YEAR TERM OF OFFICE, {result.AverageStarvationRate} PERCENT OF THE\");\n                Console.WriteLine(\"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\");\n                Console.WriteLine($\"{result.TotalStarvation} PEOPLE DIED!!\");\n\n                Console.WriteLine(\"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\");\n                Console.WriteLine($\"{result.AcresPerPerson} ACRES PER PERSON.\");\n                Console.WriteLine();\n            }\n\n            switch (result.Rating)\n            {\n                case PerformanceRating.Disgraceful:\n                    if (result.WasPlayerImpeached)\n                        Console.WriteLine($\"YOU STARVED {result.FinalStarvation} PEOPLE IN ONE YEAR!!!\");\n\n                    Console.WriteLine(\"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\");\n                    Console.WriteLine(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\");\n                    Console.WriteLine(\"ALSO BEEN DECLARED NATIONAL FINK!!!!\");\n                    break;\n                case PerformanceRating.Bad:\n                    Console.WriteLine(\"YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\");\n                    Console.WriteLine(\"THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,\");\n                    Console.WriteLine(\"FRANKLY, HATE YOUR GUTS!!\");\n                    break;\n                case PerformanceRating.Ok:\n                    Console.WriteLine(\"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\");\n                    Console.WriteLine($\"REALLY WASN'T TOO BAD AT ALL. {result.Assassins} PEOPLE\");\n                    Console.WriteLine(\"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\");\n                    Console.WriteLine(\"TRIVIAL PROBLEMS.\");\n                    break;\n                case PerformanceRating.Terrific:\n                    Console.WriteLine(\"A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\");\n                    Console.WriteLine(\"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\");\n                    break;\n            }\n        }\n\n        /// <summary>\n        /// Shows a farewell message to the user.\n        /// </summary>\n        public static void ShowFarewell()\n        {\n            Console.WriteLine(\"SO LONG FOR NOW.\");\n            Console.WriteLine();\n        }\n\n        /// <summary>\n        /// Prompts the user to buy land.\n        /// </summary>\n        public static void PromptBuyLand()\n        {\n            Console.Write(\"HOW MANY ACRES DO YOU WISH TO BUY? \");\n        }\n\n        /// <summary>\n        /// Prompts the user to sell land.\n        /// </summary>\n        public static void PromptSellLand()\n        {\n            Console.Write(\"HOW MANY ACRES DO YOU WISH TO SELL? \");\n        }\n\n        /// <summary>\n        /// Prompts the user to feed the people.\n        /// </summary>\n        public static void PromptFeedPeople()\n        {\n            Console.Write(\"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? \");\n        }\n\n        /// <summary>\n        /// Prompts the user to plant crops.\n        /// </summary>\n        public static void PromptPlantCrops()\n        {\n            Console.Write(\"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? \");\n        }\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/hammurabi.bas",
    "content": "10 PRINT TAB(32);\"HAMURABI\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n80 PRINT \"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\"\n90 PRINT \"FOR A TEN-YEAR TERM OF OFFICE.\":PRINT\n95 D1=0: P1=0\n100 Z=0: P=95:S=2800: H=3000: E=H-S\n110 Y=3: A=H/Y: I=5: Q=1\n210 D=0\n215 PRINT:PRINT:PRINT \"HAMURABI:  I BEG TO REPORT TO YOU,\": Z=Z+1\n217 PRINT \"IN YEAR\";Z;\",\";D;\"PEOPLE STARVED,\";I;\"CAME TO THE CITY,\"\n218 P=P+I\n227 IF Q>0 THEN 230\n228 P=INT(P/2)\n229 PRINT \"A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\"\n230 PRINT \"POPULATION IS NOW\";P\n232 PRINT \"THE CITY NOW OWNS \";A;\"ACRES.\"\n235 PRINT \"YOU HARVESTED\";Y;\"BUSHELS PER ACRE.\"\n250 PRINT \"THE RATS ATE\";E;\"BUSHELS.\"\n260 PRINT \"YOU NOW HAVE \";S;\"BUSHELS IN STORE.\": PRINT\n270 IF Z=11 THEN 860\n310 C=INT(10*RND(1)): Y=C+17\n312 PRINT \"LAND IS TRADING AT\";Y;\"BUSHELS PER ACRE.\"\n320 PRINT \"HOW MANY ACRES DO YOU WISH TO BUY\";\n321 INPUT Q: IF Q<0 THEN 850\n322 IF Y*Q<=S THEN 330\n323 GOSUB 710\n324 GOTO 320\n330 IF Q=0 THEN 340\n331 A=A+Q: S=S-Y*Q: C=0\n334 GOTO 400\n340 PRINT \"HOW MANY ACRES DO YOU WISH TO SELL\";\n341 INPUT Q: IF Q<0 THEN 850\n342 IF Q<A THEN 350\n343 GOSUB 720\n344 GOTO 340\n350 A=A-Q: S=S+Y*Q: C=0\n400 PRINT\n410 PRINT \"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE\";\n411 INPUT Q\n412 IF Q<0 THEN 850\n418 REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?\n420 IF Q<=S THEN 430\n421 GOSUB 710\n422 GOTO 410\n430 S=S-Q: C=1: PRINT\n440 PRINT \"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED\";\n441 INPUT D: IF D=0 THEN 511\n442 IF D<0 THEN 850\n444 REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?\n445 IF D<=A THEN 450\n446 GOSUB 720\n447 GOTO 440\n449 REM *** ENOUGH GRAIN FOR SEED?\n450 IF INT(D/2)<=S THEN 455\n452 GOSUB 710\n453 GOTO 440\n454 REM *** ENOUGH PEOPLE TO TEND THE CROPS?\n455 IF D<10*P THEN 510\n460 PRINT \"BUT YOU HAVE ONLY\";P;\"PEOPLE TO TEND THE FIELDS!  NOW THEN,\"\n470 GOTO 440\n510 S=S-INT(D/2)\n511 GOSUB 800\n512 REM *** A BOUNTIFUL HARVEST!\n515 Y=C: H=D*Y: E=0\n521 GOSUB 800\n522 IF INT(C/2)<>C/2 THEN 530\n523 REM *** RATS ARE RUNNING WILD!!\n525 E=INT(S/C)\n530 S=S-E+H\n531 GOSUB 800\n532 REM *** LET'S HAVE SOME BABIES\n533 I=INT(C*(20*A+S)/P/100+1)\n539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES?\n540 C=INT(Q/20)\n541 REM *** HORROS, A 15% CHANCE OF PLAGUE\n542 Q=INT(10*(2*RND(1)-.3))\n550 IF P<C THEN 210\n551 REM *** STARVE ENOUGH FOR IMPEACHMENT?\n552 D=P-C: IF D>.45*P THEN 560\n553 P1=((Z-1)*P1+D*100/P)/Z\n555 P=C: D1=D1+D: GOTO 215\n560 PRINT: PRINT \"YOU STARVED\";D;\"PEOPLE IN ONE YEAR!!!\"\n565 PRINT \"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\"\n566 PRINT \"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\"\n567 PRINT \"ALSO BEEN DECLARED NATIONAL FINK!!!!\": GOTO 990\n710 PRINT \"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\"\n711 PRINT S;\"BUSHELS OF GRAIN.  NOW THEN,\"\n712 RETURN\n720 PRINT \"HAMURABI:  THINK AGAIN.  YOU OWN ONLY\";A;\"ACRES.  NOW THEN,\"\n730 RETURN\n800 C=INT(RND(1)*5)+1\n801 RETURN\n850 PRINT: PRINT \"HAMURABI:  I CANNOT DO WHAT YOU WISH.\"\n855 PRINT \"GET YOURSELF ANOTHER STEWARD!!!!!\"\n857 GOTO 990\n860 PRINT \"IN YOUR 10-YEAR TERM OF OFFICE,\";P1;\"PERCENT OF THE\"\n862 PRINT \"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\"\n865 PRINT D1;\"PEOPLE DIED!!\": L=A/P\n870 PRINT \"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\"\n875 PRINT L;\"ACRES PER PERSON.\": PRINT\n880 IF P1>33 THEN 565\n885 IF L<7 THEN 565\n890 IF P1>10 THEN 940\n892 IF L<9 THEN 940\n895 IF P1>3 THEN 960\n896 IF L<10 THEN 960\n900 PRINT \"A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\"\n905 PRINT \"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\":GOTO 990\n940 PRINT \"YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\"\n945 PRINT \"THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,\"\n950 PRINT \"FRANKLY, HATE YOUR GUTS!!\":GOTO 990\n960 PRINT \"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\"\n965 PRINT \"REALLY WASN'T TOO BAD AT ALL. \";INT(P*.8*RND(1));\"PEOPLE\"\n970 PRINT \"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\"\n975 PRINT \"TRIVIAL PROBLEMS.\"\n990 PRINT: FOR N=1 TO 10: PRINT CHR$(7);: NEXT N\n995 PRINT \"SO LONG FOR NOW.\": PRINT\n999 END\n"
  },
  {
    "path": "43_Hammurabi/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "43_Hammurabi/java/src/Hamurabi.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Hamurabi\n * <p>\n * Based on the Basic game of Hamurabi here\n * https://github.com/coding-horror/basic-computer-games/blob/main/43%20Hammurabi/hammurabi.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Hamurabi {\n\n    public static final int INITIAL_POPULATION = 95;\n    public static final int INITIAL_BUSHELS = 2800;\n    public static final int INITIAL_HARVEST = 3000;\n    public static final int INITIAL_LAND_TRADING_AT = 3;\n    public static final int INITIAL_CAME_TO_CITY = 5;\n    public static final int MAX_GAME_YEARS = 10;\n    public static final double MAX_STARVATION_IN_A_YEAR = .45d;\n\n    private int year;\n    private int population;\n    private int acres;\n    private int bushels;\n    private int harvest;\n    private int landTradingAt;\n    private int cameToCity;\n    private int starvedInAYear;\n    private int starvedOverall;\n    private boolean chanceOfPlague;\n    private int ratsAte;\n    private double peopleFed;\n    private double percentageStarved;\n    private int bushelsToFeedPeople;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        STARTUP,\n        INIT,\n        YEAR_CYCLE,\n        BUY_ACRES,\n        SELL_ACRES,\n        FEED_PEOPLE,\n        PLANT_SEED,\n        CALCULATE_HARVEST,\n        CALCULATE_BABIES,\n        RESULTS,\n        FINISH_GAME,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    public Hamurabi() {\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.STARTUP;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case STARTUP:\n                    intro();\n                    gameState = GAME_STATE.INIT;\n                    break;\n\n                case INIT:\n\n                    // These are hard coded startup figures from the basic program\n                    year = 0;\n                    population = INITIAL_POPULATION;\n                    bushels = INITIAL_BUSHELS;\n                    harvest = INITIAL_HARVEST;\n                    landTradingAt = INITIAL_LAND_TRADING_AT;\n                    acres = INITIAL_HARVEST / INITIAL_LAND_TRADING_AT;\n                    cameToCity = INITIAL_CAME_TO_CITY;\n                    starvedInAYear = 0;\n                    starvedOverall = 0;\n                    chanceOfPlague = false;\n                    ratsAte = INITIAL_HARVEST - INITIAL_BUSHELS;\n                    peopleFed = 0;\n                    percentageStarved = 0;\n                    bushelsToFeedPeople = 0;\n\n                    gameState = GAME_STATE.YEAR_CYCLE;\n                    break;\n\n                case YEAR_CYCLE:\n                    System.out.println();\n                    year += 1;\n                    // End of game?\n                    if (year > MAX_GAME_YEARS) {\n                        gameState = GAME_STATE.RESULTS;\n                        break;\n\n                    }\n                    System.out.println(\"HAMURABI:  I BEG TO REPORT TO YOU,\");\n                    System.out.println(\"IN YEAR \" + year + \",\" + starvedInAYear + \" PEOPLE STARVED,\" + cameToCity + \" CAME TO THE CITY,\");\n                    population += cameToCity;\n                    if (chanceOfPlague) {\n                        population /= 2;\n                        System.out.println(\"A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\");\n                    }\n                    System.out.println(\"POPULATION IS NOW \" + population);\n                    System.out.println(\"THE CITY NOW OWNS \" + acres + \" ACRES.\");\n                    System.out.println(\"YOU HARVESTED \" + landTradingAt + \" BUSHELS PER ACRE.\");\n                    System.out.println(\"THE RATS ATE \" + ratsAte + \" BUSHELS.\");\n                    System.out.println(\"YOU NOW HAVE \" + bushels + \" BUSHELS IN STORE.\");\n                    System.out.println();\n\n                    landTradingAt = (int) (Math.random() * 10) + 17;  // Original formula unchanged\n                    System.out.println(\"LAND IS TRADING AT \" + landTradingAt + \" BUSHELS PER ACRE.\");\n\n                    gameState = GAME_STATE.BUY_ACRES;\n                    break;\n\n                case BUY_ACRES:\n                    int acresToBuy = displayTextAndGetNumber(\"HOW MANY ACRES DO YOU WISH TO BUY? \");\n                    if (acresToBuy < 0) {\n                        gameState = GAME_STATE.FINISH_GAME;\n                    }\n\n                    if (acresToBuy > 0) {\n                        if ((landTradingAt * acresToBuy) > bushels) {\n                            notEnoughBushelsMessage();\n                        } else {\n                            acres += acresToBuy;\n                            bushels -= (landTradingAt * acresToBuy);\n                            peopleFed = 0;\n                            gameState = GAME_STATE.FEED_PEOPLE;\n                        }\n                    } else {\n                        // 0 entered as buy so try to sell\n                        gameState = GAME_STATE.SELL_ACRES;\n                    }\n                    break;\n\n                case SELL_ACRES:\n                    int acresToSell = displayTextAndGetNumber(\"HOW MANY ACRES DO YOU WISH TO SELL? \");\n                    if (acresToSell < 0) {\n                        gameState = GAME_STATE.FINISH_GAME;\n                    }\n                    if (acresToSell < acres) {\n                        acres -= acresToSell;\n                        bushels += (landTradingAt * acresToSell);\n                        gameState = GAME_STATE.FEED_PEOPLE;\n                    } else {\n                        notEnoughLandMessage();\n                    }\n                    break;\n\n                case FEED_PEOPLE:\n\n                    bushelsToFeedPeople = displayTextAndGetNumber(\"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE ? \");\n                    if (bushelsToFeedPeople < 0) {\n                        gameState = GAME_STATE.FINISH_GAME;\n                    }\n\n                    if (bushelsToFeedPeople <= bushels) {\n                        bushels -= bushelsToFeedPeople;\n                        peopleFed = 1;\n                        gameState = GAME_STATE.PLANT_SEED;\n                    } else {\n                        notEnoughBushelsMessage();\n                    }\n                    break;\n\n                case PLANT_SEED:\n\n                    int acresToPlant = displayTextAndGetNumber(\"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED ? \");\n                    if (acresToPlant < 0) {\n                        gameState = GAME_STATE.FINISH_GAME;\n                    }\n\n                    if (acresToPlant <= acres) {\n                        if (acresToPlant / 2 <= bushels) {\n                            if (acresToPlant < 10 * population) {\n                                bushels -= acresToPlant / 2;\n                                peopleFed = (int) (Math.random() * 5) + 1;\n                                landTradingAt = (int) peopleFed;\n                                harvest = acresToPlant * landTradingAt;\n                                ratsAte = 0;\n                                gameState = GAME_STATE.CALCULATE_HARVEST;\n                            } else {\n                                notEnoughPeopleMessage();\n                            }\n                        } else {\n                            notEnoughBushelsMessage();\n                        }\n                    } else {\n                        notEnoughLandMessage();\n                    }\n                    break;\n\n                case CALCULATE_HARVEST:\n\n                    if ((int) (peopleFed / 2) == peopleFed / 2) {\n                        // Rats are running wild\n                        ratsAte = (int) (bushels / peopleFed);\n                    }\n                    bushels = bushels - ratsAte;\n                    bushels += harvest;\n                    gameState = GAME_STATE.CALCULATE_BABIES;\n                    break;\n\n                case CALCULATE_BABIES:\n\n                    cameToCity = (int) (peopleFed * (20 * acres + bushels) / population / 100 + 1);\n                    peopleFed = (bushelsToFeedPeople / 20.0d);\n                    // Simplify chance of plague to a true/false\n                    chanceOfPlague = (int) ((10 * (Math.random() * 2) - .3)) == 0;\n                    if (population < peopleFed) {\n                        gameState = GAME_STATE.YEAR_CYCLE;\n                    }\n\n                    double starved = population - peopleFed;\n                    if (starved < 0.0d) {\n                        starvedInAYear = 0;\n                        gameState = GAME_STATE.YEAR_CYCLE;\n                    } else {\n                        starvedInAYear = (int) starved;\n                        starvedOverall += starvedInAYear;\n                        if (starved > MAX_STARVATION_IN_A_YEAR * population) {\n                            starvedTooManyPeopleMessage((int) starved);\n                            gameState = GAME_STATE.FINISH_GAME;\n                        } else {\n                            percentageStarved = ((year - 1) * percentageStarved + starved * 100 / population) / year;\n                            population = (int) peopleFed;\n                            gameState = GAME_STATE.YEAR_CYCLE;\n                        }\n\n                    }\n\n                    break;\n\n\n                case RESULTS:\n\n                    int acresPerPerson = acres / population;\n\n                    System.out.println(\"IN YOUR 10-YEAR TERM OF OFFICE,\" + String.format(\"%.2f\", percentageStarved) + \"% PERCENT OF THE\");\n                    System.out.println(\"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\");\n                    System.out.println(starvedOverall + \" PEOPLE DIED!!\");\n                    System.out.println(\"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\");\n                    System.out.println(acresPerPerson + \" ACRES PER PERSON.\");\n                    System.out.println();\n\n                    if (percentageStarved > 33.0d || acresPerPerson < 7) {\n                        starvedTooManyPeopleMessage(starvedOverall);\n                    } else if (percentageStarved > 10.0d || acresPerPerson < 9) {\n                        heavyHandedMessage();\n                    } else if (percentageStarved > 3.0d || acresPerPerson < 10) {\n                        couldHaveBeenBetterMessage();\n                    } else {\n                        fantasticPerformanceMessage();\n                    }\n\n\n                    gameState = GAME_STATE.FINISH_GAME;\n\n                case FINISH_GAME:\n                    System.out.println(\"SO LONG FOR NOW.\");\n                    gameState = GAME_STATE.GAME_OVER;\n\n            }\n\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void starvedTooManyPeopleMessage(int starved) {\n        System.out.println();\n        System.out.println(\"YOU STARVED \" + starved + \" PEOPLE IN ONE YEAR!!!\");\n        System.out.println(\"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\");\n        System.out.println(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\");\n        System.out.println(\"ALSO BEEN DECLARED NATIONAL FINK!!!!\");\n\n    }\n\n    private void heavyHandedMessage() {\n        System.out.println(\"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\");\n        System.out.println(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\");\n        System.out.println(\"ALSO BEEN DECLARED NATIONAL FINK!!!!\");\n    }\n\n    private void couldHaveBeenBetterMessage() {\n        System.out.println(\"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\");\n        System.out.println(\"REALLY WASN'T TOO BAD AT ALL. \" + (int) (Math.random() * (population * .8)) + \" PEOPLE\");\n        System.out.println(\"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\");\n        System.out.println(\"TRIVIAL PROBLEMS.\");\n    }\n\n    private void fantasticPerformanceMessage() {\n        System.out.println(\"A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\");\n        System.out.println(\"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\");\n    }\n\n    private void notEnoughPeopleMessage() {\n        System.out.println(\"BUT YOU HAVE ONLY \" + population + \" PEOPLE TO TEND THE FIELDS!  NOW THEN,\");\n\n    }\n\n    private void notEnoughBushelsMessage() {\n        System.out.println(\"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\");\n        System.out.println(bushels + \" BUSHELS OF GRAIN.  NOW THEN,\");\n    }\n\n    private void notEnoughLandMessage() {\n        System.out.println(\"HAMURABI:  THINK AGAIN.  YOU OWN ONLY \" + acres + \" ACRES.  NOW THEN,\");\n    }\n\n\n    private void intro() {\n        System.out.println(simulateTabs(32) + \"HAMURABI\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\");\n        System.out.println(\"FOR A TEN-YEAR TERM OF OFFICE.\");\n        System.out.println();\n    }\n\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n}\n"
  },
  {
    "path": "43_Hammurabi/java/src/HamurabiGame.java",
    "content": "public class HamurabiGame {\n    public static void main(String[] args) {\n\n        Hamurabi hamurabi = new Hamurabi();\n        hamurabi.play();\n    }\n}\n"
  },
  {
    "path": "43_Hammurabi/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "43_Hammurabi/javascript/hammurabi.html",
    "content": "<html>\n<head>\n<title>HAMMURABI</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hammurabi.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "43_Hammurabi/javascript/hammurabi.js",
    "content": "// HAMMURABI\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a;\nvar s;\n\nfunction exceeded_grain()\n{\n    print(\"HAMURABI: THINK AGAIN.  YOU HAVE ONLY\\n\");\n    print(s + \" BUSHELS OF GRAIN.  NOW THEN,\\n\");\n\n}\n\nfunction exceeded_acres()\n{\n    print(\"HAMURABI: THINK AGAIN.  YOU OWN ONLY \" + a + \" ACRES.  NOW THEN,\\n\");\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(32) + \"HAMURABI\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\\n\");\n    print(\"FOR A TEN-YEAR TERM OF OFFICE.\\n\");\n    print(\"\\n\");\n\n    d1 = 0;\n    p1 = 0;\n    z = 0;\n    p = 95;\n    s = 2800;\n    h = 3000;\n    e = h - s;\n    y = 3;\n    a = h / y;\n    i = 5;\n    q = 1;\n    d = 0;\n    while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"HAMURABI:  I BEG TO REPORT TO YOU,\\n\");\n        z++;\n        print(\"IN YEAR \" + z + \", \" + d + \" PEOPLE STARVED, \" + i + \" CAME TO THE CITY,\\n\");\n        p += i;\n        if (q <= 0) {\n            p = Math.floor(p / 2);\n            print(\"A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\\n\");\n        }\n        print(\"POPULATION IS NOW \" + p + \"\\n\");\n        print(\"THE CITY NOW OWNS \" + a + \" ACRES.\\n\");\n        print(\"YOU HARVESTED \" + y + \" BUSHELS PER ACRE.\\n\");\n        print(\"THE RATS ATE \" + e + \" BUSHELS.\\n\");\n        print(\"YOU NOW HAVE \" + s + \" BUSHELS IN STORE.\\n\");\n        print(\"\\n\");\n        if (z == 11) {\n            q = 0;\n            break;\n        }\n        c = Math.floor(10 * Math.random());\n        y = c + 17;\n        print(\"LAND IS TRADING AT \" + y + \" BUSHELS PER ACRE.\\n\");\n        while (1) {\n            print(\"HOW MANY ACRES DO YOU WISH TO BUY\");\n            q = parseInt(await input());\n            if (q < 0)\n                break;\n            if (y * q > s) {\n                exceeded_grain();\n            } else\n                break;\n        }\n        if (q < 0)\n            break;\n        if (q != 0) {\n            a += q;\n            s -= y * q;\n            c = 0;\n        } else {\n            while (1) {\n                print(\"HOW MANY ACRES DO YOU WISH TO SELL\");\n                q = parseInt(await input());\n                if (q < 0)\n                    break;\n                if (q >= a) {\n                    exceeded_acres();\n                } else {\n                    break;\n                }\n            }\n            if (q < 0)\n                break;\n            a -= q;\n            s += y * q;\n            c = 0;\n        }\n        print(\"\\n\");\n        while (1) {\n            print(\"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE\");\n            q = parseInt(await input());\n            if (q < 0)\n                break;\n            if (q > s)  // Trying to use more grain than is in silos?\n                exceeded_grain();\n            else\n                break;\n        }\n        if (q < 0)\n            break;\n        s -= q;\n        c = 1;\n        print(\"\\n\");\n        while (1) {\n            print(\"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED\");\n            d = parseInt(await input());\n            if (d != 0) {\n                if (d < 0)\n                    break;\n                if (d > a) {    // Trying to plant more acres than you own?\n                    exceeded_acres();\n                } else {\n                    if (Math.floor(d / 2) > s)  // Enough grain for seed?\n                        exceeded_grain();\n                    else {\n                        if (d >= 10 * p) {\n                            print(\"BUT YOU HAVE ONLY \" + p + \" PEOPLE TO TEND THE FIELDS!  NOW THEN,\\n\");\n                        } else {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n        if (d < 0) {\n            q = -1;\n            break;\n        }\n        s -= Math.floor(d / 2);\n        c = Math.floor(Math.random() * 5) + 1;\n        // A bountiful harvest!\n        if (c % 2 == 0) {\n            // Rats are running wild!!\n            e = Math.floor(s / c);\n        }\n        s = s - e + h;\n        c = Math.floor(Math.random() * 5) + 1;\n        // Let's have some babies\n        i = Math.floor(c * (20 * a + s) / p / 100 + 1);\n        // How many people had full tummies?\n        c = Math.floor(q / 20);\n        // Horros, a 15% chance of plague\n        q = Math.floor(10 * (2 * Math.random() - 0.3));\n        if (p < c) {\n            d = 0;\n            continue;\n        }\n        // Starve enough for impeachment?\n        d = p - c;\n        if (d <= 0.45 * p) {\n            p1 = ((z - 1) * p1 + d * 100 / p) / z;\n            p = c;\n            d1 += d;\n            continue;\n        }\n        print(\"\\n\");\n        print(\"YOU STARVED \" + d + \" PEOPLE IN ONE YEAR!!!\\n\");\n        q = 0;\n        p1 = 34;\n        p = 1;\n        break;\n    }\n    if (q < 0) {\n        print(\"\\n\");\n        print(\"HAMURABI:  I CANNOT DO WHAT YOU WISH.\\n\");\n        print(\"GET YOURSELF ANOTHER STEWARD!!!!!\\n\");\n    } else {\n        print(\"IN YOUR 10-YEAR TERM OF OFFICE, \" + p1 + \" PERCENT OF THE\\n\");\n        print(\"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\\n\");\n        print(d1 + \" PEOPLE DIED!!\\n\");\n        l = a / p;\n        print(\"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\\n\");\n        print(l + \" ACRES PER PERSON.\\n\");\n        print(\"\\n\");\n        if (p1 > 33 || l < 7) {\n            print(\"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\\n\");\n            print(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\\n\");\n            print(\"ALSO BEEN DECLARED NATIONAL FINK!!!!\\n\");\n        } else if (p1 > 10 || l < 9) {\n            print(\"YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\\n\");\n            print(\"THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,\\n\");\n            print(\"FRANKLY, HATE YOUR GUTS!!\\n\");\n        } else if (p1 > 3 || l < 10) {\n            print(\"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\\n\");\n            print(\"REALLY WASN'T TOO BAD AT ALL. \" + Math.floor(p * 0.8 * Math.random()) + \" PEOPLE\\n\");\n            print(\"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\\n\");\n            print(\"TRIVIAL PROBLEMS.\\n\");\n        } else {\n            print(\"A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\\n\");\n            print(\"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\\n\");\n        }\n    }\n    print(\"\\n\");\n    print(\"SO LONG FOR NOW.\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "43_Hammurabi/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "43_Hammurabi/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "43_Hammurabi/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm",
    "content": "#!/usr/bin/env perl\npackage BasicComputerGames::Hammurabi;\n\nuse v5.24;\nuse warnings;\nuse experimental 'signatures';\n\n{\n   # Quick and dirty accessors\n   no strict 'refs';\n   for my $feature (\n      qw< year population store rats_toll had_plague planted\n      production_per_acre acres new_arrivals starved status max_year fed\n      percent_starved total_starved cost_per_acre >\n     )\n   {\n      *{__PACKAGE__ . '::' . $feature} = sub ($self, @new) {\n         $self->{$feature} = $new[0] if @new;\n         return $self->{$feature};\n      };\n   } ## end for my $feature (...)\n}\n\nsub new ($package, %args) {\n   my $self = bless {\n\n      # These defaults can be overridden by %args\n      population          => 100,\n      store               => 2800,\n      rats_toll           => 200,\n      production_per_acre => 3,\n      acres               => 1000,\n      new_arrivals        => 5,\n      fed                 => 0,\n      max_year            => 10,\n\n      %args,\n\n      # These starting values cannot be overridden by %args\n      status          => 'start',\n      year            => 1,\n      starved         => 0,\n      total_starved   => 0,\n      percent_starved => 0,\n      had_plague      => 0,\n      planted         => 0,\n      cost_per_acre   => 0,\n   }, $package;\n\n   return $self;\n} ## end sub new\n\nsub step ($self, $input) {\n   my $method = $self->can('_handle_' . $self->status);\n   $self->$method($input);\n}\n\n########################################################################\n#\n# All _handle_* methods below represents handlers for different states\n# of the game, e.g. state `start` is managed by _handle_start(). Each\n# handler receives two input arguments: an instance to the game object and\n# the input that was collected by the UI for that particular state (if\n# any).\n\n# start of the game\nsub _handle_start ($self, $input) {\n   $self->status('start_of_year');\n}\n\n# start of each year\nsub _handle_start_of_year ($self, $input) {\n   $self->cost_per_acre(int(rand(10)) + 17);\n   $self->status('advertise_cost_per_acre');\n}\n\n# intermediate state to allow for printing the cost per acre, moves\n# directly to following state\nsub _handle_advertise_cost_per_acre ($self, $input) {\n   $self->status('buy_acres');\n}\n\n# buy acres of land, making sure to be able to cover for the cost\nsub _handle_buy_acres ($self, $input) {\n   return $self->status('bail_out')   if $input < 0;\n   return $self->status('sell_acres') if $input == 0;\n   my $cpa  = $self->cost_per_acre;\n   my $cost = $cpa * $input;\n   return $self->status('buy_acres_again')\n     if $cost > $self->store;\n   $self->acres($self->acres + $input);\n   $self->store($self->store - $cost);\n   return $self->status('feeding');\n} ## end sub _handle_buy_acres\n\n# intermediate state to allow for notifying that the request for new\n# acres of land could not be covered, moves directly to the following\n# state\nsub _handle_buy_acres_again ($self, $input) {\n   $self->status('buy_acres');\n}\n\n# sell acres of land, making sure to sell only what can be sold.\nsub _handle_sell_acres ($self, $input) {\n   return $self->status('bail_out')         if $input < 0;\n   return $self->status('sell_acres_again') if $input >= $self->acres;\n   $self->acres($self->acres - $input);\n   $self->store($self->store + $self->cost_per_acre * $input);\n   return $self->status('feeding');\n} ## end sub _handle_sell_acres\n\n# intermediate state to allow for notifying that the request to sell\n# acres of land could not be covered, moves directly to the following\n# state\nsub _handle_sell_acres_again ($self, $input) {\n   $self->status('sell_acres');\n}\n\n# feed people, making sure we have the necessary resources\nsub _handle_feeding ($self, $input) {\n   return $self->status('bail_out')      if $input < 0;\n   return $self->status('feeding_again') if $input >= $self->store;\n   $self->store($self->store - $input);\n   $self->fed($input);\n   $self->status('planting');\n} ## end sub _handle_feeding\n\n# intermediate state to allow for notifying that the request to use\n# bushels of grain could not be covered, moves directly to the following\n# state\nsub _handle_feeding_again ($self, $input) {\n   $self->status('feeding');\n}\n\n# plant crops, making sure we have the land, the seeds and the workers.\nsub _handle_planting ($self, $input) {\n   return $self->status('bail_out') if $input < 0;\n\n   return $self->status('planting_fail_acres') if $input > $self->acres;\n\n   my $store = $self->store;\n   return $self->status('planting_fail_seeds')\n     if $store < int($input / 2);\n\n   return $self->status('planting_fail_people')\n     if $input >= $self->population * 10;\n\n   $self->planted($input);\n   $self->store($store - int($input / 2));\n   $self->status('simulate_year');\n} ## end sub _handle_planting\n\n# complain about lack of land to cover the planting request\nsub _handle_planting_fail_acres ($self, $input) {\n   $self->status('planting');\n}\n\n# complain about lack of seeds to cover the planting request\nsub _handle_planting_fail_seeds ($self, $input) {\n   $self->status('planting');\n}\n\n# complain about lack of workers to cover the planting request\nsub _handle_planting_fail_people ($self, $input) {\n   $self->status('planting');\n}\n\n# simulate the rest of the year after all inputs, i.e. rats, crops, etc.\nsub _handle_simulate_year ($self, $input) {\n   my $store = $self->store;\n\n   # rats might take a toll during the year\n   my $c         = 1 + int(rand(5));\n   my $rats_toll = $c % 2 ? 0 : int($store / $c);\n   $self->rats_toll($rats_toll);\n\n   # planting also gains us grain after the harvest\n   my $ppa     = $self->production_per_acre(1 + int(rand(5)));\n   my $harvest = $ppa * $self->planted;\n\n   # let's update the stored seeds finally\n   $self->store($store += $harvest - $rats_toll);\n\n   # let's see how population evolved\n   my $population = $self->population;\n\n   # how many people had full tummies\n   my $fed_people = int($self->fed / 20);\n   my $starved    = $population - $fed_people;\n   $starved = 0 if $starved < 0;    # cannot create people from seeds\n   $self->starved($starved);\n\n   # check preliminary exit condition for a very bad year\n   return $self->status('impeach_year')\n     if $starved > $population * 0.45;\n\n   # update statistics\n   $self->total_starved($self->total_starved + $starved);\n   my $perc = $self->percent_starved;\n   my $year = $self->year;\n   $perc = (($year - 1) * $perc + $starved * 100 / $population) / $year;\n   $self->percent_starved($perc);\n\n   # babies\n   my $acres    = $self->acres;\n   my $rand     = 1 + int(rand(5));\n   my $arrivals = $self->new_arrivals(\n      int(1 + $rand * (20 * $acres + $store) / $population / 100));\n\n   $population += $arrivals - $starved;\n\n   # HORROS, A 15% CHANCE OF PLAGUE\n   my $had_plague = $self->had_plague(rand(1) < 0.15);\n   $population = int($population / 2) if $had_plague;\n\n   # save population for next round\n   $self->population($population);\n\n   # advance to next year\n   $self->year(++$year);\n   if ($year > $self->max_year) {\n      $self->status('summary');\n   }\n   else {\n      $self->status('start_of_year');\n   }\n} ## end sub _handle_simulate_year\n\n# this is a transition after the impeachment message\nsub _handle_impeach_year ($self, $input) {\n   $self->status('goodbye');\n}\n\n# this is a transition after printing the summary\nsub _handle_summary ($self, $input) {\n   $self->status('goodbye');\n}\n\n# this is a transition after printing the final salutation message\nsub _handle_goodbye ($self, $input) {\n   $self->status('game_over');\n}\n\n# this is a transition after asking the king to hire someone else!\nsub _handle_bail_out ($self, $input) {\n   $self->status('game_over');\n}\n\n# The following package implements all the User Interface, using the\n# game state (as exposed by $game->status) to figure out what to print\n# and if an input is needed from the user. It all happens on the\n# standard input and output.\npackage BasicComputerGames::Hammurabi::DefaultIO;\n\n# All __io_* functions take a $game object as input, in case of need for\n# some specific data (e.g. population amount or amassed grain bushels).\n# They usually print something out and collect input from standard\n# input for states that require a user input. All functions are named\n# after the available states in BasicComputerGames::Hammurabi.\n\nsub __io_start ($game) {\n   say ' ' x 32, 'HAMURABI';\n   say ' ' x 15, 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY';\n   print \"\\n\\n\\n\";\n   say 'TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA';\n   say 'FOR A TEN-YEAR TERM OF OFFICE';\n   print \"\\n\";\n   return;\n} ## end sub __io_start\n\nsub __io_start_of_year ($game) {\n   print \"\\n\\n\";\n   say \"HAMURABI:  I BEG TO REPORT TO YOU,\";\n   printf \"IN YEAR %d , %d PEOPLE STARVED, %d CAME TO THE CITY,\\n\",\n     $game->year, $game->starved, $game->new_arrivals;\n   say 'A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.'\n     if $game->had_plague;\n   say 'POPULATION IS NOW ', $game->population;\n   say 'THE CITY NOW OWNS ', $game->acres,           ' ACRES.';\n   say 'YOU HARVESTED ', $game->production_per_acre, ' BUSHELS PER ACRE.';\n   say 'THE RATS ATE ',  $game->rats_toll,           ' BUSHELS.';\n   say 'YOU NOW HAVE ',  $game->store,               ' BUSHELS IN STORE.';\n   print \"\\n\";\n   return;\n} ## end sub __io_start_of_year\n\nsub get_input ($game = undef) {\n   while (<STDIN>) {\n      chomp(my $input = $_);\n      return 0 unless $input;\n      return $input if $input =~ m{\\A -? \\d+ \\z}mxs;\n      print \"REENTER?\\n?? \";\n   } ## end while (<STDIN>)\n   die \"\\n\";\n} ## end sub get_input\n\nsub __io_bail_out ($game) {\n   say \"\\nHAMURABI:  I CANNOT DO WHAT YOU WISH.\";\n   say 'GET YOURSELF ANOTHER STEWARD!!!!!';\n   return;\n}\n\nsub __not_enough_bushels ($game) {\n   say 'HAMURABI:  THINK AGAIN.  YOU HAVE ONLY';\n   say $game->store, ' BUSHELS OF GRAIN. NOW, THEN,';\n}\n\nsub __not_enough_acres ($game) {\n   say 'HAMURABI:  THINK AGAIN.  YOU OWN ONLY ',\n     $game->acres, ' ACRES.  NOW, THEN,';\n}\n\nsub __io_buy_acres ($game) {\n   print 'HOW MANY ACRES DO YOU WISH TO BUY?? ';\n   return get_input();\n}\n\nsub __io_advertise_cost_per_acre ($game) {\n   say 'LAND IS TRADING AT ', $game->cost_per_acre, ' BUSHELS PER ACRE.';\n   return;\n}\n\nsub __io_sell_acres ($game) {\n   print 'HOW MANY ACRES DO YOU WISH TO SELL?? ';\n   return get_input();\n}\n\nsub __io_feeding ($game) {\n   print \"\\nHOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE?? \";\n   return get_input();\n}\n\nsub __io_planting ($game) {\n   print \"\\nHOW MANY ACRES DO YOU WISH TO PLANT WITH SEED?? \";\n   return get_input();\n}\n\nsub __io_buy_acres_again ($game) { __not_enough_bushels($game) }\n\nsub __io_sell_acres_again ($game) { __not_enough_acres($game) }\n\nsub __io_feeding_again ($game) { __not_enough_bushels($game) }\n\nsub __io_planting_fail_acres ($game) { __not_enough_acres($game) }\n\nsub __io_planting_fail_seeds ($game) { __not_enough_bushels($game) }\n\nsub __io_planting_fail_people ($game) {\n   say 'BUT YOU HAVE ONLY ', $game->population,\n     ' PEOPLE TO TEND THE FIELDS!  NOW, THEN,';\n}\n\nsub __impeachment {\n   say 'DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY';\n   say 'BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE';\n   say 'ALSO BEEN DECLARED NATIONAL FINK!!!!';\n}\n\nsub __io_impeach_year ($game) {\n   printf \"\\nYOU STARVED %d PEOPLE IN ONE YEAR!!!\\n\", $game->starved;\n   return __impeachment();\n}\n\nsub __io_goodbye ($game) {\n   say \"\\nSO LONG FOR NOW.\\n\";\n   return;\n}\n\n# Final summary for the game, print statistics and evaluation\nsub __io_summary ($game) {\n   my $starved = $game->total_starved;\n   my $years   = $game->max_years;\n   my $p1      = 100 * $starved / $years;\n   my $l       = $game->acres / $game->population;\n   printf \"IN YOUR %d-YEAR TERM OF OFFICE, %d PERCENT OF THE\\n\",\n     $years, $p1;\n   say 'POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF';\n   printf \"%d PEOPLE DIED!!\\n\", $starved;\n   say 'YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH';\n   printf \"%.2f ACRES PER PERSON.\\n\\n\", $l;\n\n   if ($p1 > 33 || $l < 7) {\n      __impeachment();\n   }\n   elsif ($p1 > 10 || $l < 9) {\n      say 'YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.';\n      say 'THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,';\n      say 'FRANKLY, HATE YOUR GUTS!!';\n   }\n   elsif ($p1 > 3 || $l < 10) {\n      my $haters = int($game->population * rand(0.8));\n      say 'YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT';\n      say \"REALLY WASN'T TOO BAD AT ALL.  $haters PEOPLE\";\n      say 'WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR';\n      say 'TRIVIAL PROBLEMS.';\n   } ## end elsif ($p1 > 3 || $l < 10)\n   else {\n      say 'A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND';\n      say 'JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!';\n   }\n\n   return;\n} ## end sub __io_summary\n\n# this class method allows using this module... easily. Call with\n# arguments to be fed to the BasicComputerGames::Hammurabi constructor.\nsub run ($package, @args) {\n   my $game = BasicComputerGames::Hammurabi->new(@args);\n   while ((my $status = $game->status) ne 'game_over') {\n      eval {\n         my $retval;\n         if (my $cb = $package->can('__io_' . $status)) {\n            $retval = $cb->($game);\n         }\n         $game->step($retval);\n         1;\n      } or last;\n   } ## end while ((my $status = $game...))\n   say '';\n   return 0;\n} ## end sub run\n\n# Modulino (https://gitlab.com/polettix/notechs/-/snippets/1868370)\nexit __PACKAGE__->run(@ARGV) unless caller;\n\n1;\n__END__\n\n=pod\n\n=encoding UTF-8\n\n=head1 NAME\n\nBasicComputerGames::Hammurabi - the Hammurabi game from BASIC\n\n=head1 SYNOPSIS\n\n   use BasicComputerGames::Hammurabi;\n\n   # if you have a way to manage the UI yourself, then you can get the\n   # game logic handler\n   my $game_handler = BasicComputerGames::Hammurabi->new;\n   while ((my $status = $game_handler->status) ne 'game_over') {\n      # figure out what to print out with $status, this is totally\n      # up to the interface implementation, which also has to collect\n      # the inputs\n      my $retval = manage_ui_for($game_handler);\n\n      # now we feed whatever came from the interface back to the handler\n      $game_handler->step($retval);\n   }\n\n   # Want the plain terminal experience? No problem:\n   BasicComputerGames::Hammurabi::DefaultIO->run;\n\n=head1 IMPLEMENTATION DETAILS\n\nThe code tries to behave like the original BASIC, including some dubious\nconditions checks that e.g. do not allow using the full potential of\navailable resources for lack of an equal sign.\n\nThe calculation of the final average of starved people per year is\ndiffernet from the original and avoids what is considered (by me) a bug\nthat kicks in when there are years in which nobody starves.\n\n=head1 AUTHOR\n\nAdapted by Flavio Poletti from the BASIC version by David Ahl. Game text\ncopied verbatim from the original BASIC implementation, including typos.\n\n=cut\n"
  },
  {
    "path": "43_Hammurabi/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "43_Hammurabi/python/hamurabi.py",
    "content": "from random import random, seed\r\n\r\n\r\ndef gen_random() -> int:\r\n    return int(random() * 5) + 1\r\n\r\n\r\ndef bad_input_850() -> None:\r\n    print(\"\\nHAMURABI:  I CANNOT DO WHAT YOU WISH.\")\r\n    print(\"GET YOURSELF ANOTHER STEWARD!!!!!\")\r\n\r\n\r\ndef bad_input_710(grain_bushels: int) -> None:\r\n    print(\"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\")\r\n    print(f\"{grain_bushels} BUSHELS OF GRAIN.  NOW THEN,\")\r\n\r\n\r\ndef bad_input_720(acres: float) -> None:\r\n    print(f\"HAMURABI:  THINK AGAIN.  YOU OWN ONLY {acres} ACRES.  NOW THEN,\")\r\n\r\n\r\ndef national_fink() -> None:\r\n    print(\"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\")\r\n    print(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\")\r\n    print(\"ALSO BEEN DECLARED NATIONAL FINK!!!!\")\r\n\r\n\r\ndef b_input(promptstring: str) -> int:\r\n    \"\"\"emulate BASIC input. It rejects non-numeric values\"\"\"\r\n    x = input(promptstring)\r\n    while x.isalpha():\r\n        x = input(\"?REDO FROM START\\n? \")\r\n    return int(x)\r\n\r\n\r\ndef main() -> None:\r\n    seed()\r\n    title = \"HAMURABI\"\r\n    title = title.rjust(32, \" \")\r\n    print(title)\r\n    attribution = \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\r\n    attribution = attribution.rjust(15, \" \")\r\n    print(attribution)\r\n    print(\"\\n\\n\\n\")\r\n    print(\"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\")\r\n    print(\"FOR A TEN-YEAR TERM OF OFFICE.\\n\")\r\n\r\n    D1 = 0\r\n    P1: float = 0\r\n    year = 0\r\n    population = 95\r\n    grain_stores = 2800\r\n    H = 3000\r\n    eaten_rats = H - grain_stores\r\n    bushels_per_acre = (\r\n        3  # yield (amount of production from land). Reused as price per acre\r\n    )\r\n    acres = H / bushels_per_acre  # acres of land\r\n    immigrants = 5\r\n    plague = 1  # boolean for plague, also input for buy/sell land\r\n    people = 0\r\n\r\n    while year < 11:  # line 270. main loop. while the year is less than 11\r\n        print(\"\\n\\n\\nHAMURABI:  I BEG TO REPORT TO YOU\")\r\n        year += 1\r\n        print(\r\n            \"IN YEAR\",\r\n            year,\r\n            \",\",\r\n            people,\r\n            \"PEOPLE STARVED,\",\r\n            immigrants,\r\n            \"CAME TO THE CITY,\",\r\n        )\r\n        population = population + immigrants\r\n\r\n        if plague == 0:\r\n            population = int(population / 2)\r\n            print(\"A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\")\r\n\r\n        print(\"POPULATION IS NOW\", population)\r\n        print(\"THE CITY NOW OWNS\", acres, \"ACRES.\")\r\n        print(\"YOU HARVESTED\", bushels_per_acre, \"BUSHELS PER ACRE.\")\r\n        print(\"THE RATS ATE\", eaten_rats, \"BUSHELS.\")\r\n        print(\"YOU NOW HAVE \", grain_stores, \"BUSHELS IN STORE.\\n\")\r\n        C = int(10 * random())  # random number between 1 and 10\r\n        bushels_per_acre = C + 17\r\n        print(\"LAND IS TRADING AT\", bushels_per_acre, \"BUSHELS PER ACRE.\")\r\n\r\n        plague = -99  # dummy value to track status\r\n        while plague == -99:  # always run the loop once\r\n            plague = b_input(\"HOW MANY ACRES DO YOU WISH TO BUY? \")\r\n            if plague < 0:\r\n                plague = -1  # to avoid the corner case of Q=-99\r\n                bad_input_850()\r\n                year = 99  # jump out of main loop and exit\r\n            elif bushels_per_acre * plague > grain_stores:  # can't afford it\r\n                bad_input_710(grain_stores)\r\n                plague = -99  # give'm a second change to get it right\r\n            else:\r\n                acres = acres + plague  # increase the number of acres by Q\r\n                grain_stores = (\r\n                    grain_stores - bushels_per_acre * plague\r\n                )  # decrease the amount of grain in store to pay for it\r\n                C = 0  # WTF is C for?\r\n\r\n        if plague == 0 and year != 99:  # maybe you want to sell some land?\r\n            plague = -99\r\n            while plague == -99:\r\n                plague = b_input(\"HOW MANY ACRES DO YOU WISH TO SELL? \")\r\n                if plague < 0:\r\n                    bad_input_850()\r\n                    year = 99  # jump out of main loop and exit\r\n                elif plague <= acres:  # normal case\r\n                    acres = acres - plague  # reduce the acres\r\n                    grain_stores = (\r\n                        grain_stores + bushels_per_acre * plague\r\n                    )  # add to grain stores\r\n                    C = 0  # still don't know what C is for\r\n                else:  # Q>A error!\r\n                    bad_input_720(acres)\r\n                    plague = -99  # reloop\r\n            print(\"\\n\")\r\n\r\n        plague = -99\r\n        while plague == -99 and year != 99:\r\n            plague = b_input(\"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? \")\r\n            if plague < 0:\r\n                bad_input_850()\r\n                year = 99  # jump out of main loop and exit\r\n            # REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?\r\n            elif plague > grain_stores:\r\n                bad_input_710(grain_stores)\r\n                plague = -99  # try again!\r\n            else:  # we're good. do the transaction\r\n                grain_stores = grain_stores - plague  # remove the grain from the stores\r\n                C = 1  # set the speed of light to 1. jk\r\n\r\n        print(\"\\n\")\r\n        people = -99  # dummy value to force at least one loop\r\n        while people == -99 and year != 99:\r\n            people = b_input(\"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? \")\r\n            if people < 0:\r\n                bad_input_850()\r\n                year = 99  # jump out of main loop and exit\r\n            elif people > 0:\r\n                if people > acres:\r\n                    # REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?\r\n                    bad_input_720(acres)\r\n                    people = -99\r\n                elif int(people / 2) > grain_stores:\r\n                    # REM *** ENOUGH GRAIN FOR SEED?\r\n                    bad_input_710(grain_stores)\r\n                    people = -99\r\n                elif people > 10 * population:\r\n                    # REM *** ENOUGH PEOPLE TO TEND THE CROPS?\r\n                    print(\r\n                        \"BUT YOU HAVE ONLY\",\r\n                        population,\r\n                        \"PEOPLE TO TEND THE FIELDS!  NOW THEN,\",\r\n                    )\r\n                    people = -99\r\n                else:  # we're good. decrement the grain store\r\n                    grain_stores = grain_stores - int(people / 2)\r\n\r\n        C = gen_random()\r\n        # REM *** A BOUNTIFUL HARVEST!\r\n        bushels_per_acre = C\r\n        H = people * bushels_per_acre\r\n        C = gen_random()\r\n        eaten_rats = int(grain_stores / C) if int(C / 2) == C / 2 else 0\r\n        grain_stores = grain_stores - eaten_rats + H  # deduct losses from stores\r\n\r\n        C = gen_random()\r\n        # REM *** LET'S HAVE SOME BABIES\r\n        immigrants = int(C * (20 * acres + grain_stores) / population / 100 + 1)\r\n        # REM *** HOW MANY PEOPLE HAD FULL TUMMIES?\r\n        C = int(plague / 20)\r\n        # REM *** HORROS, A 15% CHANCE OF PLAGUE\r\n        # yeah, should be HORRORS, but left it\r\n        plague = int(10 * (2 * random() - 0.3))\r\n        if (\r\n            population >= C and year != 99\r\n        ):  # if there are some people without full bellies...\r\n            # REM *** STARVE ENOUGH FOR IMPEACHMENT?\r\n            people = population - C\r\n            if people > 0.45 * population:\r\n                print(\"\\nYOU STARVED\", people, \"PEOPLE IN ONE YEAR!!!\")\r\n                national_fink()\r\n                year = 99  # exit the loop\r\n            P1 = ((year - 1) * P1 + people * 100 / population) / year\r\n            population = C\r\n            D1 = D1 + people\r\n\r\n    if year != 99:\r\n        print(\"IN YOUR 10-YEAR TERM OF OFFICE,\", P1, \"PERCENT OF THE\")\r\n        print(\"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\")\r\n        print(D1, \"PEOPLE DIED!!\")\r\n        L = acres / population\r\n        print(\"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\")\r\n        print(L, \"ACRES PER PERSON.\\n\")\r\n        if P1 > 33 or L < 7:\r\n            national_fink()\r\n        elif P1 > 10 or L < 9:\r\n            print(\"YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\")\r\n            print(\"THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,\")\r\n            print(\"FRANKLY, HATE YOUR GUTS!!\")\r\n        elif P1 > 3 or L < 10:\r\n            print(\"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\")\r\n            print(\r\n                \"REALLY WASN'T TOO BAD AT ALL. \",\r\n                int(population * 0.8 * random()),\r\n                \"PEOPLE\",\r\n            )\r\n            print(\"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\")\r\n            print(\"TRIVIAL PROBLEMS.\")\r\n        else:\r\n            print(\"A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\")\r\n            print(\"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\\n\")\r\n        for _ in range(1, 10):\r\n            print(\"\\a\")\r\n\r\n    print(\"\\nSO LONG FOR NOW.\\n\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n"
  },
  {
    "path": "43_Hammurabi/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "43_Hammurabi/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "43_Hammurabi/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "43_Hammurabi/rust/src/main.rs",
    "content": "use std::io;\nuse rand::Rng;\n\nfn run() {\n    // Set up variables\n    let mut year = 0;\n    let mut population = 95;\n    let mut immigrants = 5;\n    let mut starved = 0;\n    let mut total_starved = 0;\n    let mut plague = false;\n    let mut grain = 2800;\n    let mut bushels_fed;\n    let mut harvest;\n    let mut planted;\n    let mut yield_acre = 3;\n    let mut eaten_rats = 200;\n    let mut acres = 1000;\n    let mut land_price;\n    let mut bought_land;\n    let mut perc_starved = 0.0;\n    let mut game_failed = false;\n\n    'main: loop {\n        year += 1;\n        if year > 11 {\n            break;\n        }\n        println!(\"\\n\\n\\nHAMURABI: I BEG TO REPORT TO YOU,\");\n        println!(\"IN YEAR {year}, {starved} PEOPLE STARVED, {immigrants} CAME TO THE CITY,\");\n        population += immigrants;\n        if plague{\n            population /= 2;\n            plague = false;\n            println!(\"A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.\");\n        }\n        println!(\"POPULATION IS NOW {population}\");\n        println!(\"THE CITY NOW OWNS {acres} ACRES.\");\n        println!(\"YOU HARVESTED {yield_acre} BUSHELS PER ACRE.\");\n        println!(\"THE RATS ATE {eaten_rats} BUSHELS.\");\n        println!(\"YOU NOW HAVE {grain} BUSHELS IN STORE.\\n\");\n        let r = rand::thread_rng().gen_range(1..10);\n        land_price = r + 17;\n        println!(\"LAND IS TRADING AT {land_price} BUSHELS PER ACRE.\");\n\n        loop {  \n            println!(\"HOW MANY ACRES DO YOU WISH TO BUY? \");\n            if let Some(qty) = get_input() {\n                // Player decides not to buy any land\n                if qty == 0 {\n                    bought_land = false;\n                    break;\n                }\n                // Trying to buy more land than you can afford?\n                if land_price * qty > grain {\n                    insufficient_grain(grain);\n                    continue;\n                }\n                // Everything checks out OK\n                if land_price * qty <= grain {\n                    acres += qty ;\n                    grain -= land_price * qty ;\n                    bought_land = true;\n                    break;\n                }\n            } else {\n                impossible_task();\n                game_failed = true;\n                break 'main;\n            }\n        }\n\n        if !bought_land {\n            loop {  \n                println!(\"HOW MANY ACRES DO YOU WISH TO SELL? \");\n                if let Some(qty) = get_input() {\n                    // Everything checks out OK\n                    if qty <= acres {\n                        acres -= qty;\n                        grain += land_price * qty;\n                        break;\n                    }\n                    // Trying to sell more land that you own\n                    insufficient_land(acres);\n                } else {\n                    impossible_task();\n                    game_failed = true;\n                    break 'main;\n                }\n            }\n        }\n\n        loop {  \n            println!(\"HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? \");\n            if let Some(qty) = get_input() {\n                // Trying to use more grain than is in silos?\n                if qty > grain {\n                    insufficient_grain(grain);\n                    continue;\n                }\n                // Everything checks out OK\n                bushels_fed = qty;\n                grain -= bushels_fed;\n                break;\n            } else {\n                impossible_task();\n                game_failed = true;\n                break 'main;\n            }\n        }\n\n        loop {  \n            println!(\"HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? \");\n            if let Some(qty) = get_input() {\n                // Trying to plant more acres than you own?\n                if qty > acres {\n                    insufficient_land(acres);\n                    continue;\n                }\n                // Enough grain for seed?\n                if qty / 2 > grain {\n                    insufficient_grain(grain);\n                    continue;\n                }\n                // Enough people to tend the crops?\n                if qty > (10 * population) {\n                    insufficient_people(population);\n                    continue;\n                }\n                // Everything checks out OK\n                planted = qty;\n                grain -= planted / 2;\n                break;\n            } else {\n                impossible_task();\n                game_failed = true;\n                break 'main;\n            }\n        }\n\n        // A bountiful harvest!\n        yield_acre = gen_random();\n        harvest = planted * yield_acre;\n        eaten_rats = 0;\n\n        // Determine if any grain was eaten by rats\n        let mut c = gen_random();\n        if c % 2 == 0 { // If c is even...\n            // Rats are running wild!\n            eaten_rats = grain / c;\n        }\n        // Update the amount of grain held\n        grain = grain - eaten_rats + harvest;\n\n        // Let's have some babies\n        c = gen_random();\n        immigrants = c * (20 * acres + grain) / population / 100 + 1;\n\n        // How many people had full tummies?\n        c = bushels_fed / 20;\n        // Horrors, a 15% chance of plague\n        let rf: f32 = rand::thread_rng().gen();\n        let plague_chance = (10. * ((2. * rf) - 0.3)) as i32;\n        if plague_chance == 0 {\n            plague = true;\n        }\n        if population >= c {\n            // Starve enough for impeachment?\n            starved = population - c;\n            if starved > (0.45 * population as f32) as u32 {\n                println!(\"YOU STARVED {starved} PEOPLE IN ONE YEAR!!!\");\n                national_fink();\n                game_failed = true;\n                break;\n            }\n            // Calculate percentage of people that starved per year on average\n            perc_starved = ((year - 1) as f32 * perc_starved + starved as f32 * 100. / population as f32) / year as f32;\n            population = c;\n            total_starved += starved;\n        }\n    }\n\n    if !game_failed {\n        println!(\"IN YOUR 10-YEAR TERM OF OFFICE {perc_starved} PERCENT OF THE\");\n        println!(\"POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\");\n        println!(\"{total_starved} PEOPLE DIED!!\");\n        let acres_head = acres / population;\n        println!(\"YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\");\n        println!(\"{acres_head} ACRES PER PERSON.\\n\");\n        if perc_starved > 33. || acres_head < 7 {\n            national_fink();\n        }\n        else if perc_starved > 10. || acres_head < 9 {\n            println!(\"YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\");\n            println!(\"THE PEOPLE (REMAINING) FIND YOU AND UNPLEASANT RULER, AND,\");\n            println!(\"FRANKLY, HATE YOUR GUTS!!\");\n        }\n        else if perc_starved > 3. || acres_head < 10 {\n            let haters = (population as f32 * 0.8 * gen_random() as f32) as u32;\n            println!(\"YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\");\n            println!(\"REALLY WASN'T TOO BAD AT ALL. {haters} PEOPLE\");\n            println!(\"WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\");\n            println!(\"TRIVIAL PROBLEMS.\");\n        } else {\n            println!(\"A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND\");\n            println!(\"JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\\n\");\n        }\n        for _ in 1..10 {\n            println!();\n        }\n    }\n            \n    println!(\"\\nSO LONG FOR NOW.\\n\");\n}\n\nfn get_input() -> Option<u32> {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input).expect(\"Failed read_line\");\n    match input.trim().parse() {\n        Ok(num) => Some(num),\n        Err(_) => None,\n    }\n}\n\nfn gen_random() -> u32 {\n    let r: f32 = rand::thread_rng().gen();\n    (r * 5.0 + 1.0) as u32\n}\n\nfn impossible_task() {\n    println!(\"HAMURABI:  I CANNOT DO WHAT YOU WISH.\");\n    println!(\"GET YOURSELF ANOTHER STEWARD!!!!!\");\n}\n\nfn insufficient_grain(grain: u32) {\n    println!(\"HAMURABI:  THINK AGAIN.  YOU HAVE ONLY\");\n    println!(\"{grain} BUSHELS OF GRAIN.  NOW THEN,\");\n}\n\nfn insufficient_land(acres: u32) {\n    println!(\"HAMURABI: THINK AGAIN. YOU OWN ONLY {acres} ACRES.  NOW THEN,\");\n}\n\nfn insufficient_people(population: u32) {\n    println!(\"BUT YOU HAVE ONLY {population} PEOPLE TO TEND THE FIELDS!  NOW THEN,\");\n}\n\nfn national_fink() {\n    println!(\"DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\");\n    println!(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\");\n    println!(\"ALSO BEEN DECLARED NATIONAL FINK!!!!\");\n}\n\nfn main() {\n    println!(\"                 HAMURABI\");\n    println!(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    print!(\"\\n\\n\\n\\n\");\n    println!(\"TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\");\n    println!(\"FOR A TEN-YEAR TERM OF OFFICE.\\n\");\n\n    run();\n}\n"
  },
  {
    "path": "43_Hammurabi/vbnet/Hammurabi.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Hammurabi\", \"Hammurabi.vbproj\", \"{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "43_Hammurabi/vbnet/Hammurabi.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Hammurabi</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "43_Hammurabi/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "44_Hangman/README.md",
    "content": "### Hangman\n\nThis is a simulation of the word guessing game, hangman. The computer picks a word, tells you how many letters in the word it has picked and then you guess a letter in the word. If you are right, the computer tells you where that letter belongs; if your letter is wrong, the computer starts to hang you. You get ten guesses before you are completely hanged:\n1. Head\n2. Body\n3. Right Arm\n4. Left Arm\n5. Right Leg\n6. Left Leg\n7. Right Hand\n8. Left Hand\n9. Right Foot\n10. Left Foot\n\nYou may add words in Data statements; however if you do, you must also change the random word selector.\n\nDavid Ahl modified this program into its current form from the one created by Kenneth Aupperle of Melville, New York.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=80)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=95)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "44_Hangman/csharp/Graphic.cs",
    "content": "using System;\n\nnamespace Hangman\n{\n    /// <summary>\n    /// Represents the main \"Hangman\" graphic.\n    /// </summary>\n    public class Graphic\n    {\n        private readonly char[,] _graphic;\n        private const int Width = 12;\n        private const int Height = 12;\n\n        public Graphic()\n        {\n            // 12 x 12 array to represent the graphics.\n            _graphic = new char[Height, Width];\n\n            // Fill it with empty spaces.\n            for (var i = 0; i < Height; i++)\n            {\n                for (var j = 0; j < Width; j++)\n                {\n                    _graphic[i, j] = ' ';\n                }\n            }\n\n            // Draw the vertical line.\n            for (var i = 0; i < Height; i++)\n            {\n                _graphic[i, 0] = 'X';\n            }\n\n            // Draw the horizontal line.\n            for (var i = 0; i < 7; i++)\n            {\n                _graphic[0, i] = 'X';\n            }\n\n            // Draw the rope.\n            _graphic[1, 6] = 'X';\n        }\n\n        public void Print()\n        {\n            for (var i = 0; i < Height; i++)\n            {\n                for (var j = 0; j < Width; j++)\n                {\n                    Console.Write(_graphic[i, j]);\n                }\n\n                Console.Write(\"\\n\"); // New line.\n            }\n        }\n\n        public void AddHead()\n        {\n            _graphic[2, 5] = '-';\n            _graphic[2, 6] = '-';\n            _graphic[2, 7] = '-';\n            _graphic[3, 4] = '(';\n            _graphic[3, 5] = '.';\n            _graphic[3, 7] = '.';\n            _graphic[3, 8] = ')';\n            _graphic[4, 5] = '-';\n            _graphic[4, 6] = '-';\n            _graphic[4, 7] = '-';\n        }\n\n        public void AddBody()\n        {\n            for (var i = 5; i < 9; i++)\n            {\n                _graphic[i, 6] = 'X';\n            }\n        }\n\n        public void AddRightArm()\n        {\n            for (var i = 3; i < 7; i++)\n            {\n                _graphic[i, i - 1] = '\\\\'; // This is the escape character for the back slash.\n            }\n        }\n\n        public void AddLeftArm()\n        {\n            _graphic[3, 10] = '/';\n            _graphic[4, 9] = '/';\n            _graphic[5, 8] = '/';\n            _graphic[6, 7] = '/';\n        }\n\n        public void AddRightLeg()\n        {\n            _graphic[9, 5] = '/';\n            _graphic[10, 4] = '/';\n        }\n\n        public void AddLeftLeg()\n        {\n            _graphic[9, 7] = '\\\\';\n            _graphic[10, 8] = '\\\\';\n        }\n\n        public void AddRightHand()\n        {\n            _graphic[2, 2] = '/';\n        }\n\n        public void AddLeftHand()\n        {\n            _graphic[2, 10] = '\\\\';\n        }\n\n        public void AddRightFoot()\n        {\n            _graphic[11, 9] = '\\\\';\n            _graphic[11, 10] = '-';\n        }\n\n        public void AddLeftFoot()\n        {\n            _graphic[11, 3] = '/';\n            _graphic[11, 2] = '-';\n        }\n    }\n}\n"
  },
  {
    "path": "44_Hangman/csharp/Hangman.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <OutputType>Exe</OutputType>\n        <TargetFramework>net5.0</TargetFramework>\n    </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "44_Hangman/csharp/Hangman.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Hangman\", \"Hangman.csproj\", \"{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "44_Hangman/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json.Serialization;\n\nnamespace Hangman\n{\n    /// <summary>\n    /// C# version of the game \"Hangman\" from the book BASIC Computer Games.\n    /// </summary>\n    static class Program\n    {\n        static void Main()\n        {\n            Console.WriteLine(Tab(32) + \"HANGMAN\");\n            Console.WriteLine(Tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            MainLoop();\n            Console.WriteLine();\n            Console.WriteLine(\"IT'S BEEN FUN!  BYE FOR NOW.\");\n        }\n\n        static void MainLoop()\n        {\n            var words = GetWords();\n            var stillPlaying = true;\n\n            while (stillPlaying)\n            {\n                if (words.Count == 0)\n                {\n                    Console.WriteLine(\"YOU DID ALL THE WORDS!!\");\n                    break;\n                }\n\n                // Get a random number from 0 to the number of words we have minus one (C# arrays are zero-based).\n                var rnd = new Random();\n                var randomNumber = rnd.Next(words.Count - 1);\n\n                // Pick a random word and remove it from the list.\n                var word = words[randomNumber];\n                words.Remove(word);\n\n                GameLoop(word);\n\n                // Game finished. Ask if player wants another one.\n                Console.WriteLine(\"WANT ANOTHER WORD? \");\n                var response = Console.ReadLine();\n                if (response == null || response.ToUpper() != \"YES\")\n                {\n                    stillPlaying = false;   // Exit the loop if the player didn't answer \"yes\".\n                }\n            }\n        }\n\n        static void GameLoop(string word)\n        {\n            var graphic = new Graphic();\n            var wrongGuesses = 0;\n            var numberOfGuesses = 0;\n            var usedLetters = new List<char>();\n\n            // The word that the user sees. Since we just started, it's just dashes.\n            var displayedWord = new char[word.Length];\n            for (var i = 0; i < word.Length; i++)\n            {\n                displayedWord[i] = '-';\n            }\n\n            var stillPlaying = true;\n            while (stillPlaying)\n            {\n                var guess = GetLetterFromPlayer(displayedWord, usedLetters);\n                usedLetters.Add(guess);\n                numberOfGuesses++;\n                var correctLetterCount = 0;\n                // Now we check every letter in the word to see if the player guessed any of them correctly.\n                for(var i = 0; i < word.Length; i++)\n                {\n                    if (word[i] == guess)\n                    {\n                        correctLetterCount++;\n                        displayedWord[i] = guess;\n                    }\n                }\n\n                if (correctLetterCount == 0)\n                {\n                    // Wrong guess.\n                    Console.WriteLine(\"SORRY, THAT LETTER ISN'T IN THE WORD.\");\n                    wrongGuesses++;\n                    DrawBody(graphic, wrongGuesses);\n                    if (wrongGuesses == 10)\n                    {\n                        // Player exhausted all their guesses. Finish the game loop.\n                        Console.WriteLine($\"SORRY, YOU LOSE.  THE WORD WAS {word}\");\n                        Console.Write(\"YOU MISSED THAT ONE.  DO YOU \");\n                        stillPlaying = false;\n                    }\n                }\n                else\n                {\n                    // Player guessed a correct letter. Let's see if there are any unguessed letters left in the word.\n                    if (displayedWord.Contains('-'))\n                    {\n                        Console.WriteLine(displayedWord);\n\n                        // Give the player a chance to guess the whole word.\n                        var wordGuess = GetWordFromPlayer();\n                        if (word == wordGuess)\n                        {\n                            // Player found the word. Mark it found.\n                            Console.WriteLine(\"YOU FOUND THE WORD!\");\n                            stillPlaying = false;   // Exit game loop.\n                        }\n                        else\n                        {\n                            // Player didn't guess the word. Continue the game loop.\n                            Console.WriteLine(\"WRONG.  TRY ANOTHER LETTER.\");\n                        }\n                    }\n                    else\n                    {\n                        // Player guessed all the letters.\n                        Console.WriteLine(\"YOU FOUND THE WORD!\");\n                        stillPlaying = false;   // Exit game loop.\n                    }\n                }\n            } // End of game loop.\n        }\n\n        /// <summary>\n        /// Display the current state of the word and all the already guessed letters, and get a new guess from the player\n        /// </summary>\n        /// <param name=\"displayedWord\">A char array that represents the current state of the guessed word</param>\n        /// <param name=\"usedLetters\">A list of chars that represents all the letters guessed so far</param>\n        /// <returns>The letter that the player has just entered as a guess</returns>\n        private static char GetLetterFromPlayer(char[] displayedWord, List<char> usedLetters)\n        {\n            while (true)    // Infinite loop, unless the player enters an unused letter.\n            {\n                Console.WriteLine();\n                Console.WriteLine(displayedWord);\n                Console.WriteLine();\n                Console.WriteLine();\n                Console.WriteLine(\"HERE ARE THE LETTERS YOU USED:\");\n                for (var i = 0; i < usedLetters.Count; i++)\n                {\n                    Console.Write(usedLetters[i]);\n\n                    // If it's not the last letter, print a comma.\n                    if (i != usedLetters.Count - 1)\n                    {\n                        Console.Write(\",\");\n                    }\n                }\n\n                Console.WriteLine();\n                Console.WriteLine(\"WHAT IS YOUR GUESS?\");\n                var guess = char.ToUpper(Console.ReadKey().KeyChar);\n                Console.WriteLine();\n\n                if (usedLetters.Contains(guess))\n                {\n                    // After this the loop will continue.\n                    Console.WriteLine(\"YOU GUESSED THAT LETTER BEFORE!\");\n                }\n                else\n                {\n                    // Break out of the loop by returning guessed letter.\n                    return guess;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets a word guess from the player.\n        /// </summary>\n        /// <returns>The guessed word.</returns>\n        private static string GetWordFromPlayer()\n        {\n            while (true)    // Infinite loop, unless the player enters something.\n            {\n                Console.WriteLine(\"WHAT IS YOUR GUESS FOR THE WORD? \");\n                var guess = Console.ReadLine();\n                if (guess != null)\n                {\n                    return guess.ToUpper();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Draw body after wrong guess.\n        /// </summary>\n        /// <param name=\"graphic\">The instance of the Graphic class being used.</param>\n        /// <param name=\"wrongGuesses\">Number of wrong guesses.</param>\n        private static void DrawBody(Graphic graphic, int wrongGuesses)\n        {\n            switch (wrongGuesses)\n                    {\n                        case 1:\n                            Console.WriteLine(\"FIRST, WE DRAW A HEAD.\");\n                            graphic.AddHead();\n                            break;\n                        case 2:\n                            Console.WriteLine(\"NOW WE DRAW A BODY.\");\n                            graphic.AddBody();\n                            break;\n                        case 3:\n                            Console.WriteLine(\"NEXT WE DRAW AN ARM.\");\n                            graphic.AddRightArm();\n                            break;\n                        case 4:\n                            Console.WriteLine(\"THIS TIME IT'S THE OTHER ARM.\");\n                            graphic.AddLeftArm();\n                            break;\n                        case 5:\n                            Console.WriteLine(\"NOW, LET'S DRAW THE RIGHT LEG.\");\n                            graphic.AddRightLeg();\n                            break;\n                        case 6:\n                            Console.WriteLine(\"THIS TIME WE DRAW THE LEFT LEG.\");\n                            graphic.AddLeftLeg();\n                            break;\n                        case 7:\n                            Console.WriteLine(\"NOW WE PUT UP A HAND.\");\n                            graphic.AddRightHand();\n                            break;\n                        case 8:\n                            Console.WriteLine(\"NEXT THE OTHER HAND.\");\n                            graphic.AddLeftHand();\n                            break;\n                        case 9:\n                            Console.WriteLine(\"NOW WE DRAW ONE FOOT.\");\n                            graphic.AddRightFoot();\n                            break;\n                        case 10:\n                            Console.WriteLine(\"HERE'S THE OTHER FOOT -- YOU'RE HUNG!!\");\n                            graphic.AddLeftFoot();\n                            break;\n                    }\n                    graphic.Print();\n        }\n\n        /// <summary>\n        /// Get a list of words to use in the game.\n        /// </summary>\n        /// <returns>List of strings.</returns>\n        private static List<string> GetWords() => new()\n        {\n            \"GUM\",\n            \"SIN\",\n            \"FOR\",\n            \"CRY\",\n            \"LUG\",\n            \"BYE\",\n            \"FLY\",\n            \"UGLY\",\n            \"EACH\",\n            \"FROM\",\n            \"WORK\",\n            \"TALK\",\n            \"WITH\",\n            \"SELF\",\n            \"PIZZA\",\n            \"THING\",\n            \"FEIGN\",\n            \"FIEND\",\n            \"ELBOW\",\n            \"FAULT\",\n            \"DIRTY\",\n            \"BUDGET\",\n            \"SPIRIT\",\n            \"QUAINT\",\n            \"MAIDEN\",\n            \"ESCORT\",\n            \"PICKAX\",\n            \"EXAMPLE\",\n            \"TENSION\",\n            \"QUININE\",\n            \"KIDNEY\",\n            \"REPLICA\",\n            \"SLEEPER\",\n            \"TRIANGLE\",\n            \"KANGAROO\",\n            \"MAHOGANY\",\n            \"SERGEANT\",\n            \"SEQUENCE\",\n            \"MOUSTACHE\",\n            \"DANGEROUS\",\n            \"SCIENTIST\",\n            \"DIFFERENT\",\n            \"QUIESCENT\",\n            \"MAGISTRATE\",\n            \"ERRONEOUSLY\",\n            \"LOUDSPEAKER\",\n            \"PHYTOTOXIC\",\n            \"MATRIMONIAL\",\n            \"PARASYMPATHOMIMETIC\",\n            \"THIGMOTROPISM\"\n        };\n\n        /// <summary>\n        /// Leave a number of spaces empty.\n        /// </summary>\n        /// <param name=\"length\">Number of spaces.</param>\n        /// <returns>The result string.</returns>\n        private static string Tab(int length) => new string(' ', length);\n    }\n}\n"
  },
  {
    "path": "44_Hangman/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "44_Hangman/hangman.bas",
    "content": "10 PRINT TAB(32);\"HANGMAN\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n25 PRINT:PRINT:PRINT\n30 DIM P$(12,12),L$(20),D$(20),N$(26),U(50)\n40 C=1: N=50\n50 FOR I=1 TO 20: D$(I)=\"-\": NEXT I: M=0\n60 FOR I=1 TO 26: N$(I)=\"\": NEXT I\n70 FOR I=1 TO 12: FOR J=1 TO 12: P$(I,J)=\" \": NEXT J: NEXT I\n80 FOR I=1 TO 12: P$(I,1)=\"X\": NEXT I\n90 FOR I=1 TO 7: P$(1,I)=\"X\": NEXT: P$(2,7)=\"X\"\n95 IF C<N THEN 100\n97 PRINT \"YOU DID ALL THE WORDS!!\": STOP\n100 Q=INT(N*RND(1))+1\n110 IF U(Q)=1 THEN 100\n115 U(Q)=1: C=C+1: RESTORE: T1=0\n150 FOR I=1 TO Q: READ A$: NEXT I\n160 L=LEN(A$): FOR I=1 TO LEN(A$): L$(I)=MID$(A$,I,1): NEXT I\n170 PRINT \"HERE ARE THE LETTERS YOU USED:\"\n180 FOR I=1 TO 26: PRINT N$(I);: IF N$(I+1)=\"\" THEN 200\n190 PRINT \",\";: NEXT I\n200 PRINT: PRINT: FOR I=1 TO L: PRINT D$(I);: NEXT I: PRINT: PRINT\n210 INPUT \"WHAT IS YOUR GUESS\";G$: R=0\n220 FOR I=1 TO 26: IF N$(I)=\"\" THEN 250\n230 IF G$=N$(I) THEN PRINT \"YOU GUESSED THAT LETTER BEFORE!\": GOTO 170\n240 NEXT I: PRINT \"PROGRAM ERROR.  RUN AGAIN.\": STOP\n250 N$(I)=G$: T1=T1+1\n260 FOR I=1 TO L: IF L$(I)=G$ THEN 280\n270 NEXT I: IF R=0 THEN 290\n275 GOTO 300\n280 D$(I)=G$: R=R+1: GOTO 270\n290 M=M+1: GOTO 400\n300 FOR I=1 TO L: IF D$(I)=\"-\" THEN 320\n310 NEXT I: GOTO 390\n320 PRINT: FOR I=1 TO L: PRINT D$(I);: NEXT I: PRINT: PRINT\n330 INPUT \"WHAT IS YOUR GUESS FOR THE WORD\";B$\n340 IF A$=B$ THEN 360\n350 PRINT \"WRONG.  TRY ANOTHER LETTER.\": PRINT: GOTO 170\n360 PRINT \"RIGHT!!  IT TOOK YOU\";T1;\"GUESSES!\"\n370 INPUT \"WANT ANOTHER WORD\";W$: IF W$=\"YES\" THEN 50\n380 PRINT: PRINT \"IT'S BEEN FUN!  BYE FOR NOW.\": GOTO 999\n390 PRINT \"YOU FOUND THE WORD!\": GOTO 370\n400 PRINT: PRINT: PRINT\"SORRY, THAT LETTER ISN'T IN THE WORD.\"\n410 ON M GOTO 415,420,425,430,435,440,445,450,455,460\n415 PRINT \"FIRST, WE DRAW A HEAD\": GOTO 470\n420 PRINT \"NOW WE DRAW A BODY.\": GOTO 470\n425 PRINT \"NEXT WE DRAW AN ARM.\": GOTO 470\n430 PRINT \"THIS TIME IT'S THE OTHER ARM.\": GOTO 470\n435 PRINT \"NOW, LET'S DRAW THE RIGHT LEG.\": GOTO 470\n440 PRINT \"THIS TIME WE DRAW THE LEFT LEG.\": GOTO 470\n445 PRINT \"NOW WE PUT UP A HAND.\": GOTO 470\n450 PRINT \"NEXT THE OTHER HAND.\": GOTO 470\n455 PRINT \"NOW WE DRAW ONE FOOT\": GOTO 470\n460 PRINT \"HERE'S THE OTHER FOOT -- YOU'RE HUNG!!\"\n470 ON M GOTO 480,490,500,510,520,530,540,550,560,570\n480 P$(3,6)=\"-\": P$(3,7)=\"-\": P$(3,8)=\"-\": P$(4,5)=\"(\": P$(4,6)=\".\"\n481 P$(4,8)=\".\":P$(4,9)=\")\":P$(5,6)=\"-\":P$(5,7)=\"-\":P$(5,8)=\"-\":GOTO 580\n490 FOR I=6 TO 9: P$(I,7)=\"X\": NEXT I: GOTO 580\n500 FOR I=4 TO 7: P$(I,I-1)=\"\\\": NEXT I: GOTO 580\n510 P$(4,11)=\"/\": P$(5,10)=\"/\": P$(6,9)=\"/\": P$(7,8)=\"/\": GOTO 580\n520 P$(10,6)=\"/\": P$(11,5)=\"/\": GOTO 580\n530 P$(10,8)=\"\\\": P$(11,9)=\"\\\": GOTO 580\n540 P$(3,11)=\"\\\": GOTO 580\n550 P$(3,3)=\"/\": GOTO 580\n560 P$(12,10)=\"\\\": P$(12,11)=\"-\": GOTO 580\n570 P$(12,3)=\"-\": P$(12,4)=\"/\"\n580 FOR I=1 TO 12: FOR J=1 TO 12: PRINT P$(I,J);: NEXT J\n590 PRINT: NEXT I: PRINT: PRINT: IF M<>10 THEN 170\n600 PRINT \"SORRY, YOU LOSE.  THE WORD WAS \";A$\n610 PRINT \"YOU MISSED THAT ONE.  DO YOU \";: GOTO 370\n620 INPUT \"TYPE YES OR NO\";Y$: IF LEFT$(Y$,1)=\"Y\" THEN 50\n700 DATA \"GUM\",\"SIN\",\"FOR\",\"CRY\",\"LUG\",\"BYE\",\"FLY\"\n710 DATA \"UGLY\",\"EACH\",\"FROM\",\"WORK\",\"TALK\",\"WITH\",\"SELF\"\n720 DATA \"PIZZA\",\"THING\",\"FEIGN\",\"FIEND\",\"ELBOW\",\"FAULT\",\"DIRTY\"\n730 DATA \"BUDGET\",\"SPIRIT\",\"QUAINT\",\"MAIDEN\",\"ESCORT\",\"PICKAX\"\n740 DATA \"EXAMPLE\",\"TENSION\",\"QUININE\",\"KIDNEY\",\"REPLICA\",\"SLEEPER\"\n750 DATA \"TRIANGLE\",\"KANGAROO\",\"MAHOGANY\",\"SERGEANT\",\"SEQUENCE\"\n760 DATA \"MOUSTACHE\",\"DANGEROUS\",\"SCIENTIST\",\"DIFFERENT\",\"QUIESCENT\"\n770 DATA \"MAGISTRATE\",\"ERRONEOUSLY\",\"LOUDSPEAKER\",\"PHYTOTOXIC\"\n780 DATA \"MATRIMONIAL\",\"PARASYMPATHOMIMETIC\",\"THIGMOTROPISM\"\n990 PRINT \"BYE NOW\"\n999 END\n"
  },
  {
    "path": "44_Hangman/java/Hangman.java",
    "content": "import java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Scanner;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * HANGMAN\n *\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\n\npublic class Hangman {\n\n\t//50 word list\n\tprivate final static List<String> words = List.of(\n\t\t\t\"GUM\", \"SIN\", \"FOR\", \"CRY\", \"LUG\", \"BYE\", \"FLY\",\n\t\t\t\"UGLY\", \"EACH\", \"FROM\", \"WORK\", \"TALK\", \"WITH\", \"SELF\",\n\t\t\t\"PIZZA\", \"THING\", \"FEIGN\", \"FIEND\", \"ELBOW\", \"FAULT\", \"DIRTY\",\n\t\t\t\"BUDGET\", \"SPIRIT\", \"QUAINT\", \"MAIDEN\", \"ESCORT\", \"PICKAX\",\n\t\t\t\"EXAMPLE\", \"TENSION\", \"QUININE\", \"KIDNEY\", \"REPLICA\", \"SLEEPER\",\n\t\t\t\"TRIANGLE\", \"KANGAROO\", \"MAHOGANY\", \"SERGEANT\", \"SEQUENCE\",\n\t\t\t\"MOUSTACHE\", \"DANGEROUS\", \"SCIENTIST\", \"DIFFERENT\", \"QUIESCENT\",\n\t\t\t\"MAGISTRATE\", \"ERRONEOUSLY\", \"LOUDSPEAKER\", \"PHYTOTOXIC\",\n\t\t\t\"MATRIMONIAL\", \"PARASYMPATHOMIMETIC\", \"THIGMOTROPISM\");\n\n\tpublic static void main(String[] args) {\n\t\tScanner scan = new Scanner(System.in);\n\n\t\tprintIntro();\n\n\t\tint[] usedWords = new int[50];\n\t\tint roundNumber = 1;\n\t\tint totalWords = words.size();\n\t\tboolean continueGame = false;\n\n\t\tdo {\n\t\t\tif (roundNumber > totalWords) {\n\t\t\t\tSystem.out.println(\"\\nYOU DID ALL THE WORDS!!\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tint randomWordIndex;\n\t\t\tdo {\n\t\t\t\trandomWordIndex = ((int) (totalWords * Math.random())) + 1;\n\t\t\t} while (usedWords[randomWordIndex] == 1);\n\t\t\tusedWords[randomWordIndex] = 1;\n\n\t\t\tboolean youWon = playRound(scan, words.get(randomWordIndex - 1));\n\t\t\tif (!youWon) {\n\t\t\t\tSystem.out.print(\"\\nYOU MISSED THAT ONE.  DO YOU WANT ANOTHER WORD? \");\n\t\t\t} else {\n\t\t\t\tSystem.out.print(\"\\nWANT ANOTHER WORD? \");\n\t\t\t}\n\t\t\tfinal String anotherWordChoice = scan.next();\n\n\t\t\tif (anotherWordChoice.toUpperCase().equals(\"YES\") || anotherWordChoice.toUpperCase().equals(\"Y\")) {\n\t\t\t\tcontinueGame = true;\n\t\t\t}\n\t\t\troundNumber++;\n\t\t} while (continueGame);\n\n\t\tSystem.out.println(\"\\nIT'S BEEN FUN!  BYE FOR NOW.\");\n\t}\n\n\tprivate static boolean playRound(Scanner scan, String word) {\n\t\tchar[] letters;\n\t\tchar[] discoveredLetters;\n\t\tint misses = 0;\n\t\tSet<Character> lettersUsed = new LinkedHashSet<>();//LinkedHashSet maintains the order of characters inserted\n\n\t\tString[][] hangmanPicture = new String[12][12];\n\t\t//initialize the hangman picture\n\t\tfor (int i = 0; i < hangmanPicture.length; i++) {\n\t\t\tfor (int j = 0; j < hangmanPicture[i].length; j++) {\n\t\t\t\thangmanPicture[i][j] = \" \";\n\t\t\t}\n\t\t}\n\t\tfor (int i = 0; i < hangmanPicture.length; i++) {\n\t\t\thangmanPicture[i][0] = \"X\";\n\t\t}\n\t\tfor (int i = 0; i < 7; i++) {\n\t\t\thangmanPicture[0][i] = \"X\";\n\t\t}\n\t\thangmanPicture[1][6] = \"X\";\n\n\t\tint totalWordGuesses = 0; //guesses\n\n\t\tint len = word.length();\n\t\tletters = word.toCharArray();\n\n\t\tdiscoveredLetters = new char[len];\n\t\tArrays.fill(discoveredLetters, '-');\n\n\t\tboolean validNextGuess = false;\n\t\tchar guessLetter = ' ';\n\n\t\twhile (misses < 10) {\n\t\t\twhile (!validNextGuess) {\n\t\t\t\tprintLettersUsed(lettersUsed);\n\t\t\t\tprintDiscoveredLetters(discoveredLetters);\n\n\t\t\t\tSystem.out.print(\"WHAT IS YOUR GUESS? \");\n\t\t\t\tvar tmpRead = scan.next();\n\t\t\t\tguessLetter = Character.toUpperCase(tmpRead.charAt(0));\n\t\t\t\tif (lettersUsed.contains(guessLetter)) {\n\t\t\t\t\tSystem.out.println(\"YOU GUESSED THAT LETTER BEFORE!\");\n\t\t\t\t} else {\n\t\t\t\t\tlettersUsed.add(guessLetter);\n\t\t\t\t\ttotalWordGuesses++;\n\t\t\t\t\tvalidNextGuess = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (word.indexOf(guessLetter) >= 0) {\n\t\t\t\t//replace all occurrences in D$ with G$\n\t\t\t\tfor (int i = 0; i < letters.length; i++) {\n\t\t\t\t\tif (letters[i] == guessLetter) {\n\t\t\t\t\t\tdiscoveredLetters[i] = guessLetter;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//check if the word is fully discovered\n\t\t\t\tboolean isWordDiscovered = true;\n\t\t\t\tfor (char discoveredLetter : discoveredLetters) {\n\t\t\t\t\tif (discoveredLetter == '-') {\n\t\t\t\t\t\tisWordDiscovered = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isWordDiscovered) {\n\t\t\t\t\tSystem.out.println(\"YOU FOUND THE WORD!\");\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tprintDiscoveredLetters(discoveredLetters);\n\t\t\t\tSystem.out.print(\"WHAT IS YOUR GUESS FOR THE WORD? \");\n\t\t\t\tfinal String wordGuess = scan.next();\n\t\t\t\tif (wordGuess.toUpperCase().equals(word)) {\n\t\t\t\t\tSystem.out.printf(\"RIGHT!!  IT TOOK YOU %s GUESSES!\", totalWordGuesses);\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\tSystem.out.println(\"WRONG.  TRY ANOTHER LETTER.\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmisses = misses + 1;\n\t\t\t\tSystem.out.println(\"\\n\\nSORRY, THAT LETTER ISN'T IN THE WORD.\");\n\t\t\t\tdrawHangman(misses, hangmanPicture);\n\t\t\t}\n\t\t\tvalidNextGuess = false;\n\t\t}\n\n\t\tSystem.out.printf(\"SORRY, YOU LOSE.  THE WORD WAS %s\", word);\n\t\treturn false;\n\t}\n\n\tprivate static void drawHangman(int m, String[][] hangmanPicture) {\n\t\tswitch (m) {\n\t\t\tcase 1:\n\t\t\t\tSystem.out.println(\"FIRST, WE DRAW A HEAD\");\n\t\t\t\thangmanPicture[2][5] = \"-\";\n\t\t\t\thangmanPicture[2][6] = \"-\";\n\t\t\t\thangmanPicture[2][7] = \"-\";\n\t\t\t\thangmanPicture[3][4] = \"(\";\n\t\t\t\thangmanPicture[3][5] = \".\";\n\t\t\t\thangmanPicture[3][7] = \".\";\n\t\t\t\thangmanPicture[3][8] = \")\";\n\t\t\t\thangmanPicture[4][5] = \"-\";\n\t\t\t\thangmanPicture[4][6] = \"-\";\n\t\t\t\thangmanPicture[4][7] = \"-\";\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tSystem.out.println(\"NOW WE DRAW A BODY.\");\n\t\t\t\tfor (var i = 5; i <= 8; i++) {\n\t\t\t\t\thangmanPicture[i][6] = \"X\";\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tSystem.out.println(\"NEXT WE DRAW AN ARM.\");\n\t\t\t\tfor (int i = 3; i <= 6; i++) {\n\t\t\t\t\thangmanPicture[i][i - 1] = \"\\\\\";\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tSystem.out.println(\"THIS TIME IT'S THE OTHER ARM.\");\n\t\t\t\thangmanPicture[3][10] = \"/\";\n\t\t\t\thangmanPicture[4][9] = \"/\";\n\t\t\t\thangmanPicture[5][8] = \"/\";\n\t\t\t\thangmanPicture[6][7] = \"/\";\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tSystem.out.println(\"NOW, LET'S DRAW THE RIGHT LEG.\");\n\t\t\t\thangmanPicture[9][5] = \"/\";\n\t\t\t\thangmanPicture[10][4] = \"/\";\n\t\t\t\tbreak;\n\t\t\tcase 6:\n\t\t\t\tSystem.out.println(\"THIS TIME WE DRAW THE LEFT LEG.\");\n\t\t\t\thangmanPicture[9][7] = \"\\\\\";\n\t\t\t\thangmanPicture[10][8] = \"\\\\\";\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\t\tSystem.out.println(\"NOW WE PUT UP A HAND.\");\n\t\t\t\thangmanPicture[2][10] = \"\\\\\";\n\t\t\t\tbreak;\n\t\t\tcase 8:\n\t\t\t\tSystem.out.println(\"NEXT THE OTHER HAND.\");\n\t\t\t\thangmanPicture[2][2] = \"/\";\n\t\t\t\tbreak;\n\t\t\tcase 9:\n\t\t\t\tSystem.out.println(\"NOW WE DRAW ONE FOOT\");\n\t\t\t\thangmanPicture[11][9] = \"\\\\\";\n\t\t\t\thangmanPicture[11][10] = \"-\";\n\t\t\t\tbreak;\n\t\t\tcase 10:\n\t\t\t\tSystem.out.println(\"HERE'S THE OTHER FOOT -- YOU'RE HUNG!!\");\n\t\t\t\thangmanPicture[11][2] = \"-\";\n\t\t\t\thangmanPicture[11][3] = \"/\";\n\t\t\t\tbreak;\n\t\t}\n\t\tfor (int i = 0; i <= 11; i++) {\n\t\t\tfor (int j = 0; j <= 11; j++) {\n\t\t\t\tSystem.out.print(hangmanPicture[i][j]);\n\t\t\t}\n\t\t\tSystem.out.print(\"\\n\");\n\t\t}\n\n\t}\n\n\tprivate static void printDiscoveredLetters(char[] D$) {\n\t\tSystem.out.println(new String(D$));\n\t\tSystem.out.println(\"\\n\");\n\t}\n\n\tprivate static void printLettersUsed(Set<Character> lettersUsed) {\n\t\tSystem.out.println(\"\\nHERE ARE THE LETTERS YOU USED:\");\n\t\tSystem.out.println(lettersUsed.stream()\n\t\t\t\t.map(Object::toString).collect(Collectors.joining(\",\")));\n\t\tSystem.out.println(\"\\n\");\n\t}\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                HANGMAN\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\\n\");\n\t}\n\n}\n"
  },
  {
    "path": "44_Hangman/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "44_Hangman/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "44_Hangman/javascript/hangman.html",
    "content": "<html>\n<head>\n<title>HANGMAN</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hangman.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "44_Hangman/javascript/hangman.js",
    "content": "// HANGMAN\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nprint(tab(32) + \"HANGMAN\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\nprint(\"\\n\");\n\nvar pa = [];\nvar la = [];\nvar da = [];\nvar na = [];\nvar ua = [];\n\nvar words = [\"GUM\",\"SIN\",\"FOR\",\"CRY\",\"LUG\",\"BYE\",\"FLY\",\n             \"UGLY\",\"EACH\",\"FROM\",\"WORK\",\"TALK\",\"WITH\",\"SELF\",\n             \"PIZZA\",\"THING\",\"FEIGN\",\"FIEND\",\"ELBOW\",\"FAULT\",\"DIRTY\",\n             \"BUDGET\",\"SPIRIT\",\"QUAINT\",\"MAIDEN\",\"ESCORT\",\"PICKAX\",\n             \"EXAMPLE\",\"TENSION\",\"QUININE\",\"KIDNEY\",\"REPLICA\",\"SLEEPER\",\n             \"TRIANGLE\",\"KANGAROO\",\"MAHOGANY\",\"SERGEANT\",\"SEQUENCE\",\n             \"MOUSTACHE\",\"DANGEROUS\",\"SCIENTIST\",\"DIFFERENT\",\"QUIESCENT\",\n             \"MAGISTRATE\",\"ERRONEOUSLY\",\"LOUDSPEAKER\",\"PHYTOTOXIC\",\n             \"MATRIMONIAL\",\"PARASYMPATHOMIMETIC\",\"THIGMOTROPISM\"];\n\n// Main control section\nasync function main()\n{\n    c = 1;\n    n = 50;\n    while (1) {\n        for (i = 1; i <= 20; i++)\n            da[i] = \"-\";\n        for (i = 1; i <= n; i++)\n            ua[i] = 0;\n        m = 0;\n        ns = \"\";\n        for (i = 1; i <= 12; i++) {\n            pa[i] = [];\n            for (j = 1; j <= 12; j++) {\n                pa[i][j] = \" \";\n            }\n        }\n        for (i = 1; i <= 12; i++) {\n            pa[i][1] = \"X\";\n        }\n        for (i = 1; i <= 7; i++) {\n            pa[1][i] = \"X\";\n        }\n        pa[2][7] = \"X\";\n        if (c >= n) {\n            print(\"YOU DID ALL THE WORDS!!\\n\");\n            break;\n        }\n        do {\n            q = Math.floor(n * Math.random()) + 1;\n        } while (ua[q] == 1) ;\n        ua[q] = 1;\n        c++;\n        t1 = 0;\n        as = words[q - 1];\n        l = as.length;\n        for (i = 1; i <= as.length; i++)\n            la[i] = as[i - 1];\n        while (1) {\n            while (1) {\n                print(\"HERE ARE THE LETTERS YOU USED:\\n\");\n                print(ns + \"\\n\");\n                print(\"\\n\");\n                for (i = 1; i <= l; i++) {\n                    print(da[i]);\n                }\n                print(\"\\n\");\n                print(\"\\n\");\n                print(\"WHAT IS YOUR GUESS\");\n                str = await input();\n                if (ns.indexOf(str) != -1) {\n                    print(\"YOU GUESSED THAT LETTER BEFORE!\\n\");\n                } else {\n                    break;\n                }\n            }\n            ns += str;\n            t1++;\n            r = 0;\n            for (i = 1; i <= l; i++) {\n                if (la[i] == str) {\n                    da[i] = str;\n                    r++;\n                }\n            }\n            if (r == 0) {\n                m++;\n                print(\"\\n\");\n                print(\"\\n\");\n                print(\"SORRY, THAT LETTER ISN'T IN THE WORD.\\n\");\n                switch (m) {\n                    case 1:\n                        print(\"FIRST, WE DRAW A HEAD\\n\");\n                        break;\n                    case 2:\n                        print(\"NOW WE DRAW A BODY.\\n\");\n                        break;\n                    case 3:\n                        print(\"NEXT WE DRAW AN ARM.\\n\");\n                        break;\n                    case 4:\n                        print(\"THIS TIME IT'S THE OTHER ARM.\\n\");\n                        break;\n                    case 5:\n                        print(\"NOW, LET'S DRAW THE RIGHT LEG.\\n\");\n                        break;\n                    case 6:\n                        print(\"THIS TIME WE DRAW THE LEFT LEG.\\n\");\n                        break;\n                    case 7:\n                        print(\"NOW WE PUT UP A HAND.\\n\");\n                        break;\n                    case 8:\n                        print(\"NEXT THE OTHER HAND.\\n\");\n                        break;\n                    case 9:\n                        print(\"NOW WE DRAW ONE FOOT.\\n\");\n                        break;\n                    case 10:\n                        print(\"HERE'S THE OTHER FOOT -- YOU'RE HUNG!!\\n\");\n                        break;\n                }\n                switch (m) {\n                    case 1:\n                        pa[3][6] = \"-\";\n                        pa[3][7] = \"-\";\n                        pa[3][8] = \"-\";\n                        pa[4][5] = \"(\";\n                        pa[4][6] = \".\";\n                        pa[4][8] = \".\";\n                        pa[4][9] = \")\";\n                        pa[5][6] = \"-\";\n                        pa[5][7] = \"-\";\n                        pa[5][8] = \"-\";\n                        break;\n                    case 2:\n                        for (i = 6; i <= 9; i++)\n                            pa[i][7] = \"X\";\n                        break;\n                    case 3:\n                        for (i = 4; i <= 7; i++)\n                            pa[i][i - 1] = \"\\\\\";\n                        break;\n                    case 4:\n                        pa[4][11] = \"/\";\n                        pa[5][10] = \"/\";\n                        pa[6][9] = \"/\";\n                        pa[7][8] = \"/\";\n                        break;\n                    case 5:\n                        pa[10][6] = \"/\";\n                        pa[11][5] = \"/\";\n                        break;\n                    case 6:\n                        pa[10][8] = \"\\\\\";\n                        pa[11][9] = \"\\\\\";\n                        break;\n                    case 7:\n                        pa[3][11] = \"\\\\\";\n                        break;\n                    case 8:\n                        pa[3][3] = \"/\";\n                        break;\n                    case 9:\n                        pa[12][10] = \"\\\\\";\n                        pa[12][11] = \"-\";\n                        break;\n                    case 10:\n                        pa[12][3] = \"-\";\n                        pa[12][4] = \"/\";\n                        break;\n                }\n                for (i = 1; i <= 12; i++) {\n                    str = \"\";\n                    for (j = 1; j <= 12; j++)\n                        str += pa[i][j];\n                    print(str + \"\\n\");\n                }\n                print(\"\\n\");\n                print(\"\\n\");\n                if (m == 10) {\n                    print(\"SORRY, YOU LOSE.  THE WORD WAS \" + as + \"\\n\");\n                    print(\"YOU MISSED THAT ONE.  DO YOU \");\n                    break;\n                }\n            } else {\n                for (i = 1; i <= l; i++)\n                    if (da[i] == \"-\")\n                        break;\n                if (i > l) {\n                    print(\"YOU FOUND THE WORD!\\n\");\n                    break;\n                }\n                print(\"\\n\");\n                for (i = 1; i <= l; i++)\n                    print(da[i]);\n                print(\"\\n\");\n                print(\"\\n\");\n                print(\"WHAT IS YOUR GUESS FOR THE WORD\");\n                bs = await input();\n                if (as == bs) {\n                    print(\"RIGHT!!  IT TOOK YOU \" + t1 + \" GUESSES!\\n\");\n                    break;\n                }\n                print(\"WRONG.  TRY ANOTHER LETTER.\\n\");\n                print(\"\\n\");\n            }\n        }\n        print(\"WANT ANOTHER WORD\");\n        str = await input();\n        if (str != \"YES\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"IT'S BEEN FUN!  BYE FOR NOW.\\n\");\n    // Lines 620 and 990 unused in original\n}\n\nmain();\n"
  },
  {
    "path": "44_Hangman/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "44_Hangman/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "44_Hangman/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "44_Hangman/perl/hangman.pl",
    "content": "#!/usr/bin/perl\r\n\r\nuse strict;\r\nuse warnings;\r\n\r\n\r\n# global variables defined here\r\n\r\nmy(@WORDS) = qw(\r\n    GUM SIN FOR CRY LUG BYE FLY\r\n    UGLY EACH FROM WORK TALK WITH SELF\r\n    PIZZA THING FEIGN FIEND ELBOW FAULT DIRTY\r\n    BUDGET SPIRIT QUAINT MAIDEN ESCORT PICKAX\r\n    EXAMPLE TENSION QUININE KIDNEY REPLICA SLEEPER\r\n    TRIANGLE KANGAROO MAHOGANY SERGEANT SEQUENCE\r\n    MOUSTACHE DANGEROUS SCIENTIST DIFFERENT QUIESCENT\r\n    MAGISTRATE ERRONEOUSLY LOUDSPEAKER PHYTOTOXIC\r\n    MATRIMONIAL PARASYMPATHOMIMETIC THIGMOTROPISM\r\n);\r\nmy(@PIC,$board,@guessedLetters,$guessCount,$hangCount);\r\nmy(%GUESSED);\r\n\r\n# Subroutines defined here.\r\n\r\n# init_variables: initialize all of the variables needed\r\n# (this covers lines 50-90 in the original BASIC program)\r\n\r\nsub init_variables {\r\n    @guessedLetters = ();\r\n    @PIC = (\r\n        'XXXXXXX     ',\r\n        'X     X     ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n        'X           ',\r\n    );\r\n    $guessCount = 0; %GUESSED = ();\r\n    $hangCount = 0;\r\n}\r\n\r\n# addchar: given a row & column, put the specified char in that place in @PIC\r\nsub addchar {\r\n    my($row,$col, $c) = @_;\r\n\r\n    substr($PIC[$row],$col,1) = $c;\r\n}\r\n\r\n\r\n# main code starts here\r\n\r\nprint ' 'x31; print \"Hangman\\n\";\r\nprint ' 'x14; print \"Creative Computing  Morristown, New Jersey\\n\\n\\n\\n\";\r\n\r\n# an iteration of the PLAY block is one complete game.\r\n# There is a continue block that will ask if the user\r\n# wants to play another game.\r\n\r\nPLAY: while (1) {\r\n\r\n    init_variables();\r\n    # Any words left?\r\n    if (@WORDS == 0) {\r\n        print \"You did all the words!\\n\";\r\n        last PLAY;\r\n    }\r\n    # splice a random word out of the @WORDS array\r\n    my($thisWord) = splice(@WORDS, int(rand(scalar @WORDS)),1);\r\n    # $board is the \"game board\" of the filled-out word\r\n    # that the user is working on\r\n    $board = '.'x(length $thisWord);\r\n\r\n    # GUESS loop is run for every time the user guesses a letter\r\n    GUESS: while(1) {\r\n        print \"Here are the letters you used:\\n\";\r\n        printf(\"%s\\n\", join(',',@guessedLetters));\r\n        printf(\"\\n\\n%s\\n\", $board);\r\n\r\n        print \"What is your guess for a letter ? \";\r\n        chomp(my $guess = <STDIN>);\r\n        # The %GUESSED hash allows us to quickly identify\r\n        # letters that have already been guessed\r\n        if ($GUESSED{lc $guess}) {\r\n            print \"You guessed that letter before!\\n\\n\";\r\n            redo GUESS;\r\n        }\r\n\r\n        # save the guessed letter\r\n        push @guessedLetters, $guess;\r\n        $GUESSED{lc $guess} = 1;\r\n        ++$guessCount;\r\n\r\n        # now look for the letter in the $thisWord var\r\n        # and put it into the $board var wherever it\r\n        # shows up. $foundLetter is a flag that indicates\r\n        # whether or not the letter is found.\r\n        my $foundLetter = 0;\r\n        for (my $i = 0; $i < length $thisWord; ++$i) {\r\n            if (lc substr($thisWord,$i,1) eq lc $guess) {\r\n                $foundLetter = 1;\r\n                substr($board, $i, 1) = substr($thisWord, $i, 1);\r\n            }\r\n        }\r\n\r\n        # The user found a letter in the solution!\r\n        if ($foundLetter) {\r\n\r\n            # Are there any '.' chars left in the board?\r\n            if (index($board, '.') < 0) {\r\n                print \"You found the word!\\n\\n\";\r\n            } else {\r\n                printf(\"%s\\n\\n\", $board);\r\n                print \"What is your guess for the word ? \";\r\n                chomp(my $guessword = <STDIN>);\r\n                if (lc $thisWord ne lc $guessword) {\r\n                    print \"Wrong.  Try another letter.\\n\";\r\n                    # Go to the next iteration of the GUESS loop\r\n                    next GUESS;\r\n                }\r\n                printf(\"Right! It took you %d %s!\\n\", $guessCount, ($guessCount == 1 ? 'guess' : 'guesses'));\r\n            }\r\n            # At this point the user has discovered the word and won.\r\n            # This \"next\" statement takes execution down to the\r\n            # continue block for the PLAY loop;\r\n            next PLAY;\r\n\r\n        } else {  # didn't find a letter\r\n\r\n            ++$hangCount;\r\n            print \"\\n\\n\\nSorry, that letter isn't in the word.\\n\";\r\n\r\n            # The addchar() calls in the block below piece together the\r\n            # hangman graphic, depending on how many wrong letters\r\n            # the user has.\r\n            if ($hangCount == 1) {\r\n                print \"First, we draw a head\\n\";\r\n                addchar(2,5,\"-\");addchar(2,6,\"-\");addchar(2,7,\"-\");\r\n                addchar(3,4,\"(\"); addchar(3,5,\".\"); addchar(3,7,\".\"); addchar(3,8,\")\");\r\n                addchar(4,5,\"-\");addchar(4,6,\"-\");addchar(4,7,\"-\");\r\n            }\r\n            if ($hangCount == 2) {\r\n                print \"Now we draw a body.\\n\";\r\n                for (5 .. 8) {\r\n                    addchar($_, 6, \"X\");\r\n                }\r\n            }\r\n            if ($hangCount == 3) {\r\n                print \"Next we draw an arm.\\n\";\r\n                for (3 .. 6) {\r\n                    addchar($_, $_-1, \"\\\\\");\r\n                }\r\n            }\r\n            if ($hangCount == 4) {\r\n                print \"This time it's the other arm.\\n\";\r\n                addchar(3,10, \"/\");\r\n                addchar(4, 9, \"/\");\r\n                addchar(5, 8, \"/\");\r\n                addchar(6, 7, \"/\");\r\n            }\r\n            if ($hangCount == 5) {\r\n                print \"Now, let's draw the right leg.\\n\";\r\n                addchar( 9,5, \"/\");\r\n                addchar(10,4, \"/\");\r\n            }\r\n            if ($hangCount == 6) {\r\n                print \"This time we draw the left leg.\\n\";\r\n                addchar(9,7,\"\\\\\");\r\n                addchar(10,8,\"\\\\\");\r\n            }\r\n            if ($hangCount == 7) {\r\n                print \"Now we put up a hand.\\n\";\r\n                addchar(2,10,\"\\\\\");\r\n            }\r\n            if ($hangCount == 8) {\r\n                print \"Next the other hand.\\n\";\r\n                addchar(2,2,\"/\");\r\n            }\r\n            if ($hangCount == 9) {\r\n                print \"Now we draw one foot\\n\";\r\n                addchar(11,9,\"\\\\\");\r\n                addchar(11,10, \"-\");\r\n            }\r\n            if ($hangCount == 10) {\r\n                print \"Here's the other foot -- you're hung!!\\n\";\r\n                addchar(11,2,\"-\");\r\n                addchar(11,3, \"/\");\r\n            }\r\n\r\n            printf(\"$_\\n\") for @PIC;\r\n            print \"\\n\\n\";\r\n\r\n            # Next guess if the user has not lost\r\n            if ($hangCount < 10) {\r\n                next GUESS;\r\n            }\r\n\r\n            printf(\"Sorry, you lose.  The word was %s\\n\", $thisWord);\r\n            next PLAY;\r\n\r\n        } # didn't find a letter block\r\n    } # GUESS block\r\n} # PLAY block\r\n\r\n# This block is reached either by the player winning (see the \"next PLAY\")\r\n# statement) or by the user losing (as the PLAY block is complete and\r\n# execution naturally comes to this continue block).\r\ncontinue {\r\n    print \"Want another word ? \";\r\n    chomp(my $in = <STDIN>);\r\n    if ($in !~ m/^y/i) {\r\n        # Exit the PLAY loop\r\n        print \"\\nIt's been fun!  Bye for now.\\n\\n\";\r\n        last PLAY;\r\n    }\r\n    # At this point execution goes to the start of the PLAY block,\r\n    # meaning a new game\r\n}\r\n"
  },
  {
    "path": "44_Hangman/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "44_Hangman/python/hangman.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nHANGMAN\n\nConverted from BASIC to Python by Trevor Hobson and Daniel Piron\n\"\"\"\n\nimport random\nfrom typing import List\n\n\nclass Canvas:\n    \"\"\"For drawing text-based figures\"\"\"\n\n    def __init__(self, width: int = 12, height: int = 12, fill: str = \" \") -> None:\n        self._buffer = []\n        for _ in range(height):\n            line = [\"\" for _ in range(width)]\n            self._buffer.append(line)\n\n        self.clear()\n\n    def clear(self, fill: str = \" \") -> None:\n        for row in self._buffer:\n            for x in range(len(row)):\n                row[x] = fill\n\n    def render(self) -> str:\n        lines = [\"\".join(line) for line in self._buffer]\n        return \"\\n\".join(lines)\n\n    def put(self, s: str, x: int, y: int) -> None:\n        # In an effort to avoid distorting the drawn image, only write the\n        # first character of the given string to the buffer.\n        self._buffer[y][x] = s[0]\n\n\ndef init_gallows(canvas: Canvas) -> None:\n    for i in range(12):\n        canvas.put(\"X\", 0, i)\n    for i in range(7):\n        canvas.put(\"X\", i, 0)\n    canvas.put(\"X\", 6, 1)\n\n\ndef draw_head(canvas: Canvas) -> None:\n    canvas.put(\"-\", 5, 2)\n    canvas.put(\"-\", 6, 2)\n    canvas.put(\"-\", 7, 2)\n    canvas.put(\"(\", 4, 3)\n    canvas.put(\".\", 5, 3)\n    canvas.put(\".\", 7, 3)\n    canvas.put(\")\", 8, 3)\n    canvas.put(\"-\", 5, 4)\n    canvas.put(\"-\", 6, 4)\n    canvas.put(\"-\", 7, 4)\n\n\ndef draw_body(canvas: Canvas) -> None:\n    for i in range(5, 9, 1):\n        canvas.put(\"X\", 6, i)\n\n\ndef draw_right_arm(canvas: Canvas) -> None:\n    for i in range(3, 7):\n        canvas.put(\"\\\\\", i - 1, i)\n\n\ndef draw_left_arm(canvas: Canvas) -> None:\n    canvas.put(\"/\", 10, 3)\n    canvas.put(\"/\", 9, 4)\n    canvas.put(\"/\", 8, 5)\n    canvas.put(\"/\", 7, 6)\n\n\ndef draw_right_leg(canvas: Canvas) -> None:\n    canvas.put(\"/\", 5, 9)\n    canvas.put(\"/\", 4, 10)\n\n\ndef draw_left_leg(canvas: Canvas) -> None:\n    canvas.put(\"\\\\\", 7, 9)\n    canvas.put(\"\\\\\", 8, 10)\n\n\ndef draw_left_hand(canvas: Canvas) -> None:\n    canvas.put(\"\\\\\", 10, 2)\n\n\ndef draw_right_hand(canvas: Canvas) -> None:\n    canvas.put(\"/\", 2, 2)\n\n\ndef draw_left_foot(canvas: Canvas) -> None:\n    canvas.put(\"\\\\\", 9, 11)\n    canvas.put(\"-\", 10, 11)\n\n\ndef draw_right_foot(canvas: Canvas) -> None:\n    canvas.put(\"-\", 2, 11)\n    canvas.put(\"/\", 3, 11)\n\n\nPHASES = (\n    (\"First, we draw a head\", draw_head),\n    (\"Now we draw a body.\", draw_body),\n    (\"Next we draw an arm.\", draw_right_arm),\n    (\"this time it's the other arm.\", draw_left_arm),\n    (\"Now, let's draw the right leg.\", draw_right_leg),\n    (\"This time we draw the left leg.\", draw_left_leg),\n    (\"Now we put up a hand.\", draw_left_hand),\n    (\"Next the other hand.\", draw_right_hand),\n    (\"Now we draw one foot\", draw_left_foot),\n    (\"Here's the other foot -- you're hung!!\", draw_right_foot),\n)\n\n\nwords = [\n    \"GUM\",\n    \"SIN\",\n    \"FOR\",\n    \"CRY\",\n    \"LUG\",\n    \"BYE\",\n    \"FLY\",\n    \"UGLY\",\n    \"EACH\",\n    \"FROM\",\n    \"WORK\",\n    \"TALK\",\n    \"WITH\",\n    \"SELF\",\n    \"PIZZA\",\n    \"THING\",\n    \"FEIGN\",\n    \"FIEND\",\n    \"ELBOW\",\n    \"FAULT\",\n    \"DIRTY\",\n    \"BUDGET\",\n    \"SPIRIT\",\n    \"QUAINT\",\n    \"MAIDEN\",\n    \"ESCORT\",\n    \"PICKAX\",\n    \"EXAMPLE\",\n    \"TENSION\",\n    \"QUININE\",\n    \"KIDNEY\",\n    \"REPLICA\",\n    \"SLEEPER\",\n    \"TRIANGLE\",\n    \"KANGAROO\",\n    \"MAHOGANY\",\n    \"SERGEANT\",\n    \"SEQUENCE\",\n    \"MOUSTACHE\",\n    \"DANGEROUS\",\n    \"SCIENTIST\",\n    \"DIFFERENT\",\n    \"QUIESCENT\",\n    \"MAGISTRATE\",\n    \"ERRONEOUSLY\",\n    \"LOUDSPEAKER\",\n    \"PHYTOTOXIC\",\n    \"MATRIMONIAL\",\n    \"PARASYMPATHOMIMETIC\",\n    \"THIGMOTROPISM\",\n]\n\n\ndef play_game(guess_target: str) -> None:\n    \"\"\"Play one round of the game\"\"\"\n    wrong_guesses = 0\n    guess_progress = [\"-\"] * len(guess_target)\n    guess_list: List[str] = []\n\n    gallows = Canvas()\n    init_gallows(gallows)\n\n    guess_count = 0\n    while True:\n        print(\"Here are the letters you used:\")\n        print(\",\".join(guess_list) + \"\\n\")\n        print(\"\".join(guess_progress) + \"\\n\")\n        guess_letter = \"\"\n        guess_word = \"\"\n        while not guess_letter:\n\n            guess_letter = input(\"What is your guess? \").upper()[0]\n            if not guess_letter.isalpha():\n                guess_letter = \"\"\n                print(\"Only letters are allowed!\")\n            elif guess_letter in guess_list:\n                guess_letter = \"\"\n                print(\"You guessed that letter before!\")\n\n        guess_list.append(guess_letter)\n        guess_count += 1\n        if guess_letter in guess_target:\n            indices = [\n                i for i, letter in enumerate(guess_target) if letter == guess_letter\n            ]\n            for i in indices:\n                guess_progress[i] = guess_letter\n            if \"\".join(guess_progress) == guess_target:\n                print(\"You found the word!\")\n                break\n            else:\n                print(\"\\n\" + \"\".join(guess_progress) + \"\\n\")\n                while not guess_word:\n                    guess_word = input(\"What is your guess for the word? \").upper()\n                    if not guess_word.isalpha():\n                        guess_word = \"\"\n                        print(\"Only words are allowed!\")\n                if guess_word == guess_target:\n                    print(\"Right!! It took you\", guess_count, \"guesses!\")\n                    break\n        else:\n            comment, draw_bodypart = PHASES[wrong_guesses]\n\n            print(comment)\n            draw_bodypart(gallows)\n            print(gallows.render())\n\n            wrong_guesses += 1\n            print(\"Sorry, that letter isn't in the word.\")\n\n            if wrong_guesses == 10:\n                print(f\"Sorry, you lose. The word was {guess_target}\")\n                break\n\n\ndef main() -> None:\n    print(\" \" * 32 + \"HANGMAN\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n\n    random.shuffle(words)\n    current_word = 0\n    word_count = len(words)\n\n    keep_playing = True\n    while keep_playing:\n\n        play_game(words[current_word])\n        current_word += 1\n\n        if current_word == word_count:\n            print(\"You did all the words!!\")\n            keep_playing = False\n        else:\n            keep_playing = (\n                input(\"Want another word? (yes or no) \").lower().startswith(\"y\")\n            )\n\n    print(\"It's been fun! Bye for now.\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "44_Hangman/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "44_Hangman/ruby/hangman.rb",
    "content": "class Canvas\n\tBUFFER = []\n\tdef initialize width = 12, height = 12, fill = \" \"\n\t\tfor i in (0...height) do\n\t\t\tline = []\n\t\t\tfor i in (0...width) do\n\t\t\t\tline << \"\"\n\t\t\tend\n\t\t\tBUFFER << line\n\t\tend\n\n\t\tclear\n\tend\n\n\tdef render\n\t\tlines = []\n\t\tfor line in BUFFER do\n\t\t\tlines << line.join(\"\")\n\t\tend\n\n\t\treturn lines.join(\"\\n\")\n\tend\n\n\tdef put s, x, y\n\t\tBUFFER[y][x] = s[0]\n\tend\n\n\tprivate\n\t\tdef clear fill = \" \"\n\t\t\tfor row in BUFFER do\n\t\t\t\tfor x in (0...(row.length)) do\n\t\t\t\t\trow[x] = fill\n\t\t\t\tend\n\t\t\tend\n\t\tend\nend\n\ndef init_gallows canvas\n\tfor i in (0...12) do\n\t\tcanvas.put(\"X\", 0, i)\n\tend\n\n\tfor i in (0...7) do\n\t\tcanvas.put(\"X\", i, 0)\n\tend\n\n\tcanvas.put(\"X\", 6, 1)\nend\n\ndef draw_head canvas\n\tcanvas.put(\"-\", 5, 2)\n\tcanvas.put(\"-\", 6, 2)\n\tcanvas.put(\"-\", 7, 2)\n\tcanvas.put(\"(\", 4, 3)\n\tcanvas.put(\".\", 5, 3)\n\tcanvas.put(\".\", 7, 3)\n\tcanvas.put(\")\", 8, 3)\n\tcanvas.put(\"-\", 5, 4)\n\tcanvas.put(\"-\", 6, 4)\n\tcanvas.put(\"-\", 7, 4)\nend\n\ndef draw_body canvas\n\tfor i in (5...9) do\n\t\tcanvas.put(\"X\", 6, i)\n\tend\nend\n\ndef draw_right_arm canvas\n\tfor i in (3...8) do\n\t\tcanvas.put(\"\\\\\", i - 1, i)\n\tend\nend\n\ndef draw_left_arm canvas\n\tcanvas.put(\"/\", 10, 3)\n\tcanvas.put(\"/\", 9, 4)\n\tcanvas.put(\"/\", 8, 5)\n\tcanvas.put(\"/\", 7, 6)\nend\n\ndef draw_right_leg canvas\n\tcanvas.put(\"/\", 5, 9)\n\tcanvas.put(\"/\", 4, 10)\nend\n\ndef draw_left_leg canvas\n\tcanvas.put(\"\\\\\", 7, 9)\n\tcanvas.put(\"\\\\\", 8, 10)\nend\n\ndef draw_left_hand canvas\n\tcanvas.put(\"\\\\\", 10, 2)\nend\n\ndef draw_right_hand canvas\n\tcanvas.put(\"/\", 2, 2)\nend\n\ndef draw_left_foot canvas\n\tcanvas.put(\"\\\\\", 9, 11)\n\tcanvas.put(\"-\", 10, 11)\nend\n\ndef draw_right_foot canvas\n\tcanvas.put(\"-\", 2, 11)\n\tcanvas.put(\"/\", 3, 11)\nend\n\nPHASES = [\n\t[\"First, we draw a head\", 'draw_head'],\n\t[\"Now we draw a body.\", 'draw_body'],\n\t[\"Next we draw an arm.\", 'draw_right_arm'],\n\t[\"this time it's the other arm.\", 'draw_left_arm'],\n\t[\"Now, let's draw the right leg.\", 'draw_right_leg'],\n\t[\"This time we draw the left leg.\", 'draw_left_leg'],\n\t[\"Now we put up a hand.\", 'draw_left_hand'],\n\t[\"Next the other hand.\", 'draw_right_hand'],\n\t[\"Now we draw one foot\", 'draw_left_foot'],\n\t[\"Here's the other foot -- you're hung!!\", 'draw_right_foot'],\n]\n\nWORDS = [\n\t\"GUM\",\n\t\"SIN\",\n\t\"FOR\",\n\t\"CRY\",\n\t\"LUG\",\n\t\"BYE\",\n\t\"FLY\",\n\t\"UGLY\",\n\t\"EACH\",\n\t\"FROM\",\n\t\"WORK\",\n\t\"TALK\",\n\t\"WITH\",\n\t\"SELF\",\n\t\"PIZZA\",\n\t\"THING\",\n\t\"FEIGN\",\n\t\"FIEND\",\n\t\"ELBOW\",\n\t\"FAULT\",\n\t\"DIRTY\",\n\t\"BUDGET\",\n\t\"SPIRIT\",\n\t\"QUAINT\",\n\t\"MAIDEN\",\n\t\"ESCORT\",\n\t\"PICKAX\",\n\t\"EXAMPLE\",\n\t\"TENSION\",\n\t\"QUININE\",\n\t\"KIDNEY\",\n\t\"REPLICA\",\n\t\"SLEEPER\",\n\t\"TRIANGLE\",\n\t\"KANGAROO\",\n\t\"MAHOGANY\",\n\t\"SERGEANT\",\n\t\"SEQUENCE\",\n\t\"MOUSTACHE\",\n\t\"DANGEROUS\",\n\t\"SCIENTIST\",\n\t\"DIFFERENT\",\n\t\"QUIESCENT\",\n\t\"MAGISTRATE\",\n\t\"ERRONEOUSLY\",\n\t\"LOUDSPEAKER\",\n\t\"PHYTOTOXIC\",\n\t\"MATRIMONIAL\",\n\t\"PARASYMPATHOMIMETIC\",\n\t\"THIGMOTROPISM\",\n]\n\ndef play_game guess_target\n\twrong_guesses = 0\n\tguess_progress = [\"-\"] * guess_target.length\n\tguess_list = []\n\n\tgallows = Canvas.new\n\tinit_gallows(gallows)\n\n\tguess_count = 0\n\twhile true\n\t\tputs \"Here are the letters you used:\"\n\t\tputs \"#{guess_list.join(\",\")}\\n\"\n\t\tputs \"#{guess_progress.join(\"\")}\\n\"\n\n\t\tguess_letter = \"\"\n\t\tguess_word = \"\"\n\t\twhile guess_letter == \"\"\n\t\t\tprint \"What is your guess? \"\n\t\t\tguess_letter = gets.chomp!.upcase[0]\n\t\t\tif !guess_letter.match?(/[[:alpha:]]/)\n\t\t\t\tguess_letter = \"\"\n\t\t\t\tputs \"Only letters are allowed!\"\n\t\t\telsif guess_list.include?(guess_letter)\n\t\t\t\tguess_letter = \"\"\n\t\t\t\tputs \"You guessed that letter before!\"\n\t\t\tend\n\t\tend\n\n\t\tguess_list << guess_letter\n\t\tguess_count += 1\n\n\t\tif guess_target.include?(guess_letter)\n\t\t\tindices = (0...guess_target.length).find_all { |i| guess_target[i,1] == guess_letter }\n\n\t\t\tfor i in indices do\n\t\t\t\tguess_progress[i] = guess_letter\n\t\t\tend\n\n\t\t\tif guess_progress.join(\"\") == guess_target\n\t\t\t\tputs \"You found the word!\"\n\t\t\t\tbreak\n\t\t\telse\n\t\t\t\tputs \"\\n#{guess_progress.join(\"\")}\\n\"\n\n\t\t\t\twhile guess_word == \"\"\n\t\t\t\t\tprint \"What is your guess for the word? \"\n\t\t\t\t\tguess_word = gets.chomp!.upcase\n\t\t\t\t\tif !guess_word.match?(/[[:alpha:]]/)\n\t\t\t\t\t\tguess_word = \"\"\n\t\t\t\t\t\tputs \"Only words are allowed!\"\n\t\t\t\t\tend\n\t\t\t\tend\n\n\t\t\t\tif guess_word == guess_target\n\t\t\t\t\tputs \"Right!! It took you #{guess_count} guesses!\"\n\t\t\t\t\tbreak\n\t\t\t\tend\n\t\t\tend\n\t\telse\n\t\t\tcomment, draw_bodypart = PHASES[wrong_guesses]\n\n\t\t\tputs comment\n\t\t\tmethod(draw_bodypart).call(gallows)\n\t\t\tputs gallows.render()\n\n\t\t\twrong_guesses += 1\n\t\t\tputs \"Sorry, that letter isn't in the word.\"\n\n\t\t\tif wrong_guesses == 10\n\t\t\t\tputs \"Sorry, you lose. The word was #{guess_target}\"\n\t\t\t\tbreak\n\t\t\tend\n\t\tend\n\tend\nend\n\n\ndef main\n\tputs \"#{(\" \" * 32)}HANGMAN\"\n\n\tshuffled = WORDS.shuffle(random: Random.new)\n\tcurrent_word = 0\n\tword_count = shuffled.length\n\n\tkeep_playing = true\n\twhile keep_playing\n\n\t\tplay_game(shuffled[current_word])\n\t\tcurrent_word += 1\n\n\t\tif current_word == word_count\n\t\t\tputs \"You did all the words!!\"\n\t\t\tkeep_playing = false\n\t\telse\n\t\t\tprint \"Want another word? (yes or no) \"\n\t\t\ta = gets.chomp!.upcase\n\t\t\tkeep_playing = true if a == 'Y' || a == 'y' || a == 'Yes' || a == 'YES' || a == 'yes'\n\t\tend\n\tend\n\tputs \"It's been fun! Bye for now.\"\nend\n\nif __FILE__ == $0\n\tmain\nend"
  },
  {
    "path": "44_Hangman/vbnet/Hangman.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Hangman\", \"Hangman.vbproj\", \"{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "44_Hangman/vbnet/Hangman.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Hangman</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "44_Hangman/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "45_Hello/README.md",
    "content": "### Hello\n\nThis is a sample of one of the great number of conversational programs. In a sense, it is like a CAI program except that its responses are just good fun. Whenever a computer is exhibited at a convention or conference with people that have not used a computer before, the conversational programs seem to get the first activity.\n\nIn this particular program, the computer dispenses advice on various problems such as sex, health, money, or job.\n\nDavid Ahl is the author of HELLO.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=82)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=97)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "45_Hello/csharp/Hello.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "45_Hello/csharp/Hello.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Hello\", \"Hello.csproj\", \"{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "45_Hello/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "45_Hello/hello.bas",
    "content": "2 PRINT TAB(33);\"HELLO\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 PRINT \"HELLO.  MY NAME IS CREATIVE COMPUTER.\"\n20 PRINT: PRINT: INPUT \"WHAT'S YOUR NAME\";N$: PRINT\n30 PRINT \"HI THERE, \";N$;\", ARE YOU ENJOYING YOURSELF HERE\";\n40 INPUT B$: PRINT\n50 IF B$=\"YES\" THEN 70\n55 IF B$=\"NO\" THEN 80\n60 PRINT N$;\", I DON'T UNDERSTAND YOUR ANSWER OF '\";B$;\"'.\"\n65 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE\";: GOTO 40\n70 PRINT \"I'M GLAD TO HEAR THAT, \";N$;\".\": PRINT\n75 GOTO 100\n80 PRINT \"OH, I'M SORRY TO HEAR THAT, \";N$;\". MAYBE WE CAN\"\n85 PRINT \"BRIGHTEN UP YOUR VISIT A BIT.\"\n100 PRINT\n105 PRINT \"SAY, \";N$;\", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\"\n110 PRINT \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\"\n120 PRINT \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)\";\n125 INPUT C$\n126 PRINT\n130 IF C$=\"SEX\" THEN 200\n132 IF C$=\"HEALTH\" THEN 180\n134 IF C$=\"MONEY\" THEN 160\n136 IF C$=\"JOB\" THEN 145\n138 PRINT \"OH, \";N$;\", YOUR ANSWER OF \";C$;\" IS GREEK TO ME.\"\n140 GOTO 250\n145 PRINT \"I CAN SYMPATHIZE WITH YOU \";N$;\".  I HAVE TO WORK\"\n148 PRINT \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\"\n150 PRINT \"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, \";N$;\",\"\n153 PRINT \"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\"\n155 GOTO 250\n160 PRINT \"SORRY, \";N$;\", I'M BROKE TOO.  WHY DON'T YOU SELL\"\n162 PRINT \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\"\n164 PRINT \"SO YOU WON'T NEED SO MUCH MONEY?\"\n170 GOTO 250\n180 PRINT \"MY ADVICE TO YOU \";N$;\" IS:\"\n185 PRINT \"     1.  TAKE TWO ASPRIN\"\n188 PRINT \"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\"\n190 PRINT \"     3.  GO TO BED (ALONE)\"\n195 GOTO 250\n200 INPUT \"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE\";D$: PRINT\n210 IF D$=\"TOO MUCH\" THEN 220\n212 IF D$=\"TOO LITTLE\" THEN 230\n215 PRINT \"DON'T GET ALL SHOOK, \";N$;\", JUST ANSWER THE QUESTION\"\n217 INPUT \"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT\";D$:GOTO 210\n220 PRINT \"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\"\n225 PRINT \"IF IT BOTHERS YOU, \";N$;\", TAKE A COLD SHOWER.\"\n228 GOTO 250\n230 PRINT \"WHY ARE YOU HERE IN SUFFERN, \";N$;\"?  YOU SHOULD BE\"\n235 PRINT \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\"\n240 PRINT \"REAL ACTION.\"\n250 PRINT\n255 PRINT \"ANY MORE PROBLEMS YOU WANT SOLVED, \";N$;\n260 INPUT E$: PRINT\n270 IF E$=\"YES\" THEN 280\n273 IF E$=\"NO\" THEN 300\n275 PRINT \"JUST A SIMPLE 'YES' OR 'NO' PLEASE, \";N$;\".\"\n277 GOTO 255\n280 PRINT \"WHAT KIND (SEX, MONEY, HEALTH, JOB)\";\n282 GOTO 125\n300 PRINT\n302 PRINT \"THAT WILL BE $5.00 FOR THE ADVICE, \";N$;\".\"\n305 PRINT \"PLEASE LEAVE THE MONEY ON THE TERMINAL.\"\n307 FOR I=1 TO 2000: NEXT I\n310 PRINT: PRINT: PRINT\n315 PRINT \"DID YOU LEAVE THE MONEY\";\n320 INPUT G$: PRINT\n325 IF G$=\"YES\" THEN 350\n330 IF G$=\"NO\" THEN 370\n335 PRINT \"YOUR ANSWER OF '\";G$;\"' CONFUSES ME, \";N$;\".\"\n340 PRINT \"PLEASE RESPOND WITH 'YES' OR 'NO'.\": GOTO 315\n350 PRINT \"HEY, \";N$;\"??? YOU LEFT NO MONEY AT ALL!\"\n355 PRINT \"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\"\n360 PRINT:PRINT \"WHAT A RIP OFF, \";N$;\"!!!\":PRINT\n365 GOTO 385\n370 PRINT \"THAT'S HONEST, \";N$;\", BUT HOW DO YOU EXPECT\"\n375 PRINT \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\"\n380 PRINT \"DON'T PAY THEIR BILLS?\"\n385 PRINT:PRINT \"TAKE A WALK, \";N$;\".\":PRINT:PRINT:GOTO 999\n390 PRINT \"NICE MEETING YOU, \";N$;\", HAVE A NICE DAY.\"\n400 REM\n999 END\n"
  },
  {
    "path": "45_Hello/java/Hello.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of Hello\n * <p>\n * Based on the BASIC game of Hello here\n * https://github.com/coding-horror/basic-computer-games/blob/main/45%20Hello/hello.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Hello {\n\n  private static final int MONEY_WAIT_MS = 3000;\n\n  private final boolean goodEnding = false;\n\n  private final Scanner scan;  // For user input\n\n  public Hello() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Hello\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"HELLO\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    boolean moreProblems = true;\n\n    String userCategory = \"\";\n    String userName = \"\";\n    String userResponse = \"\";\n\n    // Name question\n    System.out.println(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\\n\");\n    System.out.print(\"WHAT'S YOUR NAME? \");\n    userName = scan.nextLine();\n    System.out.println(\"\");\n\n    // Enjoyment question\n    System.out.print(\"HI THERE, \" + userName + \", ARE YOU ENJOYING YOURSELF HERE? \");\n\n    while (true) {\n      userResponse = scan.nextLine();\n      System.out.println(\"\");\n\n      if (userResponse.toUpperCase().equals(\"YES\")) {\n        System.out.println(\"I'M GLAD TO HEAR THAT, \" + userName + \".\\n\");\n        break;\n      }\n      else if (userResponse.toUpperCase().equals(\"NO\")) {\n        System.out.println(\"OH, I'M SORRY TO HEAR THAT, \" + userName + \". MAYBE WE CAN\");\n        System.out.println(\"BRIGHTEN UP YOUR VISIT A BIT.\");\n        break;\n      }\n      else {\n        System.out.println(userName + \", I DON'T UNDERSTAND YOUR ANSWER OF '\" + userResponse + \"'.\");\n        System.out.print(\"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE? \");\n      }\n    }\n\n    // Category question\n    System.out.println(\"\");\n    System.out.println(\"SAY, \" + userName + \", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\");\n    System.out.println(\"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\");\n    System.out.print(\"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)? \");\n\n    while (moreProblems) {\n      userCategory = scan.nextLine();\n      System.out.println(\"\");\n\n      // Sex advice\n      if (userCategory.toUpperCase().equals(\"SEX\")) {\n        System.out.print(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE? \");\n        userResponse = scan.nextLine();\n        System.out.println(\"\");\n\n        while (true) {\n          if (userResponse.toUpperCase().equals(\"TOO MUCH\")) {\n            System.out.println(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\");\n            System.out.println(\"IF IT BOTHERS YOU, \" + userName + \", TAKE A COLD SHOWER.\");\n            break;\n          }\n          else if (userResponse.toUpperCase().equals(\"TOO LITTLE\")) {\n            System.out.println(\"WHY ARE YOU HERE IN SUFFERN, \" + userName + \"?  YOU SHOULD BE\");\n            System.out.println(\"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\");\n            System.out.println(\"REAL ACTION.\");\n            break;\n          }\n          else {\n            System.out.println(\"DON'T GET ALL SHOOK, \" + userName + \", JUST ANSWER THE QUESTION\");\n            System.out.print(\"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT? \");\n            userResponse = scan.nextLine();\n          }\n        }\n      }\n      // Health advice\n      else if (userCategory.toUpperCase().equals(\"HEALTH\")) {\n        System.out.println(\"MY ADVICE TO YOU \" + userName + \" IS:\");\n        System.out.println(\"     1.  TAKE TWO ASPRIN\");\n        System.out.println(\"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\");\n        System.out.println(\"     3.  GO TO BED (ALONE)\");\n      }\n      // Money advice\n      else if (userCategory.toUpperCase().equals(\"MONEY\")) {\n        System.out.println(\"SORRY, \" + userName + \", I'M BROKE TOO.  WHY DON'T YOU SELL\");\n        System.out.println(\"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\");\n        System.out.println(\"SO YOU WON'T NEED SO MUCH MONEY?\");\n      }\n      // Job advice\n      else if (userCategory.toUpperCase().equals(\"JOB\")) {\n        System.out.println(\"I CAN SYMPATHIZE WITH YOU \" + userName + \".  I HAVE TO WORK\");\n        System.out.println(\"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\");\n        System.out.println(\"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, \" + userName + \",\");\n        System.out.println(\"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\");\n      }\n      else {\n        System.out.println(\"OH, \" + userName + \", YOUR ANSWER OF \" + userCategory + \" IS GREEK TO ME.\");\n      }\n\n      // More problems question\n      while (true) {\n        System.out.println(\"\");\n        System.out.print(\"ANY MORE PROBLEMS YOU WANT SOLVED, \" + userName + \"? \");\n        userResponse = scan.nextLine();\n        System.out.println(\"\");\n\n        if (userResponse.toUpperCase().equals(\"YES\")) {\n          System.out.print(\"WHAT KIND (SEX, MONEY, HEALTH, JOB)? \");\n          break;\n        }\n        else if (userResponse.toUpperCase().equals(\"NO\")) {\n          moreProblems = false;\n          break;\n        }\n        else {\n          System.out.println(\"JUST A SIMPLE 'YES' OR 'NO' PLEASE, \" + userName + \".\");\n        }\n      }\n    }\n\n    // Payment question\n    System.out.println(\"\");\n    System.out.println(\"THAT WILL BE $5.00 FOR THE ADVICE, \" + userName + \".\");\n    System.out.println(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\");\n\n    // Pause\n    try {\n      Thread.sleep(MONEY_WAIT_MS);\n    } catch (Exception e) {\n      System.out.println(\"Caught Exception: \" + e.getMessage());\n    }\n\n    System.out.println(\"\\n\\n\");\n\n    while (true) {\n      System.out.print(\"DID YOU LEAVE THE MONEY? \");\n      userResponse = scan.nextLine();\n      System.out.println(\"\");\n\n      if (userResponse.toUpperCase().equals(\"YES\")) {\n        System.out.println(\"HEY, \" + userName + \"??? YOU LEFT NO MONEY AT ALL!\");\n        System.out.println(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\");\n        System.out.println(\"\");\n        System.out.println(\"WHAT A RIP OFF, \" + userName + \"!!!\\n\");\n        break;\n      }\n      else if (userResponse.toUpperCase().equals(\"NO\")) {\n        System.out.println(\"THAT'S HONEST, \" + userName + \", BUT HOW DO YOU EXPECT\");\n        System.out.println(\"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\");\n        System.out.println(\"DON'T PAY THEIR BILLS?\");\n        break;\n      }\n      else {\n        System.out.println(\"YOUR ANSWER OF '\" + userResponse + \"' CONFUSES ME, \" + userName + \".\");\n        System.out.println(\"PLEASE RESPOND WITH 'YES' OR 'NO'.\");\n      }\n    }\n\n    // Legacy included unreachable code\n    if (goodEnding) {\n      System.out.println(\"NICE MEETING YOU, \" + userName + \", HAVE A NICE DAY.\");\n    }\n    else {\n      System.out.println(\"\");\n      System.out.println(\"TAKE A WALK, \" + userName + \".\\n\");\n    }\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    Hello hello = new Hello();\n    hello.play();\n\n  }  // End of method main\n\n}  // End of class Hello\n"
  },
  {
    "path": "45_Hello/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "45_Hello/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "45_Hello/javascript/hello.html",
    "content": "<html>\n<head>\n<title>HELLO</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hello.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "45_Hello/javascript/hello.js",
    "content": "// HELLO\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(33) + \"HELLO\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"WHAT'S YOUR NAME\");\n    ns = await input();\n    print(\"\\n\");\n    print(\"HI THERE, \" + ns + \", ARE YOU ENJOYING YOURSELF HERE\");\n    while (1) {\n        bs = await input();\n        print(\"\\n\");\n        if (bs == \"YES\") {\n            print(\"I'M GLAD TO HEAR THAT, \" + ns + \".\\n\");\n            print(\"\\n\");\n            break;\n        } else if (bs == \"NO\") {\n            print(\"OH, I'M SORRY TO HEAR THAT, \" + ns + \". MAYBE WE CAN\\n\");\n            print(\"BRIGHTEN UP YOUR VISIT A BIT.\\n\");\n            break;\n        } else {\n            print(\"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE\");\n        }\n    }\n    print(\"\\n\");\n    print(\"SAY, \" + ns + \", I CAN SOLVED ALL KINDS OF PROBLEMS EXCEPT\\n\");\n    print(\"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\\n\");\n    print(\"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)\");\n    while (1) {\n        cs = await input();\n        print(\"\\n\");\n        if (cs != \"SEX\" && cs != \"HEALTH\" && cs != \"MONEY\" && cs != \"JOB\") {\n            print(\"OH, \" + ns + \", YOUR ANSWER OF \" + cs + \" IS GREEK TO ME.\\n\");\n        } else if (cs == \"JOB\") {\n            print(\"I CAN SYMPATHIZE WITH YOU \" + ns + \".  I HAVE TO WORK\\n\");\n            print(\"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\\n\");\n            print(\"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, \" + ns + \",\\n\");\n            print(\"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\\n\");\n        } else if (cs == \"MONEY\") {\n            print(\"SORRY, \" + ns + \", I'M BROKE TOO.  WHY DON'T YOU SELL\\n\");\n            print(\"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\\n\");\n            print(\"SO YOU WON'T NEED SO MUCH MONEY?\\n\");\n        } else if (cs == \"HEALTH\") {\n            print(\"MY ADVICE TO YOU \" + ns + \" IS:\\n\");\n            print(\"     1.  TAKE TWO ASPRIN\\n\");\n            print(\"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\\n\");\n            print(\"     3.  GO TO BED (ALONE)\\n\");\n        } else {\n            print(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE\");\n            while (1) {\n                ds = await input();\n                print(\"\\n\");\n                if (ds == \"TOO MUCH\") {\n                    print(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\\n\");\n                    print(\"IF IT BOTHERS YOU, \" + ns + \", TAKE A COLD SHOWER.\\n\");\n                    break;\n                } else if (ds == \"TOO LITTLE\") {\n                    print(\"WHY ARE YOU HERE IN SUFFERN, \" + ns + \"?  YOU SHOULD BE\\n\");\n                    print(\"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\\n\");\n                    print(\"REAL ACTION.\\n\");\n                    break;\n                } else {\n                    print(\"DON'T GET ALL SHOOK, \" + ns + \", JUST ANSWER THE QUESTION\\n\");\n                    print(\"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT\");\n                }\n            }\n        }\n        print(\"\\n\");\n        print(\"ANY MORE PROBLEMS YOU WANT SOLVED, \" + ns);\n        es = await input();\n        print(\"\\n\");\n        if (es == \"YES\") {\n            print(\"WHAT KIND (SEX, MONEY, HEALTH, JOB)\");\n        } else if (es == \"NO\") {\n            print(\"THAT WILL BE $5.00 FOR THE ADVICE, \" + ns + \".\\n\");\n            print(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\\n\");\n            print(\"\\n\");\n//            d = new Date().valueOf();\n//            while (new Date().valueOf() - d < 2000) ;\n            print(\"\\n\");\n            print(\"\\n\");\n            while (1) {\n                print(\"DID YOU LEAVE THE MONEY\");\n                gs = await input();\n                print(\"\\n\");\n                if (gs == \"YES\") {\n                    print(\"HEY, \" + ns + \"??? YOU LEFT NO MONEY AT ALL!\\n\");\n                    print(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\\n\");\n                    print(\"\\n\");\n                    print(\"WHAT A RIP OFF, \" + ns + \"!!!\\n\");\n                    print(\"\\n\");\n                    break;\n                } else if (gs == \"NO\") {\n                    print(\"THAT'S HONEST, \" + ns + \", BUT HOW DO YOU EXPECT\\n\");\n                    print(\"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENT\\n\");\n                    print(\"DON'T PAY THEIR BILLS?\\n\");\n                    break;\n                } else {\n                    print(\"YOUR ANSWER OF '\" + gs + \"' CONFUSES ME, \" + ns + \".\\n\");\n                    print(\"PLEASE RESPOND WITH 'YES' OR 'NO'.\\n\");\n                }\n            }\n            break;\n        }\n    }\n    print(\"\\n\");\n    print(\"TAKE A WALK, \" + ns + \".\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // Line 390 not used in original\n}\n\nmain();\n"
  },
  {
    "path": "45_Hello/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "45_Hello/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "45_Hello/lua/hello.lua",
    "content": "-- HELLO\r\n--\r\n-- Converted from BASIC to Lua by Recanman\r\n\r\nlocal function tab(space)\r\n    local str = \"\"\r\n\r\n    for _ = space, 1, -1 do\r\n        str = str .. \" \"\r\n    end\r\n\r\n    return str\r\nend\r\n\r\n-- reused from Bagels.lua\r\nfunction getInput(prompt)\r\n    io.write(prompt)\r\n    io.flush()\r\n    local input = io.read(\"l\")\r\n    if not input then  --- test for EOF\r\n        print(\"GOODBYE\")\r\n        os.exit(0)\r\n    end\r\n    return input\r\nend\r\n\r\nprint(tab(33) .. \"HELLO\\n\")\r\nprint(tab(15) .. \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\r\nprint(\"\\n\")\r\nprint(\"\\n\")\r\nprint(\"\\n\")\r\n\r\nprint(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\")\r\nprint(\"\\n\")\r\nprint(\"\\n\")\r\n\r\nprint(\"WHAT'S YOUR NAME\")\r\nlocal ns = getInput(\"? \")\r\n\r\nprint(\"\\n\")\r\nprint(\"HI THERE, \" .. ns .. \", ARE YOU ENJOYING YOURSELF HERE\")\r\n\r\nwhile true do\r\n    local bs = getInput(\"? \")\r\n    print(\"\\n\")\r\n    if bs == \"YES\" then\r\n        print(\"I'M GLAD TO HEAR THAT, \" .. ns .. \".\\n\")\r\n        print(\"\\n\")\r\n        break\r\n    elseif bs == \"NO\" then\r\n        print(\"OH, I'M SORRY TO HEAR THAT, \" .. ns .. \". MAYBE WE CAN\\n\")\r\n        print(\"BRIGHTEN UP YOUR VISIT A BIT.\\n\")\r\n        break\r\n    else\r\n        print(\"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE\")\r\n    end\r\nend\r\n\r\nlocal function main()\r\n    print(\"\\n\")\r\n    print(\"SAY, \" .. ns .. \", I CAN SOLVED ALL KINDS OF PROBLEMS EXCEPT\\n\")\r\n    print(\"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\\n\")\r\n    print(\"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)\")\r\n\r\n    while true do\r\n        local cs = getInput(\"? \")\r\n        print(\"\\n\")\r\n\r\n        if cs ~= \"SEX\" and cs ~= \"HEALTH\" and cs ~= \"MONEY\" and cs ~= \"JOB\" then\r\n            print(\"OH, \" .. ns .. \", YOUR ANSWER OF \" .. cs .. \" IS GREEK TO ME.\\n\")\r\n        elseif cs == \"JOB\" then\r\n            print(\"I CAN SYMPATHIZE WITH YOU \" .. ns .. \".  I HAVE TO WORK\\n\")\r\n            print(\"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\\n\")\r\n            print(\"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, \" .. ns .. \",\\n\")\r\n            print(\"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\\n\")\r\n        elseif cs == \"MONEY\" then\r\n            print(\"SORRY, \" .. ns .. \", I'M BROKE TOO.  WHY DON'T YOU SELL\\n\")\r\n            print(\"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\\n\")\r\n            print(\"SO YOU WON'T NEED SO MUCH MONEY?\\n\")\r\n        elseif cs == \"HEALTH\" then\r\n            print(\"MY ADVICE TO YOU \" .. ns .. \" IS:\\n\")\r\n            print(tab(5) .. \"1.  TAKE TWO ASPRIN\\n\")\r\n            print(tab(5) .. \"2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\\n\")\r\n            print(tab(5) .. \"3.  GO TO BED (ALONE)\\n\")\r\n        elseif cs == \"SEX\" then\r\n            print(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE\")\r\n\r\n            while true do\r\n                local ds = getInput(\"? \")\r\n                print(\"\\n\")\r\n\r\n                if ds == \"TOO MUCH\" then\r\n                    print(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\\n\")\r\n                    print(\"IF IT BOTHERS YOU, \" .. ns .. \", TAKE A COLD SHOWER.\\n\")\r\n                    break\r\n                elseif ds == \"TOO LITTLE\" then\r\n                    print(\"WHY ARE YOU HERE IN SUFFERN, \" .. ns .. \"?  YOU SHOULD BE\\n\")\r\n                    print(\"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\\n\")\r\n                    print(\"REAL ACTION.\\n\")\r\n                    break\r\n                else\r\n                    print(\"DON'T GET ALL SHOOK, \" .. ns .. \", JUST ANSWER THE QUESTION\\n\")\r\n                    print(\"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT\")\r\n                end\r\n            end\r\n        end\r\n\r\n        print(\"\\n\")\r\n        print(\"ANY MORE PROBLEMS YOU WANT SOLVED, \" .. ns)\r\n\r\n        local es = getInput(\"? \")\r\n\r\n        if es == \"YES\" then\r\n            print(\"WHAT KIND (SEX, MONEY, HEALTH, JOB)\")\r\n        elseif es == \"NO\" then\r\n            print(\"THAT WILL BE $5.00 FOR THE ADVICE, \" .. ns .. \".\\n\")\r\n            print(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\\n\")\r\n            print(\"\\n\")\r\n            print(\"\\n\")\r\n            print(\"\\n\")\r\n\r\n            while true do\r\n                print(\"DID YOU LEAVE THE MONEY\")\r\n\r\n                local gs = getInput(\"? \")\r\n                print(\"\\n\")\r\n\r\n                if gs == \"YES\" then\r\n                    print(\"HEY, \" .. ns .. \"??? YOU LEFT NO MONEY AT ALL!\\n\")\r\n                    print(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\\n\")\r\n                    print(\"\\n\")\r\n                    print(\"WHAT A RIP OFF, \" .. ns .. \"!!!\\n\")\r\n                    print(\"\\n\")\r\n                    break\r\n                elseif gs == \"NO\" then\r\n                    print(\"THAT'S HONEST, \" .. ns .. \", BUT HOW DO YOU EXPECT\\n\")\r\n                    print(\"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENT\\n\")\r\n                    print(\"DON'T PAY THEIR BILLS?\\n\")\r\n                    break\r\n                else\r\n                    print(\"YOUR ANSWER OF '\" .. gs .. \"' CONFUSES ME, \" .. ns .. \".\\n\")\r\n                    print(\"PLEASE RESPOND WITH 'YES' OR 'NO'.\\n\")\r\n                end\r\n            end\r\n\r\n            break\r\n        end\r\n    end\r\n\r\n    print(\"\\n\")\r\n    print(\"TAKE A WALK, \" .. ns .. \".\\n\")\r\n    print(\"\\n\")\r\n    print(\"\\n\")\r\nend\r\n\r\nmain()"
  },
  {
    "path": "45_Hello/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "45_Hello/perl/hello.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\nprint ' ' x 33 . \"HELLO\\n\";\nprint ' ' x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\\n\\n\";\nprint \"WHAT'S YOUR NAME?\\n\";\nchomp( my $N = uc <STDIN> );\n\nprint \"\\nHI THERE, $N, ARE YOU ENJOYING YOURSELF HERE?\\n\";\n\nGREET:\n{\n    chomp( my $B = uc <STDIN> );\n    print \"\\n\";\n\n    if ( $B eq 'YES' ) {\n        print \"I'M GLAD TO HEAR THAT, $N.\\n\\n\";\n    }\n    elsif ( $B eq 'NO' ) {\n        print \"OH, I'M SORRY TO HEAR THAT, $N. MAYBE WE CAN\\n\";\n        print \"BRIGHTEN UP YOUR VISIT A BIT.\\n\";\n    }\n    else {\n        print \"$N, I DON'T UNDERSTAND YOUR ANSWER OF '$B'.\\n\";\n        print \"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE?\\n\";\n        redo GREET;\n    }\n}\n\nprint \"\\nSAY, $N, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\\n\";\nprint \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\\n\";\nprint \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)?\\n\";\n\nADVICE:\n{\n    chomp( my $C = uc <STDIN> );\n    print \"\\n\";\n\n    if ( $C eq 'SEX' ) {\n        print \"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?\\n\";\n\n        SEX:\n        {\n            chomp( my $D = uc <STDIN> );\n            print \"\\n\";\n\n            if ( $D eq 'TOO MUCH' ) {\n                print \"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\\n\";\n                print \"IF IT BOTHERS YOU, $N, TAKE A COLD SHOWER.\\n\";\n            }\n            elsif ( $D eq 'TOO LITTLE' ) {\n                print \"WHY ARE YOU HERE IN SUFFERN, $N?  YOU SHOULD BE\\n\";\n                print \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\\n\";\n                print \"REAL ACTION.\\n\";\n            }\n            else {\n                print \"DON'T GET ALL SHOOK, $N, JUST ANSWER THE QUESTION\\n\";\n                print \"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT?\\n\";\n                redo SEX;\n            }\n        }\n    }\n    elsif ( $C eq 'HEALTH' ) {\n        print \"MY ADVICE TO YOU $N IS:\\n\";\n        print \"     1.  TAKE TWO ASPRIN\\n\";\n        print \"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\\n\";\n        print \"     3.  GO TO BED (ALONE)\\n\";\n    }\n    elsif ( $C eq 'MONEY' ) {\n        print \"SORRY, $N, I'M BROKE TOO.  WHY DON'T YOU SELL\\n\";\n        print \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\\n\";\n        print \"SO YOU WON'T NEED SO MUCH MONEY?\\n\";\n    }\n    elsif ( $C eq 'JOB' ) {\n        print \"I CAN SYMPATHIZE WITH YOU $N.  I HAVE TO WORK\\n\";\n        print \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\\n\";\n        print \"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, $N,\\n\";\n        print \"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\\n\";\n    }\n    else {\n        print \"OH, $N, YOUR ANSWER OF '$C' IS GREEK TO ME.\\n\";\n    }\n\n    MORE:\n    {\n        print \"\\nANY MORE PROBLEMS YOU WANT SOLVED, $N?\\n\";\n        chomp( my $E = uc <STDIN> );\n        print \"\\n\";\n\n        if ( $E eq 'YES' ) {\n            print \"WHAT KIND (SEX, MONEY, HEALTH, JOB)?\\n\";\n            redo ADVICE;\n        }\n        elsif ( $E eq 'NO' ) {\n            print \"\\nTHAT WILL BE \\$5.00 FOR THE ADVICE, $N.\\n\";\n            print \"PLEASE LEAVE THE MONEY ON THE TERMINAL.\\n\";\n        }\n        else {\n            print \"JUST A SIMPLE 'YES' OR 'NO' PLEASE, $N.\\n\";\n            redo MORE;\n        }\n    }\n\n    sleep 2;\n    print \"\\n\\n\\n\";\n\n    MONEY:\n    {\n        print \"DID YOU LEAVE THE MONEY?\\n\";\n        chomp( my $G = uc <STDIN> );\n        print \"\\n\";\n\n        if ( $G eq 'YES' ) {\n            print \"HEY, $N??? YOU LEFT NO MONEY AT ALL!\\n\";\n            print \"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\\n\";\n            print \"\\nWHAT A RIP OFF, $N!!!\\n\\n\";\n        }\n        elsif ( $G eq 'NO' ) {\n            print \"THAT'S HONEST, $N, BUT HOW DO YOU EXPECT\\n\";\n            print \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\\n\";\n            print \"DON'T PAY THEIR BILLS?\\n\";\n        }\n        else {\n            print \"YOUR ANSWER OF '$G' CONFUSES ME, $N.\\n\";\n            print \"PLEASE RESPOND WITH 'YES' OR 'NO'.\\n\";\n            redo MONEY;\n        }\n\n        print \"\\nTAKE A WALK, $N.\\n\\n\\n\";\n    }\n}\n"
  },
  {
    "path": "45_Hello/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "45_Hello/python/hello.py",
    "content": "\"\"\"\nHELLO\n\nA very simple \"chat\" bot.\n\nWarning, the advice given here is bad.\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport time\nfrom typing import Optional, Tuple\n\n\ndef get_yes_or_no() -> Tuple[bool, Optional[bool], str]:\n    msg = input()\n    if msg.upper() == \"YES\":\n        return True, True, msg\n    elif msg.upper() == \"NO\":\n        return True, False, msg\n    else:\n        return False, None, msg\n\n\ndef ask_enjoy_question(user_name: str) -> None:\n    print(f\"HI THERE, {user_name}, ARE YOU ENJOYING YOURSELF HERE?\")\n\n    while True:\n        valid, value, msg = get_yes_or_no()\n\n        if valid:\n            if value:\n                print(f\"I'M GLAD TO HEAR THAT, {user_name}.\")\n                print()\n            else:\n                print(f\"OH, I'M SORRY TO HEAR THAT, {user_name}. MAYBE WE CAN\")\n                print(\"BRIGHTEN UP YOUR VISIT A BIT.\")\n            break\n        else:\n            print(f\"{user_name}, I DON'T UNDERSTAND YOUR ANSWER OF '{msg}'.\")\n            print(\"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE?\")\n\n\ndef prompt_for_problems(user_name: str) -> str:\n    print()\n    print(f\"SAY, {user_name}, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\")\n    print(\"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\")\n    print(\"YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB)\")\n\n    return input().upper()\n\n\ndef prompt_too_much_or_too_little() -> Tuple[bool, Optional[bool]]:\n    answer = input().upper()\n    if answer == \"TOO MUCH\":\n        return True, True\n    elif answer == \"TOO LITTLE\":\n        return True, False\n    return False, None\n\n\ndef solve_sex_problem(user_name: str) -> None:\n    print(\"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?\")\n    while True:\n        valid, too_much = prompt_too_much_or_too_little()\n        if valid:\n            if too_much:\n                print(\"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\")\n                print(f\"IF IT BOTHERS YOU, {user_name}, TAKE A COLD SHOWER.\")\n            else:\n                print(f\"WHY ARE YOU HERE IN SUFFERN, {user_name}?  YOU SHOULD BE\")\n                print(\"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\")\n                print(\"REAL ACTION.\")\n            return\n        else:\n            print(f\"DON'T GET ALL SHOOK, {user_name}, JUST ANSWER THE QUESTION\")\n            print(\"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT?\")\n\n\ndef solve_money_problem(user_name: str) -> None:\n    print(f\"SORRY, {user_name}, I'M BROKE TOO.  WHY DON'T YOU SELL\")\n    print(\"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\")\n    print(\"SO YOU WON'T NEED SO MUCH MONEY?\")\n\n\ndef solve_health_problem(user_name: str) -> None:\n    print(f\"MY ADVICE TO YOU {user_name} IS:\")\n    print(\"     1.  TAKE TWO ASPRIN\")\n    print(\"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\")\n    print(\"     3.  GO TO BED (ALONE)\")\n\n\ndef solve_job_problem(user_name: str) -> None:\n    print(f\"I CAN SYMPATHIZE WITH YOU {user_name}.  I HAVE TO WORK\")\n    print(\"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\")\n    print(f\"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, {user_name},\")\n    print(\"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\")\n\n\ndef alert_unknown_problem_type(user_name: str, problem_type: str) -> None:\n    print(f\"OH, {user_name}, YOUR ANSWER OF {problem_type} IS GREEK TO ME.\")\n\n\ndef ask_question_loop(user_name: str) -> None:\n    while True:\n        problem_type = prompt_for_problems(user_name)\n        if problem_type == \"SEX\":\n            solve_sex_problem(user_name)\n        elif problem_type == \"HEALTH\":\n            solve_health_problem(user_name)\n        elif problem_type == \"MONEY\":\n            solve_money_problem(user_name)\n        elif problem_type == \"JOB\":\n            solve_job_problem(user_name)\n        else:\n            alert_unknown_problem_type(user_name, problem_type)\n\n        while True:\n            print()\n            print(f\"ANY MORE PROBLEMS YOU WANT SOLVED, {user_name}?\")\n\n            valid, value, msg = get_yes_or_no()\n            if valid:\n                if not value:\n                    return\n                print(\"WHAT KIND (SEX, MONEY, HEALTH, JOB)\")\n                break\n            print(f\"JUST A SIMPLE 'YES' OR 'NO' PLEASE, {user_name}.\")\n\n\ndef ask_for_fee(user_name: str) -> None:\n    print()\n    print(f\"THAT WILL BE $5.00 FOR THE ADVICE, {user_name}.\")\n    print(\"PLEASE LEAVE THE MONEY ON THE TERMINAL.\")\n    time.sleep(4)\n    print()\n    print()\n    print()\n    print(\"DID YOU LEAVE THE MONEY?\")\n\n    while True:\n        valid, value, msg = get_yes_or_no()\n        if valid:\n            if value:\n                print(f\"HEY, {user_name}, YOU LEFT NO MONEY AT ALL!\")\n                print(\"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\")\n                print()\n                print(f\"WHAT A RIP OFF, {user_name}!!!\")\n                print()\n            else:\n                print(f\"THAT'S HONEST, {user_name}, BUT HOW DO YOU EXPECT\")\n                print(\"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\")\n                print(\"DON'T PAY THEIR BILLS?\")\n            return\n        else:\n            print(f\"YOUR ANSWER OF '{msg}' CONFUSES ME, {user_name}.\")\n            print(\"PLEASE RESPOND WITH 'YES' or 'NO'.\")\n\n\ndef unhappy_goodbye(user_name: str) -> None:\n    print()\n    print(f\"TAKE A WALK, {user_name}.\")\n    print()\n    print()\n\n\ndef happy_goodbye(user_name: str) -> None:\n    print(f\"NICE MEETING YOU, {user_name}, HAVE A NICE DAY.\")\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"HELLO\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\\n\")\n    print(\"WHAT'S YOUR NAME?\")\n    user_name = input()\n    print()\n\n    ask_enjoy_question(user_name)\n\n    ask_question_loop(user_name)\n\n    ask_for_fee(user_name)\n\n    unhappy_goodbye(user_name)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "45_Hello/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "45_Hello/ruby/hello.rb",
    "content": "class Hello\n  def start\n    puts  \"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\\n\"\n    print \"WHAT'S YOUR NAME? \"\n    user_name = gets.chomp!\n\n    ask_enjoy_question(user_name)\n\n    ask_question_loop(user_name)\n\n    isHonest = ask_for_fee(user_name)\n    \n    if isHonest\n      happy_goodbye(user_name)\n    else\n      unhappy_goodbye(user_name)\n    end\n  end\n  private\n    def get_yes_or_no\n      msg = gets.chomp!\n      if msg.upcase() == \"YES\"\n          return true, true, msg\n      elsif msg.upcase() == \"NO\"\n          return true, false, msg\n      else\n          return false, false, msg\n      end\n    end\n\n    def ask_enjoy_question user_name\n      print \"\\nHI THERE, #{user_name}, ARE YOU ENJOYING YOURSELF HERE? \"\n\n      while true\n        valid, value, msg = get_yes_or_no()\n\n        if valid\n          if value\n            puts \"\\nI'M GLAD TO HEAR THAT, #{user_name}.\"\n            break\n          else\n            puts \"\\nOH, I'M SORRY TO HEAR THAT, #{user_name}. MAYBE WE CAN\"\n            puts \"BRIGHTEN UP YOUR VISIT A BIT.\"\n            break\n          end\n        else\n          puts \"\\n#{user_name}, I DON'T UNDERSTAND YOUR ANSWER OF '#{msg}'.\"\n          print \"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE? \"\n        end\n      end\n    end\n\n    def prompt_for_problems user_name\n      puts \"\\nSAY, #{user_name}, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\" \n      puts \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\"\n      print \"YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB) \"\n  \n      problem_type = gets.chomp!\n      return problem_type\n    end\n\n    def prompt_too_much_or_too_little\n      answer = gets.chomp!\n      if answer.upcase() == \"TOO MUCH\"\n        return true, true\n      elsif answer.upcase() == \"TOO LITTLE\"\n        return true, false\n      else\n        return false, false\n      end\n    end\n\n    def solve_sex_problem user_name\n      print \"\\nIS YOUR PROBLEM TOO MUCH OR TOO LITTLE? \"\n      while true\n        valid, too_much = prompt_too_much_or_too_little()\n        if valid\n          if too_much\n            puts \"\\nYOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\"\n            puts \"IF IT BOTHERS YOU, #{user_name}, TAKE A COLD SHOWER.\"\n            break\n          else\n            puts \"\\nWHY ARE YOU HERE IN SUFFERN, #{user_name}?  YOU SHOULD BE\"\n            puts \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\"\n            puts \"REAL ACTION.\"\n            break\n          end\n        else\n          puts \"\\nDON'T GET ALL SHOOK, #{user_name}, JUST ANSWER THE QUESTION\"\n          print \"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT? \"\n        end\n      end\n    end\n\n    def solve_health_problem user_name\n      puts \"\\nMY ADVICE TO YOU #{user_name} IS:\"\n      puts \"     1.  TAKE TWO ASPRIN\"\n      puts \"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\"\n      puts \"     3.  GO TO BED (ALONE)\"\n    end\n\n    def solve_money_problem user_name\n      puts \"\\nSORRY, #{user_name}, I'M BROKE TOO.  WHY DON'T YOU SELL\"\n      puts \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\"\n      puts \"SO YOU WON'T NEED SO MUCH MONEY?\"\n    end\n\n    def solve_job_problem user_name\n      puts \"\\nI CAN SYMPATHIZE WITH YOU #{user_name}.  I HAVE TO WORK\"\n      puts \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\"\n      puts \"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, #{user_name},\"\n      puts \"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\"\n    end\n\n    def alert_unknown_problem_type user_name, problem_type\n      puts \"\\nOH, #{user_name}, YOUR ANSWER OF #{problem_type} IS GREEK TO ME.\"\n    end\n\n    def ask_question_loop user_name\n      while true\n        problem_type = prompt_for_problems(user_name)\n        if problem_type == \"SEX\"\n          solve_sex_problem(user_name)\n        elsif problem_type == \"HEALTH\"\n          solve_health_problem(user_name)\n        elsif problem_type == \"MONEY\"\n          solve_money_problem(user_name)\n        elsif problem_type == \"JOB\"\n          solve_job_problem(user_name)\n        else\n          alert_unknown_problem_type(user_name, problem_type)\n        end\n\n        while true\n          print \"\\nANY MORE PROBLEMS YOU WANT SOLVED, #{user_name}? \"\n\n          valid, value, msg = get_yes_or_no()\n          if valid\n            if value\n              puts \"\\nWHAT KIND (SEX, MONEY, HEALTH, JOB)\"\n              break\n            else\n              return\n            end\n          else\n            puts \"\\nJUST A SIMPLE 'YES' OR 'NO' PLEASE, #{user_name}.\"\n          end\n        end\n      end\n    end\n\n    def ask_for_fee user_name\n      puts \"\\nTHAT WILL BE $5.00 FOR THE ADVICE, #{user_name}.\"\n      puts \"PLEASE LEAVE THE MONEY ON THE TERMINAL.\"\n      sleep(3)\n      print \"\\n\\nDID YOU LEAVE THE MONEY? \"\n  \n      while true\n        valid, value, msg = get_yes_or_no()\n        if valid\n            if value\n              puts \"\\nHEY, #{user_name}, YOU LEFT NO MONEY AT ALL!\"\n              puts \"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\"\n              puts \"\\nWHAT A RIP OFF, #{user_name}!!!\"\n              return false\n            else\n              puts \"\\nTHAT'S HONEST, #{user_name}, BUT HOW DO YOU EXPECT\"\n              puts \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\"\n              puts \"DON'T PAY THEIR BILLS?\"\n              return true\n            end\n        else\n          puts \"\\nYOUR ANSWER OF '#{msg}' CONFUSES ME, #{user_name}.\"\n          print \"PLEASE RESPOND WITH 'YES' or 'NO'. \"\n        end\n      end\n    end\n\n    def unhappy_goodbye user_name\n      puts \"\\nTAKE A WALK, #{user_name}.\\n\\n\"\n    end\n  \n    def happy_goodbye user_name\n      puts \"\\nNICE MEETING YOU, #{user_name}, HAVE A NICE DAY.\"\n    end\nend\n\nif __FILE__ == $0\n  hello = Hello.new\n  hello.start()\nend"
  },
  {
    "path": "45_Hello/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n"
  },
  {
    "path": "45_Hello/rust/src/main.rs",
    "content": "/** HELLO GAME BY DAVID AHL\n * https://github.com/coding-horror/basic-computer-games/blob/main/45_Hello/hello.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 17/02/25\n*/\n\nuse std::io::Write;\n\nfn main() {\n    // 2 PRINT TAB(33);\"HELLO\"\n    // 4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    // 6 PRINT: PRINT: PRINT\n    print!(\n        \"{}{}\\n{}{}\\n\\n\\n\\n\", \n        \" \".repeat(33),\n        \"HELLO\",\n        \" \".repeat(15),\n        \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n\n    let mut input = String::new();\n    \n    //10 PRINT \"HELLO.  MY NAME IS CREATIVE COMPUTER.\"\n    //20 PRINT: PRINT: INPUT \"WHAT'S YOUR NAME\";N$: PRINT\n    print!(\"HELLO. MY NAME IS CREATIVE COMPUTER.\\n\\nWHAT'S YOUR NAME? \");\n    let _ = std::io::stdout().flush().unwrap();\n    input.clear();\n    std::io::stdin().read_line(&mut input).unwrap();\n    let n = input.trim().to_uppercase();\n    \n    //30 PRINT \"HI THERE, \";N$;\", ARE YOU ENJOYING YOURSELF HERE\";\n    //40 INPUT B$: PRINT\n    print!(\"\\nHI THERE, {n}, ARE YOU ENJOYING YOURSELF HERE? \");\n    loop {\n        let _ = std::io::stdout().flush().unwrap();\n        input.clear();\n        std::io::stdin().read_line(&mut input).unwrap();\n        let b = input.trim().to_uppercase();\n\n        //50 IF B$=\"YES\" THEN 70    \n        if b == \"YES\" {\n            //70 PRINT \"I'M GLAD TO HEAR THAT, \";N$;\".\": PRINT\n            //75 GOTO 100\n            println!(\"\\nI'M GLAD TO HEAR THAT, {n}.\");\n            break;\n        }\n        //55 IF B$=\"NO\" THEN 80\n        else if b == \"NO\" { \n            //80 PRINT \"OH, I'M SORRY TO HEAR THAT, \";N$;\". MAYBE WE CAN\"\n            //85 PRINT \"BRIGHTEN UP YOUR VISIT A BIT.\"\n            println!(\"\\nOH, I'M SORRY TO HEAR THAT, {n}. MAYBE WE CAN\\n{}\",\n                \"BRIGHTEN UP YOUR VISIT A BIT.\"\n            );\n            break;\n        }\n        else {\n            //60 PRINT N$;\", I DON'T UNDERSTAND YOUR ANSWER OF '\";B$;\"'.\"\n            //65 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE\";: GOTO 40\n            print!(\"\\n{n}, I DON'T UNDERSTAND YOUR ANSWER OF '{b}'.\\n{}\",\n                \"PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE? \"\n            );\n        }\n    }\n    \n    //100 PRINT\n    //105 PRINT \"SAY, \";N$;\", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\"\n    //110 PRINT \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\"\n    //120 PRINT \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)\";\n    //125 INPUT C$\n    //126 PRINT\n    print!(\"\\nSAY, {n}, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\\n{}\\n{}\",\n        \"THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\",\n        \"YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)? \"\n    );\n    'outer: loop {\n        let _ = std::io::stdout().flush().unwrap();\n        input.clear();\n        std::io::stdin().read_line(&mut input).unwrap();\n        let c = input.trim().to_uppercase();\n\n        //130 IF C$=\"SEX\" THEN 200\n        if c == \"SEX\" {\n            loop {\n                //200 INPUT \"IS YOUR PROBLEM TOO MUCH OR TOO LITTLE\";D$: PRINT\n                print!(\"\\nIS YOUR PROBLEM TOO MUCH OR TOO LITTLE? \");\n                let _ = std::io::stdout().flush().unwrap();\n                input.clear();\n                std::io::stdin().read_line(&mut input).unwrap();\n                let d = input.trim().to_uppercase();\n                \n                //210 IF D$=\"TOO MUCH\" THEN 220\n                if d == \"TOO MUCH\" {\n                    //220 PRINT \"YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\"\n                    //225 PRINT \"IF IT BOTHERS YOU, \";N$;\", TAKE A COLD SHOWER.\"\n                    //228 GOTO 250\n                    println!(\"\\nYOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\\n{}\",\n                        format!(\"IF IT BOTHERS YOU, {n}, TAKE A COLD SHOWER.\")\n                    );\n                    break;\n                }\n                //212 IF D$=\"TOO LITTLE\" THEN 230\n                else if d == \"TOO LITTLE\" {\n                    //230 PRINT \"WHY ARE YOU HERE IN SUFFERN, \";N$;\"?  YOU SHOULD BE\"\n                    //235 PRINT \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\"\n                    //240 PRINT \"REAL ACTION.\"\n                    //250 PRINT\n                    println!(\"\\nWHY ARE YOU HERE IN SUFFERN, {n}? YOU SHOULD BE\\n{}\\n{}\",\n                        \"IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH\",\n                        \"SOME REAL ACTION.\"\n                    );\n                    break;\n                }\n                else {\n                    //215 PRINT \"DON'T GET ALL SHOOK, \";N$;\", JUST ANSWER THE QUESTION\"\n                    //217 INPUT \"WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT\";D$:GOTO 210\n                    println!(\"\\nDON'T GET ALL SHOOK, {n}, JUST ANSWER THE QUESTION\\n{}\",\n                        \"WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT? \"\n                    );\n                }\n            }\n        }\n        //132 IF C$=\"HEALTH\" THEN 180\n        else if c == \"HEALTH\" {\n            //180 PRINT \"MY ADVICE TO YOU \";N$;\" IS:\"\n            //185 PRINT \"     1.  TAKE TWO ASPRIN\"\n            //188 PRINT \"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\"\n            //190 PRINT \"     3.  GO TO BED (ALONE)\"\n            //195 GOTO 250\n            println!(\"\\nMY ADVICE TO YOU {n} IS:\\n{}\\n{}\\n{}\",\n                \"     1.  TAKE TWO ASPRIN\",\n                \"     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\",\n                \"     3.  GO TO BED (ALONE)\"\n            );\n        }\n        //134 IF C$=\"MONEY\" THEN 160\n        else if c == \"MONEY\" {\n            //160 PRINT \"SORRY, \";N$;\", I'M BROKE TOO.  WHY DON'T YOU SELL\"\n            //162 PRINT \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\"\n            //164 PRINT \"SO YOU WON'T NEED SO MUCH MONEY?\"\n            //170 GOTO 250\n            println!(\"\\nSORRY, {n}, I'M BROKE TOO.  WHY DON'T YOU SELL\\n{}\\n{}\",\n                \"ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\",\n                \"SO YOU WON'T NEED SO MUCH MONEY? \"\n            );\n        }\n        //136 IF C$=\"JOB\" THEN 145\n        else if c == \"JOB\" {\n            //145 PRINT \"I CAN SYMPATHIZE WITH YOU \";N$;\".  I HAVE TO WORK\"\n            //148 PRINT \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\"\n            //150 PRINT \"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, \";N$;\",\"\n            //153 PRINT \"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\"\n            //155 GOTO 250\n            println!(\"\\nI CAN SYMPATHIZE WITH YOU {n}.  I HAVE TO WORK\\n{}\\n{}\\n{}\",\n                \"VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\",\n                format!(\"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, {n}\"),\n                \"IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\"\n            );\n        }\n        else {\n            //138 PRINT \"OH, \";N$;\", YOUR ANSWER OF \";C$;\" IS GREEK TO ME.\"\n            //140 GOTO 250\n            println!(\"\\nOH, {n}, YOUR ANSWER OF {c} IS GREEK TO ME.\");\n        }\n        \n        loop {\n            //255 PRINT \"ANY MORE PROBLEMS YOU WANT SOLVED, \";N$;\n            //260 INPUT E$: PRINT\n            print!(\"\\nANY MORE PROBLEMS YOU WANT SOLVED, {n}? \");\n            let _ = std::io::stdout().flush().unwrap();\n            input.clear();\n            std::io::stdin().read_line(&mut input).unwrap();\n            let e = input.trim().to_uppercase();\n            \n            //270 IF E$=\"YES\" THEN 280\n            if e == \"YES\" {\n                //280 PRINT \"WHAT KIND (SEX, MONEY, HEALTH, JOB)\";\n                //282 GOTO 125\n                print!(\"\\nWHAT KIND (SEX, MONEY, HEALTH, JOB)? \");\n                continue 'outer;\n            }\n            //273 IF E$=\"NO\" THEN 300\n            else if e == \"NO\" {\n                break 'outer;\n            }\n            else {\n                //275 PRINT \"JUST A SIMPLE 'YES' OR 'NO' PLEASE, \";N$;\".\"\n                //277 GOTO 255\n                println!(\"\\nJUST A SIMPLE 'YES' OR 'NO' PLEASE, {n}.\");\n            }\n        }\n    }\n    //300 PRINT\n    //302 PRINT \"THAT WILL BE $5.00 FOR THE ADVICE, \";N$;\".\"\n    //305 PRINT \"PLEASE LEAVE THE MONEY ON THE TERMINAL.\"\n    println!(\"\\nTHAT WILL BE $5.00 FOR THE ADVICE, {n}.\\n{}\",\n        \"PLEASE LEAVE THE MONEY ON THE TERMINAL.\"\n    );\n    //307 FOR I=1 TO 2000: NEXT I\n    //310 PRINT: PRINT: PRINT\n    loop {\n        //315 PRINT \"DID YOU LEAVE THE MONEY\";\n        //320 INPUT G$: PRINT\n        print!(\"\\nDID YOU LEAVE THE MONEY? \");\n        let _ = std::io::stdout().flush().unwrap();\n        input.clear();\n        std::io::stdin().read_line(&mut input).unwrap();\n        let g = input.trim().to_uppercase();\n        \n        //325 IF G$=\"YES\" THEN 350\n        if g == \"YES\" {\n            //350 PRINT \"HEY, \";N$;\"??? YOU LEFT NO MONEY AT ALL!\"\n            //355 PRINT \"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\"\n            //360 PRINT:PRINT \"WHAT A RIP OFF, \";N$;\"!!!\":PRINT\n            //365 GOTO 385\n            println!(\"\\nHEY, {n}??? YOU LEFT NO MONEY AT ALL!\\n{}\\n{}\",\n                \"YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\",\n                format!(\"WHAT A RIP OFF, {n}!!!\\n\\nTAKE A WALK, {n}\")\n            );\n            break;\n        }\n        //330 IF G$=\"NO\" THEN 370\n        else if g == \"NO\" {\n            //370 PRINT \"THAT'S HONEST, \";N$;\", BUT HOW DO YOU EXPECT\"\n            //375 PRINT \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\"\n            //380 PRINT \"DON'T PAY THEIR BILLS?\"\n            //385 PRINT:PRINT \"TAKE A WALK, \";N$;\".\":PRINT:PRINT:GOTO 999\n            println!(\"\\nTHAT'S HONEST, {n}, BUT HOW DO YOU EXPECT\\n{}\\n{}\",\n                \"ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\",\n                format!(\"DON'T PAY THEIR BILLS?\\n\\nTAKE A WALK, {n}\")\n            );\n            break;\n        }\n        else {\n            //335 PRINT \"YOUR ANSWER OF '\";G$;\"' CONFUSES ME, \";N$;\".\"\n            //340 PRINT \"PLEASE RESPOND WITH 'YES' OR 'NO'.\": GOTO 315\n            println!(\"YOUR ANSWER OF '{g}' CONFUSES ME, {n}.\\n{}\",\n                \"PLEASE RESPOND WITH 'YES' OR 'NO'.\"\n            );\n        }    \n    }\n    \n    //390 PRINT \"NICE MEETING YOU, \";N$;\", HAVE A NICE DAY.\" -> unreachable\n    //400 REM\n    //999 END\n}\n"
  },
  {
    "path": "45_Hello/vbnet/Hello.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Hello\", \"Hello.vbproj\", \"{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "45_Hello/vbnet/Hello.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Hello</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "45_Hello/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "46_Hexapawn/README.md",
    "content": "### Hexapawn\n\nThe game of Hexapawn and a method to learn a strategy for playing the game was described in Martin Gardner’s “Mathematical Games” column in the March 1962 issue of _Scientific American_. The method described in the article was for a hypothetical learning machine composed of match boxes and colored beads. This has been generalized in the program HEX.\n\nThe program learns by elimination of bad moves. All positions encountered by the program and acceptable moves from them are stored in an array. When the program encounters an unfamiliar position, the position and all legal moves from it are added to the list. If the program loses a game, it erases the move that led to defeat. If it hits a position from which all moves have been deleted (they all led to defeat), it erases the move that got it there and resigns. Eventually, the program learns to play extremely well and, indeed, is unbeatable. The learning strategy could be adopted to other simple games with a finite number of moves (tic-tac-toe, small board checkers, or other chess-based games).\n\nThe original version of this program was written by R.A. Kaapke. It was subsequently modified by Jeff Dalton and finally by Steve North of Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=83)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=98)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- There are valid board positions that will cause the program to print \"ILLEGAL BOARD PATTERN\" and break.  For example: human 8,5; computer 1,5; human 9,5; computer 3,5; human 7,5.  This is a valid game-over pattern, but it is not detected as such because of incorrect logic in lines 240-320 (intended to detect whether the computer has any legal moves).\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "46_Hexapawn/csharp/Board.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\n\nusing static Hexapawn.Pawn;\n\nnamespace Hexapawn;\n\ninternal class Board : IEnumerable<Pawn>, IEquatable<Board>\n{\n    private readonly Pawn[] _cells;\n\n    public Board()\n    {\n        _cells = new[]\n        {\n            Black, Black, Black,\n            None,  None,  None,\n            White, White, White\n        };\n    }\n\n    public Board(params Pawn[] cells)\n    {\n        _cells = cells;\n    }\n\n    public Pawn this[int index]\n    {\n        get => _cells[index - 1];\n        set => _cells[index - 1] = value;\n    }\n\n    public Board Reflected => new(Cell.AllCells.Select(c => this[c.Reflected]).ToArray());\n\n    public IEnumerator<Pawn> GetEnumerator() => _cells.OfType<Pawn>().GetEnumerator();\n\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n    public override string ToString()\n    {\n        var builder = new StringBuilder().AppendLine();\n        for (int row = 0; row < 3; row++)\n        {\n            builder.Append(\"          \");\n            for (int col = 0; col < 3; col++)\n            {\n                builder.Append(_cells[row * 3 + col]);\n            }\n            builder.AppendLine();\n        }\n        return builder.ToString();\n    }\n\n    public bool Equals(Board other) => other?.Zip(this).All(x => x.First == x.Second) ?? false;\n\n    public override bool Equals(object obj) => Equals(obj as Board);\n\n    public override int GetHashCode()\n    {\n        var hash = 19;\n\n        for (int i = 0; i < 9; i++)\n        {\n            hash = hash * 53 + _cells[i].GetHashCode();\n        }\n\n        return hash;\n    }\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/Cell.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Hexapawn;\n\n// Represents a cell on the board, numbered 1 to 9, with support for finding the reflection of the reference around\n// the middle column of the board.\ninternal class Cell\n{\n    private static readonly Cell[] _cells = new Cell[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };\n    private static readonly Cell[] _reflected = new Cell[] { 3, 2, 1, 6, 5, 4, 9, 8, 7 };\n    private readonly int _number;\n    private Cell(int number)\n    {\n        if (number < 1 || number > 9)\n        {\n            throw new ArgumentOutOfRangeException(nameof(number), number, \"Must be from 1 to 9\");\n        }\n        _number = number;\n    }\n    // Facilitates enumerating all the cells.\n    public static IEnumerable<Cell> AllCells => _cells;\n    // Takes a value input by the user and attempts to create a Cell reference\n    public static bool TryCreate(float input, out Cell cell)\n    {\n        if (IsInteger(input) && input >= 1 && input <= 9)\n        {\n            cell = (int)input;\n            return true;\n        }\n        cell = default;\n        return false;\n        static bool IsInteger(float value) => value - (int)value == 0;\n    }\n    // Returns the reflection of the cell reference about the middle column of the board.\n    public Cell Reflected => _reflected[_number - 1];\n    // Allows the cell reference to be used where an int is expected, such as the indexer in Board.\n    public static implicit operator int(Cell c) => c._number;\n    public static implicit operator Cell(int number) => new(number);\n    public override string ToString() => _number.ToString();\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/Computer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing static Hexapawn.Pawn;\n\nnamespace Hexapawn;\n\n/// <summary>\n/// Encapsulates the logic of the computer player.\n/// </summary>\ninternal class Computer\n{\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n    private readonly Dictionary<Board, List<Move>> _potentialMoves;\n    private (List<Move>, Move) _lastMove;\n    public Computer(TextIO io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n\n        // This dictionary implements the data in the original code, which encodes board positions for which the\n        // computer has a legal move, and the list of possible moves for each position:\n        //   900 DATA -1,-1,-1,1,0,0,0,1,1,-1,-1,-1,0,1,0,1,0,1\n        //   905 DATA -1,0,-1,-1,1,0,0,0,1,0,-1,-1,1,-1,0,0,0,1\n        //   910 DATA -1,0,-1,1,1,0,0,1,0,-1,-1,0,1,0,1,0,0,1\n        //   915 DATA 0,-1,-1,0,-1,1,1,0,0,0,-1,-1,-1,1,1,1,0,0\n        //   920 DATA -1,0,-1,-1,0,1,0,1,0,0,-1,-1,0,1,0,0,0,1\n        //   925 DATA 0,-1,-1,0,1,0,1,0,0,-1,0,-1,1,0,0,0,0,1\n        //   930 DATA 0,0,-1,-1,-1,1,0,0,0,-1,0,0,1,1,1,0,0,0\n        //   935 DATA 0,-1,0,-1,1,1,0,0,0,-1,0,0,-1,-1,1,0,0,0\n        //   940 DATA 0,0,-1,-1,1,0,0,0,0,0,-1,0,1,-1,0,0,0,0\n        //   945 DATA -1,0,0,-1,1,0,0,0,0\n        //   950 DATA 24,25,36,0,14,15,36,0,15,35,36,47,36,58,59,0\n        //   955 DATA 15,35,36,0,24,25,26,0,26,57,58,0\n        //   960 DATA 26,35,0,0,47,48,0,0,35,36,0,0,35,36,0,0\n        //   965 DATA 36,0,0,0,47,58,0,0,15,0,0,0\n        //   970 DATA 26,47,0,0,47,58,0,0,35,36,47,0,28,58,0,0,15,47,0,0\n        //\n        // The original code loaded this data into two arrays.\n        //   40 FOR I=1 TO 19: FOR J=1 TO 9: READ B(I,J): NEXT J: NEXT I\n        //   45 FOR I=1 TO 19: FOR J=1 TO 4: READ M(I,J): NEXT J: NEXT I\n        //\n        // When finding moves for the computer the first array was searched for the current board position, or the\n        // reflection of it, and the resulting index was used in the second array to get the possible moves.\n        // With this dictionary we can just use the current board as the index, and retrieve a list of moves for\n        // consideration by the computer.\n        _potentialMoves = new()\n        {\n            [new(Black, Black, Black, White, None,  None,  None,  White, White)] = Moves((2, 4), (2, 5), (3, 6)),\n            [new(Black, Black, Black, None,  White, None,  White, None,  White)] = Moves((1, 4), (1, 5), (3, 6)),\n            [new(Black, None,  Black, Black, White, None,  None,  None,  White)] = Moves((1, 5), (3, 5), (3, 6), (4, 7)),\n            [new(None,  Black, Black, White, Black, None,  None,  None,  White)] = Moves((3, 6), (5, 8), (5, 9)),\n            [new(Black, None,  Black, White, White, None,  None,  White, None)]  = Moves((1, 5), (3, 5), (3, 6)),\n            [new(Black, Black, None,  White, None,  White, None,  None,  White)] = Moves((2, 4), (2, 5), (2, 6)),\n            [new(None,  Black, Black, None,  Black, White, White, None,  None)]  = Moves((2, 6), (5, 7), (5, 8)),\n            [new(None,  Black, Black, Black, White, White, White, None,  None)]  = Moves((2, 6), (3, 5)),\n            [new(Black, None,  Black, Black, None,  White, None,  White, None)]  = Moves((4, 7), (4, 8)),\n            [new(None,  Black, Black, None,  White, None,  None,  None,  White)] = Moves((3, 5), (3, 6)),\n            [new(None,  Black, Black, None,  White, None,  White, None,  None)]  = Moves((3, 5), (3, 6)),\n            [new(Black, None,  Black, White, None,  None,  None,  None,  White)] = Moves((3, 6)),\n            [new(None,  None,  Black, Black, Black, White, None,  None,  None)]  = Moves((4, 7), (5, 8)),\n            [new(Black, None,  None,  White, White, White, None,  None,  None)]  = Moves((1, 5)),\n            [new(None,  Black, None,  Black, White, White, None,  None,  None)]  = Moves((2, 6), (4, 7)),\n            [new(Black, None,  None,  Black, Black, White, None,  None,  None)]  = Moves((4, 7), (5, 8)),\n            [new(None,  None,  Black, Black, White, None,  None,  None,  None)]  = Moves((3, 5), (3, 6), (4, 7)),\n            [new(None,  Black, None,  White, Black, None,  None,  None,  None)]  = Moves((2, 8), (5, 8)),\n            [new(Black, None,  None,  Black, White, None,  None,  None,  None)]  = Moves((1, 5), (4, 7))\n        };\n    }\n\n    // Try to make a move. We first try to find a legal move for the current board position.\n    public bool TryMove(Board board)\n    {\n        if (TryGetMoves(board, out var moves, out var reflected) &&\n            TrySelectMove(moves, out var move))\n        {\n            // We've found a move, so we record it as the last move made, and then announce and make the move.\n            _lastMove = (moves, move);\n            // If we found the move from a reflacted match of the board we need to make the reflected move.\n            if (reflected) { move = move.Reflected; }\n            _io.WriteLine($\"I move {move}\");\n            move.Execute(board);\n            return true;\n        }\n        // We haven't found a move for this board position, so remove the previous move that led to this board\n        // position from future consideration. We don't want to make that move again, because we now know it's a\n        // non-winning move.\n        ExcludeLastMoveFromFuturePlay();\n        return false;\n    }\n\n    // Looks up the given board and its reflection in the potential moves dictionary. If it's found then we have a\n    // list of potential moves. If the board is not found in the dictionary then the computer has no legal moves,\n    // and the human player wins.\n    private bool TryGetMoves(Board board, out List<Move> moves, out bool reflected)\n    {\n        if (_potentialMoves.TryGetValue(board, out moves))\n        {\n            reflected = false;\n            return true;\n        }\n        if (_potentialMoves.TryGetValue(board.Reflected, out moves))\n        {\n            reflected = true;\n            return true;\n        }\n        reflected = default;\n        return false;\n    }\n\n    // Get a random move from the list. If the list is empty, then we've previously eliminated all the moves for\n    // this board position as being non-winning moves. We therefore resign the game.\n    private bool TrySelectMove(List<Move> moves, out Move move)\n    {\n        if (moves.Any())\n        {\n            move = moves[_random.Next(moves.Count)];\n            return true;\n        }\n        _io.WriteLine(\"I resign.\");\n        move = null;\n        return false;\n    }\n\n    private void ExcludeLastMoveFromFuturePlay()\n    {\n        var (moves, move) = _lastMove;\n        moves.Remove(move);\n    }\n\n    private static List<Move> Moves(params Move[] moves) => moves.ToList();\n\n    public bool IsFullyAdvanced(Board board) =>\n        board[9] == Black || board[8] == Black || board[7] == Black;\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/Game.cs",
    "content": "using System;\nusing Games.Common.IO;\n\nnamespace Hexapawn;\n\n// A single game of Hexapawn\ninternal class Game\n{\n    private readonly TextIO _io;\n    private readonly Board _board;\n\n    public Game(TextIO io)\n    {\n        _board = new Board();\n        _io = io;\n    }\n\n    public object Play(Human human, Computer computer)\n    {\n        _io.WriteLine(_board);\n        while(true)\n        {\n            human.Move(_board);\n            _io.WriteLine(_board);\n            if (!computer.TryMove(_board))\n            {\n                return human;\n            }\n            _io.WriteLine(_board);\n            if (computer.IsFullyAdvanced(_board) || human.HasNoPawns(_board))\n            {\n                return computer;\n            }\n            if (!human.HasLegalMove(_board))\n            {\n                _io.Write(\"You can't move, so \");\n                return computer;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/GameSeries.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing Hexapawn.Resources;\n\nnamespace Hexapawn;\n\n// Runs series of games between the computer and the human player\ninternal class GameSeries\n{\n    private readonly TextIO _io;\n    private readonly Computer _computer;\n    private readonly Human _human;\n    private readonly Dictionary<object, int> _wins;\n\n    public GameSeries(TextIO io, IRandom random)\n    {\n        _io = io;\n        _computer = new(io, random);\n        _human = new(io);\n        _wins = new() { [_computer] = 0, [_human] = 0 };\n    }\n\n    public void Play()\n    {\n        _io.Write(Resource.Streams.Title);\n\n        if (_io.GetYesNo(\"Instructions\") == 'Y')\n        {\n            _io.Write(Resource.Streams.Instructions);\n        }\n\n        while (true)\n        {\n            var game = new Game(_io);\n\n            var winner = game.Play(_human, _computer);\n            _wins[winner]++;\n            _io.WriteLine(winner == _computer ? \"I win.\" : \"You win.\");\n\n            _io.Write($\"I have won {_wins[_computer]} and you {_wins[_human]}\");\n            _io.WriteLine($\" out of {_wins.Values.Sum()} games.\");\n            _io.WriteLine();\n        }\n    }\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/Hexapawn.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources\\*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "46_Hexapawn/csharp/Hexapawn.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Hexapawn\", \"Hexapawn.csproj\", \"{785DA416-2609-4DB1-9F18-63CF6AC9927E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {D662AD9F-88B1-4AC9-83AD-DBFC08F384A8}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "46_Hexapawn/csharp/Human.cs",
    "content": "using System;\nusing System.Linq;\nusing Games.Common.IO;\nusing static Hexapawn.Cell;\nusing static Hexapawn.Move;\nusing static Hexapawn.Pawn;\n\nnamespace Hexapawn;\n\ninternal class Human\n{\n    private readonly TextIO _io;\n\n    public Human(TextIO io)\n    {\n        _io = io;\n    }\n\n    public void Move(Board board)\n    {\n        while (true)\n        {\n            var move = _io.ReadMove(\"Your move\");\n\n            if (TryExecute(board, move)) { return; }\n\n            _io.WriteLine(\"Illegal move.\");\n        }\n    }\n\n    public bool HasLegalMove(Board board)\n    {\n        foreach (var from in AllCells.Where(c => c > 3))\n        {\n            if (board[from] != White) { continue; }\n\n            if (HasLegalMove(board, from))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private bool HasLegalMove(Board board, Cell from) =>\n        Right(from).IsRightDiagonalToCapture(board) ||\n        Straight(from).IsStraightMoveToEmptySpace(board) ||\n        from > 4 && Left(from).IsLeftDiagonalToCapture(board);\n\n    public bool HasNoPawns(Board board) => board.All(c => c != White);\n\n    public bool TryExecute(Board board, Move move)\n    {\n        if (board[move.From] != White) { return false; }\n\n        if (move.IsStraightMoveToEmptySpace(board) ||\n            move.IsLeftDiagonalToCapture(board) ||\n            move.IsRightDiagonalToCapture(board))\n        {\n            move.Execute(board);\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/IReadWriteExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Games.Common.IO;\n\nnamespace Hexapawn;\n\n// Provides input methods which emulate the BASIC interpreter's keyboard input routines\ninternal static class IReadWriteExtensions\n{\n    internal static char GetYesNo(this IReadWrite io, string prompt)\n    {\n        while (true)\n        {\n            var response = io.ReadString($\"{prompt} (Y-N)\").FirstOrDefault();\n            if (\"YyNn\".Contains(response))\n            {\n                return char.ToUpperInvariant(response);\n            }\n        }\n    }\n\n    // Implements original code:\n    //   120 PRINT \"YOUR MOVE\";\n    //   121 INPUT M1,M2\n    //   122 IF M1=INT(M1)AND M2=INT(M2)AND M1>0 AND M1<10 AND M2>0 AND M2<10 THEN 130\n    //   123 PRINT \"ILLEGAL CO-ORDINATES.\"\n    //   124 GOTO 120\n    internal static Move ReadMove(this IReadWrite io, string prompt)\n    {\n        while(true)\n        {\n            var (from, to) = io.Read2Numbers(prompt);\n\n            if (Move.TryCreate(from, to, out var move))\n            {\n                return move;\n            }\n\n            io.WriteLine(\"Illegal Coordinates.\");\n        }\n    }\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/Move.cs",
    "content": "using static Hexapawn.Pawn;\n\nnamespace Hexapawn;\n\n/// <summary>\n/// Represents a move which may, or may not, be legal.\n/// </summary>\ninternal class Move\n{\n    private readonly Cell _from;\n    private readonly Cell _to;\n    private readonly int _metric;\n\n    public Move(Cell from, Cell to)\n    {\n        _from = from;\n        _to = to;\n        _metric = _from - _to;\n    }\n\n    public void Deconstruct(out Cell from, out Cell to)\n    {\n        from = _from;\n        to = _to;\n    }\n\n    public Cell From => _from;\n\n    // Produces the mirror image of the current moved, reflected around the central column of the board.\n    public Move Reflected => (_from.Reflected, _to.Reflected);\n\n    // Allows a tuple of two ints to be implicitly converted to a Move.\n    public static implicit operator Move((int From, int To) value) => new(value.From, value.To);\n\n    // Takes floating point coordinates, presumably from keyboard input, and attempts to create a Move object.\n    public static bool TryCreate(float input1, float input2, out Move move)\n    {\n        if (Cell.TryCreate(input1, out var from) &&\n            Cell.TryCreate(input2, out var to))\n        {\n            move = (from, to);\n            return true;\n        }\n\n        move = default;\n        return false;\n    }\n\n    public static Move Right(Cell from) => (from, from - 2);\n    public static Move Straight(Cell from) => (from, from - 3);\n    public static Move Left(Cell from) => (from, from - 4);\n\n    public bool IsStraightMoveToEmptySpace(Board board) => _metric == 3 && board[_to] == None;\n\n    public bool IsLeftDiagonalToCapture(Board board) => _metric == 4 && _from != 7 && board[_to] == Black;\n\n    public bool IsRightDiagonalToCapture(Board board) =>\n        _metric == 2 && _from != 9 && _from != 6 && board[_to] == Black;\n\n    public void Execute(Board board)\n    {\n        board[_to] = board[_from];\n        board[_from] = None;\n    }\n\n    public override string ToString() => $\"from {_from} to {_to}\";\n}\n"
  },
  {
    "path": "46_Hexapawn/csharp/Pawn.cs",
    "content": "namespace Hexapawn;\n\n// Represents the contents of a cell on the board\ninternal class Pawn\n{\n    public static readonly Pawn Black = new('X');\n    public static readonly Pawn White = new('O');\n    public static readonly Pawn None = new('.');\n\n    private readonly char _symbol;\n\n    private Pawn(char symbol)\n    {\n        _symbol = symbol;\n    }\n\n    public override string ToString() => _symbol.ToString();\n}\n\n"
  },
  {
    "path": "46_Hexapawn/csharp/Program.cs",
    "content": "﻿using Games.Common.IO;\nusing Games.Common.Randomness;\nusing Hexapawn;\n\nnew GameSeries(new ConsoleIO(), new RandomNumberGenerator()).Play();\n\n"
  },
  {
    "path": "46_Hexapawn/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "46_Hexapawn/csharp/Resources/Instructions.txt",
    "content": "\nThis program plays the game of Hexapawn.\nHexapawn is played with Chess pawns on a 3 by 3 board.\nThe pawns are move as in Chess - one space forward to\nan empty space, or one space forward and diagonally to\ncapture an opposing man.  On the board, your pawns\nare 'O', the computer's pawns are 'X', and empty\nsquares are '.'.  To enter a move, type the number of\nthe square you are moving from, followed by the number\nof the square you will move to.  The numbers must be\nseparated by a comma.\n\nThe computer starts a series of games knowing only when\nthe game is won (a draw is impossible) and how to move.\nIt has no strategy at first and just moves randomly.\nHowever, it learns from each game.  Thus winning becomes\nmore and more difficult.  Also, to help offset your\ninitial advantage, you will not be told how to win the\ngame but must learn this by playing.\n\nThe numbering of the board is as follows:\n          123\n          456\n          789\n\nFor example, to move your rightmost pawn forward,\nyou would type 9,6 in response to the question\n'Your move ?'.  Since I'm a good sport, you'll always\ngo first.\n\n"
  },
  {
    "path": "46_Hexapawn/csharp/Resources/Resource.cs",
    "content": "using System.IO;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Hexapawn.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Instructions => GetStream();\n        public static Stream Title => GetStream();\n    }\n\n    private static Stream GetStream([CallerMemberName] string name = null)\n        => Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Hexapawn.Resources.{name}.txt\");\n}"
  },
  {
    "path": "46_Hexapawn/csharp/Resources/Title.txt",
    "content": "                                Hexapawn\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "46_Hexapawn/hexapawn.bas",
    "content": "1 PRINT TAB(32);\"HEXAPAWN\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 REM  HEXAPAWN:  INTERPRETATION OF HEXAPAWN GAME AS PRESENTED IN\n5 REM  MARTIN GARDNER'S \"THE UNEXPECTED HANGING AND OTHER MATHEMATIC-\n6 REM  AL DIVERSIONS\", CHAPTER EIGHT:  A MATCHBOX GAME-LEARNING MACHINE\n7 REM  ORIGINAL VERSION FOR H-P TIMESHARE SYSTEM BY R.A. KAAPKE 5/5/76\n8 REM  INSTRUCTIONS BY JEFF DALTON\n9 REM  CONVERSION TO MITS BASIC BY STEVE NORTH\n10 DIM B(19,9),M(19,4),S(9),P$(3)\n15 W=0: L=0\n20 DEF FNR(X)=-3*(X=1)-(X=3)-4*(X=6)-6*(X=4)-7*(X=9)-9*(X=7)+FNS(X)\n25 DEF FNS(X)=-X*(X=2 OR X=5 OR X=8)\n30 DEF FNM(Y)=Y-INT(Y/10)*10\n35 P$=\"X.O\"\n40 FOR I=1 TO 19: FOR J=1 TO 9: READ B(I,J): NEXT J: NEXT I\n45 FOR I=1 TO 19: FOR J=1 TO 4: READ M(I,J): NEXT J: NEXT I\n50 PRINT \"INSTRUCTIONS (Y-N)\";\n60 INPUT A$\n70 A$=LEFT$(A$,1)\n80 IF A$=\"Y\" THEN 2000\n90 IF A$<>\"N\" THEN 50\n100 X=0: Y=0\n111 S(4)=0: S(5)=0: S(6)=0\n112 S(1)=-1: S(2)=-1: S(3)=-1\n113 S(7)=1: S(8)=1: S(9)=1\n115 GOSUB 1000\n120 PRINT \"YOUR MOVE\";\n121 INPUT M1,M2\n122 IF M1=INT(M1)AND M2=INT(M2)AND M1>0 AND M1<10 AND M2>0 AND M2<10 THEN 130\n123 PRINT \"ILLEGAL CO-ORDINATES.\"\n124 GOTO 120\n130 IF S(M1)=1 THEN 150\n140 PRINT \"ILLEGAL MOVE.\": GOTO 120\n150 IF S(M2)=1 THEN 140\n160 IF M2-M1<>-3 AND S(M2)<>-1 THEN 140\n170 IF M2>M1 THEN 140\n180 IF M2-M1=-3 AND (S(M2)<>0) THEN 140\n185 IF M2-M1<-4 THEN 140\n186 IF M1=7 AND M2=3 THEN 140\n190 S(M1)=0\n200 S(M2)=1\n205 GOSUB 1000\n210 IF S(1)=1 OR S(2)=1 OR S(3)=1 THEN 820\n220 FOR I=1 TO 9\n221 IF S(I)=-1 THEN 230\n222 NEXT I\n223 GOTO 820\n230 FOR I=1 TO 9\n240 IF S(I)<>-1 THEN 330\n250 IF S(I+3)=0 THEN 350\n260 IF FNR(I)=I THEN 320\n270 IF I>3 THEN 300\n280 IF S(5)=1 THEN 350\n290 GOTO 330\n300 IF S(8)=1 THEN 350\n310 GOTO 330\n320 IF S(I+2)=1 OR S(I+4)=1 THEN 350\n330 NEXT I\n340 GOTO 820\n350 FOR I=1 TO 19\n360 FOR J=1 TO 3\n370 FOR K=3 TO 1 STEP -1\n380 T((J-1)*3+K)=B(I,(J-1)*3+4-K)\n390 NEXT K\n400 NEXT J\n410 FOR J=1 TO 9\n420 IF S(J)<>B(I,J) THEN 460\n430 NEXT J\n440 R=0\n450 GOTO 540\n460 FOR J=1 TO 9\n470 IF S(J)<>T(J) THEN 510\n480 NEXT J\n490 R=1\n500 GOTO 540\n510 NEXT I\n511 REMEMBER THE TERMINATION OF THIS LOOP IS IMPOSSIBLE\n512 PRINT \"ILLEGAL BOARD PATTERN.\"\n530 STOP\n540 X=I\n550 FOR I=1 TO 4\n560 IF M(X,I)<>0 THEN 600\n570 NEXT I\n580 PRINT \"I RESIGN.\"\n590 GOTO 820\n600 Y=INT(RND(1)*4+1)\n601 IF M(X,Y)=0 THEN 600\n610 IF R<>0 THEN 630\n620 PRINT \"I MOVE FROM \";STR$(INT(M(X,Y)/10));\" TO \";STR$(FNM(M(X,Y)))\n622 S(INT(M(X,Y)/10))=0\n623 S(FNM(M(X,Y)))=-1\n624 GOTO 640\n630 PRINT \"I MOVE FROM \";STR$(FNR(INT(M(X,Y)/10)));\" TO \";\n631 PRINT STR$(FNR(FNM(M(X,Y))))\n632 S(FNR(INT(M(X,Y)/10)))=0\n633 S(FNR(FNM(M(X,Y))))=-1\n640 GOSUB 1000\n641 IF S(7)=-1 OR S(8)=-1 OR S(9)=-1 THEN 870\n650 FOR I=1 TO 9\n660 IF S(I)=1 THEN 690\n670 NEXT I\n680 GOTO 870\n690 FOR I=1 TO 9\n700 IF S(I)<>1 THEN 790\n710 IF S(I-3)=0 THEN 120\n720 IF FNR(I)=I THEN 780\n730 IF I<7 THEN 760\n740 IF S(5)=-1 THEN 120\n750 GOTO 790\n760 IF S(2)=-1 THEN 120\n770 GOTO 790\n780 IF S(I-2)=-1 OR S(I-4)=-1 THEN 120\n790 NEXT I\n800 PRINT \"YOU CAN'T MOVE, SO \";\n810 GOTO 870\n820 PRINT \"YOU WIN.\"\n830 M(X,Y)=0\n840 L=L+1\n850 PRINT \"I HAVE WON\";W;\"AND YOU\";L;\"OUT OF\";L+W;\"GAMES.\"\n851 PRINT\n860 GOTO 100\n870 PRINT \"I WIN.\"\n880 W=W+1\n890 GOTO 850\n900 DATA -1,-1,-1,1,0,0,0,1,1,-1,-1,-1,0,1,0,1,0,1\n905 DATA -1,0,-1,-1,1,0,0,0,1,0,-1,-1,1,-1,0,0,0,1\n910 DATA -1,0,-1,1,1,0,0,1,0,-1,-1,0,1,0,1,0,0,1\n915 DATA 0,-1,-1,0,-1,1,1,0,0,0,-1,-1,-1,1,1,1,0,0\n920 DATA -1,0,-1,-1,0,1,0,1,0,0,-1,-1,0,1,0,0,0,1\n925 DATA 0,-1,-1,0,1,0,1,0,0,-1,0,-1,1,0,0,0,0,1\n930 DATA 0,0,-1,-1,-1,1,0,0,0,-1,0,0,1,1,1,0,0,0\n935 DATA 0,-1,0,-1,1,1,0,0,0,-1,0,0,-1,-1,1,0,0,0\n940 DATA 0,0,-1,-1,1,0,0,0,0,0,-1,0,1,-1,0,0,0,0\n945 DATA -1,0,0,-1,1,0,0,0,0\n950 DATA 24,25,36,0,14,15,36,0,15,35,36,47,36,58,59,0\n955 DATA 15,35,36,0,24,25,26,0,26,57,58,0\n960 DATA 26,35,0,0,47,48,0,0,35,36,0,0,35,36,0,0\n965 DATA 36,0,0,0,47,58,0,0,15,0,0,0\n970 DATA 26,47,0,0,47,58,0,0,35,36,47,0,28,58,0,0,15,47,0,0\n1000 PRINT\n1010 FOR I=1 TO 3\n1020 FOR J=1 TO 3\n1030 PRINT TAB(10);MID$(P$,S((I-1)*3+J)+2,1);\n1040 NEXT J\n1050 PRINT\n1060 NEXT I\n1070 PRINT\n1080 RETURN\n2000 PRINT: PRINT \"THIS PROGRAM PLAYS THE GAME OF HEXAPAWN.\"\n2010 PRINT \"HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.\"\n2020 PRINT \"THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO\"\n2030 PRINT \"AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO\"\n2040 PRINT \"CAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS\"\n2050 PRINT \"ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY \"\n2060 PRINT \"SQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF\"\n2070 PRINT \"THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER\"\n2080 PRINT \"OF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE\"\n2090 PRINT \"SEPERATED BY A COMMA.\": PRINT\n2100 PRINT \"THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN\"\n2105 PRINT \"THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE.\"\n2110 PRINT \"IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY.\"\n2120 PRINT \"HOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES\"\n2130 PRINT \"MORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR\"\n2140 PRINT \"INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE\"\n2150 PRINT \"GAME BUT MUST LEARN THIS BY PLAYING.\"\n2160 PRINT: PRINT \"THE NUMBERING OF THE BOARD IS AS FOLLOWS:\"\n2170 PRINT TAB(10);\"123\": PRINT TAB(10);\"456\": PRINT TAB(10);\"789\"\n2180 PRINT: PRINT \"FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,\"\n2190 PRINT \"YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION\"\n2200 PRINT \"'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS\"\n2210 PRINT \"GO FIRST.\": PRINT\n2220 GOTO 100\n9999 END\n"
  },
  {
    "path": "46_Hexapawn/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "46_Hexapawn/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "46_Hexapawn/javascript/hexapawn.html",
    "content": "<html>\n<head>\n<title>HEXAPAWN</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hexapawn.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "46_Hexapawn/javascript/hexapawn.js",
    "content": "// HEXAPAWN\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar ba = [,\n          [,-1,-1,-1,1,0,0,0,1,1],\n          [,-1,-1,-1,0,1,0,1,0,1],\n          [,-1,0,-1,-1,1,0,0,0,1],\n          [,0,-1,-1,1,-1,0,0,0,1],\n          [,-1,0,-1,1,1,0,0,1,0],\n          [,-1,-1,0,1,0,1,0,0,1],\n          [,0,-1,-1,0,-1,1,1,0,0],\n          [,0,-1,-1,-1,1,1,1,0,0],\n          [,-1,0,-1,-1,0,1,0,1,0],\n          [,0,-1,-1,0,1,0,0,0,1],\n          [,0,-1,-1,0,1,0,1,0,0],\n          [,-1,0,-1,1,0,0,0,0,1],\n          [,0,0,-1,-1,-1,1,0,0,0],\n          [,-1,0,0,1,1,1,0,0,0],\n          [,0,-1,0,-1,1,1,0,0,0],\n          [,-1,0,0,-1,-1,1,0,0,0],\n          [,0,0,-1,-1,1,0,0,0,0],\n          [,0,-1,0,1,-1,0,0,0,0],\n          [,-1,0,0,-1,1,0,0,0,0]];\nvar ma = [,\n          [,24,25,36,0],\n          [,14,15,36,0],\n          [,15,35,36,47],\n          [,36,58,59,0],\n          [,15,35,36,0],\n          [,24,25,26,0],\n          [,26,57,58,0],\n          [,26,35,0,0],\n          [,47,48,0,0],\n          [,35,36,0,0],\n          [,35,36,0,0],\n          [,36,0,0,0],\n          [,47,58,0,0],\n          [,15,0,0,0],\n          [,26,47,0,0],\n          [,47,58,0,0],\n          [,35,36,47,0],\n          [,28,58,0,0],\n          [,15,47,0,0]];\nvar s = [];\nvar t = [];\nvar ps = \"X.O\";\n\nfunction show_board()\n{\n    print(\"\\n\");\n    for (var i = 1; i <= 3; i++) {\n        print(tab(10));\n        for (var j = 1; j <= 3; j++) {\n            print(ps[s[(i - 1) * 3 + j] + 1]);\n        }\n        print(\"\\n\");\n    }\n}\n\nfunction mirror(x)\n{\n    if (x == 1)\n        return 3;\n    if (x == 3)\n        return 1;\n    if (x == 6)\n        return 4;\n    if (x == 4)\n        return 6;\n    if (x == 9)\n        return 7;\n    if (x == 7)\n        return 9;\n    return x;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"HEXAPAWN\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // HEXAPAWN:  INTERPRETATION OF HEXAPAWN GAME AS PRESENTED IN\n    // MARTIN GARDNER'S \"THE UNEXPECTED HANGING AND OTHER MATHEMATIC-\n    // AL DIVERSIONS\", CHAPTER EIGHT:  A MATCHBOX GAME-LEARNING MACHINE\n    // ORIGINAL VERSION FOR H-P TIMESHARE SYSTEM BY R.A. KAAPKE 5/5/76\n    // INSTRUCTIONS BY JEFF DALTON\n    // CONVERSION TO MITS BASIC BY STEVE NORTH\n    for (i = 0; i <= 9; i++) {\n        s[i] = 0;\n    }\n    w = 0;\n    l = 0;\n    do {\n        print(\"INSTRUCTIONS (Y-N)\");\n        str = await input();\n        str = str.substr(0, 1);\n    } while (str != \"Y\" && str != \"N\") ;\n    if (str == \"Y\") {\n        print(\"\\n\");\n        print(\"THIS PROGRAM PLAYS THE GAME OF HEXAPAWN.\\n\");\n        print(\"HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.\\n\");\n        print(\"THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO\\n\");\n        print(\"AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO\\n\");\n        print(\"CAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS\\n\");\n        print(\"ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY \\n\");\n        print(\"SQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF\\n\");\n        print(\"THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER\\n\");\n        print(\"OF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE\\n\");\n        print(\"SEPERATED BY A COMMA.\\n\");\n        print(\"\\n\");\n        print(\"THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN\\n\");\n        print(\"THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE.\\n\");\n        print(\"IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY.\\n\");\n        print(\"HOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES\\n\");\n        print(\"MORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR\\n\");\n        print(\"INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE\\n\");\n        print(\"GAME BUT MUST LEARN THIS BY PLAYING.\\n\");\n        print(\"\\n\");\n        print(\"THE NUMBERING OF THE BOARD IS AS FOLLOWS:\\n\");\n        print(tab(10) + \"123\\n\");\n        print(tab(10) + \"456\\n\");\n        print(tab(10) + \"789\\n\");\n        print(\"\\n\");\n        print(\"FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,\\n\");\n        print(\"YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION\\n\");\n        print(\"'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS\\n\");\n        print(\"GO FIRST.\\n\");\n        print(\"\\n\");\n    }\n    while (1) {\n        x = 0;\n        y = 0;\n        s[4] = 0;\n        s[5] = 0;\n        s[6] = 0;\n        s[1] = -1;\n        s[2] = -1;\n        s[3] = -1;\n        s[7] = 1;\n        s[8] = 1;\n        s[9] = 1;\n        show_board();\n        while (1) {\n            while (1) {\n                print(\"YOUR MOVE\");\n                str = await input();\n                m1 = parseInt(str);\n                m2 = parseInt(str.substr(str.indexOf(\",\") + 1));\n                if (m1 > 0 && m1 < 10 && m2 > 0 && m2 < 10) {\n                    if (s[m1] != 1 || s[m2] == 1 || (m2 - m1 != -3 && s[m2] != -1) || (m2 > m1) || (m2 - m1 == -3 && s[m2] != 0) || (m2 - m1 < -4) || (m1 == 7 && m2 == 3))\n                        print(\"ILLEGAL MOVE.\\n\");\n                    else\n                        break;\n                } else {\n                    print(\"ILLEGAL CO-ORDINATES.\\n\");\n                }\n            }\n\n            // Move player's pawn\n            s[m1] = 0;\n            s[m2] = 1;\n            show_board();\n\n            // Find computer pawns\n            for (i = 1; i <= 9; i++) {\n                if (s[i] == -1)\n                    break;\n            }\n            // If none or player reached top then finish\n            if (i > 9 || s[1] == 1 || s[2] == 1 || s[3] == 1) {\n                computer = false;\n                break;\n            }\n            // Find computer pawns with valid move\n            for (i = 1; i <= 9; i++) {\n                if (s[i] != -1)\n                    continue;\n                if (s[i + 3] == 0\n                 || (mirror(i) == i && (s[i + 2] == 1 || s[i + 4] == 1))\n                 || (i <= 3 && s[5] == 1)\n                 || s[8] == 1)\n                    break;\n            }\n            if (i > 9) {  // Finish if none possible\n                computer = false;\n                break;\n            }\n            for (i = 1; i <= 19; i++) {\n                for (j = 1; j <= 3; j++) {\n                    for (k = 3; k >= 1; k--) {\n                        t[(j - 1) * 3 + k] = ba[i][(j - 1) * 3 + 4 - k];\n                    }\n                }\n                for (j = 1; j <= 9; j++) {\n                    if (s[j] != ba[i][j])\n                        break;\n                }\n                if (j > 9) {\n                    r = 0;\n                    break;\n                }\n                for (j = 1; j <= 9; j++) {\n                    if (s[j] != t[j])\n                        break;\n                }\n                if (j > 9) {\n                    r = 1;\n                    break;\n                }\n            }\n            if (i > 19) {\n                print(\"ILLEGAL BOARD PATTERN\\n\");\n                break;\n            }\n            x = i;\n            for (i = 1; i <= 4; i++) {\n                if (ma[x][i] != 0)\n                    break;\n            }\n            if (i > 4) {\n                print(\"I RESIGN.\\n\");\n                computer = false;\n                break;\n            }\n            // Select random move from possibilities\n            do {\n                y = Math.floor(Math.random() * 4 + 1);\n            } while (ma[x][y] == 0) ;\n            // Announce move\n            if (r == 0) {\n                print(\"I MOVE FROM \" + Math.floor(ma[x][y] / 10) + \" TO \" + ma[x][y] % 10 + \"\\n\");\n                s[Math.floor(ma[x][y] / 10)] = 0;\n                s[ma[x][y] % 10] = -1;\n            } else {\n                print(\"I MOVE FROM \" + mirror(Math.floor(ma[x][y] / 10)) + \" TO \" + mirror(ma[x][y]) % 10 + \"\\n\");\n                s[mirror(Math.floor(ma[x][y] / 10))] = 0;\n                s[mirror(ma[x][y] % 10)] = -1;\n            }\n            show_board();\n            // Finish if computer reaches bottom\n            if (s[7] == -1 || s[8] == -1 || s[9] == -1) {\n                computer = true;\n                break;\n            }\n            // Finish if no player pawns\n            for (i = 1; i <= 9; i++) {\n                if (s[i] == 1)\n                    break;\n            }\n            if (i > 9) {\n                computer = true;\n                break;\n            }\n            // Finish if player cannot move\n            for (i = 1; i <= 9; i++) {\n                if (s[i] != 1)\n                    continue;\n                if (s[i - 3] == 0)\n                    break;\n                if (mirror(i) != i) {\n                    if (i >= 7) {\n                        if (s[5] == -1)\n                            break;\n                    } else {\n                        if (s[2] == -1)\n                            break;\n                    }\n                } else {\n                    if (s[i - 2] == -1 || s[i - 4] == -1)\n                        break;\n                }\n\n            }\n            if (i > 9) {\n                print(\"YOU CAN'T MOVE, SO \");\n                computer = true;\n                break;\n            }\n        }\n        if (computer) {\n            print(\"I WIN.\\n\");\n            w++;\n        } else {\n            print(\"YOU WIN\\n\");\n            ma[x][y] = 0;\n            l++;\n        }\n        print(\"I HAVE WON \" + w + \" AND YOU \" + l + \" OUT OF \" + (l + w) + \" GAMES.\\n\");\n        print(\"\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "46_Hexapawn/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "46_Hexapawn/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "46_Hexapawn/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "46_Hexapawn/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "46_Hexapawn/python/hexapawn.py",
    "content": "\"\"\"\nHEXAPAWN\n\nA machine learning game, an interpretation of HEXAPAWN game as\npresented in Martin Gardner's \"The Unexpected Hanging and Other\nMathematical Diversions\", Chapter Eight: A Matchbox Game-Learning\nMachine.\n\nOriginal version for H-P timeshare system by R.A. Kaapke 5/5/76\nInstructions by Jeff Dalton\nConversion to MITS BASIC by Steve North\n\n\nPort to Python by Dave LeCompte\n\"\"\"\n\n# PORTING NOTES:\n#\n# I printed out the BASIC code and hand-annotated what each little block\n# of code did, which feels amazingly retro.\n#\n# I encourage other porters that have a complex knot of GOTOs and\n# semi-nested subroutines to do hard-copy hacking, it might be a\n# different perspective that helps.\n#\n# A spoiler - the objective of the game is not documented, ostensibly to\n# give the human player a challenge. If a player (human or computer)\n# advances a pawn across the board to the far row, that player wins. If\n# a player has no legal moves (either by being blocked, or all their\n# pieces having been captured), that player loses.\n#\n# The original BASIC had 2 2-dimensional tables stored in DATA at the\n# end of the program. This encoded all 19 different board configurations\n# (Hexapawn is a small game), with reflections in one table, and then in\n# a parallel table, for each of the 19 rows, a list of legal moves was\n# encoded by turning them into 2-digit decimal numbers. As gameplay\n# continued, the AI would overwrite losing moves with 0 in the second\n# array.\n#\n# My port takes this \"parallel array\" structure and turns that\n# information into a small Python class, BoardLayout. BoardLayout stores\n# the board description and legal moves, but stores the moves as (row,\n# column) 2-tuples, which is easier to read. The logic for checking if a\n# BoardLayout matches the current board, as well as removing losing move\n# have been moved into methods of this class.\n\nimport random\nfrom typing import Iterator, List, NamedTuple, Optional, Tuple\n\nPAGE_WIDTH = 64\n\nHUMAN_PIECE = 1\nEMPTY_SPACE = 0\nCOMPUTER_PIECE = -1\n\n\nclass ComputerMove(NamedTuple):\n    board_index: int\n    move_index: int\n    m1: int\n    m2: int\n\n\nwins = 0\nlosses = 0\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef print_instructions() -> None:\n    print(\n        \"\"\"\nTHIS PROGRAM PLAYS THE GAME OF HEXAPAWN.\nHEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.\nTHE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO\nAN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO\nCAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS\nARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY\nSQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF\nTHE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER\nOF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE\nSEPERATED BY A COMMA.\n\nTHE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN\nTHE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE.\nIT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY.\nHOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES\nMORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR\nINITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE\nGAME BUT MUST LEARN THIS BY PLAYING.\n\nTHE NUMBERING OF THE BOARD IS AS FOLLOWS:\n          123\n          456\n          789\n\nFOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,\nYOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION\n'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS\nGO FIRST.\n\n\"\"\"\n    )\n\n\ndef prompt_yes_no(msg: str) -> bool:\n    while True:\n        print(msg)\n        response = input().upper()\n        if response[0] == \"Y\":\n            return True\n        elif response[0] == \"N\":\n            return False\n\n\ndef reverse_space_name(space_name: int) -> int:\n    # reverse a space name in the range 1-9 left to right\n    assert 1 <= space_name <= 9\n\n    reflections = {1: 3, 2: 2, 3: 1, 4: 6, 5: 5, 6: 4, 7: 9, 8: 8, 9: 7}\n    return reflections[space_name]\n\n\ndef is_space_in_center_column(space_name: int) -> bool:\n    return reverse_space_name(space_name) == space_name\n\n\nclass BoardLayout:\n    def __init__(self, cells: List[int], move_list: List[Tuple[int, int]]) -> None:\n        self.cells = cells\n        self.moves = move_list\n\n    def _check_match_no_mirror(self, cell_list: List[int]) -> bool:\n        return all(\n            board_contents == cell_list[space_index]\n            for space_index, board_contents in enumerate(self.cells)\n        )\n\n    def _check_match_with_mirror(self, cell_list: List[int]) -> bool:\n        for space_index, board_contents in enumerate(self.cells):\n            reversed_space_index = reverse_space_name(space_index + 1) - 1\n            if board_contents != cell_list[reversed_space_index]:\n                return False\n        return True\n\n    def check_match(self, cell_list: List[int]) -> Tuple[bool, Optional[bool]]:\n        if self._check_match_with_mirror(cell_list):\n            return True, True\n        elif self._check_match_no_mirror(cell_list):\n            return True, False\n        return False, None\n\n    def get_random_move(\n        self, reverse_board: Optional[bool]\n    ) -> Optional[Tuple[int, int, int]]:\n        if not self.moves:\n            return None\n        move_index = random.randrange(len(self.moves))\n\n        m1, m2 = self.moves[move_index]\n        if reverse_board:\n            m1 = reverse_space_name(m1)\n            m2 = reverse_space_name(m2)\n\n        return move_index, m1, m2\n\n\nboards = [\n    BoardLayout([-1, -1, -1, 1, 0, 0, 0, 1, 1], [(2, 4), (2, 5), (3, 6)]),\n    BoardLayout([-1, -1, -1, 0, 1, 0, 1, 0, 1], [(1, 4), (1, 5), (3, 6)]),\n    BoardLayout([-1, 0, -1, -1, 1, 0, 0, 0, 1], [(1, 5), (3, 5), (3, 6), (4, 7)]),\n    BoardLayout([0, -1, -1, 1, -1, 0, 0, 0, 1], [(3, 6), (5, 8), (5, 9)]),\n    BoardLayout([-1, 0, -1, 1, 1, 0, 0, 1, 0], [(1, 5), (3, 5), (3, 6)]),\n    BoardLayout([-1, -1, 0, 1, 0, 1, 0, 0, 1], [(2, 4), (2, 5), (2, 6)]),\n    BoardLayout([0, -1, -1, 0, -1, 1, 1, 0, 0], [(2, 6), (5, 7), (5, 8)]),\n    BoardLayout([0, -1, -1, -1, 1, 1, 1, 0, 0], [(2, 6), (3, 5)]),\n    BoardLayout([-1, 0, -1, -1, 0, 1, 0, 1, 0], [(4, 7), (4, 8)]),\n    BoardLayout([0, -1, -1, 0, 1, 0, 0, 0, 1], [(3, 5), (3, 6)]),\n    BoardLayout([0, -1, -1, 0, 1, 0, 1, 0, 0], [(3, 5), (3, 6)]),\n    BoardLayout([-1, 0, -1, 1, 0, 0, 0, 0, 1], [(3, 6)]),\n    BoardLayout([0, 0, -1, -1, -1, 1, 0, 0, 0], [(4, 7), (5, 8)]),\n    BoardLayout([-1, 0, 0, 1, 1, 1, 0, 0, 0], [(1, 5)]),\n    BoardLayout([0, -1, 0, -1, 1, 1, 0, 0, 0], [(2, 6), (4, 7)]),\n    BoardLayout([-1, 0, 0, -1, -1, 1, 0, 0, 0], [(4, 7), (5, 8)]),\n    BoardLayout([0, 0, -1, -1, 1, 0, 0, 0, 0], [(3, 5), (3, 6), (4, 7)]),\n    BoardLayout([0, -1, 0, 1, -1, 0, 0, 0, 0], [(2, 8), (5, 8)]),\n    BoardLayout([-1, 0, 0, -1, 1, 0, 0, 0, 0], [(1, 5), (4, 7)]),\n]\n\n\ndef get_move(board_index: int, move_index: int) -> Tuple[int, int]:\n    assert board_index >= 0 and board_index < len(boards)\n    board = boards[board_index]\n\n    assert move_index >= 0 and move_index < len(board.moves)\n\n    return board.moves[move_index]\n\n\ndef remove_move(board_index: int, move_index: int) -> None:\n    assert board_index >= 0 and board_index < len(boards)\n    board = boards[board_index]\n\n    assert move_index >= 0 and move_index < len(board.moves)\n\n    del board.moves[move_index]\n\n\ndef init_board() -> List[int]:\n    return [COMPUTER_PIECE] * 3 + [EMPTY_SPACE] * 3 + [HUMAN_PIECE] * 3\n\n\ndef print_board(board: List[int]) -> None:\n    piece_dict = {COMPUTER_PIECE: \"X\", EMPTY_SPACE: \".\", HUMAN_PIECE: \"O\"}\n\n    space = \" \" * 10\n    print()\n    for row in range(3):\n        line = \"\"\n        for column in range(3):\n            line += space\n            space_number = row * 3 + column\n            space_contents = board[space_number]\n            line += piece_dict[space_contents]\n        print(line)\n    print()\n\n\ndef get_coordinates() -> Tuple[int, int]:\n    while True:\n        try:\n            print(\"YOUR MOVE?\")\n            response = input()\n            m1, m2 = (int(c) for c in response.split(\",\"))\n            return m1, m2\n        except ValueError:\n            print_illegal()\n\n\ndef print_illegal() -> None:\n    print(\"ILLEGAL MOVE.\")\n\n\ndef board_contents(board: List[int], space_number: int) -> int:\n    return board[space_number - 1]\n\n\ndef set_board(board: List[int], space_number: int, new_value: int) -> None:\n    board[space_number - 1] = new_value\n\n\ndef is_legal_human_move(board: List[int], m1: int, m2: int) -> bool:\n    if board_contents(board, m1) != HUMAN_PIECE:\n        # Start space doesn't contain player's piece\n        return False\n    if board_contents(board, m2) == HUMAN_PIECE:\n        # Destination space contains player's piece (can't capture your own piece)\n        return False\n\n    is_capture = m2 - m1 != -3\n    if is_capture and board_contents(board, m2) != COMPUTER_PIECE:\n        # Destination does not contain computer piece\n        return False\n\n    if m2 > m1:\n        # can't move backwards\n        return False\n\n    if (not is_capture) and board_contents(board, m2) != EMPTY_SPACE:\n        # Destination is not open\n        return False\n\n    return False if m2 - m1 < -4 else m1 != 7 or m2 != 3\n\n\ndef player_piece_on_back_row(board: List[int]) -> bool:\n    return any(board_contents(board, space) == HUMAN_PIECE for space in range(1, 4))\n\n\ndef computer_piece_on_front_row(board: List[int]) -> bool:\n    return any(board_contents(board, space) == COMPUTER_PIECE for space in range(7, 10))\n\n\ndef all_human_pieces_captured(board: List[int]) -> bool:\n    return not list(get_human_spaces(board))\n\n\ndef all_computer_pieces_captured(board: List[int]) -> bool:\n    return not list(get_computer_spaces(board))\n\n\ndef human_win(last_computer_move: ComputerMove) -> None:\n    print(\"YOU WIN\")\n    remove_move(last_computer_move.board_index, last_computer_move.move_index)\n    global losses\n    losses += 1\n\n\ndef computer_win(has_moves: bool) -> None:\n    msg = (\"YOU CAN'T MOVE, SO \" if not has_moves else \"\") + \"I WIN\"\n    print(msg)\n    global wins\n    wins += 1\n\n\ndef show_scores() -> None:\n    print(f\"I HAVE WON {wins} AND YOU {losses} OUT OF {wins + losses} GAMES.\\n\")\n\n\ndef human_has_move(board: List[int]) -> bool:\n    for i in get_human_spaces(board):\n        if board_contents(board, i - 3) == EMPTY_SPACE:\n            # can move piece forward\n            return True\n        elif is_space_in_center_column(i):\n            if (board_contents(board, i - 2) == COMPUTER_PIECE) or (\n                board_contents(board, i - 4) == COMPUTER_PIECE\n            ):\n                # can capture from center\n                return True\n            else:\n                continue\n        elif i < 7:\n            assert i in [4, 6]\n            if board_contents(board, 2) == COMPUTER_PIECE:\n                # can capture computer piece at 2\n                return True\n            else:\n                continue\n        elif board_contents(board, 5) == COMPUTER_PIECE:\n            assert i in [7, 9]\n            # can capture computer piece at 5\n            return True\n        else:\n            continue\n    return False\n\n\ndef get_board_spaces() -> Iterator[int]:\n    \"\"\"generates the space names (1-9)\"\"\"\n    yield from range(1, 10)\n\n\ndef get_board_spaces_with(board: List[int], val: int) -> Iterator[int]:\n    \"\"\"generates spaces containing pieces of type val\"\"\"\n    for i in get_board_spaces():\n        if board_contents(board, i) == val:\n            yield i\n\n\ndef get_human_spaces(board: List[int]) -> Iterator[int]:\n    yield from get_board_spaces_with(board, HUMAN_PIECE)\n\n\ndef get_empty_spaces(board: List[int]) -> Iterator[int]:\n    yield from get_board_spaces_with(board, EMPTY_SPACE)\n\n\ndef get_computer_spaces(board: List[int]) -> Iterator[int]:\n    yield from get_board_spaces_with(board, COMPUTER_PIECE)\n\n\ndef has_computer_move(board: List[int]) -> bool:\n    for i in get_computer_spaces(board):\n        if board_contents(board, i + 3) == EMPTY_SPACE:\n            # can move forward (down)\n            return True\n\n        if is_space_in_center_column(i):\n            # i is in the middle column\n            if (board_contents(board, i + 2) == HUMAN_PIECE) or (\n                board_contents(board, i + 4) == HUMAN_PIECE\n            ):\n                return True\n        elif (\n            i > 3\n            and board_contents(board, 8) == HUMAN_PIECE\n            or i <= 3\n            and board_contents(board, 5) == HUMAN_PIECE\n        ):\n            # can capture on 8\n            return True\n        elif i <= 3 or board_contents(board, 8) == HUMAN_PIECE:\n            continue\n    return False\n\n\ndef find_board_index_that_matches_board(board: List[int]) -> Tuple[int, Optional[bool]]:\n    for board_index, board_layout in enumerate(boards):\n        matches, is_reversed = board_layout.check_match(board)\n        if matches:\n            return board_index, is_reversed\n\n    # This point should never be reached\n    # In future, mypy might be able to check exhaustiveness via assert_never\n    raise RuntimeError(\"ILLEGAL BOARD PATTERN.\")\n\n\ndef pick_computer_move(board: List[int]) -> Optional[ComputerMove]:\n    if not has_computer_move(board):\n        return None\n\n    board_index, reverse_board = find_board_index_that_matches_board(board)\n\n    m = boards[board_index].get_random_move(reverse_board)\n\n    if m is None:\n        print(\"I RESIGN\")\n        return None\n\n    move_index, m1, m2 = m\n\n    return ComputerMove(board_index, move_index, m1, m2)\n\n\ndef get_human_move(board: List[int]) -> Tuple[int, int]:\n    while True:\n        m1, m2 = get_coordinates()\n\n        if not is_legal_human_move(board, m1, m2):\n            print_illegal()\n        else:\n            return m1, m2\n\n\ndef apply_move(board: List[int], m1: int, m2: int, piece_value: int) -> None:\n    set_board(board, m1, EMPTY_SPACE)\n    set_board(board, m2, piece_value)\n\n\ndef play_game() -> None:\n    last_computer_move = None\n\n    board = init_board()\n\n    while True:\n        print_board(board)\n\n        m1, m2 = get_human_move(board)\n\n        apply_move(board, m1, m2, HUMAN_PIECE)\n\n        print_board(board)\n\n        if player_piece_on_back_row(board) or all_computer_pieces_captured(board):\n            assert last_computer_move is not None\n            human_win(last_computer_move)\n            return\n\n        computer_move = pick_computer_move(board)\n        if computer_move is None:\n            assert last_computer_move is not None\n            human_win(last_computer_move)\n            return\n\n        last_computer_move = computer_move\n\n        m1, m2 = last_computer_move.m1, last_computer_move.m2\n\n        print(f\"I MOVE FROM {m1} TO {m2}\")\n        apply_move(board, m1, m2, COMPUTER_PIECE)\n\n        print_board(board)\n\n        if computer_piece_on_front_row(board):\n            computer_win(True)\n            return\n        elif (not human_has_move(board)) or (all_human_pieces_captured(board)):\n            computer_win(False)\n            return\n\n\ndef main() -> None:\n    print_header(\"HEXAPAWN\")\n    if prompt_yes_no(\"INSTRUCTIONS (Y-N)?\"):\n        print_instructions()\n\n    global wins, losses\n    wins = 0\n    losses = 0\n\n    while True:\n        play_game()\n        show_scores()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "46_Hexapawn/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "46_Hexapawn/vbnet/Hexapawn.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Hexapawn\", \"Hexapawn.vbproj\", \"{83C2A51C-6014-4CC7-A4AF-81004B5F721F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "46_Hexapawn/vbnet/Hexapawn.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Hexapawn</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "46_Hexapawn/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "47_Hi-Lo/README.md",
    "content": "### Hi-Lo\n\nThis game is an adaptation of the game GUESS; however, instead of just guessing a number between 1 and 100, in this game you win dollars when you guess the number. The directions, in the words of the author, are as follows:\n1. There is an amount of money, between one and one hundred dollars, in the “HI-LO” jackpot.\n2. You will have six chances in which to guess the amount of money in the jackpot.\n3. After each guess, the computer will tell whether the guess was too high or too low.\n4. If the correct amount of money is not guessed after six chances, the computer will print the amount in the jackpot.\n5. If the correct amount of money is guessed within the six chance limit, the computer will register this amount.\n6. After each sequence of guesses, you have the choice of playing again or ending the program. If a new game is played, a new amount of money will constitute the jackpot.\n7. If youwin more than once, then your earnings are totalled.\n\nThe author is Dean ALtman of Fort Worth, Texas.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=85)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=100)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "47_Hi-Lo/csharp/HiLo.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "47_Hi-Lo/csharp/HiLo.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"HiLo\", \"HiLo.csproj\", \"{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {BF77DB59-426B-4A01-A8AC-09AAF42DA633}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "47_Hi-Lo/csharp/Program.cs",
    "content": "﻿using System;\n\nConsole.WriteLine(Tab(34) +                 \"HI LO\");\nConsole.WriteLine(Tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\nConsole.WriteLine();\nConsole.WriteLine();\nConsole.WriteLine();\nConsole.WriteLine(\"THIS IS THE GAME OF HI LO.\");\nConsole.WriteLine();\nConsole.WriteLine(\"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\");\nConsole.WriteLine(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\");\nConsole.WriteLine(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\");\nConsole.WriteLine(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\");\nConsole.WriteLine(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\");\nConsole.WriteLine();\n\n// rnd is our random number generator\nRandom rnd = new();\n\nbool playAgain = false;\nint totalWinnings = 0;\n\ndo // Our game loop\n{\n    int jackpot = rnd.Next(100) + 1; // [0..99] + 1 -> [1..100]\n    int guess = 1;\n\n    while (true) // Our guessing loop\n    {\n        Console.WriteLine();\n        int amount = ReadInt(\"YOUR GUESS \");\n\n        if (amount == jackpot)\n        {\n            Console.WriteLine($\"GOT IT!!!!!!!!!!   YOU WIN {jackpot} DOLLARS.\");\n            totalWinnings += jackpot;\n            Console.WriteLine($\"YOUR TOTAL WINNINGS ARE NOW {totalWinnings} DOLLARS.\");\n            break;\n        }\n        else if (amount > jackpot)\n        {\n            Console.WriteLine(\"YOUR GUESS IS TOO HIGH.\");\n        }\n        else\n        {\n            Console.WriteLine(\"YOUR GUESS IS TOO LOW.\");\n        }\n\n        guess++;\n        if (guess > 6)\n        {\n            Console.WriteLine($\"YOU BLEW IT...TOO BAD...THE NUMBER WAS {jackpot}\");\n            break;\n        }\n    }\n\n    Console.WriteLine();\n    Console.Write(\"PLAY AGAIN (YES OR NO) \");\n    playAgain = Console.ReadLine().ToUpper().StartsWith(\"Y\");\n\n} while (playAgain);\n\nConsole.WriteLine();\nConsole.WriteLine(\"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\");\n\n// Tab(n) returns n spaces\nstatic string Tab(int n) => new String(' ', n);\n\n// ReadInt asks the user to enter a number\nstatic int ReadInt(string question)\n{\n    while (true)\n    {\n        Console.Write(question);\n        var input = Console.ReadLine().Trim();\n        if (int.TryParse(input, out int value))\n        {\n            return value;\n        }\n        Console.WriteLine(\"!Invalid Number Entered.\");\n    }\n}\n"
  },
  {
    "path": "47_Hi-Lo/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "47_Hi-Lo/hi-lo.bas",
    "content": "10 PRINT TAB(34);\"HI LO\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"THIS IS THE GAME OF HI LO.\":PRINT\n110 PRINT \"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\"\n120 PRINT \"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\"\n130 PRINT \"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\"\n140 PRINT \"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\"\n150 PRINT \"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\":PRINT\n160 R=0\n170 B=0:PRINT\n180 Y=INT(100*RND(1))\n200 PRINT \"YOUR GUESS\";\n210 INPUT A\n220 B=B+1\n230 IF A=Y THEN 300\n240 IF A>Y THEN 270\n250 PRINT \"YOUR GUESS IS TOO LOW.\":GOTO 280\n270 PRINT \"YOUR GUESS IS TOO HIGH.\"\n280 PRINT:IF B<6 THEN 200\n290 PRINT \"YOU BLEW IT...TOO BAD...THE NUMBER WAS\";Y\n295 R=0:GOTO 350\n300 PRINT \"GOT IT!!!!!!!!!!   YOU WIN\";Y;\"DOLLARS.\"\n310 R=R+Y\n320 PRINT \"YOUR TOTAL WINNINGS ARE NOW\";R;\"DOLLARS.\"\n350 PRINT:PRINT \"PLAY AGAIN (YES OR NO)\";\n360 INPUT A$:IF A$=\"YES\" THEN 170\n380 PRINT:PRINT \"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\"\n390 END\n"
  },
  {
    "path": "47_Hi-Lo/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "47_Hi-Lo/java/src/HiLo.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of HiLo\n *\n * Based on the Basic game of Hi-Lo here\n * https://github.com/coding-horror/basic-computer-games/blob/main/47%20Hi-Lo/hi-lo.bas\n *\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n *        new features - no additional text, error checking, etc has been added.\n */\npublic class HiLo {\n\n    public static final int LOW_NUMBER_RANGE = 1;\n    public static final int HIGH_NUMBER_RANGE = 100;\n    public static final int MAX_GUESSES = 6;\n\n    private enum GAME_STATE {\n        STARTING,\n        START_GAME,\n        GUESSING,\n        PLAY_AGAIN,\n        GAME_OVER\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // Players Winnings\n    private int playerAmountWon;\n\n    // Players guess count;\n    private int playersGuesses;\n\n    // Computers random number\n    private int computersNumber;\n\n    public HiLo() {\n\n        gameState = GAME_STATE.STARTING;\n        playerAmountWon = 0;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     *\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    intro();\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Generate computers number for player to guess, etc.\n                case START_GAME:\n                    init();\n                    System.out.println(\"O.K.  I HAVE A NUMBER IN MIND.\");\n                    gameState = GAME_STATE.GUESSING;\n                    break;\n\n                // Player guesses the number until they get it or run out of guesses\n                case GUESSING:\n                    int guess = playerGuess();\n\n                    // Check if the player guessed the number\n                    if(validateGuess(guess)) {\n                        System.out.println(\"GOT IT!!!!!!!!!!   YOU WIN \" + computersNumber\n                                + \" DOLLARS.\");\n                        playerAmountWon += computersNumber;\n                        System.out.println(\"YOUR TOTAL WINNINGS ARE NOW \"\n                                + playerAmountWon + \" DOLLARS.\");\n                        gameState = GAME_STATE.PLAY_AGAIN;\n                    } else {\n                        // incorrect guess\n                        playersGuesses++;\n                        // Ran out of guesses?\n                        if (playersGuesses == MAX_GUESSES) {\n                            System.out.println(\"YOU BLEW IT...TOO BAD...THE NUMBER WAS \"\n                                    + computersNumber);\n                            playerAmountWon = 0;\n                            gameState = GAME_STATE.PLAY_AGAIN;\n                        }\n                    }\n                    break;\n\n                // Play again, or exit game?\n                case PLAY_AGAIN:\n                    System.out.println();\n                    if(yesEntered(displayTextAndGetInput(\"PLAY AGAIN (YES OR NO) \"))) {\n                        gameState = GAME_STATE.START_GAME;\n                    } else {\n                        // Chose not to play again\n                        System.out.println(\"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\");\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Checks the players guess against the computers randomly generated number\n     *\n     * @param theGuess the players guess\n     * @return true if the player guessed correctly, false otherwise\n     */\n    private boolean validateGuess(int theGuess) {\n\n        // Correct guess?\n        if(theGuess == computersNumber) {\n            return true;\n        }\n\n        if(theGuess > computersNumber) {\n            System.out.println(\"YOUR GUESS IS TOO HIGH.\");\n        } else {\n            System.out.println(\"YOUR GUESS IS TOO LOW.\");\n        }\n\n        return false;\n    }\n\n    private void init() {\n        playersGuesses = 0;\n        computersNumber = randomNumber();\n    }\n\n    public void intro() {\n        System.out.println(\"HI LO\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println();\n        System.out.println(\"IS THE GAME OF HI LO.\");\n        System.out.println();\n        System.out.println(\"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\");\n        System.out.println(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\");\n        System.out.println(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\");\n        System.out.println(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\");\n        System.out.println(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\");\n    }\n\n    /**\n     * Get players guess from kb\n     *\n     * @return players guess as an int\n     */\n    private int playerGuess() {\n        return Integer.parseInt((displayTextAndGetInput(\"YOUR GUESS? \")));\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text  player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        // Cycle through the variable number of values and test each\n        for(String val:values) {\n            if(text.equalsIgnoreCase(val)) {\n                return true;\n            }\n        }\n\n        // no matches\n        return false;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Generate random number\n     * Used as a single digit of the computer player\n     *\n     * @return random number\n     */\n    private int randomNumber() {\n        return (int) (Math.random()\n                * (HIGH_NUMBER_RANGE - LOW_NUMBER_RANGE + 1) + LOW_NUMBER_RANGE);\n    }\n}\n"
  },
  {
    "path": "47_Hi-Lo/java/src/HiLoGame.java",
    "content": "public class HiLoGame {\n\n    public static void main(String[] args) {\n\n        HiLo hiLo = new HiLo();\n        hiLo.play();\n    }\n}\n"
  },
  {
    "path": "47_Hi-Lo/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "47_Hi-Lo/javascript/hi-lo.html",
    "content": "<html>\n<head>\n<title>HI-LO</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hi-lo.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "47_Hi-Lo/javascript/hi-lo.js",
    "content": "// HI-LO\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"HI LO\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS THE GAME OF HI LO.\\n\");\n    print(\"\\n\");\n    print(\"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\\n\");\n    print(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\\n\");\n    print(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\\n\");\n    print(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\\n\");\n    print(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\\n\");\n    print(\"\\n\");\n    r = 0;\n    while (1) {\n        b = 0;\n        print(\"\\n\");\n        y = Math.floor(100 * Math.random());\n        for (b = 1; b <= 6; b++) {\n            print(\"YOUR GUESS\");\n            a = parseInt(await input());\n            if (a < y) {\n                print(\"YOUR GUESS IS TOO LOW.\\n\");\n            } else if (a > y) {\n                print(\"YOUR GUESS IS TOO HIGH.\\n\");\n            } else {\n                break;\n            }\n            print(\"\\n\");\n        }\n        if (b > 6) {\n            print(\"YOU BLEW IT...TOO BAD...THE NUMBER WAS \" + y + \"\\n\");\n            r = 0;\n        } else {\n            print(\"GOT IT!!!!!!!!!!   YOU WIN \" + y + \" DOLLARS.\\n\");\n            r += y;\n            print(\"YOUR TOTAL WINNINGS ARE NOW \" + r + \" DOLLARS.\\n\");\n        }\n        print(\"\\n\");\n        print(\"PLAY AGAIN (YES OR NO)\");\n        str = await input();\n        str = str.toUpperCase();\n        if (str != \"YES\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "47_Hi-Lo/kotlin/HiLo.kt",
    "content": "\nfun main() {\n    println(introText)\n    var winnings = 0\n    do {\n        winnings += playGame()\n        println(\"YOUR TOTAL WINNINGS ARE NOW $winnings DOLLARS\")\n    } while(playAgain())\n\n    println(\"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\")\n}\n\nfun playGame():Int {\n    val amount = (1..100).random()\n    repeat(6) {\n        println(\"YOUR GUESS\")\n        val guess = readln().toInt()\n        when {\n            guess == amount -> {\n                println(\"GOT IT!!!!!!!! YOU WIN $amount DOLLARS.\")\n                return amount\n            }\n            guess > amount -> println(\"YOUR GUESS IS TOO HIGH\")\n            else -> println(\"YOUR GUESS IS TOO LOW\")\n        }\n    }\n    println(\"YOU BLEW IT...TOO BAD...THE NUMBER WAS $amount\")\n    return 0\n}\n\nfun playAgain():Boolean {\n    println(\"PLAY AGAIN (YES OR NO)\")\n    return readLine()?.uppercase() == \"YES\"\n}\n\n\nval introText = \"\"\"\n    HI LO\n    CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n    THIS IS THE GAME OF HI LO.\n\n    YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\n    HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\n    GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\n    THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\n    IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS\n\n\"\"\".trimIndent()\n"
  },
  {
    "path": "47_Hi-Lo/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "47_Hi-Lo/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "47_Hi-Lo/lua/hilo.lua",
    "content": "local function hilo (randomNum)\n   local numTries = 0\n   math.randomseed(os.time())\n\n   local randomNum = math.random(1, 100)\n   print(randomNum)\n\n   while numTries < 6 do\n      print(\"\")\n\n      io.write(\"YOUR GUESS? \")\n   \n      local guess = io.read(\"*n\")\n\n      numTries = numTries + 1\n\n      if guess < randomNum then\n         print(\"YOUR GUESS IS TOO LOW\")\n      end\n\n      if guess > randomNum then\n         print(\"YOUR GUESS IS TOO HIGH\")\n      end\n\n      if guess == randomNum then\n         print(\"GOT IT!!!!!!!!!!   YOU WIN \" .. randomNum .. \" DOLLARS.\")\n         break\n      end\n    end\n \n    if numTries == 6 then\n       print(\"\")\n       print(\"YOU BLEW IT...TOO BAD...THE NUMBER WAS \" .. randomNum)\n       return 0\n    else\n       return randomNum\n    end\nend\n\nlocal THIRTY_FOUR_TABS=string.rep(\"\\t\",34)\nprint(THIRTY_FOUR_TABS, \"HI LO\")\n\nlocal FIFTEEN_TABS=string.rep(\"\\t\",15)\nprint(FIFTEEN_TABS, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n\nlocal THREE_NEWLINES=string.rep(\"\\n\", 3)\nprint(THREE_NEWLINES)\n\nprint(\"THIS IS THE GAME OF HI LO.\")\nprint(\"\")\nprint(\"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\")\nprint(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\")\nprint(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\")\nprint(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\")\nprint(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\")\n\nlocal wonSoFar = 0\n\n::continue::\nlocal won = 0\nlocal won = hilo(randomNum)\nwonSoFar = won + wonSoFar\nprint(\"YOUR TOTAL WINNINGS ARE NOW \" .. wonSoFar .. \" DOLLARS.\")\n\n--- This flush is here because if not then it will keep the newline in the\n--- input buffer and cause the program to inadvertantly go to the \n--- Invalid Answer!\n--- part of the code which we don't want the program to do. Appears to be a\n--- Lua-ism.\n\nio.stdin:flush()\nio.write(\"PLAY AGAIN (YES OR NO)? \")\nanswer = io.read()\n\nwhile(not(answer == \"YES\" or answer == \"NO\")) do\n   io.write(\"Invalid Answer! Try again (YES/NO): \")\n   answer = io.read()\nend\n\nif answer == \"YES\" then\n   goto continue\nelse\n   print(\"\")\n   print(\"SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\") \n   os.exit()\nend"
  },
  {
    "path": "47_Hi-Lo/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "47_Hi-Lo/perl/hi-lo.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 34 . \"HI LO\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"THIS IS THE GAME OF HI LO.\\n\"; print \"\\n\";\nprint \"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\\n\";\nprint \"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS. IF YOU\\n\";\nprint \"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\\n\";\nprint \"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY. HOWEVER,\\n\";\nprint \"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\\n\"; print \"\\n\";\nmy $R=0;\nmy $A;\ndo {\n\tprint \"\\n\";\n\tmy $Y=int(100*rand(1));\n\tforeach (1..6) {\n\t\tprint \"YOUR GUESS $Y\";\n\t\tprint \"? \"; chomp($A = <STDIN>);\n\t\tif ($A eq $Y) { last; }\n\t\tif ($A>$Y) {\n\t\t\tprint \"YOUR GUESS IS TOO HIGH.\\n\";\n\t\t\t} else {\n\t\t\tprint \"YOUR GUESS IS TOO LOW.\\n\";\n\t\t\t}\n\t\tprint \"\\n\";\n\t\t}\n\n\tif ($A==$Y) {\n\t\t$R=$R+$Y;\n\t\tprint \"GOT IT!!!!!!!!!! YOU WIN $Y DOLLARS.\\n\";\n\t\tprint \"YOUR TOTAL WINNINGS ARE NOW $R DOLLARS.\\n\";\n\t\t} else {\n\t\t$R=0;\n\t\tprint \"YOU BLEW IT...TOO BAD...THE NUMBER WAS $Y\"\n\t\t}\n\tprint \"\\n\"; print \"PLAY AGAIN (YES OR NO)\";\n\tprint \"? \"; chomp($A = <STDIN>);\n\t} until (uc($A) ne \"YES\");\nprint \"\\n\"; print \"SO LONG. HOPE YOU ENJOYED YOURSELF!!!\\n\";\nexit;\n"
  },
  {
    "path": "47_Hi-Lo/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "47_Hi-Lo/python/hilo.py",
    "content": "#!/usr/bin/env python3\nimport random\n\nMAX_ATTEMPTS = 6\nQUESTION_PROMPT = \"? \"\n\n\ndef main() -> None:\n    print(\"HI LO\")\n    print(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"THIS IS THE GAME OF HI LO.\\n\")\n    print(\"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\")\n    print(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\")\n    print(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\")\n    print(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\")\n    print(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\\n\\n\")\n\n    total_winnings = 0\n    while True:\n        print()\n        secret = random.randint(1, 100)\n        guessed_correctly = False\n\n        for _attempt in range(MAX_ATTEMPTS):\n            print(\"YOUR GUESS\", end=QUESTION_PROMPT)\n            guess = int(input())\n\n            if guess == secret:\n                print(f\"GOT IT!!!!!!!!!!   YOU WIN {secret} DOLLARS.\")\n                guessed_correctly = True\n                break\n            elif guess > secret:\n                print(\"YOUR GUESS IS TOO HIGH.\")\n            else:\n                print(\"YOUR GUESS IS TOO LOW.\")\n\n        if guessed_correctly:\n            total_winnings += secret\n            print(f\"YOUR TOTAL WINNINGS ARE NOW {total_winnings} DOLLARS.\")\n        else:\n            print(f\"YOU BLEW IT...TOO BAD...THE NUMBER WAS {secret}\")\n\n        print(\"\\n\")\n        print(\"PLAY AGAIN (YES OR NO)\", end=QUESTION_PROMPT)\n        answer = input().upper()\n        if answer != \"YES\":\n            break\n\n    print(\"\\nSO LONG.  HOPE YOU ENJOYED YOURSELF!!!\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "47_Hi-Lo/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/) by [R.T. Lechow](https://github.com/rtlechow)\n"
  },
  {
    "path": "47_Hi-Lo/ruby/hi_lo.rb",
    "content": "#!/usr/bin/env ruby\nMAX_TRIES = 6\nRANGE = (1..100)\n\ndef intro\n  puts <<~END_OF_INTRO\n    #{'HI LO'.center(74)}\n    #{\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\".center(76)}\n    THIS IS THE GAME OF HI LO.\\n\n    YOU WILL HAVE #{MAX_TRIES} TRIES TO GUESS THE AMOUNT OF MONEY IN THE\n    HI LO JACKPOT, WHICH IS BETWEEN #{RANGE.min} AND #{RANGE.max} DOLLARS.  IF YOU\n    GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\n    THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\n    IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\\n\\n\n  END_OF_INTRO\nend\n\ndef make_guess\n  puts 'YOUR GUESS?'\n  @guess = gets.to_i\nend\n\ndef check_guess\n  if @guess == @number\n    @guessed_correctly = true\n    @total_winnings += @number\n    puts <<~END_OF_WIN_TEXT\n      GOT IT!!!!!!!!!!   YOU WIN #{@number} DOLLARS.\n      YOUR TOTAL WINNINGS ARE NOW #{@total_winnings} DOLLARS.\n    END_OF_WIN_TEXT\n  else\n    puts \"YOUR GUESS IS TOO #{@guess > @number ? 'HIGH' : 'LOW'}.\\n\\n\"\n  end\nend\n\ndef blew_it\n  @total_winnings = 0\n  puts \"YOU BLEW IT...TOO BAD...THE NUMBER WAS #{@number}\"\nend\n\ndef outro\n  puts \"\\nSO LONG.  HOPE YOU ENJOYED YOURSELF!!!\"\nend\n\nintro\n@total_winnings = 0\nloop do\n  @guessed_correctly = false\n  @number = rand(RANGE)\n  MAX_TRIES.times do\n    make_guess\n    check_guess\n    break if @guessed_correctly\n  end\n  blew_it unless @guessed_correctly\n  puts \"\\nPLAY AGAIN (YES OR NO)?\"\n  break if gets.start_with?(/n/i)\nend\noutro\n"
  },
  {
    "path": "47_Hi-Lo/rust/Cargo.toml",
    "content": "[package]\nname = \"guessing_game\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.3\""
  },
  {
    "path": "47_Hi-Lo/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "47_Hi-Lo/rust/src/main.rs",
    "content": "use rand::Rng;\nuse std::io;\n\nfn main() {\n    println!(\n        \"{: >39}\\n{: >57}\\n\\n\\n\",\n        \"HI LO\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    println!(\"THIS IS THE GAME OF HI LO.\\n\");\n    println!(\"YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\");\n    println!(\"HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\");\n    println!(\"GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\");\n    println!(\"THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\");\n    println!(\"IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\\n\");\n\n    let mut total: u32 = 0;\n    loop {\n        let jackpot_amount = rand::thread_rng().gen_range(1..101); // generates a random number between 1 and 100\n        for i in 0..6 {\n            println!(\"YOUR GUESS?\");\n\n            let mut guess = String::new();\n\n            io::stdin()\n                .read_line(&mut guess)\n                .expect(\"Failed to read the line\");\n\n            // this converts the input string into unsigned 32bit number and if the input entered is not a number\n            // it will again prompt the user to enter the guess number\n            let guess: u32 = match guess.trim().parse() {\n                Ok(num) => num,\n                Err(_) => {\n                    println!(\"PLEASE ENTER A NUMBER VALUE.\\n\");\n                    continue;\n                }\n            };\n\n            // compare it with the jackpot amount\n            if guess == jackpot_amount {\n                println!(\"\\nGOT IT!!!!!!!!!!   YOU WIN {} DOLLARS.\", jackpot_amount);\n                total += jackpot_amount;\n                println!(\"YOUR TOTAL WINNINGS ARE NOW {} DOLLARS.\\n\", total);\n                break;\n            } else if guess < jackpot_amount {\n                println!(\"YOUR GUESS IS TOO LOW.\\n\");\n            } else {\n                println!(\"YOUR GUESS IS TOO HIGH.\\n\");\n            }\n\n            // if 6 tries are over make total jackpot amount to zero\n            if i == 5 {\n                total = 0;\n                println!(\n                    \"YOU BLEW IT...TOO BAD...THE NUMBER WAS {}\\n\",\n                    jackpot_amount\n                );\n            }\n        }\n        println!(\"PLAY AGAIN (YES OR NO)?\");\n        let mut tocontinue = String::new();\n        io::stdin()\n            .read_line(&mut tocontinue)\n            .expect(\"Error Getting your input\");\n        let tocontinue = tocontinue.trim().to_ascii_uppercase();\n        if tocontinue.eq(\"YES\") {\n            println!(\"\\n\");\n            continue;\n        } else {\n            println!(\"\\nSO LONG.  HOPE YOU ENJOYED YOURSELF!!!\\n\");\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "47_Hi-Lo/vbnet/HiLo.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"HiLo\", \"HiLo.vbproj\", \"{B93E0994-AEC4-4FC9-93C2-FC708368B32F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "47_Hi-Lo/vbnet/HiLo.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>HiLo</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "47_Hi-Lo/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "48_High_IQ/README.md",
    "content": "### High IQ\n\nThis is a computerized version of an old European solitaire game of logic. The game starts with a pegboard shaped like a cross having pegs in every hole but the center. The object is to remove all 32 pegs, or as many as possible, by jumping into an empty hole, then removing the jumped peg.\n\nThere are several different winning strategies for playing, and of course, each strategy can be played eight different ways on the board. Can you find a consistent winner?\n\nCharles Lund wrote this game while at The American School in The Hague, Netherlands.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=86)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=101)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "48_High_IQ/csharp/HighIQ.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "48_High_IQ/csharp/HighIQ.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"HighIQ\", \"HighIQ.csproj\", \"{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "48_High_IQ/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "48_High_IQ/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "48_High_IQ/d/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -dip1000 -run highiq.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n\n\n## Discussion\n\nThe original BASIC game code made use of calculus and clever choises of field IDs to determine the validity of moves.\nThis is the original layout of IDs over the board:\n\n```\n          13   14   15\n\n          22   23   24\n\n29   30   31   32   33   34   35\n\n38   39   40   41   42   43   44\n\n47   48   49   50   51   52   53\n\n          58   59   60\n\n          67   68   69\n```\n\nThis seems not very logical, because, wouldn't it make much more sense to let columns increase with 1 and rows increase\nwith 10, so you'd get a consistent coordinate system? It seems that the original author's first step in validating\nmoves was to check that moves jumped from one field over another one onto the next. He did this by making sure that\nadjacent IDs alter between even and odd horizontally *and* vertically. So a valid move was always from an even ID to an\neven ID *or* from an odd ID to an odd ID. So one of the checks that the BASIC code made was that the sum of both IDs\nwas even. This is of course not a sufficient test, because moves that jump over three fields are illegal. Therefore the\nIDs seem to have been carefully laid oud so that the IDs increase with 1 horizontally, and 9 vertically, everywhere. So\nthe only valid difference between IDs for a horizontal move was always 2, and the only valid difference for a vertical\nmove was always 18.\n\nFact of the matter is, however, that checking for difference is sufficient and the even sum rule is superfluous, so\nthere is no need for the peculiar distribution of field IDs. Therefore I have chosen the following more logical\ndistribution:\n\n```\n          13   14   15\n\n          23   24   25\n\n31   32   33   34   35   36   37\n\n41   42   43   44   45   46   47\n\n51   52   53   54   55   56   57\n\n          63   64   65\n\n          73   74   75\n```\n\nAs a consequence, the implementation of the game code has become much simpler; Not alone due to one less check, but due\nto the fact that conversions between IDs and board coordinates have become unnecessary and thus we can work with a single\nrepresentation of the board state.\n\nThis version makes a prettier print of the board than the BASIC original, with coordinates for every move, and explains\nillegal moves.\n\n\n## Demo\n\n```\n                      H-I-Q\n(After Creative Computing  Morristown, New Jersey)\n\n\nFields are identified by 2-digit numbers, each\nbetween 1 and 7. Example: the middle field is 44,\nthe bottom middle is 74.\n\n      _1  _2  _3  _4  _5  _6  _7\n            ┌───┬───┬───┐\n 1_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 2_         │ ■ │ ■ │ ■ │\n    ┌───┬───┼───┼───┼───┼───┬───┐\n 3_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 4_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    └───┴───┼───┼───┼───┼───┴───┘\n 6_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 7_         │ ■ │ ■ │ ■ │\n            └───┴───┴───┘\n\nMove which peg? 23\nThe peg at 23 has nowhere to go. Try again.\n\nMove which peg? 24\nTo where? 34\nField 34 is occupied. Try again.\nTo where? 54\nField 54 is occupied. Try again.\nTo where? 44\n\n      _1  _2  _3  _4  _5  _6  _7\n            ┌───┬───┬───┐\n 1_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 2_         │ ■ │   │ ■ │\n    ┌───┬───┼───┼───┼───┼───┬───┐\n 3_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    └───┴───┼───┼───┼───┼───┴───┘\n 6_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 7_         │ ■ │ ■ │ ■ │\n            └───┴───┴───┘\n\nMove which peg? 14\nThe peg at 14 has nowhere to go. Try again.\n\nMove which peg? 24\nThere is no peg at 24. Try again.\n\nMove which peg? 44\nThe peg at 44 has nowhere to go. Try again.\n\nMove which peg? 32\nTo where? 22\nField 22 is ouside the board. Try again.\nTo where? 33\nField 33 is occupied. Try again.\nTo where? 34\n\n      _1  _2  _3  _4  _5  _6  _7\n            ┌───┬───┬───┐\n 1_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 2_         │ ■ │   │ ■ │\n    ┌───┬───┼───┼───┼───┼───┬───┐\n 3_ │ ■ │   │   │ ■ │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    └───┴───┼───┼───┼───┼───┴───┘\n 6_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 7_         │ ■ │ ■ │ ■ │\n            └───┴───┴───┘\n\nMove which peg? 44\nTo where? 33\nYou cannot move diagonally. Try again.\nTo where? 24\n\n      _1  _2  _3  _4  _5  _6  _7\n            ┌───┬───┬───┐\n 1_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 2_         │ ■ │ ■ │ ■ │\n    ┌───┬───┼───┼───┼───┼───┬───┐\n 3_ │ ■ │   │   │   │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 4_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    └───┴───┼───┼───┼───┼───┴───┘\n 6_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 7_         │ ■ │ ■ │ ■ │\n            └───┴───┴───┘\n\nMove which peg? 36\nTo where? 33\nYou can't jump that far. Try again.\nTo where? 35\nField 35 is occupied. Try again.\nTo where? 34\n\n      _1  _2  _3  _4  _5  _6  _7\n            ┌───┬───┬───┐\n 1_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 2_         │ ■ │ ■ │ ■ │\n    ┌───┬───┼───┼───┼───┼───┬───┐\n 3_ │ ■ │   │   │ ■ │   │   │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 4_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │\n    ├───┼───┼───┼───┼───┼───┼───┤\n 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │\n    └───┴───┼───┼───┼───┼───┴───┘\n 6_         │ ■ │ ■ │ ■ │\n            ├───┼───┼───┤\n 7_         │ ■ │ ■ │ ■ │\n            └───┴───┴───┘\n\nMove which peg? 46\nTo where? 36\nYou need to jump over another peg. Try again.\nTo where? down\nField 00 is ouside the board. Try again.\nTo where?\n```\n"
  },
  {
    "path": "48_High_IQ/d/highiq.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std;\n\nvoid main()\n{\n    enum width = 50;\n    writeln(center(\"H-I-Q\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\", width));\n    writeln(wrap(\"Fields are identified by 2-digit numbers, each between 1 and 7. \" ~\n                 \"Example: the middle field is 44, the bottom middle is 74.\", width));\n\n    Board board;\n\n    while (true)\n    {\n        while (!board.isGameOver)\n        {\n            writeln(board); // Calls board.toString().\n            board.makeMove;\n        }\n        writeln(board, \"\\nThe game is over.\\nYou had \", board.numPegs, \" pieces remaining.\");\n        if (board.numPegs == 1)\n            writeln(\"Bravo!  You made a perfect score!\\n\",\n                    \"Make a screen dump as a record of your accomplishment!\\n\");\n        write(\"Play again? (Yes or No) \");\n        if (readString.toLower != \"yes\")\n            break;\n        writeln; writeln;\n        board = Board.init;\n    }\n    writeln(\"\\nSo long for now.\\n\");\n}\n\n/// Representation of the game board with pegs.\nstruct Board\n{\n    enum {outside, taken, empty};\n    int[8][8] state = [\n        1: [                    3: taken, 4: taken, 5: taken],\n        2: [                    3: taken, 4: taken, 5: taken],\n        3: [1: taken, 2: taken, 3: taken, 4: taken, 5: taken, 6: taken, 7: taken],\n        4: [1: taken, 2: taken, 3: taken, 4: empty, 5: taken, 6: taken, 7: taken],\n        5: [1: taken, 2: taken, 3: taken, 4: taken, 5: taken, 6: taken, 7: taken],\n        6: [                    3: taken, 4: taken, 5: taken],\n        7: [                    3: taken, 4: taken, 5: taken]\n    ]; // Row 0 and column 0 are unused. Default is 0 (outside).\n\n    /// Returns a string representing the board and its current state.\n    string toString() const\n    {\n        dchar[][] lines = [(\"      _1  _2  _3  _4  _5  _6  _7 \").to!(dchar[]),\n                           (\"            ┌───┬───┬───┐        \").to!(dchar[]),\n                           (\" 1_         │   │   │   │        \").to!(dchar[]),\n                           (\"            ├───┼───┼───┤        \").to!(dchar[]),\n                           (\" 2_         │   │   │   │        \").to!(dchar[]),\n                           (\"    ┌───┬───┼───┼───┼───┼───┬───┐\").to!(dchar[]),\n                           (\" 3_ │   │   │   │   │   │   │   │\").to!(dchar[]),\n                           (\"    ├───┼───┼───┼───┼───┼───┼───┤\").to!(dchar[]),\n                           (\" 4_ │   │   │   │   │   │   │   │\").to!(dchar[]),\n                           (\"    ├───┼───┼───┼───┼───┼───┼───┤\").to!(dchar[]),\n                           (\" 5_ │   │   │   │   │   │   │   │\").to!(dchar[]),\n                           (\"    └───┴───┼───┼───┼───┼───┴───┘\").to!(dchar[]),\n                           (\" 6_         │   │   │   │        \").to!(dchar[]),\n                           (\"            ├───┼───┼───┤        \").to!(dchar[]),\n                           (\" 7_         │   │   │   │        \").to!(dchar[]),\n                           (\"            └───┴───┴───┘        \").to!(dchar[])];\n        foreach (y, row; state)\n            foreach (x, field; row)\n                if (field == taken)\n                    lines[y * 2][x * 4 + 2] = '■';\n        return lines.join(\"\\n\").to!string;\n    }\n\n    /// Tests for possible moves.\n    bool isGameOver() const\n    {\n        foreach (r, row; state)\n            foreach (c, field; row)\n                if (field == taken && canMoveFrom(r, c))\n                    return false;\n        return true;\n    }\n\n    bool canMoveFrom(int row, int col) const\n    {\n        if (row >= 3 && state[row - 2][col] == empty)   // Up\n            return state[row - 1][col] == taken;\n        if (row <= 5 && state[row + 2][col] == empty)   // Down\n            return state[row + 1][col] == taken;\n        if (col >= 3 && state[row][col - 2] == empty)   // Left\n            return state[row][col - 1] == taken;\n        if (col <= 5 && state[row][col + 2] == empty)   // Right\n            return state[row][col + 1] == taken;\n        return false;\n    }\n\n    /// Asks for input, validates the move and updates the board.\n    void makeMove()\n    {\n        bool isOutside(int row, int col)\n        {\n            if (row < 1 || row > 7 ||\n                col < 1 || col > 7 ||\n                state[row][col] == outside)\n            {\n                writeln(\"Field \", row, col, \" is ouside the board. Try again.\");\n                return true;\n            }\n            return false;\n        }\n\n        while (true)\n        {\n            auto from = (){\n                while (true)\n                {\n                    write(\"\\nMove which peg? \");\n                    int field = readInt;\n                    int row = field / 10, col = field % 10;\n                    if (isOutside(row, col))\n                        continue;\n                    if (state[row][col] != taken)\n                    {\n                        writeln(\"There is no peg at \", field, \". Try again.\");\n                        continue;\n                    }\n                    if (!canMoveFrom(row, col))\n                    {\n                        writeln(\"The peg at \", field, \" has nowhere to go. Try again.\");\n                        continue;\n                    }\n                    return tuple!(\"row\", \"col\")(row, col);\n                }\n            }();\n            auto to = (){\n                while (true)\n                {\n                    write(\"To where? \");\n                    int field = readInt;\n                    int row = field / 10, col = field % 10;\n                    if (isOutside(row, col))\n                        continue;\n                    if (state[row][col] == taken)\n                    {\n                        writeln(\"Field \", field, \" is occupied. Try again.\");\n                        continue;\n                    }\n                    if (row != from.row && col != from.col)\n                    {\n                        writeln(\"You cannot move diagonally. Try again.\");\n                        continue;\n                    }\n                    if (row == from.row && col == from.col)\n                    {\n                        writeln(\"You aren't going anywhere. Try again.\");\n                        continue;\n                    }\n                    if (abs(row - from.row) + abs(col - from.col) > 2)\n                    {\n                        writeln(\"You can't jump that far. Try again.\");\n                        continue;\n                    }\n                    if (abs(row - from.row) + abs(col - from.col) < 2 ||\n                        state[(row + from.row) / 2][(col + from.col) / 2] != taken)\n                    {\n                        writeln(\"You need to jump over another peg. Try again.\");\n                        continue;\n                    }\n                    return tuple!(\"row\", \"col\")(row, col);\n                }\n            }();\n            // The move is legal. Update the board state.\n            state[from.row][from.col] = empty;\n            state[  to.row][  to.col] = taken;\n            state[(from.row + to.row) / 2][(from.col + to.col) / 2] = empty;\n            writeln;\n            break;\n        }\n    }\n\n    /// Returns the number of remaining pegs on the board.\n    int numPegs() const\n    {\n        int num = 0;\n        foreach (row; state)\n            foreach (field; row)\n                if (field == taken)\n                    num++;\n        return num;\n    }\n}\n\n/// Reads an integer from standard input.\nint readInt() nothrow\n{\n    try\n        return readString.to!int;\n    catch (Exception)   // Not an integer.\n        return 0;\n}\n\n/// Reads a string from standard input.\nstring readString() nothrow\n{\n    try\n        return trustedReadln.strip;\n    catch (Exception)   // readln throws on I/O and Unicode errors, which we handle here.\n        return \"\";\n}\n\n/** An @trusted wrapper around readln.\n *\n * This is the only function that formally requires manual review for memory-safety.\n * [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)\n * which would remove the need to have any @trusted code in this program.\n */\nstring trustedReadln() @trusted\n{\n    return readln;\n}\n\nversion (Windows)\n{\n    // Make the Windows console do a better job at printing UTF-8 strings,\n    // and restore the default upon termination.\n\n    import core.sys.windows.windows;\n\n    shared static this() @trusted\n    {\n        SetConsoleOutputCP(CP_UTF8);\n    }\n\n    shared static ~this() @trusted\n    {\n        SetConsoleOutputCP(GetACP);\n    }\n}\n"
  },
  {
    "path": "48_High_IQ/highiq.bas",
    "content": "1 PRINT TAB(33);\"H-I-Q\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 DIM B(70),T(9,9)\n5 PRINT \"HERE IS THE BOARD:\": PRINT\n6 PRINT \"          !    !    !\"\n7 PRINT \"         13   14   15\": PRINT\n8 PRINT \"          !    !    !\"\n9 PRINT \"         22   23   24\": PRINT\n10 PRINT \"!    !    !    !    !    !    !\"\n11 PRINT \"29   30   31   32   33   34   35\": PRINT\n12 PRINT \"!    !    !    !    !    !    !\"\n13 PRINT \"38   39   40   41   42   43   44\": PRINT\n14 PRINT \"!    !    !    !    !    !    !\"\n15 PRINT \"47   48   49   50   51   52   53\": PRINT\n16 PRINT \"          !    !    !\"\n17 PRINT \"         58   59   60\": PRINT\n18 PRINT \"          !    !    !\"\n19 PRINT \"         67   68   69\": PRINT\n20 PRINT \"TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\"\n22 PRINT \"WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG\"\n24 PRINT \"NUMBERS.  OK, LET'S BEGIN.\"\n28 REM *** SET UP BOARD\n29 FOR R=1 TO 9\n30 FOR C=1 TO 9\n31 IF (R-4)*(R-5)*(R-6)=0 THEN 40\n32 IF (C-4)*(C-5)*(C-6)=0 THEN 40\n35 T(R,C)=-5\n36 GOTO 50\n40 IF (R-1)*(C-1)*(R-9)*(C-9)=0 THEN 35\n42 T(R,C)=5\n50 NEXT C\n60 NEXT R\n65 T(5,5)=0: GOSUB 500\n70 REM *** INPUT MOVE AND CHECK ON LEGALITY\n75 FOR W=1 TO 33\n77 READ M\n79 DATA 13,14,15,22,23,24,29,30,31,32,33,34,35,38,39,40,41\n81 DATA 42,43,44,47,48,49,50,51,52,53,58,59,60,67,68,69\n83 B(M)=-7: NEXT W\n86 B(41)=-3\n100 INPUT \"MOVE WHICH PIECE\";Z\n110 IF B(Z)=-7 THEN 140\n120 PRINT \"ILLEGAL MOVE, TRY AGAIN...\": GOTO 100\n140 INPUT \"TO WHERE\";P\n150 IF B(P)=0 THEN 120\n153 IF B(P)=-7 THEN 120\n156 IF Z=P THEN 100\n160 IF ((Z+P)/2)=INT((Z+P)/2) THEN 180\n170 GOTO 120\n180 IF (ABS(Z-P)-2)*(ABS(Z-P)-18)<>0 THEN 120\n190 GOSUB 1000\n200 GOSUB 500\n210 GOSUB 1500\n220 GOTO 100\n500 REM *** PRINT BOARD\n510 FOR X=1 TO 9\n520 FOR Y=1 TO 9\n525 IF (X-1)*(X-9)*(Y-1)*(Y-9)=0 THEN 550\n530 IF (X-4)*(X-5)*(X-6)=0 THEN 570\n540 IF (Y-4)*(Y-5)*(Y-6)=0 THEN 570\n550 REM\n560 GOTO 610\n570 IF T(X,Y)<>5 THEN 600\n580 PRINT TAB(Y*2);\"!\";\n590 GOTO 610\n600 PRINT TAB(Y*2);\"O\";\n610 REM\n615 NEXT Y\n620 PRINT\n630 NEXT X\n640 RETURN\n1000 REM *** UPDATE BOARD\n1005 C=1: FOR X=1 TO 9\n1020 FOR Y=1 TO 9\n1030 IF C<>Z THEN 1220\n1040 IF C+2<>P THEN 1080\n1045 IF T(X,Y+1)=0 THEN 120\n1050 T(X,Y+2)=5\n1060 T(X,Y+1)=0: B(C+1)=-3\n1070 GOTO 1200\n1080 IF C+18<>P THEN 1130\n1085 IF T(X+1,Y)=0 THEN 120\n1090 T(X+2,Y)=5: T(X+1,Y)=0: B(C+9)=-3\n1120 GOTO 1200\n1130 IF C-2<>P THEN 1170\n1135 IF T(X,Y-1)=0 THEN 120\n1140 T(X,Y-2)=5: T(X,Y-1)=0: B(C-1)=-3\n1160 GOTO 1200\n1170 IF C-18<>P THEN 1220\n1175 IF T(X-1,Y)=0 THEN 120\n1180 T(X-2,Y)=5: T(X-1,Y)=0: B(C-9)=-3\n1200 B(Z)=-3: B(P)=-7\n1210 T(X,Y)=0: GOTO 1240\n1220 C=C+1\n1225 NEXT Y\n1230 NEXT X\n1240 RETURN\n1500 REM*** CHECK IF GAME IS OVER\n1505 F=0\n1510 FOR R=2 TO 8\n1520 FOR C=2 TO 8\n1530 IF T(R,C)<>5 THEN 1580\n1535 F=F+1\n1540 FOR A=R-1 TO R+1\n1545 T=0\n1550 FOR B=C-1 TO C+1\n1560 T=T+T(A,B)\n1561 NEXT B\n1564 IF T<>10 THEN 1567\n1565 IF T(A,C)<>0 THEN 1630\n1567 NEXT A\n1568 FOR X=C-1 TO C+1\n1569 T=0\n1570 FOR Y=R-1 TO R+1\n1571 T=T+T(Y,X)\n1572 NEXT Y\n1573 IF T<>10 THEN 1575\n1574 IF T(R,X)<>0 THEN 1630\n1575 NEXT X\n1580 NEXT C\n1590 NEXT R\n1600 REM *** GAME IS OVER\n1605 PRINT \"THE GAME IS OVER.\"\n1610 PRINT \"YOU HAD\";F;\"PIECES REMAINING.\"\n1611 IF F<>1 THEN 1615\n1612 PRINT \"BRAVO!  YOU MADE A PERFECT SCORE!\"\n1613 PRINT \"SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!\"\n1615 PRINT: INPUT \"PLAY AGAIN (YES OR NO)\";A$\n1617 IF A$=\"NO\" THEN 2000\n1618 RESTORE: GOTO 28\n1620 STOP\n1630 RETURN\n2000 PRINT: PRINT \"SO LONG FOR NOW.\": PRINT\n2010 END\n"
  },
  {
    "path": "48_High_IQ/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "48_High_IQ/java/src/HighIQ.java",
    "content": "import java.io.PrintStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Scanner;\n\n/**\n * Game of HighIQ\n * <p>\n * Based on the Basic Game of HighIQ Here:\n * https://github.com/coding-horror/basic-computer-games/blob/main/48_High_IQ/highiq.bas\n *\n * No additional functionality has been added\n */\npublic class HighIQ {\n\n    //Game board, as a map of position numbers to their values\n    private final Map<Integer, Boolean> board;\n\n    //Output stream\n    private final PrintStream out;\n\n    //Input scanner to use\n    private final Scanner scanner;\n\n\n    public HighIQ(Scanner scanner) {\n        out = System.out;\n        this.scanner = scanner;\n        board = new HashMap<>();\n\n        //Set of all locations to put initial pegs on\n        int[] locations = new int[]{\n                13, 14, 15, 22, 23, 24, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 58, 59, 60, 67, 68, 69\n        };\n\n        for (int i : locations) {\n            board.put(i, true);\n        }\n\n        board.put(41, false);\n    }\n\n    /**\n     * Plays the actual game, from start to finish.\n     */\n    public void play() {\n        do {\n            printBoard();\n            while (!move()) {\n                out.println(\"ILLEGAL MOVE, TRY AGAIN...\");\n            }\n        } while (!isGameFinished());\n\n        int pegCount = 0;\n        for (Integer key : board.keySet()) {\n            if (board.getOrDefault(key, false)) {\n                pegCount++;\n            }\n        }\n\n        out.println(\"YOU HAD \" + pegCount + \" PEGS REMAINING\");\n\n        if (pegCount == 1) {\n            out.println(\"BRAVO!  YOU MADE A PERFECT SCORE!\");\n            out.println(\"SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!\");\n        }\n    }\n\n    /**\n     * Makes an individual move\n     * @return True if the move was valid, false if the user made an error and the move is invalid\n     */\n    public boolean move() {\n        out.println(\"MOVE WHICH PIECE\");\n        int from = scanner.nextInt();\n\n        //using the getOrDefault, which will make the statement false if it is an invalid position\n        if (!board.getOrDefault(from, false)) {\n            return false;\n        }\n\n        out.println(\"TO WHERE\");\n        int to = scanner.nextInt();\n\n        if (board.getOrDefault(to, true)) {\n            return false;\n        }\n\n        //Do nothing if they are the same\n        if (from == to) {\n            return true;\n        }\n\n        //using the difference to check if the relative locations are valid\n        int difference = Math.abs(to - from);\n        if (difference != 2 && difference != 18) {\n            return false;\n        }\n\n        //check if there is a peg between from and to\n        if (!board.getOrDefault((to + from) / 2, false)) {\n            return false;\n        }\n\n        //Actually move\n        board.put(from,false);\n        board.put(to,true);\n        board.put((from + to) / 2, false);\n\n        return true;\n    }\n\n    /**\n     * Checks if the game is finished\n     * @return True if there are no more moves, False otherwise\n     */\n    public boolean isGameFinished() {\n        for (Integer key : board.keySet()) {\n            if (board.get(key)) {\n                //Spacing is either 1 or 9\n                //Looking to the right and down from every point, checking for both directions of movement\n                for (int space : new int[]{1, 9}) {\n                    Boolean nextToPeg = board.getOrDefault(key + space, false);\n                    Boolean hasMovableSpace = !board.getOrDefault(key - space, true) || !board.getOrDefault(key + space * 2, true);\n                    if (nextToPeg && hasMovableSpace) {\n                        return false;\n                    }\n                }\n            }\n        }\n        return true;\n    }\n\n    public void printBoard() {\n        for (int i = 0; i < 7; i++) {\n            for (int j = 11; j < 18; j++) {\n                out.print(getChar(j + 9 * i));\n            }\n            out.println();\n        }\n    }\n\n    private char getChar(int position) {\n        Boolean value = board.get(position);\n        if (value == null) {\n            return ' ';\n        } else if (value) {\n            return '!';\n        } else {\n            return 'O';\n        }\n    }\n}\n"
  },
  {
    "path": "48_High_IQ/java/src/HighIQGame.java",
    "content": "import java.util.Scanner;\n\npublic class HighIQGame {\n    public static void main(String[] args) {\n\n        printInstructions();\n\n        Scanner scanner = new Scanner(System.in);\n        do {\n            new HighIQ(scanner).play();\n            System.out.println(\"PLAY AGAIN (YES OR NO)\");\n        } while(scanner.nextLine().equalsIgnoreCase(\"yes\"));\n    }\n\n    public static void printInstructions() {\n        System.out.println(\"\\t\\t\\t H-I-Q\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println(\"HERE IS THE BOARD:\");\n        System.out.println(\"          !    !    !\");\n        System.out.println(\"         13   14   15\\n\");\n        System.out.println(\"          !    !    !\");\n        System.out.println(\"         22   23   24\\n\");\n        System.out.println(\"!    !    !    !    !    !    !\");\n        System.out.println(\"29   30   31   32   33   34   35\\n\");\n        System.out.println(\"!    !    !    !    !    !    !\");\n        System.out.println(\"38   39   40   41   42   43   44\\n\");\n        System.out.println(\"!    !    !    !    !    !    !\");\n        System.out.println(\"47   48   49   50   51   52   53\\n\");\n        System.out.println(\"          !    !    !\");\n        System.out.println(\"         58   59   60\\n\");\n        System.out.println(\"          !    !    !\");\n        System.out.println(\"         67   68   69\");\n        System.out.println(\"TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\");\n        System.out.println(\"WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG\");\n        System.out.println(\"NUMBERS.  OK, LET'S BEGIN.\");\n    }\n}\n"
  },
  {
    "path": "48_High_IQ/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "48_High_IQ/javascript/highiq.html",
    "content": "<html>\n<head>\n<title>H-I-Q</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"highiq.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "48_High_IQ/javascript/highiq.js",
    "content": "// H-I-Q\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar b = [];\nvar t = [];\nvar m = [,13,14,15,\n          22,23,24,\n    29,30,31,32,33,34,35,\n    38,39,40,41,42,43,44,\n    47,48,49,50,51,52,53,\n          58,59,60,\n          67,68,69];\nvar z;\nvar p;\n\n//\n// Print board\n//\nfunction print_board()\n{\n    for (x = 1; x <= 9; x++) {\n        str = \"\";\n        for (y = 1; y <= 9; y++) {\n            if (x == 1 || x == 9 || y == 1 || y == 9)\n                continue;\n            if (x == 4 || x == 5 || x == 6 || y == 4 || y == 5 || y == 6) {\n                while (str.length < y * 2)\n                    str += \" \";\n                if (t[x][y] == 5)\n                    str += \"!\";\n                else\n                    str += \"O\";\n            }\n        }\n        print(str + \"\\n\");\n    }\n}\n\n//\n// Update board\n//\nfunction update_board()\n{\n    c = 1;\n    for (var x = 1; x <= 9; x++) {\n        for (var y = 1; y <= 9; y++, c++) {\n            if (c != z)\n                continue;\n            if (c + 2 == p) {\n                if (t[x][y + 1] == 0)\n                    return false;\n                t[x][y + 2] = 5;\n                t[x][y + 1] = 0;\n                b[c + 1] = -3;\n            } else if (c + 18 == p) {\n                if (t[x + 1][y] == 0)\n                    return false;\n                t[x + 2][y] = 5;\n                t[x + 1][y] = 0;\n                b[c + 9] = -3;\n            } else if (c - 2 == p) {\n                if (t[x][y - 1] == 0)\n                    return false;\n                t[x][y - 2] = 5;\n                t[x][y - 1] = 0;\n                b[c - 1] = -3;\n            } else if (c - 18 == p) {\n                if (t[x - 1][y] == 0)\n                    return false;\n                t[x - 2][y] = 5;\n                t[x - 1][y] = 0;\n                b[c - 9] = -3;\n            } else {\n                continue;\n            }\n            b[z] = -3;\n            b[p] = -7;\n            t[x][y] = 0;\n            return true;\n        }\n    }\n}\n\n//\n// Check for game over\n//\n// Rewritten because original subroutine was buggy\n//\nfunction check_game_over()\n{\n    f = 0;\n    for (r = 2; r <= 8; r++) {\n        for (c = 2; c <= 8; c++) {\n            if (t[r][c] != 5)\n                continue;\n            f++;\n            if (r > 3 && t[r - 1][c] == 5 && t[r - 2][c] == 0)\n                return false;\n            if (c > 3 && t[r][c - 1] == 5 && t[r][c - 2] == 0)\n                return false;\n            if (r < 7 && t[r + 1][c] == 5 && t[r + 2][c] == 0)\n                return false;\n            if (c < 7 && t[r][c + 1] == 5 && t[r][c + 2] == 0)\n                return false;\n        }\n    }\n    return true;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"H-I-Q\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (r = 0; r <= 70; r++)\n        b[r] = 0;\n    print(\"HERE IS THE BOARD:\\n\");\n    print(\"\\n\");\n    print(\"          !    !    !\\n\");\n    print(\"         13   14   15\\n\");\n    print(\"\\n\");\n    print(\"          !    !    !\\n\");\n    print(\"         22   23   24\\n\");\n    print(\"\\n\");\n    print(\"!    !    !    !    !    !    !\\n\");\n    print(\"29   30   31   32   33   34   35\\n\");\n    print(\"\\n\");\n    print(\"!    !    !    !    !    !    !\\n\");\n    print(\"38   39   40   41   42   43   44\\n\");\n    print(\"\\n\");\n    print(\"!    !    !    !    !    !    !\\n\");\n    print(\"47   48   49   50   51   52   53\\n\");\n    print(\"\\n\");\n    print(\"          !    !    !\\n\");\n    print(\"         58   59   60\\n\");\n    print(\"\\n\");\n    print(\"          !    !    !\\n\");\n    print(\"         67   68   69\\n\");\n    print(\"\\n\");\n    print(\"TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\\n\");\n    print(\"WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG\\n\");\n    print(\"NUMBERS.  OK, LET'S BEGIN.\\n\");\n    while (1) {\n        // Set up board\n        for (r = 1; r <= 9; r++) {\n            t[r] = [];\n            for (c = 1; c <= 9; c++) {\n                if (r == 4 || r == 5 || r == 6 || c == 4 || c == 5 || c == 6 && (r != 1 && c != 1 && r != 9 && c != 9)) {\n                    t[r][c] = 5;\n                } else {\n                    t[r][c] = -5;\n                }\n            }\n        }\n        t[5][5] = 0;\n        print_board();\n        // Init secondary board\n        for (w = 1; w <= 33; w++) {\n            b[m[w]] = -7;\n        }\n        b[41] = -3;\n        // Input move and check on legality\n        do {\n            while (1) {\n                print(\"MOVE WHICH PIECE\");\n                z = parseInt(await input());\n                if (b[z] == -7) {\n                    print(\"TO WHERE\");\n                    p = parseInt(await input());\n                    if (p != z\n                        && b[p] != 0\n                        && b[p] != -7\n                        && (z + p) % 2 == 0\n                        && (Math.abs(z - p) - 2) * (Math.abs(z - p) - 18) == 0\n                        && update_board())\n                        break;\n                }\n                print(\"ILLEGAL MOVE, TRY AGAIN...\\n\");\n            }\n            print_board();\n        } while (!check_game_over()) ;\n        // Game is over\n        print(\"THE GAME IS OVER.\\n\");\n        print(\"YOU HAD \" + f + \" PIECES REMAINING.\\n\");\n        if (f == 1) {\n            print(\"BRAVO!  YOU MADE A PERFECT SCORE!\\n\");\n            print(\"SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!\\n\");\n        }\n        print(\"\\n\");\n        print(\"PLAY AGAIN (YES OR NO)\");\n        str = await input();\n        if (str == \"NO\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"SO LONG FOR NOW.\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "48_High_IQ/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "48_High_IQ/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "48_High_IQ/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "48_High_IQ/python/High_IQ.py",
    "content": "from typing import Dict\r\n\r\n\r\ndef new_board() -> Dict[int, str]:\r\n    \"\"\"\r\n    Using a dictionary in python to store the board,\r\n    since we are not including all numbers within a given range.\r\n    \"\"\"\r\n    return {\r\n        13: \"!\",\r\n        14: \"!\",\r\n        15: \"!\",\r\n        22: \"!\",\r\n        23: \"!\",\r\n        24: \"!\",\r\n        29: \"!\",\r\n        30: \"!\",\r\n        31: \"!\",\r\n        32: \"!\",\r\n        33: \"!\",\r\n        34: \"!\",\r\n        35: \"!\",\r\n        38: \"!\",\r\n        39: \"!\",\r\n        40: \"!\",\r\n        42: \"!\",\r\n        43: \"!\",\r\n        44: \"!\",\r\n        47: \"!\",\r\n        48: \"!\",\r\n        49: \"!\",\r\n        50: \"!\",\r\n        51: \"!\",\r\n        52: \"!\",\r\n        53: \"!\",\r\n        58: \"!\",\r\n        59: \"!\",\r\n        60: \"!\",\r\n        67: \"!\",\r\n        68: \"!\",\r\n        69: \"!\",\r\n        41: \"O\",\r\n    }\r\n\r\n\r\ndef print_instructions() -> None:\r\n    print(\r\n        \"\"\"\r\nHERE IS THE BOARD:\r\n\r\n          !    !    !\r\n         13   14   15\r\n\r\n          !    !    !\r\n         22   23   24\r\n\r\n!    !    !    !    !    !    !\r\n29   30   31   32   33   34   35\r\n\r\n!    !    !    !    !    !    !\r\n38   39   40   41   42   43   44\r\n\r\n!    !    !    !    !    !    !\r\n47   48   49   50   51   52   53\r\n\r\n          !    !    !\r\n         58   59   60\r\n\r\n          !    !    !\r\n         67   68   69\r\n\r\nTO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\r\nWILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG\r\nNUMBERS.  OK, LET'S BEGIN.\r\n    \"\"\"\r\n    )\r\n\r\n\r\ndef print_board(board: Dict[int, str]) -> None:\r\n    \"\"\"Prints the boards using indexes in the passed parameter\"\"\"\r\n    print(\" \" * 2 + board[13] + board[14] + board[15])\r\n    print(\" \" * 2 + board[22] + board[23] + board[24])\r\n    print(\r\n        board[29]\r\n        + board[30]\r\n        + board[31]\r\n        + board[32]\r\n        + board[33]\r\n        + board[34]\r\n        + board[35]\r\n    )\r\n    print(\r\n        board[38]\r\n        + board[39]\r\n        + board[40]\r\n        + board[41]\r\n        + board[42]\r\n        + board[43]\r\n        + board[44]\r\n    )\r\n    print(\r\n        board[47]\r\n        + board[48]\r\n        + board[49]\r\n        + board[50]\r\n        + board[51]\r\n        + board[52]\r\n        + board[53]\r\n    )\r\n    print(\" \" * 2 + board[58] + board[59] + board[60])\r\n    print(\" \" * 2 + board[67] + board[68] + board[69])\r\n\r\n\r\ndef play_game() -> None:\r\n    # Create new board\r\n    board = new_board()\r\n\r\n    # Main game loop\r\n    while not is_game_finished(board):\r\n        print_board(board)\r\n        while not move(board):\r\n            print(\"ILLEGAL MOVE! TRY AGAIN\")\r\n\r\n    peg_count = sum(1 for key in board.keys() if board[key] == \"!\")\r\n    print(f\"YOU HAD {str(peg_count)} PEGS REMAINING\")\r\n\r\n    if peg_count == 1:\r\n        print(\"BRAVO! YOU MADE A PERFECT SCORE!\")\r\n        print(\"SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!\")\r\n\r\n\r\ndef move(board: Dict[int, str]) -> bool:\r\n    \"\"\"Queries the user to move. Returns false if the user puts in an invalid input or move, returns true if the move was successful\"\"\"\r\n    start_input = input(\"MOVE WHICH PIECE? \")\r\n\r\n    if not start_input.isdigit():\r\n        return False\r\n\r\n    start = int(start_input)\r\n\r\n    if start not in board or board[start] != \"!\":\r\n        return False\r\n\r\n    end_input = input(\"TO WHERE? \")\r\n\r\n    if not end_input.isdigit():\r\n        return False\r\n\r\n    end = int(end_input)\r\n\r\n    if end not in board or board[end] != \"O\":\r\n        return False\r\n\r\n    difference = abs(start - end)\r\n    center = int((end + start) / 2)\r\n    if difference in [2, 18] and board[center] == \"!\":\r\n        board[start] = \"O\"\r\n        board[center] = \"O\"\r\n        board[end] = \"!\"\r\n        return True\r\n    else:\r\n        return False\r\n\r\n\r\ndef main() -> None:\r\n    print(\" \" * 33 + \"H-I-Q\")\r\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\r\n    print_instructions()\r\n    play_game()\r\n\r\n\r\ndef is_game_finished(board) -> bool:\r\n    \"\"\"Check all locations and whether or not a move is possible at that location.\"\"\"\r\n    for pos in board.keys():\r\n        if board[pos] == \"!\":\r\n            for space in [1, 9]:\r\n                # Checks if the next location has a peg\r\n                next_to_peg = ((pos + space) in board) and board[pos + space] == \"!\"\r\n                # Checks both going forward (+ location) or backwards (-location)\r\n                has_movable_space = (\r\n                    pos - space not in board\r\n                    or board[pos - space] != \"!\"\r\n                    or pos + space * 2 not in board\r\n                    or board[pos + space * 2] != \"!\"\r\n                )\r\n                if next_to_peg and has_movable_space:\r\n                    return False\r\n    return True\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n"
  },
  {
    "path": "48_High_IQ/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n\n[Implementation](./High_IQ.py) by [Thomas Kwashnak](https://github.com/LittleTealeaf)\n"
  },
  {
    "path": "48_High_IQ/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "48_High_IQ/vbnet/HighIQ.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"HighIQ\", \"HighIQ.vbproj\", \"{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "48_High_IQ/vbnet/HighIQ.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>HighIQ</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "48_High_IQ/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "49_Hockey/README.md",
    "content": "### Hockey\n\nThis is a simulation of a ice hockey game. The computer, in this case, moderates and referees the pay between two human opponents. Of course, one person could play both sides.\n\nThe program asks for team names, player names, and even the name of the referee. Four types of shot are permitted and a shot may be aimed at one of four areas. You are also asked about passing. The game is very comprehensive with lots of action, face offs, blocks, passes, 4 on 2 situations, and so on. Unfortunately there are no penalties.\n\nThe original author is Robert Puopolo; modifications by Steve North of Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=88)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=103)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- An apparent missing line 430 causes the code to fall through from the \"FLIPS A WRISTSHOT\" case directly to the \"BACKHANDS ONE\" case.\n- The author consistently misspells the verb \"lets\" (writing it like the contraction \"let's\"), while having no trouble with \"leads\", \"gets\", \"hits\", etc.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "49_Hockey/csharp/Hockey.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "49_Hockey/csharp/Hockey.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Hockey\", \"Hockey.csproj\", \"{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "49_Hockey/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "49_Hockey/hockey.bas",
    "content": "2 PRINT TAB(33);\"HOCKEY\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 REM ROBERT PUOPOLO ALG. 1 140 MCCOWAN 6/7/73 HOCKEY\n30 LET X=1\n40 PRINT:PRINT:PRINT\n50 PRINT \"WOULD YOU LIKE THE INSTRUCTIONS\";:INPUT C$\n55 PRINT\n60 IF C$=\"NO\" THEN 90\n65 IF C$=\"YES\" THEN 80\n70 PRINT \"ANSWER YES OR NO!!\":GOTO 50\n80 GOTO 1720\n90 DIM A$(7),B$(7),H(20),T(5),T1(5),T2(5),T3(5)\n100 PRINT \"ENTER THE TWO TEAMS\";:INPUT A$(7),B$(7)\n105 PRINT\n110 PRINT \"ENTER THE NUMBER OF MINUTES IN A GAME\";:INPUT T6\n115 PRINT\n120 IF T6<1 THEN 110:PRINT\n130 PRINT \"WOULD THE \" A$(7) \" COACH ENTER HIS TEAM\"\n135 PRINT\n140 FOR I=1 TO 6:PRINT \"PLAYER\"I;:INPUT A$(I):NEXT I:PRINT\n150 PRINT \"WOULD THE \" B$(7) \" COACH DO THE SAME\"\n155 PRINT\n160 FOR T=1 TO 6:PRINT \"PLAYER\"T;:INPUT B$(T):NEXT T:PRINT\n170 PRINT \"INPUT THE REFEREE FOR THIS GAME\";:INPUT R$\n180 PRINT:PRINT TAB(10);A$(7) \" STARTING LINEUP\"\n190 FOR T=1 TO 6:PRINT A$(T):NEXT T\n200 PRINT:PRINT TAB(10);B$(7)\" STARTING LINEUP\"\n210 FOR T=1 TO 6:PRINT B$(T):NEXT T:PRINT\n220 PRINT \"WE'RE READY FOR TONIGHTS OPENING FACE-OFF.\"\n230 PRINT R$ \" WILL DROP THE PUCK BETWEEN \" A$(2) \" AND \" B$(2)\n240 FOR L=1 TO T6:IF L=1 THEN 260\n250 PRINT \"AND WE'RE READY FOR THE FACE-OFF\"\n260 C=INT(2*RND(X))+1:ON C GOTO 270,280\n270 PRINT A$(7) \" HAS CONTROL OF THE PUCK\":GOTO 290\n280 PRINT B$(7) \" HAS CONTROL.\"\n290 PRINT \"PASS\";:INPUT P:FOR N=1 TO 3:H(N)=0:NEXT N\n300 IF P<0 THEN 290\n305 IF P>3 THEN 290\n310 FOR J=1 TO (P+2)\n320 H(J)=INT(5*RND(X))+1\n330 NEXT J:IF H(J-1)=H(J-2) THEN 310\n331 IF P+2<3 THEN 350\n335 IF H(J-1)=H(J-3) THEN 310\n340 IF H(J-2)=H(J-3) THEN 310\n350 IF P=0 THEN 360\n355 GOTO 490\n360 INPUT \"SHOT\";S:IF S<1 THEN 360\n365 IF S>4 THEN 360\n370 ON C GOTO 380,480\n380 PRINT A$(H(J-1));:G=H(J-1):G1=0:G2=0\n390 ON S GOTO 400,420,440,460\n400 PRINT \" LET'S A BOOMER GO FROM THE RED LINE!!\"\n410 Z=10:GOTO 890\n420 PRINT \" FLIPS A WRISTSHOT DOWN THE ICE\"\n440 PRINT \" BACKHANDS ONE IN ON THE GOALTENDER\"\n450 Z=25:GOTO 890\n460 PRINT \" SNAPS A LONG FLIP SHOT\"\n470 Z=17:GOTO 890\n480 PRINT B$(H(J-1));:G1=0:G2=0:G=H(J-1):GOTO 390\n490 ON C GOTO 500,640\n500 ON P GOTO 510,540,570\n510 PRINT A$(H(J-2)) \" LEADS \" A$(H(J-1)) \" WITH A PERFECT PASS.\"\n520 PRINT A$(H(J-1)) \" CUTTING IN!!!\"\n530 G=H(J-1):G1=H(J-2):G2=0:Z1=3:GOTO 770\n540 PRINT A$(H(J-2)) \" GIVES TO A STREAKING \" A$(H(J-1))\n550 PRINT A$(H(J-3)) \" COMES DOWN ON \" B$(5) \" AND \" B$(4)\n560 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=2:GOTO 770\n570 PRINT \"OH MY GOD!! A ' 4 ON 2 ' SITUATION\"\n580 PRINT A$(H(J-3)) \" LEADS \" A$(H(J-2))\n590 PRINT A$(H(J-2)) \" IS WHEEELING THROUGH CENTER.\"\n600 PRINT A$(H(J-2)) \" GIVES AND GOES WITH \" A$(H(J-1))\n610 PRINT \"PRETTY PASSING!\"\n620 PRINT A$(H(J-1)) \" DROPS IT TO \" A$(H(J-4))\n630 G=H(J-4):G1=H(J-1):G2=H(J-2):Z1=1:GOTO 770\n640 ON P GOTO 650,670,720\n650 PRINT B$(H(J-1)) \" HITS \" B$(H(J-2)) \" FLYING DOWN THE LEFT SIDE\"\n660 G=H(J-2):G1=H(J-1):G2=0:Z1=3:GOTO 770\n670 PRINT \"IT'S A ' 3 ON 2 '!\"\n680 PRINT \"ONLY \" A$(4) \" AND \" A$(5) \" ARE BACK.\"\n690 PRINT B$(H(J-2)) \" GIVES OFF TO \" B$(H(J-1))\n700 PRINT B$(H(J-1)) \" DROPS TO \" B$(H(J-3))\n710 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=2:GOTO 770\n720 PRINT \" A ' 3 ON 2 ' WITH A ' TRAILER '!\"\n730 PRINT B$(H(J-4)) \" GIVES TO \" B$(H(J-2)) \" WHO SHUFFLES IT OFF TO\"\n740 PRINT B$(H(J-1)) \" WHO FIRES A WING TO WING PASS TO \"\n750 PRINT B$(H(J-3)) \" AS HE CUTS IN ALONE!!\"\n760 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=1:GOTO 770\n770 PRINT \"SHOT\";:INPUT S:IF S>4 THEN 770:IF S<1 THEN 770\n780 ON C GOTO 790,880\n790 PRINT A$(G);:ON S GOTO 800,820,840,860\n800 PRINT \" LET'S A BIG SLAP SHOT GO!!\"\n810 Z=4:Z=Z+Z1:GOTO 890\n820 PRINT \" RIPS A WRIST SHOT OFF\"\n830 Z=2:Z=Z+Z1:GOTO 890\n840 PRINT \" GETS A BACKHAND OFF\"\n850 Z=3:Z=Z+Z1:GOTO 890\n860 PRINT \" SNAPS OFF A SNAP SHOT\"\n870 Z=2:Z=Z+Z1:GOTO 890\n880 PRINT B$(G);:ON S GOTO 800,820,840,860\n890 PRINT \"AREA\";:INPUT A:IF A<1 THEN 890\n895 IF A>4 THEN 890\n900 ON C GOTO 910,920\n910 S2=S2+1:GOTO 930\n920 S3=S3+1\n930 A1=INT(4*RND(X))+1:IF A<>A1 THEN 1200\n940 H(20)=INT(100*RND(X))+1\n950 IF INT(H(20)/Z)=H(20)/Z THEN 1160\n960 ON C GOTO 970,980\n970 PRINT \"GOAL \" A$(7):H(9)=H(9)+1:GOTO 990\n980 PRINT \"SCORE \" B$(7):H(8)=H(8)+1\n990 FOR B1=1 TO 25:PRINT CHR$(7);:NEXT B1:PRINT\n1000 PRINT \"SCORE: \";:IF H(8)>H(9) THEN 1020\n1010 PRINT A$(7)\":\";H(9),B$(7)\":\";H(8):GOTO 1030\n1020 PRINT B$(7)\":\";H(8),A$(7)\":\";H(9)\n1030 ON C GOTO 1040,1100\n1040 PRINT \"GOAL SCORED BY: \" A$(G):IF G1=0 THEN 1070\n1050 IF G2=0 THEN 1080\n1060 PRINT \" ASSISTED BY: \" A$(G1) \" AND \" A$(G2):GOTO 1090\n1070 PRINT \" UNASSISTED.\":GOTO 1090\n1080 PRINT \" ASSISTED BY: \" A$(G1)\n1090 T(G)=T(G)+1:T1(G1)=T1(G1)+1:T1(G2)=T1(G2)+1:GOTO 1540\n1100 PRINT \"GOAL SCORED BY: \" B$(G);\n1110 IF G1=0 THEN 1130\n1115 IF G2=0 THEN 1140\n1120 PRINT \" ASSISTED BY: \" B$(G1) \" AND \" B$(G2):GOTO 1150\n1130 PRINT \" UNASSISTED\":GOTO 1150\n1140 PRINT \" ASSISTED BY: \" B$(G1):GOTO 1150\n1150 T2(G)=T2(G)+1:T3(G1)=T3(G1)+1:T3(G2)=T3(G2)+1:GOTO 1540\n1160 A2=INT(100*RND(X))+1:IF INT(A2/4)=A2/4 THEN 1170\n1165 GOTO 1200\n1170 ON C GOTO 1180,1190\n1180 PRINT \"SAVE \" B$(6) \" --  REBOUND\":GOTO 940\n1190 PRINT \"SAVE \" A$(6) \" --  FOLLOW UP\":GOTO 940\n1200 S1=INT(6*RND(X))+1\n1210 ON C GOTO 1220,1380\n1220 ON S1 GOTO 1230,1260,1290,1300,1330,1350\n1230 PRINT \"KICK SAVE AND A BEAUTY BY \" B$(6)\n1240 PRINT \"CLEARED OUT BY \" B$(3)\n1250 GOTO 260\n1260 PRINT \"WHAT A SPECTACULAR GLOVE SAVE BY \" B$(6)\n1270 PRINT \"AND \" B$(6) \" GOLFS IT INTO THE CROWD\"\n1280 GOTO 1540\n1290 PRINT \"SKATE SAVE ON A LOW STEAMER BY \" B$(6):GOTO 260\n1300 PRINT \"PAD SAVE BY \" B$(6) \" OFF THE STICK\"\n1310 PRINT \"OF \"A$(G) \" AND \" B$(6) \" COVERS UP\"\n1320 GOTO 1540\n1330 PRINT \"WHISTLES ONE OVER THE HEAD OF \" B$(6)\n1340 GOTO 260\n1350 PRINT B$(6) \" MAKES A FACE SAVE!! AND HE IS HURT\"\n1360 PRINT \"THE DEFENSEMAN \" B$(5) \" COVERS UP FOR HIM\"\n1370 GOTO 1540\n1380 ON S1 GOTO 1390,1410,1440,1470,1490,1520\n1390 PRINT \"STICK SAVE BY \" A$(6)\n1400 PRINT \"AND CLEARED OUT BY \" A$(4):GOTO 260\n1410 PRINT \"OH MY GOD!! \" B$(G) \" RATTLES ONE OFF THE POST\"\n1420 PRINT \"TO THE RIGHT OF \" A$(6) \" AND \" A$(6) \" COVERS \";\n1430 PRINT \"ON THE LOOSE PUCK!\":GOTO 1540\n1440 PRINT \"SKATE SAVE BY \" A$(6)\n1450 PRINT A$(6) \" WHACKS THE LOOSE PUCK INTO THE STANDS\"\n1460 GOTO 1540\n1470 PRINT \"STICK SAVE BY \" A$(6) \" AND HE CLEARS IT OUT HIMSELF\"\n1480 GOTO 260\n1490 PRINT \"KICKED OUT BY \" A$(6)\n1500 PRINT \"AND IT REBOUNDS ALL THE WAY TO CENTER ICE\"\n1510 GOTO 260\n1520 PRINT \"GLOVE SAVE \" A$(6) \" AND HE HANGS ON\"\n1530 GOTO 1540\n1540 NEXT L:FOR N=1 TO 30:PRINT CHR$(7);:NEXT N:PRINT \"THAT'S THE SIREN\"\n1550 PRINT:PRINT TAB(15);\"FINAL SCORE:\"\n1560 IF H(8)>H(9) THEN 1580\n1570 PRINT A$(7)\":\";H(9),B$(7)\":\";H(8):GOTO 1590\n1580 PRINT B$(7)\":\";H(8),A$(7)\":\";H(9)\n1590 PRINT: PRINT TAB(10);\"SCORING SUMMARY\":PRINT\n1600 PRINT TAB(25);A$(7)\n1610 PRINT TAB(5);\"NAME\";TAB(20);\"GOALS\";TAB(35);\"ASSISTS\"\n1620 PRINT TAB(5);\"----\";TAB(20);\"-----\";TAB(35);\"-------\"\n1630 FOR I=1 TO 5:PRINT TAB(5);A$(I);TAB(21);T(I);TAB(36);T1(I)\n1640 NEXT I:PRINT\n1650 PRINT TAB(25);B$(7)\n1660 PRINT TAB(5);\"NAME\";TAB(20);\"GOALS\";TAB(35);\"ASSISTS\"\n1670 PRINT TAB(5);\"----\";TAB(20);\"-----\";TAB(35);\"-------\"\n1680 FOR T=1 TO 5:PRINT TAB(5);B$(T);TAB(21);T2(T);TAB(36);T3(T)\n1690 NEXT T:PRINT\n1700 PRINT \"SHOTS ON NET\":PRINT A$(7)\":\";S2:PRINT B$(7)\":\";S3\n1710 END\n1720 PRINT: PRINT \"THIS IS A SIMULATED HOCKEY GAME.\"\n1730 PRINT \"QUESTION     RESPONSE\"\n1740 PRINT \"PASS         TYPE IN THE NUMBER OF PASSES YOU WOULD\"\n1750 PRINT \"             LIKE TO MAKE, FROM 0 TO 3.\"\n1760 PRINT \"SHOT         TYPE THE NUMBER CORRESPONDING TO THE SHOT\"\n1770 PRINT \"             YOU WANT TO MAKE.  ENTER:\"\n1780 PRINT \"             1 FOR A SLAPSHOT\"\n1790 PRINT \"             2 FOR A WRISTSHOT\"\n1800 PRINT \"             3 FOR A BACKHAND\"\n1810 PRINT \"             4 FOR A SNAP SHOT\"\n1820 PRINT \"AREA         TYPE IN THE NUMBER CORRESPONDING TO\"\n1830 PRINT \"             THE AREA YOU ARE AIMING AT.  ENTER:\"\n1840 PRINT \"             1 FOR UPPER LEFT HAND CORNER\"\n1850 PRINT \"             2 FOR UPPER RIGHT HAND CORNER\"\n1860 PRINT \"             3 FOR LOWER LEFT HAND CORNER\"\n1870 PRINT \"             4 FOR LOWER RIGHT HAND CORNER\"\n1880 PRINT\n1890 PRINT \"AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES\"\n1900 PRINT \"OF YOUR PLAYERS.  THEY ARE ENTERED IN THE ORDER: \"\n1910 PRINT \"LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,\"\n1920 PRINT \"RIGHT DEFENSE, GOALKEEPER.  ANY OTHER INPUT REQUIRED WILL\"\n1930 PRINT \"HAVE EXPLANATORY INSTRUCTIONS.\"\n1940 GOTO 90\n1950 END\n"
  },
  {
    "path": "49_Hockey/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "49_Hockey/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "49_Hockey/javascript/hockey.html",
    "content": "<html>\n<head>\n<title>HOCKEY</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hockey.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "49_Hockey/javascript/hockey.js",
    "content": "// HOCKEY\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar as = [];\nvar bs = [];\nvar ha = [];\nvar ta = [];\nvar t1 = [];\nvar t2 = [];\nvar t3 = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"HOCKEY\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // Robert Puopolo Alg. 1 140 McCowan 6/7/73 Hockey\n    for (c = 0; c <= 20; c++)\n        ha[c] = 0;\n    for (c = 1; c <= 5; c++) {\n        ta[c] = 0;\n        t1[c] = 0;\n        t2[c] = 0;\n        t3[c] = 0;\n    }\n    x = 1;\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"WOULD YOU LIKE THE INSTRUCTIONS\");\n        str = await input();\n        print(\"\\n\");\n        if (str == \"YES\" || str == \"NO\")\n            break;\n        print(\"ANSWER YES OR NO!!\\n\");\n    }\n    if (str == \"YES\") {\n        print(\"\\n\");\n        print(\"THIS IS A SIMULATED HOCKEY GAME.\\n\");\n        print(\"QUESTION     RESPONSE\\n\");\n        print(\"PASS         TYPE IN THE NUMBER OF PASSES YOU WOULD\\n\");\n        print(\"             LIKE TO MAKE, FROM 0 TO 3.\\n\");\n        print(\"SHOT         TYPE THE NUMBER CORRESPONDING TO THE SHOT\\n\");\n        print(\"             YOU WANT TO MAKE.  ENTER:\\n\");\n        print(\"             1 FOR A SLAPSHOT\\n\");\n        print(\"             2 FOR A WRISTSHOT\\n\");\n        print(\"             3 FOR A BACKHAND\\n\");\n        print(\"             4 FOR A SNAP SHOT\\n\");\n        print(\"AREA         TYPE IN THE NUMBER CORRESPONDING TO\\n\");\n        print(\"             THE AREA YOU ARE AIMING AT.  ENTER:\\n\");\n        print(\"             1 FOR UPPER LEFT HAND CORNER\\n\");\n        print(\"             2 FOR UPPER RIGHT HAND CORNER\\n\");\n        print(\"             3 FOR LOWER LEFT HAND CORNER\\n\");\n        print(\"             4 FOR LOWER RIGHT HAND CORNER\\n\");\n        print(\"\\n\");\n        print(\"AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES\\n\");\n        print(\"OF YOUR PLAYERS.  THEY ARE ENTERED IN THE ORDER: \\n\");\n        print(\"LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,\\n\");\n        print(\"RIGHT DEFENSE, GOALKEEPER.  ANY OTHER INPUT REQUIRED WILL\\n\");\n        print(\"HAVE EXPLANATORY INSTRUCTIONS.\\n\");\n    }\n    print(\"ENTER THE TWO TEAMS\");\n    str = await input();\n    c = str.indexOf(\",\");\n    as[7] = str.substr(0, c);\n    bs[7] = str.substr(c + 1);\n    print(\"\\n\");\n    do {\n        print(\"ENTER THE NUMBER OF MINUTES IN A GAME\");\n        t6 = parseInt(await input());\n        print(\"\\n\");\n    } while (t6 < 1) ;\n    print(\"\\n\");\n    print(\"WOULD THE \" + as[7] + \" COACH ENTER HIS TEAM\\n\");\n    print(\"\\n\");\n    for (i = 1; i <= 6; i++) {\n        print(\"PLAYER \" + i + \" \");\n        as[i] = await input();\n    }\n    print(\"\\n\");\n    print(\"WOULD THE \" + bs[7] + \" COACH DO THE SAME\\n\");\n    print(\"\\n\");\n    for (t = 1; t <= 6; t++) {\n        print(\"PLAYER \" + t + \" \");\n        bs[t] = await input();\n    }\n    print(\"\\n\");\n    print(\"INPUT THE REFEREE FOR THIS GAME\");\n    rs = await input();\n    print(\"\\n\");\n    print(tab(10) + as[7] + \" STARTING LINEUP\\n\");\n    for (t = 1; t <= 6; t++) {\n        print(as[t] + \"\\n\");\n    }\n    print(\"\\n\");\n    print(tab(10) + bs[7] + \" STARTING LINEUP\\n\");\n    for (t = 1; t <= 6; t++) {\n        print(bs[t] + \"\\n\");\n    }\n    print(\"\\n\");\n    print(\"WE'RE READY FOR TONIGHTS OPENING FACE-OFF.\\n\");\n    print(rs + \" WILL DROP THE PUCK BETWEEN \" + as[2] + \" AND \" + bs[2] + \"\\n\");\n    s2 = 0;\n    s3 = 0;\n    for (l = 1; l <= t6; l++) {\n        c = Math.floor(2 * Math.random()) + 1;\n        if (c == 1)\n            print(as[7] + \" HAS CONTROL OF THE PUCK\\n\");\n        else\n            print(bs[7] + \" HAS CONTROL.\\n\");\n        do {\n\n            print(\"PASS\");\n            p = parseInt(await input());\n            for (n = 1; n <= 3; n++)\n                ha[n] = 0;\n        } while (p < 0 || p > 3) ;\n        do {\n            for (j = 1; j <= p + 2; j++)\n                ha[j] = Math.floor(5 * Math.random()) + 1;\n        } while (ha[j - 1] == ha[j - 2] || (p + 2 >= 3 && (ha[j - 1] == ha[j - 3] || ha[j - 2] == ha[j - 3]))) ;\n        if (p == 0) {\n            while (1) {\n                print(\"SHOT\");\n                s = parseInt(await input());\n                if (s >= 1 && s <= 4)\n                    break;\n            }\n            if (c == 1) {\n                print(as[ha[j - 1]]);\n                g = ha[j - 1];\n                g1 = 0;\n                g2 = 0;\n            } else {\n                print(bs[ha[j - 1]]);\n                g2 = 0;\n                g2 = 0;\n                g = ha[j - 1];\n            }\n            switch (s) {\n                case 1:\n                    print(\" LET'S A BOOMER GO FROM THE RED LINE!!\\n\");\n                    z = 10;\n                    break;\n                case 2:\n                    print(\" FLIPS A WRISTSHOT DOWN THE ICE\\n\");\n                    // Probable missing line 430 in original\n                case 3:\n                    print(\" BACKHANDS ONE IN ON THE GOALTENDER\\n\");\n                    z = 25;\n                    break;\n                case 4:\n                    print(\" SNAPS A LONG FLIP SHOT\\n\");\n                    z = 17;\n                    break;\n            }\n        } else {\n            if (c == 1) {\n                switch (p) {\n                    case 1:\n                        print(as[ha[j - 2]] + \" LEADS \" + as[ha[j - 1]] + \" WITH A PERFECT PASS.\\n\");\n                        print(as[ha[j - 1]] + \" CUTTING IN!!!\\n\");\n                        g = ha[j - 1];\n                        g1 = ha[j - 2];\n                        g2 = 0;\n                        z1 = 3;\n                        break;\n                    case 2:\n                        print(as[ha[j - 2]] + \" GIVES TO A STREAKING \" + as[ha[j - 1]] + \"\\n\");\n                        print(as[ha[j - 3]] + \" COMES DOWN ON \" + bs[5] + \" AND \" + bs[4] + \"\\n\");\n                        g = ha[j - 3];\n                        g1 = ha[j - 1];\n                        g2 = ha[j - 2];\n                        z1 = 2;\n                        break;\n                    case 3:\n                        print(\"OH MY GOD!! A ' 4 ON 2 ' SITUATION\\n\");\n                        print(as[ha[j - 3]] + \" LEADS \" + as[ha[j - 2]] + \"\\n\");\n                        print(as[ha[j - 2]] + \" IS WHEELING THROUGH CENTER.\\n\");\n                        print(as[ha[j - 2]] + \" GIVES AND GOEST WITH \" + as[ha[j - 1]] + \"\\n\");\n                        print(\"PRETTY PASSING!\\n\");\n                        print(as[ha[j - 1]] + \" DROPS IT TO \" + as[ha[j - 4]] + \"\\n\");\n                        g = ha[j - 4];\n                        g1 = ha[j - 1];\n                        g2 = ha[j - 2];\n                        z1 = 1;\n                        break;\n                }\n            } else {\n                switch (p) {\n                    case 1:\n                        print(bs[ha[j - 1]] + \" HITS \" + bs[ha[j - 2]] + \" FLYING DOWN THE LEFT SIDE\\n\");\n                        g = ha[j - 2];\n                        g1 = ha[j - 1];\n                        g2 = 0;\n                        z1 = 3;\n                        break;\n                    case 2:\n                        print(\"IT'S A ' 3 ON 2 '!\\n\");\n                        print(\"ONLY \" + as[4] + \" AND \" + as[5] + \" ARE BACK.\\n\");\n                        print(bs[ha[j - 2]] + \" GIVES OFF TO \" + bs[ha[j - 1]] + \"\\n\");\n                        print(bs[ha[j - 1]] + \" DROPS TO \" + bs[ha[j - 3]] + \"\\n\");\n                        g = ha[j - 3];\n                        g1 = ha[j - 1];\n                        g2 = ha[j - 2];\n                        z1 = 2;\n                        break;\n                    case 3:\n                        print(\" A '3 ON 2 ' WITH A ' TRAILER '!\\n\");\n                        print(bs[ha[j - 4]] + \" GIVES TO \" + bs[ha[j - 2]] + \" WHO SHUFFLES IT OFF TO\\n\");\n                        print(bs[ha[j - 1]] + \" WHO FIRES A WING TO WING PASS TO \\n\");\n                        print(bs[ha[j - 3]] + \" AS HE CUTS IN ALONE!!\\n\");\n                        g = ha[j - 3];\n                        g1 = ha[j - 1];\n                        g2 = ha[j - 2];\n                        z1 = 1;\n                        break;\n                }\n            }\n            do {\n                print(\"SHOT\");\n                s = parseInt(await input());\n            } while (s < 1 || s > 4) ;\n            if (c == 1)\n                print(as[g]);\n            else\n                print(bs[g]);\n            switch (s) {\n                case 1:\n                    print(\" LET'S A BIG SLAP SHOT GO!!\\n\");\n                    z = 4;\n                    z += z1;\n                    break;\n                case 2:\n                    print(\" RIPS A WRIST SHOT OFF\\n\");\n                    z = 2;\n                    z += z1;\n                    break;\n                case 3:\n                    print(\" GETS A BACKHAND OFF\\n\");\n                    z = 3;\n                    z += z1;\n                    break;\n                case 4:\n                    print(\" SNAPS OFF A SNAP SHOT\\n\");\n                    z = 2;\n                    z += z1;\n                    break;\n            }\n        }\n        do {\n            print(\"AREA\");\n            a = parseInt(await input());\n        } while (a < 1 || a > 4) ;\n        if (c == 1)\n            s2++;\n        else\n            s3++;\n        a1 = Math.floor(4 * Math.random()) + 1;\n        if (a == a1) {\n            while (1) {\n                ha[20] = Math.floor(100 * Math.random()) + 1;\n                if (ha[20] % z != 0)\n                    break;\n                a2 = Math.floor(100 * Math.random()) + 1;\n                if (a2 % 4 == 0) {\n                    if (c == 1)\n                        print(\"SAVE \" + bs[6] + \" --  REBOUND\\n\");\n                    else\n                        print(\"SAVE \" + as[6] + \" --  FOLLOW up\\n\");\n                    continue;\n                } else {\n                    a1 = a + 1;  // So a != a1\n                }\n            }\n            if (ha[20] % z != 0) {\n                if (c == 1) {\n                    print(\"GOAL \" + as[7] + \"\\n\");\n                    ha[9]++;\n                } else {\n                    print(\"SCORE \" + bs[7] + \"\\n\");\n                    ha[8]++;\n                }\n                // Bells in origninal\n                print(\"\\n\");\n                print(\"SCORE: \");\n                if (ha[8] <= ha[9]) {\n                    print(as[7] + \": \" + ha[9] + \"\\t\" + bs[7] + \": \" + ha[8] + \"\\n\");\n                } else {\n                    print(bs[7] + \": \" + ha[8] + \"\\t\" + as[7] + \": \" + ha[9] + \"\\n\");\n                }\n                if (c == 1) {\n                    print(\"GOAL SCORED BY: \" + as[g] + \"\\n\");\n                    if (g1 != 0) {\n                        if (g2 != 0) {\n                            print(\" ASSISTED BY: \" + as[g1] + \" AND \" + as[g2] + \"\\n\");\n                        } else {\n                            print(\" ASSISTED BY: \" + as[g1] + \"\\n\");\n                        }\n                    } else {\n                        print(\" UNASSISTED.\\n\");\n                    }\n                    ta[g]++;\n                    t1[g1]++;\n                    t1[g2]++;\n                    // 1540\n                } else {\n                    print(\"GOAL SCORED BY: \" + bs[g] + \"\\n\");\n                    if (g1 != 0) {\n                        if (g2 != 0) {\n                            print(\" ASSISTED BY: \" + bs[g1] + \" AND \" + bs[g2] + \"\\n\");\n                        } else {\n                            print(\" ASSISTED BY: \" + bs[g1] + \"\\n\");\n                        }\n                    } else {\n                        print(\" UNASSISTED.\\n\");\n                    }\n                    t2[g]++;\n                    t3[g1]++;\n                    t3[g2]++;\n                    // 1540\n                }\n            }\n        }\n        if (a != a1) {\n            s1 = Math.floor(6 * Math.random()) + 1;\n            if (c == 1) {\n                switch (s1) {\n                    case 1:\n                        print(\"KICK SAVE AND A BEAUTY BY \" + bs[6] + \"\\n\");\n                        print(\"CLEARED OUT BY \" + bs[3] + \"\\n\");\n                        l--;\n                        continue;\n                    case 2:\n                        print(\"WHAT A SPECTACULAR GLOVE SAVE BY \" + bs[6] + \"\\n\");\n                        print(\"AND \" + bs[6] + \" GOLFS IT INTO THE CROWD\\n\");\n                        break;\n                    case 3:\n                        print(\"SKATE SAVE ON A LOW STEAMER BY \" + bs[6] + \"\\n\");\n                        l--;\n                        continue;\n                    case 4:\n                        print(\"PAD SAVE BY \" + bs[6] + \" OFF THE STICK\\n\");\n                        print(\"OF \" + as[g] + \" AND \" + bs[6] + \" COVERS UP\\n\");\n                        break;\n                    case 5:\n                        print(\"WHISTLES ONE OVER THE HEAD OF \" + bs[6] + \"\\n\");\n                        l--;\n                        continue;\n                    case 6:\n                        print(bs[6] + \" MAKES A FACE SAVE!! AND HE IS HURT\\n\");\n                        print(\"THE DEFENSEMAN \" + bs[5] + \" COVERS UP FOR HIM\\n\");\n                        break;\n                }\n            } else {\n                switch (s1) {\n                    case 1:\n                        print(\"STICK SAVE BY \" + as[6] +\"\\n\");\n                        print(\"AND CLEARED OUT BY \" + as[4] + \"\\n\");\n                        l--;\n                        continue;\n                    case 2:\n                        print(\"OH MY GOD!! \" + bs[g] + \" RATTLES ONE OFF THE POST\\n\");\n                        print(\"TO THE RIGHT OF \" + as[6] + \" AND \" + as[6] + \" COVERS \");\n                        print(\"ON THE LOOSE PUCK!\\n\");\n                        break;\n                    case 3:\n                        print(\"SKATE SAVE BY \" + as[6] + \"\\n\");\n                        print(as[6] + \" WHACKS THE LOOSE PUCK INTO THE STANDS\\n\");\n                        break;\n                    case 4:\n                        print(\"STICK SAVE BY \" + as[6] + \" AND HE CLEARS IT OUT HIMSELF\\n\");\n                        l--;\n                        continue;\n                    case 5:\n                        print(\"KICKED OUT BY \" + as[6] + \"\\n\");\n                        print(\"AND IT REBOUNDS ALL THE WAY TO CENTER ICE\\n\");\n                        l--;\n                        continue;\n                    case 6:\n                        print(\"GLOVE SAVE \" + as[6] + \" AND HE HANGS ON\\n\");\n                        break;\n                }\n            }\n        }\n        print(\"AND WE'RE READY FOR THE FACE-OFF\\n\");\n    }\n    // Bells chime\n    print(\"THAT'S THE SIREN\\n\");\n    print(\"\\n\");\n    print(tab(15) + \"FINAL SCORE:\\n\");\n    if (ha[8] <= ha[9]) {\n        print(as[7] + \": \" + ha[9] + \"\\t\" + bs[7] + \": \" + ha[8] + \"\\n\");\n    } else {\n        print(bs[7] + \": \" + ha[8] + \"\\t\" + as[7] + \": \" + ha[9] + \"\\n\");\n    }\n    print(\"\\n\");\n    print(tab(10) + \"SCORING SUMMARY\\n\");\n    print(\"\\n\");\n    print(tab(25) + as[7] + \"\\n\");\n    print(\"\\tNAME\\tGOALS\\tASSISTS\\n\");\n    print(\"\\t----\\t-----\\t-------\\n\");\n    for (i = 1; i <= 5; i++) {\n        print(\"\\t\" + as[i] + \"\\t\" + ta[i] + \"\\t\" + t1[i] + \"\\n\");\n    }\n    print(\"\\n\");\n    print(tab(25) + bs[7] + \"\\n\");\n    print(\"\\tNAME\\tGOALS\\tASSISTS\\n\");\n    print(\"\\t----\\t-----\\t-------\\n\");\n    for (t = 1; t <= 5; t++) {\n        print(\"\\t\" + bs[t] + \"\\t\" + t2[t] + \"\\t\" + t3[t] + \"\\n\");\n    }\n    print(\"\\n\");\n    print(\"SHOTS ON NET\\n\");\n    print(as[7] + \": \" + s2 + \"\\n\");\n    print(bs[7] + \": \" + s3 + \"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "49_Hockey/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "49_Hockey/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "49_Hockey/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "49_Hockey/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n\n\n## Porting Notes\n\nVariables:\n\n* C: Do you want instructions?\n* A$(7): Team name + player names (6 players)\n* B$(7): Team name + player names (6 players)\n* T6: Minutes per game\n* R: REFEREE\n\nFunctions:\n\n* REM: A line comment\n* `INT(2*RND(X))+1`: X is constantly 1. That means that this expression is simpler expressed as `randint(1,2)`\n\n---\n\nLooking at the JS implementation:\n\n* as[7] / bs[7]: The team name\n* ha[8] : Score of team B\n* ha[9] : Score of team A\n"
  },
  {
    "path": "49_Hockey/python/hockey.py",
    "content": "\"\"\"\nHOCKEY\n\nA simulation of an ice hockey game.\n\nThe original author is Robert Puopolo;\nmodifications by Steve North of Creative Computing.\n\nPorted to Python by Martin Thoma in 2022\n\"\"\"\n\nfrom dataclasses import dataclass, field\nfrom random import randint\nfrom typing import List, Tuple\n\nNB_PLAYERS = 6\n\n\n@dataclass\nclass Team:\n    # TODO: It would be better to use a Player-class (name, goals, assits)\n    #       and have the attributes directly at each player. This would avoid\n    #       dealing with indices that much\n    #\n    #       I'm also rather certain that I messed up somewhere with the indices\n    #       - instead of using those, one could use actual player positions:\n    #       LEFT WING,    CENTER,        RIGHT WING\n    #       LEFT DEFENSE, RIGHT DEFENSE, GOALKEEPER\n    name: str\n    players: List[str]  # 6 players\n    shots_on_net: int = 0\n    goals: List[int] = field(default_factory=lambda: [0 for _ in range(NB_PLAYERS)])\n    assists: List[int] = field(default_factory=lambda: [0 for _ in range(NB_PLAYERS)])\n    score: int = 0\n\n    def show_lineup(self) -> None:\n        print(\" \" * 10 + f\"{self.name} STARTING LINEUP\")\n        for player in self.players:\n            print(player)\n\n\ndef ask_binary(prompt: str, error_msg: str) -> bool:\n    while True:\n        answer = input(prompt).lower()\n        if answer in [\"y\", \"yes\"]:\n            return True\n        if answer in [\"n\", \"no\"]:\n            return False\n        print(error_msg)\n\n\ndef get_team_names() -> Tuple[str, str]:\n    while True:\n        answer = input(\"ENTER THE TWO TEAMS: \")\n        if answer.count(\",\") == 1:\n            return answer.split(\",\")  # type: ignore\n        print(\"separated by a single comma\")\n\n\ndef get_pass() -> int:\n    while True:\n        answer = input(\"PASS? \")\n        try:\n            passes = int(answer)\n            if passes >= 0 and passes <= 3:\n                return passes\n        except ValueError:\n            print(\"ENTER A NUMBER BETWEEN 0 AND 3\")\n\n\ndef get_minutes_per_game() -> int:\n    while True:\n        answer = input(\"ENTER THE NUMBER OF MINUTES IN A GAME \")\n        try:\n            minutes = int(answer)\n            if minutes >= 1:\n                return minutes\n        except ValueError:\n            print(\"ENTER A NUMBER\")\n\n\ndef get_player_names(prompt: str) -> List[str]:\n    players = []\n    print(prompt)\n    for i in range(1, 7):\n        player = input(f\"PLAYER {i}: \")\n        players.append(player)\n    return players\n\n\ndef make_shot(\n    controlling_team: int, team_a: Team, team_b: Team, player_index: List[int], j: int\n) -> Tuple[int, int, int, int]:\n    while True:\n        try:\n            s = int(input(\"SHOT? \"))\n        except ValueError:\n            continue\n        if s >= 1 and s <= 4:\n            break\n    if controlling_team == 1:\n        print(team_a.players[player_index[j - 1]])\n    else:\n        print(team_b.players[player_index[j - 1]])\n    g = player_index[j - 1]\n    g1 = 0\n    g2 = 0\n    if s == 1:\n        print(\" LET'S A BOOMER GO FROM THE RED LINE!!\\n\")  # line 400\n        z = 10\n    elif s == 2:\n        print(\" FLIPS A WRISTSHOT DOWN THE ICE\\n\")  # line 420\n        # Probable missing line 430 in original\n    elif s == 3:\n        print(\" BACKHANDS ONE IN ON THE GOALTENDER\\n\")\n        z = 25\n    elif s == 4:\n        print(\" SNAPS A LONG FLIP SHOT\\n\")\n        # line 460\n        z = 17\n    return z, g, g1, g2\n\n\ndef print_header() -> None:\n    print(\" \" * 33 + \"HOCKEY\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef instructions() -> None:\n    if ask_binary(\n        \"WOULD YOU LIKE THE INSTRUCTIONS? \", \"ANSWER YES OR NO!!\"\n    ):\n        print()\n        print(\"THIS IS A SIMULATED HOCKEY GAME.\")\n        print(\"QUESTION     RESPONSE\")\n        print(\"PASS         TYPE IN THE NUMBER OF PASSES YOU WOULD\")\n        print(\"             LIKE TO MAKE, FROM 0 TO 3.\")\n        print(\"SHOT         TYPE THE NUMBER CORRESPONDING TO THE SHOT\")\n        print(\"             YOU WANT TO MAKE.  ENTER:\")\n        print(\"             1 FOR A SLAPSHOT\")\n        print(\"             2 FOR A WRISTSHOT\")\n        print(\"             3 FOR A BACKHAND\")\n        print(\"             4 FOR A SNAP SHOT\")\n        print(\"AREA         TYPE IN THE NUMBER CORRESPONDING TO\")\n        print(\"             THE AREA YOU ARE AIMING AT.  ENTER:\")\n        print(\"             1 FOR UPPER LEFT HAND CORNER\")\n        print(\"             2 FOR UPPER RIGHT HAND CORNER\")\n        print(\"             3 FOR LOWER LEFT HAND CORNER\")\n        print(\"             4 FOR LOWER RIGHT HAND CORNER\")\n        print(\"AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES\")\n        print(\"OF YOUR PLAYERS.  THEY ARE ENTERED IN THE ORDER: \")\n        print(\"LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,\")\n        print(\"RIGHT DEFENSE, GOALKEEPER.  ANY OTHER INPUT REQUIRED WILL\")\n        print(\"HAVE EXPLANATORY INSTRUCTIONS.\")\n\n\ndef team1_action(\n    pass_value: int, player_index: List[int], team_a: Team, team_b: Team, j: int\n) -> Tuple[int, int, int, int]:\n    if pass_value == 1:\n        print(\n            team_a.players[player_index[j - 2]]\n            + \" LEADS \"\n            + team_a.players[player_index[j - 1]]\n            + \" WITH A PERFECT PASS.\\n\"\n        )\n        print(team_a.players[player_index[j - 1]] + \" CUTTING IN!!!\\n\")\n        scoring_player = player_index[j - 1]\n        goal_assistant1 = player_index[j - 2]\n        goal_assistant2 = 0\n        z1 = 3\n    elif pass_value == 2:\n        print(\n            team_a.players[player_index[j - 2]]\n            + \" GIVES TO A STREAKING \"\n            + team_a.players[player_index[j - 1]]\n        )\n        print(\n            team_a.players[player_index[j - 3]]\n            + \" COMES DOWN ON \"\n            + team_b.players[4]\n            + \" AND \"\n            + team_b.players[3]\n        )\n        scoring_player = player_index[j - 3]\n        goal_assistant1 = player_index[j - 1]\n        goal_assistant2 = player_index[j - 2]\n        z1 = 2\n    elif pass_value == 3:\n        print(\"OH MY GOD!! A ' 4 ON 2 ' SITUATION\\n\")\n        print(\n            team_a.players[player_index[j - 3]]\n            + \" LEADS \"\n            + team_a.players[player_index[j - 2]]\n            + \"\\n\"\n        )\n        print(team_a.players[player_index[j - 2]] + \" IS WHEELING THROUGH CENTER.\\n\")\n        print(\n            team_a.players[player_index[j - 2]]\n            + \" GIVES AND GOEST WITH \"\n            + team_a.players[player_index[j - 1]]\n        )\n        print(\"PRETTY PASSING!\\n\")\n        print(\n            team_a.players[player_index[j - 1]]\n            + \" DROPS IT TO \"\n            + team_a.players[player_index[j - 4]]\n        )\n        scoring_player = player_index[j - 4]\n        goal_assistant1 = player_index[j - 1]\n        goal_assistant2 = player_index[j - 2]\n        z1 = 1\n    return scoring_player, goal_assistant1, goal_assistant2, z1\n\n\ndef team2_action(\n    pass_value: int, player_index: List[int], team_a: Team, team_b: Team, j: int\n) -> Tuple[int, int, int, int]:\n    if pass_value == 1:\n        print(\n            team_b.players[player_index[j - 1]]\n            + \" HITS \"\n            + team_b.players[player_index[j - 2]]\n            + \" FLYING DOWN THE LEFT SIDE\\n\"\n        )\n        scoring_player = player_index[j - 2]\n        goal_assistant1 = player_index[j - 1]\n        goal_assistant2 = 0\n        z1 = 3\n    elif pass_value == 2:\n        print(\"IT'S A ' 3 ON 2 '!\\n\")\n        print(f\"ONLY {team_a.players[3]} AND {team_a.players[4]} ARE BACK.\\n\")\n        print(\n            team_b.players[player_index[j - 2]]\n            + \" GIVES OFF TO \"\n            + team_b.players[player_index[j - 1]]\n        )\n        print(\n            team_b.players[player_index[j - 1]]\n            + \" DROPS TO \"\n            + team_b.players[player_index[j - 3]]\n        )\n        scoring_player = player_index[j - 3]\n        goal_assistant1 = player_index[j - 1]\n        goal_assistant2 = player_index[j - 2]\n        z1 = 2\n    elif pass_value == 3:\n        print(\" A '3 ON 2 ' WITH A ' TRAILER '!\\n\")\n        print(\n            team_b.players[player_index[j - 4]]\n            + \" GIVES TO \"\n            + team_b.players[player_index[j - 2]]\n            + \" WHO SHUFFLES IT OFF TO\\n\"\n        )\n        print(\n            team_b.players[player_index[j - 1]] + \" WHO FIRES A WING TO WING PASS TO \\n\"\n        )\n        print(team_b.players[player_index[j - 3]] + \" AS HE CUTS IN ALONE!!\\n\")\n        scoring_player = player_index[j - 3]\n        goal_assistant1 = player_index[j - 1]\n        goal_assistant2 = player_index[j - 2]\n        z1 = 1\n    return scoring_player, goal_assistant1, goal_assistant2, z1\n\n\ndef final_message(team_a: Team, team_b: Team, player_index: List[int]) -> None:\n    # Bells chime\n    print(\"THAT'S THE SIREN\\n\")\n    print(\"\\n\")\n    print(\" \" * 15 + \"FINAL SCORE:\\n\")\n    if team_b.score <= team_a.score:\n        print(f\"{team_a.name}: {team_a.score}\\t{team_b.name}: {team_b.score}\\n\")\n    else:\n        print(f\"{team_b.name}: {team_b.score}\\t{team_a.name}\\t:{team_a.score}\\n\")\n    print(\"\\n\")\n    print(\" \" * 10 + \"SCORING SUMMARY\\n\")\n    print(\"\\n\")\n    print(\" \" * 25 + team_a.name + \"\\n\")\n    print(\"\\tNAME\\tGOALS\\tASSISTS\\n\")\n    print(\"\\t----\\t-----\\t-------\\n\")\n    for i in range(1, 6):\n        print(f\"\\t{team_a.players[i]}\\t{team_a.goals[i]}\\t{team_a.assists[i]}\\n\")\n    print(\"\\n\")\n    print(\" \" * 25 + team_b.name + \"\\n\")\n    print(\"\\tNAME\\tGOALS\\tASSISTS\\n\")\n    print(\"\\t----\\t-----\\t-------\\n\")\n    for t in range(1, 6):\n        print(f\"\\t{team_b.players[t]}\\t{team_b.goals[t]}\\t{team_b.assists[t]}\\n\")\n    print(\"\\n\")\n    print(\"SHOTS ON NET\\n\")\n    print(f\"{team_a.name}: {team_a.shots_on_net}\\n\")\n    print(f\"{team_b.name}: {team_b.shots_on_net}\\n\")\n\n\ndef main() -> None:\n    # Intro\n    print_header()\n    player_index: List[int] = [0 for _ in range(21)]\n    print(\"\\n\" * 3)\n    instructions()\n\n    # Gather input\n    team_name_a, team_name_b = get_team_names()\n    print()\n    minutes_per_game = get_minutes_per_game()\n    print()\n    players_a = get_player_names(f\"WOULD THE {team_name_a} COACH ENTER HIS TEAM\")\n    print()\n    players_b = get_player_names(f\"WOULD THE {team_name_b} COACH DO THE SAME\")\n    team_a = Team(team_name_a, players_a)\n    team_b = Team(team_name_b, players_b)\n    print()\n    referee = input(\"INPUT THE REFEREE FOR THIS GAME: \")\n    print()\n    team_a.show_lineup()\n    print()\n    team_b.show_lineup()\n    print(\"WE'RE READY FOR TONIGHTS OPENING FACE-OFF.\")\n    print(\n        f\"{referee} WILL DROP THE PUCK BETWEEN \"\n        f\"{team_a.players[0]} AND {team_b.players[0]}\"\n    )\n    remaining_time = minutes_per_game\n\n    # Play the game\n    while remaining_time > 0:\n        cont, remaining_time = simulate_game_round(\n            team_a, team_b, player_index, remaining_time\n        )\n        remaining_time -= 1\n        if cont == \"break\":\n            break\n\n    # Outro\n    final_message(team_a, team_b, player_index)\n\n\ndef handle_hit(\n    controlling_team: int,\n    team_a: Team,\n    team_b: Team,\n    player_index: List[int],\n    goal_player: int,\n    goal_assistant1: int,\n    goal_assistant2: int,\n    hit_area: int,\n    z: int,\n) -> int:\n    while True:\n        player_index[20] = randint(1, 100)\n        if player_index[20] % z != 0:\n            break\n        a2 = randint(1, 100)\n        if a2 % 4 == 0:\n            if controlling_team == 1:\n                print(f\"SAVE {team_b.players[5]} --  REBOUND\\n\")\n            else:\n                print(f\"SAVE {team_a.players[5]} --  FOLLOW up\\n\")\n            continue\n        else:\n            hit_area += 1\n    if player_index[20] % z != 0:\n        if controlling_team == 1:\n            print(f\"GOAL {team_a.name}\\n\")\n            team_a.score += 1\n        else:\n            print(f\"SCORE {team_b.name}\\n\")\n            team_b.score += 1\n        # Bells in origninal\n        print(\"\\n\")\n        print(\"SCORE: \")\n        if team_b.score <= team_a.score:\n            print(f\"{team_a.name}: {team_a.score}\\t{team_b.name}: {team_b.score}\\n\")\n        else:\n            print(f\"{team_b.name}: {team_b.score}\\t{team_a.name}: {team_a.score}\\n\")\n        team = team_a if controlling_team == 1 else team_b\n        print(f\"GOAL SCORED BY: {team.players[goal_player]}\\n\")\n        if goal_assistant1 != 0:\n            if goal_assistant2 != 0:\n                print(\n                    f\" ASSISTED BY: {team.players[goal_assistant1]}\"\n                    f\" AND {team.players[goal_assistant2]}\"\n                )\n            else:\n                print(f\" ASSISTED BY: {team.players[goal_assistant1]}\")\n            team.assists[goal_assistant1] += 1\n            team.assists[goal_assistant2] += 1\n        else:\n            print(\" UNASSISTED.\\n\")\n        team.goals[goal_player] += 1\n\n    return hit_area\n\n\ndef handle_miss(\n    controlling_team: int,\n    team_a: Team,\n    team_b: Team,\n    remaining_time: int,\n    goal_player: int,\n) -> Tuple[str, int]:\n    saving_player = randint(1, 7)\n    if controlling_team == 1:\n        if saving_player == 1:\n            print(f\"KICK SAVE AND A BEAUTY BY {team_b.players[5]}\\n\")\n            print(f\"CLEARED OUT BY {team_b.players[3]}\\n\")\n            remaining_time -= 1\n            return (\"continue\", remaining_time)\n        if saving_player == 2:\n            print(f\"WHAT A SPECTACULAR GLOVE SAVE BY {team_b.players[5]}\\n\")\n            print(f\"AND {team_b.players[5]} GOLFS IT INTO THE CROWD\\n\")\n            return (\"break\", remaining_time)\n        if saving_player == 3:\n            print(f\"SKATE SAVE ON A LOW STEAMER BY {team_b.players[5]}\\n\")\n            remaining_time -= 1\n            return (\"continue\", remaining_time)\n        if saving_player == 4:\n            print(f\"PAD SAVE BY {team_b.players[5]} OFF THE STICK\\n\")\n            print(\n                f\"OF {team_a.players[goal_player]} AND \"\n                f\"{team_b.players[5]} COVERS UP\\n\"\n            )\n            return (\"break\", remaining_time)\n        if saving_player == 5:\n            print(f\"WHISTLES ONE OVER THE HEAD OF {team_b.players[5]}\\n\")\n            remaining_time -= 1\n            return (\"continue\", remaining_time)\n        if saving_player == 6:\n            print(f\"{team_b.players[5]} MAKES A FACE SAVE!! AND HE IS HURT\\n\")\n            print(f\"THE DEFENSEMAN {team_b.players[5]} COVERS UP FOR HIM\\n\")\n            return (\"break\", remaining_time)\n    else:\n        if saving_player == 1:\n            print(f\"STICK SAVE BY {team_a.players[5]}\\n\")\n            print(f\"AND CLEARED OUT BY {team_a.players[3]}\\n\")\n            remaining_time -= 1\n            return (\"continue\", remaining_time)\n        if saving_player == 2:\n            print(\n                \"OH MY GOD!! \"\n                f\"{team_b.players[goal_player]} RATTLES ONE OFF THE POST\\n\"\n            )\n            print(\n                f\"TO THE RIGHT OF {team_a.players[5]} AND \"\n                f\"{team_a.players[5]} COVERS \"\n            )\n            print(\"ON THE LOOSE PUCK!\\n\")\n            return (\"break\", remaining_time)\n        if saving_player == 3:\n            print(f\"SKATE SAVE BY {team_a.players[5]}\\n\")\n            print(team_a.players[5] + \" WHACKS THE LOOSE PUCK INTO THE STANDS\\n\")\n            return (\"break\", remaining_time)\n        if saving_player == 4:\n            print(f\"STICK SAVE BY {team_a.players[5]} AND HE CLEARS IT OUT HIMSELF\\n\")\n            remaining_time -= 1\n            return (\"continue\", remaining_time)\n        if saving_player == 5:\n            print(f\"KICKED OUT BY {team_a.players[5]}\\n\")\n            print(\"AND IT REBOUNDS ALL THE WAY TO CENTER ICE\\n\")\n            remaining_time -= 1\n            return (\"continue\", remaining_time)\n        if saving_player == 6:\n            print(f\"GLOVE SAVE {team_a.players[5]} AND HE HANGS ON\\n\")\n            return (\"break\", remaining_time)\n    return (\"continue\", remaining_time)\n\n\ndef simulate_game_round(\n    team_a: Team, team_b: Team, player_index: List[int], remaining_time: int\n) -> Tuple[str, int]:\n    controlling_team = randint(1, 2)\n    if controlling_team == 1:\n        print(f\"{team_a.name} HAS CONTROL OF THE PUCK.\")\n    else:\n        print(f\"{team_b.name} HAS CONTROL.\")\n    pass_value = get_pass()\n    for i in range(1, 4):\n        player_index[i] = 0\n\n    # Line 310:\n    while True:\n        j = 0\n        for j in range(1, (pass_value + 2) + 1):\n            player_index[j] = randint(1, 5)\n        if (\n            player_index[j - 1] == player_index[j - 2]\n            or pass_value >= 1\n            and (\n                player_index[j - 1] == player_index[j - 3]\n                or player_index[j - 2] == player_index[j - 3]\n            )\n        ):\n            break\n    if pass_value == 0:  # line 350\n        z, goal_player, goal_assistant1, goal_assistant2 = make_shot(\n            controlling_team, team_a, team_b, player_index, j\n        )\n    else:\n        if controlling_team == 1:\n            goal_player, goal_assistant1, goal_assistant2, z1 = team1_action(\n                pass_value, player_index, team_a, team_b, j\n            )\n        else:\n            goal_player, goal_assistant1, goal_assistant2, z1 = team2_action(\n                pass_value, player_index, team_a, team_b, j\n            )\n        while True:\n            shot_type = int(input(\"SHOT? \"))\n            if shot_type >= 1 and shot_type <= 4:\n                break\n        if controlling_team == 1:\n            print(team_a.players[goal_player], end=\"\")\n        else:\n            print(team_b.players[goal_player], end=\"\")\n        if shot_type == 1:\n            print(\" LET'S A BIG SLAP SHOT GO!!\\n\")\n            z = 4\n            z += z1\n        elif shot_type == 2:\n            print(\" RIPS A WRIST SHOT OFF\\n\")\n            z = 2\n            z += z1\n        elif shot_type == 3:\n            print(\" GETS A BACKHAND OFF\\n\")\n            z = 3\n            z += z1\n        elif shot_type == 4:\n            print(\" SNAPS OFF A SNAP SHOT\\n\")\n            z = 2\n            z += z1\n    while True:\n        goal_area = int(input(\"AREA? \"))\n        if goal_area >= 1 and goal_area <= 4:\n            break\n    if controlling_team == 1:\n        team_a.shots_on_net += 1\n    else:\n        team_b.shots_on_net += 1\n    hit_area = randint(1, 5)\n    if goal_area == hit_area:\n        hit_area = handle_hit(\n            controlling_team,\n            team_a,\n            team_b,\n            player_index,\n            goal_player,\n            goal_assistant1,\n            goal_assistant2,\n            hit_area,\n            z,\n        )\n    if goal_area != hit_area:\n        return handle_miss(\n            controlling_team, team_a, team_b, remaining_time, goal_player\n        )\n    print(\"AND WE'RE READY FOR THE FACE-OFF\\n\")\n    return (\"continue\", remaining_time)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "49_Hockey/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "49_Hockey/vbnet/Hockey.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Hockey\", \"Hockey.vbproj\", \"{9ED23BC7-7C12-4B48-8E85-F21E310813D5}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "49_Hockey/vbnet/Hockey.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Hockey</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "49_Hockey/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "50_Horserace/README.md",
    "content": "### Horserace\n\nThis program simulates a one-mile horse race for three-year old throughbreds. Up to ten people may place bets on the race up to $10,000 each. However, you may only bet to win. You place your bet by inputting the number of the horse, a comma, and the amount of your bet. The computer then shows the position of the horses at seven points around the track and at the finish. Payoffs and winnings are shown at the end.\n\nThe program was written by Laurie Chevalier while a student at South Portland High School.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=92)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=107)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "50_Horserace/csharp/Horserace.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "50_Horserace/csharp/Horserace.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Horserace\", \"Horserace.csproj\", \"{B1CD8505-43BA-4C2C-A458-54E14539DB35}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "50_Horserace/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "50_Horserace/horserace.bas",
    "content": "100 PRINT TAB(31);\"HORSERACE\"\n110 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n120 PRINT:PRINT:PRINT\n210 DIM S(8)\n220 PRINT \"WELCOME TO SOUTH PORTLAND HIGH RACETRACK\"\n230 PRINT \"                      ...OWNED BY LAURIE CHEVALIER\"\n240 PRINT \"DO YOU WANT DIRECTIONS\";\n250 INPUT X$\n260 IF X$=\"NO\" THEN 320\n270 PRINT\"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\"\n280 PRINT\"MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.\"\n290 PRINT \"DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\"\n300 PRINT\"NUMBER.  THE HORSES RACE DOWN THE PAPER!\"\n310 PRINT\n320 PRINT \"HOW MANY WANT TO BET\";\n330 INPUT C\n340 PRINT \"WHEN ? APPEARS,TYPE NAME\"\n350 FOR A=1 TO C\n360 INPUT W$(A)\n370 NEXT A\n380 PRINT\n390 PRINT\"HORSE\",,\"NUMBER\",\"ODDS\"\n400 PRINT\n410 FOR I=1 TO 8: S(I)=0: NEXT I\n420 LET R=0\n430 FOR A=1 TO 8\n440 LET D(A)=INT(10*RND(1)+1)\n450 NEXT A\n460 FOR A=1 TO 8\n470 LET R=R+D(A)\n480 NEXT A\n490 LET V$(1)=\"JOE MAW\"\n500 LET V$(2)=\"L.B.J.\"\n510 LET V$(3)=\"MR.WASHBURN\"\n520 LET V$(4)=\"MISS KAREN\"\n530 LET V$(5)=\"JOLLY\"\n540 LET V$(6)=\"HORSE\"\n550 LET V$(7)=\"JELLY DO NOT\"\n560 LET V$(8)=\"MIDNIGHT\"\n570 FOR N=1 TO 8\n580 PRINT V$(N),,N,R/D(N);\":1\"\n590 NEXT N\n600 PRINT\"--------------------------------------------------\"\n610 PRINT \"PLACE YOUR BETS...HORSE # THEN AMOUNT\"\n620 FOR J=1 TO C\n630 PRINT W$(J);\n640 INPUT Q(J),P(J)\n650 IF P(J)<1 THEN 670\n660 IF P(J)<100000 THEN 690\n670 PRINT\"  YOU CAN'T DO THAT!\"\n680 GOTO 630\n690 NEXT J\n700 PRINT\n710 PRINT\"1 2 3 4 5 6 7 8\"\n720 PRINT\"XXXXSTARTXXXX\"\n730 FOR I=1 TO 8\n740 LET M=I\n750 LET M(I)=M\n760 LET Y(M(I))=INT(100*RND(1)+1)\n770 IF Y(M(I))<10 THEN 860\n780 LET S=INT(R/D(I)+.5)\n790 IF Y(M(I))<S+17 THEN 880\n800 IF Y(M(I))<S+37 THEN 900\n810 IF Y(M(I))<S+57 THEN 920\n820 IF Y(M(I))<77+S THEN 940\n830 IF Y(M(I))<S+92 THEN 960\n840 LET Y(M(I))=7\n850 GOTO 970\n860 LET Y(M(I))=1\n870 GOTO 970\n880 LET Y(M(I))=2\n890 GOTO 970\n900 LET Y(M(I))=3\n910 GOTO 970\n920 LET Y(M(I))=4\n930 GOTO 970\n940 LET Y(M(I))=5\n950 GOTO 970\n960 LET Y(M(I))=6\n970 NEXT I\n980 LET M=I\n990 FOR I=1 TO 8\n1000 LET S(M(I))=S(M(I))+Y(M(I))\n1010 NEXT I\n1020 LET I=1\n1030 FOR L=1 TO 8\n1040 FOR I=1 TO 8-L\n1050 IF S(M(I))<S(M(I+1))THEN 1090\n1060 LET H=M(I)\n1070 LET M(I)=M(I+1)\n1080 LET M(I+1)=H\n1090 NEXT I\n1100 NEXT L\n1110 LET T=S(M(8))\n1120 FOR I=1 TO 8\n1130 LET B=S(M(I))-S(M(I-1))\n1140 IF B=0 THEN 1190\n1150 FOR A=1 TO B\n1160 PRINT\n1170 IF S(M(I))>27 THEN 1240\n1180 NEXT A\n1190 PRINT M(I);\n1200 NEXT I\n1210 FOR A=1 TO 28-T\n1220 PRINT\n1230 NEXT A\n1240 PRINT \"XXXXFINISHXXXX\";\n1242 PRINT\n1243 PRINT\n1244 PRINT \"---------------------------------------------\"\n1245 PRINT\n1250 IF T<28 THEN 720\n1270 PRINT \"THE RACE RESULTS ARE:\"\n1272 LET Z9=1\n1280 FOR I=8 TO 1 STEP-1\n1290 LET F=M(I)\n1300 PRINT\n1310 PRINT Z9;\"PLACE HORSE NO.\";F,\"AT \";R/D(F);\":1\"\n1312 LET Z9=Z9+1\n1320  NEXT I\n1330 FOR J=1 TO C\n1340 IF Q(J)<>M(8) THEN 1370\n1350 LET N=Q(J)\n1355 PRINT\n1360 PRINT W$(J);\" WINS $\";(R/D(N))*P(J)\n1370 NEXT J\n1372 PRINT \"DO YOU WANT TO BET ON THE NEXT RACE ?\"\n1374 INPUT \"YES OR NO\"; O$\n1376 IF O$=\"YES\" THEN 380\n1380 END\n"
  },
  {
    "path": "50_Horserace/java/Horserace.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Scanner;\n\n/**\n * HORSERACE\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class Horserace {\n\n    private static final String[] horseNames = {\n            \"JOE MAW\",\n            \"L.B.J.\",\n            \"MR.WASHBURN\",\n            \"MISS KAREN\",\n            \"JOLLY\",\n            \"HORSE\",\n            \"JELLY DO NOT\",\n            \"MIDNIGHT\"\n    };\n    public static final int MAX_DISTANCE = 28;\n    public static final int NUM_HORSES = 8;\n\n    public static void main(String[] args) {\n        printHeader();\n\n        Scanner scanner = new Scanner(System.in);\n        Random random = new Random();\n\n        printHelp(scanner);\n\n        List<String> betNames = readBetNames(scanner);\n\n        boolean donePlaying = false;\n        while (!donePlaying) {\n\n            int[] odds = generateOdds(random);\n            int sumOdds = Arrays.stream(odds).sum();\n            printOdds(sumOdds, odds);\n\n            Map<String, Bet> bets = takeBets(scanner, betNames);\n\n            var horsePositions = runRace(horseNames.length, sumOdds, odds, random);\n\n            printRaceResults(horsePositions, bets, sumOdds, odds);\n\n            donePlaying = readDonePlaying(scanner);\n        }\n    }\n\n    private static int[] generateOdds(Random random) {\n        int[] odds = new int[NUM_HORSES];\n        for (int i = 0; i < NUM_HORSES; i++) {\n            odds[i] = (int) (10 * random.nextFloat() + 1);\n        }\n        return odds;\n    }\n\n    private static void printOdds(int R, int[] D) {\n        System.out.printf(\"%n%-28s%-14s%-14s%n%n\", \"HORSE\", \"NUMBER\", \"ODDS\");\n        for (int n = 0; n < horseNames.length; n++) {\n            System.out.printf(\"%-28s% -14d%.6f :1%n\", horseNames[n], n + 1, ((float) R / D[n]));\n        }\n    }\n\n    private static boolean readDonePlaying(Scanner scan) {\n        System.out.println(\"DO YOU WANT TO BET ON THE NEXT RACE ?\");\n        System.out.print(\"YES OR NO? \");\n        String choice = scan.nextLine();\n        return !choice.equalsIgnoreCase(\"YES\");\n    }\n\n    /**\n     * Simulate the race run, returning the final positions of the horses.\n     */\n    private static int[] runRace(int numberOfHorses, int sumOdds, int[] odds, Random random) {\n        int[] positionChange = new int[numberOfHorses];\n\n        System.out.println();\n        System.out.println(\"1 2 3 4 5 6 7 8\");\n\n        int totalDistance = 0;\n        int[] currentPositions = new int[NUM_HORSES];\n        int[] horsePositions = new int[NUM_HORSES];\n\n        while (totalDistance < MAX_DISTANCE) {\n            System.out.println(\"XXXXSTARTXXXX\");\n\n            for (int i = 0; i < numberOfHorses; i++) {\n                horsePositions[i] = i + 1;\n                positionChange[i] = calculatePositionChanges(sumOdds, odds[i], random);\n                currentPositions[i] += positionChange[i];\n            }\n\n            sortHorsePositionsBasedOnCurrent(currentPositions, horsePositions);\n\n            totalDistance = currentPositions[horsePositions[7] - 1];\n\n            boolean raceFinished = false;\n            int i = 0;\n            while (i < NUM_HORSES && !raceFinished) {\n                int distanceToNextHorse = currentPositions[(horsePositions[i] - 1)] - (i < 1 ? 0 : currentPositions[(horsePositions[i - 1] - 1)]);\n                if (distanceToNextHorse != 0) {\n                    int a = 0;\n                    while (a < distanceToNextHorse && !raceFinished) {\n                        System.out.println();\n                        if (currentPositions[horsePositions[i] - 1] >= MAX_DISTANCE) {\n                            raceFinished = true;\n                        }\n                        a++;\n                    }\n                }\n\n                if (!raceFinished) {\n                    System.out.print(\" \" + horsePositions[i] + \" \"); // Print horse number\n                }\n                i++;\n            }\n\n            if (!raceFinished) {\n                //Print additional empty lines\n                for (int a = 0; a < MAX_DISTANCE - totalDistance; a++) {\n                    System.out.println();\n                }\n            }\n\n            System.out.println(\"XXXXFINISHXXXX\");\n            System.out.println(\"\\n\");\n            System.out.println(\"---------------------------------------------\");\n            System.out.println(\"\\n\");\n        }\n\n        return horsePositions;\n    }\n\n    /**\n     * Sorts the horsePositions array in place, based on the currentPositions of the horses.\n     * (bubble sort)\n     */\n    private static void sortHorsePositionsBasedOnCurrent(int[] currentPositions, int[] horsePositions) {\n        for (int l = 0; l < NUM_HORSES; l++) {\n            int i = 0;\n            /*\n            uses a do-while instead of a for loop here, because in BASIC\n            a FOR I=1 TO 0 causes at least one execution of the loop\n            */\n            do {\n                if (currentPositions[horsePositions[i] - 1] >= currentPositions[horsePositions[i + 1] - 1]) {\n                    int h = horsePositions[i];\n                    horsePositions[i] = horsePositions[i + 1];\n                    horsePositions[i + 1] = h;\n                }\n                i++;\n            } while (i < (7 - l));\n        }\n    }\n\n    private static int calculatePositionChanges(int r, int d, Random random) {\n        int positionChange = (int) (100 * random.nextFloat() + 1);\n\n        if (positionChange < 10) {\n            positionChange = 1;\n        } else {\n            int s = (int) ((float) r / d + 0.5);\n            if (positionChange < (s + 17)) {\n                positionChange = 2;\n            } else if (positionChange < s + 37) {\n                positionChange = 3;\n            } else if (positionChange < s + 57) {\n                positionChange = 4;\n            } else if (positionChange < s + 77) {\n                positionChange = 5;\n            } else if (positionChange < s + 92) {\n                positionChange = 6;\n            } else {\n                positionChange = 7;\n            }\n        }\n\n        return positionChange;\n    }\n\n    private static void printRaceResults(int[] m, Map<String, Bet> bets, int r, int[] d) {\n        System.out.println(\"THE RACE RESULTS ARE:\");\n        int z9 = 1;\n        for (int i = 7; i >= 0; i--) {\n            int f = m[i];\n            System.out.println();\n            System.out.println(z9 + \" PLACE HORSE NO. \" + f + \" AT \" + (r / d[f - 1]) + \":1\");\n            z9++;\n        }\n        bets.forEach((betName, bet) -> {\n            if (bet.horseNumber == m[7]) {\n                int n = bet.horseNumber;\n                System.out.println();\n                System.out.printf(\"%s WINS $ %.2f %n\", bet.betName, ((float) r / d[n]) * bet.amount);\n            }\n        });\n    }\n\n    private static Map<String, Bet> takeBets(Scanner scanner, List<String> betNames) {\n        Map<String, Bet> bets = new HashMap<>();\n        System.out.println(\"--------------------------------------------------\");\n        System.out.println(\"PLACE YOUR BETS...HORSE # THEN AMOUNT\");\n        for (String betName : betNames) {\n            boolean validInput = false;\n            while (!validInput) {\n                int horseNumber = readInt(betName, scanner);//Q in the original\n                double betAmount = readDouble(\"?\", scanner); //P in the original\n                if (betAmount < 1 || betAmount > 100000) {\n                    System.out.println(\"  YOU CAN'T DO THAT!\");\n                } else {\n                    bets.put(betName, new Bet(betName, horseNumber, betAmount));\n                    validInput = true;\n                }\n            }\n        }\n\n        return bets;\n    }\n\n    private static void printHelp(Scanner scanner) {\n        System.out.print(\"DO YOU WANT DIRECTIONS\");\n\n        String directions = readChoice(scanner);\n\n        if (!directions.equalsIgnoreCase(\"NO\")) {\n            System.out.println(\"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\");\n            System.out.println(\"MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.\");\n            System.out.println(\"DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\");\n            System.out.println(\"NUMBER.  THE HORSES RACE DOWN THE PAPER!\");\n            System.out.println();\n        }\n    }\n\n    private static String readChoice(Scanner scanner) {\n        System.out.print(\"? \");\n        return scanner.nextLine();\n    }\n\n    private static int readInt(String prompt, Scanner scanner) {\n        System.out.print(prompt);\n        while (true) {\n            System.out.print(\"? \");\n            String input = scanner.nextLine();\n            try {\n                return Integer.parseInt(input);\n            } catch (NumberFormatException e) {\n                System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n            }\n        }\n    }\n\n    private static double readDouble(String prompt, Scanner scanner) {\n        System.out.print(prompt);\n        while (true) {\n            System.out.print(\"? \");\n            String input = scanner.nextLine();\n            try {\n                return Double.parseDouble(input);\n            } catch (NumberFormatException e) {\n                System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n            }\n        }\n    }\n\n    private static List<String> readBetNames(Scanner scanner) {\n        int c = readInt(\"HOW MANY WANT TO BET \", scanner);\n        System.out.println(\"WHEN ? APPEARS,TYPE NAME\");\n        List<String> names = new ArrayList<>();\n        for (int i = 1; i <= c; i++) {\n            System.out.print(\"? \");\n            names.add(scanner.nextLine());\n        }\n\n        return names;\n    }\n\n    private static void printHeader() {\n        System.out.println(\"                                               HORSERACE\");\n        System.out.println(\"                            CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n        System.out.println(\"\\n\\n\");\n        System.out.println(\"WELCOME TO SOUTH PORTLAND HIGH RACETRACK\");\n        System.out.println(\"                      ...OWNED BY LAURIE CHEVALIER\");\n    }\n\n    private static class Bet {\n        String betName;\n        int horseNumber;\n        double amount;\n\n        public Bet(String betName, int horseNumber, double amount) {\n            this.betName = betName;\n            this.horseNumber = horseNumber;\n            this.amount = amount;\n        }\n\n        @Override\n        public String toString() {\n            return \"Bet{\" +\n                    \"betName='\" + betName + '\\'' +\n                    \", horseNumber=\" + horseNumber +\n                    \", amount=\" + amount +\n                    '}';\n        }\n    }\n}\n\n"
  },
  {
    "path": "50_Horserace/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "50_Horserace/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "50_Horserace/javascript/horserace.html",
    "content": "<html>\n<head>\n<title>HORSERACE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"horserace.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "50_Horserace/javascript/horserace.js",
    "content": "// HORSERACE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar sa = [];\nvar ws = [];\nvar da = [];\nvar qa = [];\nvar pa = [];\nvar ma = [];\nvar ya = [];\nvar vs = [];\n\n// Main program\nasync function main()\n{\n    print(tab(31) + \"HORSERACE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"WELCOME TO SOUTH PORTLAND HIGH RACETRACK\\n\");\n    print(\"                      ...OWNED BY LAURIE CHEVALIER\\n\");\n    print(\"DO YOU WANT DIRECTIONS\");\n    str = await input();\n    if (str == \"YES\") {\n        print(\"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\\n\");\n        print(\"MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.\\n\");\n        print(\"DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\\n\");\n        print(\"NUMBER.  THE HORSES RACE DOWN THE PAPER!\\n\");\n        print(\"\\n\");\n    }\n    print(\"HOW MANY WANT TO BET\");\n    c = parseInt(await input());\n    print(\"WHEN ? APPEARS,TYPE NAME\\n\");\n    for (a = 1; a <= c; a++) {\n        ws[a] = await input();\n    }\n    do {\n        print(\"\\n\");\n        print(\"HORSE\\t\\tNUMBERS\\tODDS\\n\");\n        print(\"\\n\");\n        for (i = 1; i <= 8; i++) {\n            sa[i] = 0;\n        }\n        r = 0;\n        for (a = 1; a <= 8; a++) {\n            da[a] = Math.floor(10 * Math.random() + 1);\n        }\n        for (a = 1; a <= 8; a++) {\n            r = r + da[a];\n        }\n        vs[1] = \"JOE MAN\";\n        vs[2] = \"L.B.J.\";\n        vs[3] = \"MR.WASHBURN\";\n        vs[4] = \"MISS KAREN\";\n        vs[5] = \"JOLLY\";\n        vs[6] = \"HORSE\";\n        vs[7] = \"JELLY DO NOT\";\n        vs[8] = \"MIDNIGHT\";\n        for (n = 1; n <= 8; n++) {\n            print(vs[n] + \"\\t\\t\" + n + \"\\t\" + (r / da[n]) + \":1\\n\");\n        }\n        print(\"--------------------------------------------------\\n\");\n        print(\"PLACE YOUR BETS...HORSE # THEN AMOUNT\\n\");\n        for (j = 1; j <= c; j++) {\n            while (1) {\n                print(ws[j]);\n                str = await input();\n                qa[j] = parseInt(str);\n                pa[j] = parseInt(str.substr(str.indexOf(\",\") + 1));\n                if (pa[j] < 1 || pa[j] >= 100000) {\n                    print(\"  YOU CAN'T DO THAT!\\N\");\n                } else {\n                    break;\n                }\n            }\n        }\n        print(\"\\n\");\n        print(\"1 2 3 4 5 6 7 8\\n\");\n        t = 0;\n        do {\n            print(\"XXXXSTARTXXXX\\n\");\n            for (i = 1; i <= 8; i++) {\n                m = i;\n                ma[i] = m;\n                ya[ma[i]] = Math.floor(100 * Math.random() + 1);\n                if (ya[ma[i]] < 10) {\n                    ya[ma[i]] = 1;\n                    continue;\n                }\n                s = Math.floor(r / da[i] + 0.5);\n                if (ya[ma[i]] < s + 17) {\n                    ya[ma[i]] = 2;\n                    continue;\n                }\n                if (ya[ma[i]] < s + 37) {\n                    ya[ma[i]] = 3;\n                    continue;\n                }\n                if (ya[ma[i]] < s + 57) {\n                    ya[ma[i]] = 4;\n                    continue;\n                }\n                if (ya[ma[i]] < s + 77) {\n                    ya[ma[i]] = 5;\n                    continue;\n                }\n                if (ya[ma[i]] < s + 92) {\n                    ya[ma[i]] = 6;\n                    continue;\n                }\n                ya[ma[i]] = 7;\n            }\n            m = i;\n            for (i = 1; i <= 8; i++) {\n                sa[ma[i]] = sa[ma[i]] + ya[ma[i]];\n            }\n            i = 1;\n            for (l = 1; l <= 8; l++) {\n                for (i = 1; i <= 8 - l; i++) {\n                    if (sa[ma[i]] < sa[ma[i + 1]])\n                        continue;\n                    h = ma[i];\n                    ma[i] = ma[i + 1];\n                    ma[i + 1] = h;\n                }\n            }\n            t = sa[ma[8]];\n            for (i = 1; i <= 8; i++) {\n                b = sa[ma[i]] - sa[ma[i - 1]];\n                if (b != 0) {\n                    for (a = 1; a <= b; a++) {\n                        print(\"\\n\");\n                        if (sa[ma[i]] > 27)\n                            break;\n                    }\n                    if (a <= b)\n                        break;\n                }\n                print(\" \" + ma[i] + \" \");\n            }\n            for (a = 1; a < 28 - t; a++) {\n                print(\"\\n\");\n            }\n            print(\"XXXXFINISHXXXX\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"---------------------------------------------\\n\");\n            print(\"\\n\");\n        } while (t < 28) ;\n        print(\"THE RACE RESULTS ARE:\\n\");\n        z9 = 1;\n        for (i = 8; i >= 1; i--) {\n            f = ma[i];\n            print(\"\\n\");\n            print(\"\" + z9 + \" PLACE HORSE NO. \" + f + \" AT \" + (r / da[f]) + \":1\\n\");\n            z9++;\n        }\n        for (j = 1; j <= c; j++) {\n            if (qa[j] != ma[8])\n                continue;\n            n = qa[j];\n            print(\"\\n\");\n            print(ws[j] + \" WINS $\" + (r / da[n]) * pa[j] + \"\\n\");\n        }\n        print(\"DO YOU WANT TO BET ON THE NEXT RACE ?\\n\");\n        print(\"YES OR NO\");\n        str = await input();\n    } while (str == \"YES\") ;\n}\n\nmain();\n"
  },
  {
    "path": "50_Horserace/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "50_Horserace/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "50_Horserace/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "50_Horserace/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "50_Horserace/python/horserace.py",
    "content": "import math\nimport random\nimport time\nfrom typing import List, Tuple\n\n\ndef basic_print(*zones, **kwargs) -> None:\n    \"\"\"Simulates the PRINT command from BASIC to some degree.\n    Supports `printing zones` if given multiple arguments.\"\"\"\n\n    line = \"\"\n    if len(zones) == 1:\n        line = str(zones[0])\n    else:\n        line = \"\".join([f\"{str(zone):<14}\" for zone in zones])\n    identation = kwargs.get(\"indent\", 0)\n    end = kwargs.get(\"end\", \"\\n\")\n    print(\" \" * identation + line, end=end)\n\n\ndef basic_input(prompt: str, type_conversion=None):\n    \"\"\"BASIC INPUT command with optional type conversion\"\"\"\n\n    while True:\n        try:\n            inp = input(f\"{prompt}? \")\n            if type_conversion is not None:\n                inp = type_conversion(inp)\n            break\n        except ValueError:\n            basic_print(\"INVALID INPUT!\")\n    return inp\n\n\n# horse names do not change over the program, therefore making it a global.\n# throught the game, the ordering of the horses is used to indentify them\nHORSE_NAMES = [\n    \"JOE MAW\",\n    \"L.B.J.\",\n    \"MR.WASHBURN\",\n    \"MISS KAREN\",\n    \"JOLLY\",\n    \"HORSE\",\n    \"JELLY DO NOT\",\n    \"MIDNIGHT\",\n]\n\n\ndef introduction() -> None:\n    \"\"\"Print the introduction, and optional the instructions\"\"\"\n\n    basic_print(\"HORSERACE\", indent=31)\n    basic_print(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", indent=15)\n    basic_print(\"\\n\\n\")\n    basic_print(\"WELCOME TO SOUTH PORTLAND HIGH RACETRACK\")\n    basic_print(\"                      ...OWNED BY LAURIE CHEVALIER\")\n    y_n = basic_input(\"DO YOU WANT DIRECTIONS\")\n\n    # if no instructions needed, return\n    if y_n.upper() == \"NO\":\n        return\n\n    basic_print(\"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\")\n    basic_print(\"MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.\")\n    basic_print(\"DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\")\n    basic_print(\"NUMBER.  THE HORSES RACE DOWN THE PAPER!\")\n    basic_print(\"\")\n\n\ndef setup_players() -> List[str]:\n    \"\"\"Gather the number of players and their names\"\"\"\n\n    # ensure we get an integer value from the user\n    number_of_players = basic_input(\"HOW MANY WANT TO BET\", int)\n\n    basic_print(\"WHEN ? APPEARS,TYPE NAME\")\n    return [basic_input(\"\") for _ in range(number_of_players)]\n\n\ndef setup_horses() -> List[float]:\n    \"\"\"Generates random odds for each horse. Returns a list of\n    odds, indexed by the order of the global HORSE_NAMES.\"\"\"\n\n    odds = [random.randrange(1, 10) for _ in HORSE_NAMES]\n    total = sum(odds)\n\n    # rounding odds to two decimals for nicer output,\n    # this is not in the origin implementation\n    return [round(total / odd, 2) for odd in odds]\n\n\ndef print_horse_odds(odds) -> None:\n    \"\"\"Print the odds for each horse\"\"\"\n\n    basic_print(\"\")\n    for i in range(len(HORSE_NAMES)):\n        basic_print(HORSE_NAMES[i], i, f\"{odds[i]}:1\")\n    basic_print(\"\")\n\n\ndef get_bets(player_names: List[str]) -> List[Tuple[int, float]]:\n    \"\"\"For each player, get the number of the horse to bet on,\n    as well as the amount of money to bet\"\"\"\n\n    basic_print(\"--------------------------------------------------\")\n    basic_print(\"PLACE YOUR BETS...HORSE # THEN AMOUNT\")\n\n    bets: List[Tuple[int, float]] = []\n    for name in player_names:\n        horse = basic_input(name, int)\n        amount = None\n        while amount is None:\n            amount = basic_input(\"\", float)\n            if amount < 1 or amount >= 100000:\n                basic_print(\"  YOU CAN'T DO THAT!\")\n                amount = None\n        bets.append((horse, amount))\n\n    basic_print(\"\")\n\n    return bets\n\n\ndef get_distance(odd: float) -> int:\n    \"\"\"Advances a horse during one step of the racing simulation.\n    The amount travelled is random, but scaled by the odds of the horse\"\"\"\n\n    d = random.randrange(1, 100)\n    s = math.ceil(odd)\n    if d < 10:\n        return 1\n    elif d < s + 17:\n        return 2\n    elif d < s + 37:\n        return 3\n    elif d < s + 57:\n        return 4\n    elif d < s + 77:\n        return 5\n    elif d < s + 92:\n        return 6\n    else:\n        return 7\n\n\ndef print_race_state(total_distance, race_pos) -> None:\n    \"\"\"Outputs the current state/stop of the race.\n    Each horse is placed according to the distance they have travelled. In\n    case some horses travelled the same distance, their numbers are printed\n    on the same name\"\"\"\n\n    # we dont want to modify the `race_pos` list, since we need\n    # it later. Therefore we generating an interator from the list\n    race_pos_iter = iter(race_pos)\n\n    # race_pos is stored by last to first horse in the race.\n    # we get the next horse we need to print out\n    next_pos = next(race_pos_iter)\n\n    # start line\n    basic_print(\"XXXXSTARTXXXX\")\n\n    # print all 28 lines/unit of the race course\n    for line in range(28):\n\n        # ensure we still have a horse to print and if so, check if the\n        # next horse to print is not the current line\n        # needs iteration, since multiple horses can share the same line\n        while next_pos is not None and line == total_distance[next_pos]:\n            basic_print(f\"{next_pos} \", end=\"\")\n            next_pos = next(race_pos_iter, None)\n        else:\n            # if no horses are left to print for this line, print a new line\n            basic_print(\"\")\n\n    # finish line\n    basic_print(\"XXXXFINISHXXXX\")\n\n\ndef simulate_race(odds) -> List[int]:\n    num_horses = len(HORSE_NAMES)\n\n    # in spirit of the original implementation, using two arrays to\n    # track the total distance travelled, and create an index from\n    # race position -> horse index\n    total_distance = [0] * num_horses\n\n    # race_pos maps from the position in the race, to the index of the horse\n    # it will later be sorted from last to first horse, based on the\n    # distance travelled by each horse.\n    # e.g. race_pos[0] => last horse\n    #      race_pos[-1] => winning horse\n    race_pos = list(range(num_horses))\n\n    basic_print(\"\\n1 2 3 4 5 6 7 8\")\n\n    while True:\n\n        # advance each horse by a random amount\n        for i in range(num_horses):\n            total_distance[i] += get_distance(odds[i])\n\n        # bubble sort race_pos based on total distance travelled\n        # in the original implementation, race_pos is reset for each\n        # simulation step, so we keep this behaviour here\n        race_pos = list(range(num_horses))\n        for line in range(num_horses):\n            for i in range(num_horses - 1 - line):\n                if total_distance[race_pos[i]] < total_distance[race_pos[i + 1]]:\n                    continue\n                race_pos[i], race_pos[i + 1] = race_pos[i + 1], race_pos[i]\n\n        # print current state of the race\n        print_race_state(total_distance, race_pos)\n\n        # goal line is defined as 28 units from start\n        # check if the winning horse is already over the finish line\n        if total_distance[race_pos[-1]] >= 28:\n            return race_pos\n\n        # this was not in the original BASIC implementation, but it makes the\n        # race visualization a nice animation (if the terminal size is set to 31 rows)\n        time.sleep(1)\n\n\ndef print_race_results(race_positions, odds, bets, player_names) -> None:\n    \"\"\"Print the race results, as well as the winnings of each player\"\"\"\n\n    # print the race positions first\n    basic_print(\"THE RACE RESULTS ARE:\")\n    for position, horse_idx in enumerate(reversed(race_positions), start=1):\n        line = f\"{position} PLACE HORSE NO. {horse_idx} AT {odds[horse_idx]}:1\"\n        basic_print(\"\")\n        basic_print(line)\n\n    # followed by the amount the players won\n    winning_horse_idx = race_positions[-1]\n    for idx, name in enumerate(player_names):\n        (horse, amount) = bets[idx]\n        if horse == winning_horse_idx:\n            basic_print(\"\")\n            basic_print(f\"{name} WINS ${amount * odds[winning_horse_idx]}\")\n\n\ndef main_loop(player_names, horse_odds) -> None:\n    \"\"\"Main game loop\"\"\"\n\n    while True:\n        print_horse_odds(horse_odds)\n        bets = get_bets(player_names)\n        final_race_positions = simulate_race(horse_odds)\n        print_race_results(final_race_positions, horse_odds, bets, player_names)\n\n        basic_print(\"DO YOU WANT TO BET ON THE NEXT RACE ?\")\n        one_more = basic_input(\"YES OR NO\")\n        if one_more.upper() != \"YES\":\n            break\n\n\ndef main() -> None:\n    # introduction, player names and horse odds are only generated once\n    introduction()\n    player_names = setup_players()\n    horse_odds = setup_horses()\n\n    # main loop of the game, the player can play multiple races, with the\n    # same odds\n    main_loop(player_names, horse_odds)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "50_Horserace/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "50_Horserace/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "50_Horserace/rust/src/game.rs",
    "content": "use std::{thread, time::Duration};\n\nuse crate::{horses::Horses, players::Players};\n\npub struct Game {\n    horses: Horses,\n    players: Players,\n}\n\nimpl Game {\n    pub fn new() -> Self {\n        Game {\n            horses: Horses::new(),\n            players: Players::new(),\n        }\n    }\n\n    pub fn play(&mut self) -> bool {\n        self.horses.randomize_odds();\n        self.horses.print_table();\n\n        self.players.make_bets();\n\n        println!(\"\\n1 2 3 4 5 6 7 8\");\n\n        for _ in 1..=7 {\n            self.horses.advance();\n            self.draw();\n            thread::sleep(Duration::from_secs(1));\n        }\n\n        let winner = self.horses.print_placements();\n        self.players.process_winner(winner);\n\n        return self.players.prompt_next_round();\n    }\n\n    pub fn draw(&self) {\n        println!(\"=============\");\n        println!(\"XXXXSTARTXXXX\");\n        for row in 1..=28 {\n            let neighbors = self.horses.get_at(row);\n\n            match neighbors.len() {\n                0 => println!(),\n                1 => println!(\"{}\", neighbors[0].no),\n                _ => {\n                    for h in neighbors {\n                        print!(\"{} \", h.no);\n                    }\n                    println!();\n                }\n            }\n        }\n        println!(\"XXXXFINISHXXXX\");\n    }\n}\n"
  },
  {
    "path": "50_Horserace/rust/src/horses.rs",
    "content": "use rand::Rng;\n\npub struct Horse {\n    pub name: String,\n    pub no: u8,\n    pub odd: f32,\n    pub position: u8,\n}\n\nimpl Horse {\n    fn new(name: &str, no: u8) -> Self {\n        Horse {\n            name: name.to_string(),\n            no,\n            odd: 0.,\n            position: 0,\n        }\n    }\n}\n\npub struct Horses {\n    horses: [Horse; 8],\n}\n\nimpl Horses {\n    pub fn new() -> Self {\n        Horses {\n            horses: [\n                Horse::new(\"JOE MAW\", 1),\n                Horse::new(\"L.B.J.\", 2),\n                Horse::new(\"MR.WASHBURN\", 3),\n                Horse::new(\"MISS KAREN\", 4),\n                Horse::new(\"JOLLY\", 5),\n                Horse::new(\"HORSE\", 6),\n                Horse::new(\"JELLY DO NOT\", 7),\n                Horse::new(\"MIDNIGHT\", 8),\n            ],\n        }\n    }\n\n    pub fn randomize_odds(&mut self) {\n        let mut odds = Vec::new();\n\n        for _ in 1..=8 {\n            odds.push(rand::thread_rng().gen_range(1.0..=10.));\n        }\n\n        let total: f32 = odds.iter().sum();\n\n        for (i, o) in odds.iter().enumerate() {\n            let o = total / o;\n            self.horses[i].odd = o;\n        }\n    }\n\n    pub fn advance(&mut self) {\n        for h in self.horses.iter_mut() {\n            let distance = rand::thread_rng().gen_range(1..=100);\n            let scale = h.odd.ceil() as i32;\n\n            let dt = if distance < 10 {\n                1\n            } else if distance < scale + 17 {\n                2\n            } else if distance < scale + 37 {\n                3\n            } else if distance < scale + 57 {\n                4\n            } else if distance < scale + 77 {\n                5\n            } else if distance < scale + 92 {\n                6\n            } else {\n                7\n            };\n\n            h.position += dt as u8;\n        }\n    }\n\n    pub fn get_at(&self, row: usize) -> Vec<&Horse> {\n        self.horses\n            .iter()\n            .filter(|h| h.position == row as u8)\n            .collect()\n    }\n\n    pub fn print_table(&self) {\n        println!(\"HORSE\\t\\tNUMBER\\t\\tODDS\\t\\t\\n\");\n        for horse in self.horses.iter() {\n            let (h, n, o) = (horse.name.clone(), horse.no, horse.odd);\n\n            if h.len() > 7 {\n                println!(\"{}\\t{}\\t\\t{:.2} :1\", h, n, o);\n            } else {\n                println!(\"{}\\t\\t{}\\t\\t{:.2} :1\", h, n, o);\n            }\n        }\n        println!(\"-----------------------------------------\\n\")\n    }\n\n    pub fn print_placements(&mut self) -> u8 {\n        self.horses.sort_by(|a, b| b.position.cmp(&a.position));\n\n        println!(\"\\nTHE RACE RESULTS ARE:\\n\");\n\n        for (i, h) in self.horses.iter_mut().enumerate() {\n            println!(\"{} PLACE HORSE NO. {}\\t\\tAT {:.2} :1\", i + 1, h.no, h.odd);\n            h.position = 0;\n        }\n\n        self.horses[0].no\n    }\n}\n"
  },
  {
    "path": "50_Horserace/rust/src/main.rs",
    "content": "use crate::{game::Game, util::PromptResult};\n\nmod game;\nmod horses;\nmod players;\nmod util;\n\nfn main() {\n    println!(\"\\n\\n\\t\\tHORSERACE\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n    println!(\"WELCOME TO SOUTH PORTLAND HIGH RACETRACK\\n\\t\\t...OWNED BY LAURIE CHEVALIER\");\n\n    if let PromptResult::YesNo(yes) = util::prompt(Some(false), \"DO YOU WANT DIRECTIONS?\") {\n        if yes {\n            println!(\"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\");\n            println!(\"MAY BET ANY AMOUNT UNDER $100,000 ON ONE HORSE.\");\n            println!(\"DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\");\n            println!(\"NUMBER.  THE HORSES RACE DOWN THE PAPER!\\n\");\n        }\n    }\n\n    let mut game = Game::new();\n    let mut again = true;\n\n    while again {\n        again = game.play();\n    }\n}\n"
  },
  {
    "path": "50_Horserace/rust/src/players.rs",
    "content": "use crate::util::{self, PromptResult};\n\n#[derive(Debug)]\npub struct Player {\n    pub name: String,\n    pub money: u32,\n    pub playing: bool,\n    pub horse_no: u8,\n    pub bet: u32,\n}\n\nimpl Player {\n    fn new(name: String) -> Self {\n        Player {\n            name,\n            money: 100000,\n            playing: true,\n            horse_no: 0,\n            bet: 0,\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct Players {\n    players: Vec<Player>,\n}\n\nimpl Players {\n    pub fn new() -> Self {\n        let players;\n\n        loop {\n            if let PromptResult::Numeric(n) = util::prompt(Some(true), \"HOW MANY WANT TO BET?\") {\n                if n <= 0 {\n                    println!(\"THERE CAN'T BE (LESS THAN) ZERO PLAYERS!\");\n                } else if n > 10 {\n                    println!(\"THERE CAN'T BE MORE THAN TEN PLAYERS!\");\n                } else {\n                    println!(\"WHEN ? APPEARS, TYPE NAME\");\n                    players = Players::generate_players(n);\n                    break;\n                }\n            }\n        }\n\n        Players { players }\n    }\n\n    pub fn make_bets(&mut self) {\n        println!(\"PLACE YOUR BETS...HORSE # THEN AMOUNT\");\n\n        for p in self.players.iter_mut() {\n            if !p.playing {\n                continue;\n            }\n\n            let name = format!(\"{}?\", p.name);\n\n            'prompt: loop {\n                if let PromptResult::Normal(response) = util::prompt(None, name.as_str()) {\n                    let response: Vec<&str> = response.trim().split(\",\").collect();\n\n                    for (i, n) in response.iter().enumerate() {\n                        if let Ok(n) = n.parse::<i32>() {\n                            if n.is_negative() {\n                                println!(\"YOU CAN'T ENTER A NEGATIVE NUMBER!\")\n                            } else {\n                                match i {\n                                    0 => {\n                                        if n > 8 {\n                                            println!(\"INVALID HORSE #\")\n                                        } else {\n                                            p.horse_no = n as u8;\n                                        }\n                                    }\n                                    1 => {\n                                        if n == 0 {\n                                            println!(\"YOU CAN'T BET NOTHING!\");\n                                        } else if n > p.money as i32 {\n                                            println!(\"YOU DON'T HAVE ENOUGH MONEY!\")\n                                        } else {\n                                            p.bet = n as u32;\n                                            break 'prompt;\n                                        }\n                                    }\n                                    _ => println!(\"YOU CAN'T ENTER MORE THAN 2 NUMBERS!\"),\n                                }\n                            }\n                        } else {\n                            println!(\"ONLY ENTER NUMBERS PLEASE!\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    fn generate_players(n: i32) -> Vec<Player> {\n        let mut players: Vec<Player> = Vec::new();\n\n        for _ in 0..n {\n            loop {\n                if let PromptResult::Normal(name) = util::prompt(None, \"?\") {\n                    let name = name.trim().to_uppercase();\n\n                    if name.is_empty() {\n                        println!(\"NAME CAN'T BE EMPTY!\");\n                    } else if let Some(_) = players.iter().find(|p| p.name == name) {\n                        println!(\"THERE IS ALREADY A PLAYER WITH THAT NAME!\");\n                    } else {\n                        players.push(Player::new(name));\n                        break;\n                    }\n                }\n            }\n        }\n\n        players\n    }\n\n    pub fn process_winner(&mut self, no: u8) {\n        println!();\n        for p in self.players.iter_mut() {\n            if !p.playing {\n                continue;\n            }\n\n            if p.horse_no == no {\n                p.money += p.bet;\n                println!(\"{} WON ${}! THEY HAVE ${}.\", p.name, p.bet, p.money);\n            } else {\n                p.money -= p.bet;\n                println!(\"{} LOST ${}. THEY HAVE ${} LEFT.\", p.name, p.bet, p.money);\n            }\n            p.bet = 0;\n            p.horse_no = 0;\n        }\n        println!();\n    }\n\n    pub fn prompt_next_round(&mut self) -> bool {\n        for p in self.players.iter_mut() {\n            let msg = format!(\"{}, DO YOU WANT TO BET ON THE NEXT RACE?\", p.name);\n            if let PromptResult::YesNo(yes) = util::prompt(Some(false), msg.as_str()) {\n                p.playing = yes;\n            }\n        }\n\n        if let None = self.players.iter().find(|p| p.playing) {\n            return false;\n        }\n\n        true\n    }\n}\n"
  },
  {
    "path": "50_Horserace/rust/src/util.rs",
    "content": "use std::io;\n\npub enum PromptResult {\n    Normal(String),\n    YesNo(bool),\n    Numeric(i32),\n}\n\npub fn prompt(is_numeric: Option<bool>, msg: &str) -> PromptResult {\n    use PromptResult::*;\n\n    println!(\"{msg}\");\n\n    loop {\n        let mut input = String::new();\n\n        io::stdin()\n            .read_line(&mut input)\n            .expect(\"Failed to read input.\");\n\n        if let Some(is_numeric) = is_numeric {\n            let input = input.trim();\n\n            if is_numeric {\n                if let Ok(n) = input.parse::<i32>() {\n                    return Numeric(n);\n                }\n                println!(\"PLEASE ENTER A VALID NUMBER!\");\n            } else {\n                match input.to_uppercase().as_str() {\n                    \"YES\" | \"Y\" => return YesNo(true),\n                    \"NO\" | \"N\" => return YesNo(false),\n                    _ => println!(\"PLEASE ENTER (Y)ES OR (N)O.\"),\n                }\n            }\n        } else {\n            return Normal(input);\n        }\n    }\n}\n"
  },
  {
    "path": "50_Horserace/vbnet/Horserace.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Horserace\", \"Horserace.vbproj\", \"{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "50_Horserace/vbnet/Horserace.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Horserace</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "50_Horserace/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "51_Hurkle/README.md",
    "content": "### Hurkle\n\nHurkle? A Hurkle is a happy beast and lives in another galaxy on a planet named Lirht that has three moons. Hurkle are favorite pets of the Gwik, the dominant race of Lihrt and … well, to find out more, read “The Hurkle is a Happy Beast,” a story in the book _A Way Home_ by Theodore Sturgeon.\n\nIn this program a shy hurkle is hiding on a 10 by 10 grid. Homebase is point 0,0 in the _Southwest_ corner. Your guess as to the gridpoint where the hurkle is hiding should be a pair of whole numbers, separated by a comma. After each try, the computer will tell you the approximate direction to go look for the Hurkle. You get five guesses to find him; you may change this number, although four guesses is actually enough.\n\nThis program was written by Bob Albrecht of People’s Computer Company.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=94)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=109)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "51_Hurkle/csharp/.gitignore",
    "content": "\n# Created by https://www.toptal.com/developers/gitignore/api/csharp\n# Edit at https://www.toptal.com/developers/gitignore?templates=csharp\n\n### Csharp ###\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*[.json, .xml, .info]\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# End of https://www.toptal.com/developers/gitignore/api/csharp\n"
  },
  {
    "path": "51_Hurkle/csharp/CardinalDirection.cs",
    "content": "namespace hurkle\n{\n    internal enum CardinalDirection\n    {\n        None,\n        North,\n        NorthEast,\n        East,\n        SouthEast,\n        South,\n        SouthWest,\n        West,\n        NorthWest\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/ConsoleHurkleView.cs",
    "content": "using System;\n\nnamespace hurkle\n{\n    internal class ConsoleHurkleView : IHurkleView\n    {\n        public GamePoint GetGuess(GuessViewModel guessViewModel)\n        {\n            Console.WriteLine($\"GUESS #{guessViewModel.CurrentGuessNumber}\");\n            var inputLine = Console.ReadLine();\n            var seperateStrings = inputLine.Split(',', 2, StringSplitOptions.TrimEntries);\n            var guessPoint = new GamePoint{\n                X = int.Parse(seperateStrings[0]),\n                Y = int.Parse(seperateStrings[1])\n            };\n\n            return guessPoint;\n        }\n\n        public void ShowDirection(FailedGuessViewModel failedGuessViewModel)\n        {\n            Console.Write(\"GO \");\n            switch(failedGuessViewModel.Direction)\n            {\n                case CardinalDirection.East:\n                    Console.WriteLine(\"EAST\");\n                    break;\n                case CardinalDirection.North:\n                    Console.WriteLine(\"NORTH\");\n                    break;\n                case CardinalDirection.South:\n                    Console.WriteLine(\"SOUTH\");\n                    break;\n                case CardinalDirection.West:\n                    Console.WriteLine(\"WEST\");\n                    break;\n                case CardinalDirection.NorthEast:\n                    Console.WriteLine(\"NORTHEAST\");\n                    break;\n                case CardinalDirection.NorthWest:\n                    Console.WriteLine(\"NORTHWEST\");\n                    break;\n                case CardinalDirection.SouthEast:\n                    Console.WriteLine(\"SOUTHEAST\");\n                    break;\n                case CardinalDirection.SouthWest:\n                    Console.WriteLine(\"SOUTHWEST\");\n                    break;\n            }\n\n            Console.WriteLine();\n        }\n\n        public void ShowLoss(LossViewModel lossViewModel)\n        {\n            Console.WriteLine();\n            Console.WriteLine($\"SORRY, THAT'S {lossViewModel.MaxGuesses} GUESSES\");\n            Console.WriteLine($\"THE HURKLE IS AT {lossViewModel.HurkleLocation.X},{lossViewModel.HurkleLocation.Y}\");\n        }\n\n        public void ShowVictory(VictoryViewModel victoryViewModel)\n        {\n            Console.WriteLine();\n            Console.WriteLine($\"YOU FOUND HIM IN {victoryViewModel.CurrentGuessNumber} GUESSES!\");\n        }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/FailedGuessViewModel.cs",
    "content": "namespace hurkle\n{\n    internal class FailedGuessViewModel\n    {\n        public CardinalDirection Direction { get; init; }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/GamePoint.cs",
    "content": "namespace hurkle\n{\n    internal class GamePoint\n    {\n        public int X {get;init;}\n        public int Y {get;init;}\n\n        public CardinalDirection GetDirectionTo(GamePoint target)\n        {\n            if(X == target.X)\n            {\n                if(Y > target.Y)\n                {\n                    return CardinalDirection.South;\n                }\n                else if(Y < target.Y)\n                {\n                    return CardinalDirection.North;\n                }\n                else\n                {\n                    return CardinalDirection.None;\n                }\n            }\n            else if(X > target.X)\n            {\n                if(Y == target.Y)\n                {\n                    return CardinalDirection.West;\n                }\n                else if(Y > target.Y)\n                {\n                    return CardinalDirection.SouthWest;\n                }\n                else\n                {\n                    return CardinalDirection.NorthWest;\n                }\n            }\n            else\n            {\n                if(Y == target.Y)\n                {\n                    return CardinalDirection.East;\n                }\n                else if(Y > target.Y)\n                {\n                    return CardinalDirection.SouthEast;\n                }\n                else{\n                    return CardinalDirection.NorthEast;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/GuessViewModel.cs",
    "content": "namespace hurkle\n{\n    internal class GuessViewModel\n    {\n        public int CurrentGuessNumber {get;init;}\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/Hurkle.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "51_Hurkle/csharp/Hurkle.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Hurkle\", \"Hurkle.csproj\", \"{BE321D5B-93BD-4F91-A875-564DC9D4094F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {42DC6AE5-5127-4B1B-BD5E-F3B1CCDC3822}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "51_Hurkle/csharp/HurkleGame.cs",
    "content": "using System;\n\nnamespace hurkle\n{\n    internal class HurkleGame\n    {\n        private readonly Random _random = new Random();\n        private readonly IHurkleView _view;\n        private readonly int guesses;\n        private readonly int gridSize;\n\n        public HurkleGame(int guesses, int gridSize, IHurkleView view)\n        {\n            _view = view;\n            this.guesses = guesses;\n            this.gridSize = gridSize;\n        }\n\n        public void PlayGame()\n        {\n            // BASIC program was generating a float between 0 and 1\n            // then multiplying by the size of the grid to to a number\n            // between 1 and 10. C# allows you to do that directly.\n            var hurklePoint = new GamePoint{\n                X = _random.Next(0, gridSize),\n                Y = _random.Next(0, gridSize)\n            };\n\n            for(var K=1;K<=guesses;K++)\n            {\n                var guessPoint = _view.GetGuess(new GuessViewModel{CurrentGuessNumber = K});\n\n                var direction = guessPoint.GetDirectionTo(hurklePoint);\n                switch(direction)\n                {\n                    case CardinalDirection.None:\n                        _view.ShowVictory(new VictoryViewModel{CurrentGuessNumber = K});\n                        return;\n                    default:\n                        _view.ShowDirection(new FailedGuessViewModel{Direction = direction});\n                        continue;\n                }\n            }\n\n            _view.ShowLoss(new LossViewModel{MaxGuesses = guesses, HurkleLocation = hurklePoint } );\n        }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/IHurkleView.cs",
    "content": "namespace hurkle\n{\n    internal interface IHurkleView\n    {\n        GamePoint GetGuess(GuessViewModel guessViewModel);\n        void ShowVictory(VictoryViewModel victoryViewModel);\n        void ShowDirection(FailedGuessViewModel failedGuessViewModel);\n        void ShowLoss(LossViewModel lossViewModel);\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/LossViewModel.cs",
    "content": "namespace hurkle\n{\n    internal class LossViewModel\n    {\n        public int MaxGuesses { get; init; }\n        public GamePoint HurkleLocation { get; init; }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace hurkle\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            /*\n            Original source transscription\n            10 PRINT TAB(33);\"HURKLE\"\n            20 PRINT TAB(15);\"CREATIVE COMPUTING NORRISTOWN, NEW JERSEY\"\n            30 PRINT;PRINT;PRINT\n            */\n            Console.WriteLine(new string(' ', 33) + @\"HURKLE\");\n            Console.WriteLine(new string(' ', 15) + @\"CREATIVE COMPUTING NORRISTOWN, NEW JERSEY\");\n            /*\n            110 N=5\n            120 G=10\n            */\n            var N=5;\n            var G=10;\n            /*\n            210 PRINT\n            220 PRINT \"A HURKLE IS HIDING ON A\";G;\"BY\";G;\"GRID. HOMEBASE\"\n            230 PRINT \"ON THE GRID IS POINT 0,0 AND ANY GRIDPOINT IS A\"\n            240 PRINT \"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. TRY TO\"\n            250 PRINT \"GUESS THE HURKLE'S GRIDPOINT. YOU GET\";N;\"TRIES.\"\n            260 PRINT \"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\"\n            270 PRINT \"DIRECTION TO GO TO LOOK FOR THE HURKLE.\"\n            280 PRINT\n            */\n            // Using string formatting via the '$' string\n            Console.WriteLine();\n            Console.WriteLine($\"A HURKLE IS HIDING ON A {G} BY {G} GRID. HOMEBASE\");\n            Console.WriteLine(@\"ON THE GRID IS POINT 0,0 AND ANY GRIDPOINT IS A\");\n            Console.WriteLine(@\"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. TRY TO\");\n            Console.WriteLine($\"GUESS THE HURKLE'S GRIDPOINT. YOU GET {N} TRIES.\");\n            Console.WriteLine(@\"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\");\n            Console.WriteLine(@\"DIRECTION TO GO TO LOOK FOR THE HURKLE.\");\n            Console.WriteLine();\n\n            var view = new ConsoleHurkleView();\n            var hurkle = new HurkleGame(N,G, view);\n            while(true)\n            {\n                hurkle.PlayGame();\n\n                Console.WriteLine(\"PLAY AGAIN? (Y)ES/(N)O\");\n                var playAgainResponse = Console.ReadLine();\n                if(playAgainResponse.Trim().StartsWith(\"y\", StringComparison.InvariantCultureIgnoreCase))\n                {\n                    Console.WriteLine();\n                    Console.WriteLine(\"LET'S PLAY AGAIN. HURKLE IS HIDING\");\n                    Console.WriteLine();\n                }else{\n                    Console.WriteLine(\"THANKS FOR PLAYING!\");\n                    break;\n                }\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\nThis is demonstrating seperating the user interface from the application logic through the\nuse of the View/ViewModel/Controller pattern.\n\nIt also makes an effort to be relatively immutable.\n"
  },
  {
    "path": "51_Hurkle/csharp/VictoryViewModel.cs",
    "content": "namespace hurkle\n{\n    internal class VictoryViewModel\n    {\n        public int CurrentGuessNumber {get; init;}\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/hurkle.bas",
    "content": "10 PRINT TAB(33);\"HURKLE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n110 N=5\n120 G=10\n210 PRINT\n220 PRINT \"A HURKLE IS HIDING ON A\";G;\"BY\";G;\"GRID. HOMEBASE\"\n230 PRINT \"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\"\n235 PRINT \"AND ANY POINT ON THE GRID IS DESIGNATED BY A\"\n240 PRINT \"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\"\n245 PRINT \"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\"\n246 PRINT \"IS THE VERTICAL POSITION. YOU MUST TRY TO\"\n250 PRINT \"GUESS THE HURKLE'S GRIDPOINT. YOU GET\";N;\"TRIES.\"\n260 PRINT \"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\"\n270 PRINT \"DIRECTION TO GO TO LOOK FOR THE HURKLE.\"\n280 PRINT\n285 A=INT(G*RND(1))\n286 B=INT(G*RND(1))\n310 FOR K=1 TO N\n320 PRINT \"GUESS #\";K;\n330 INPUT X,Y\n340 IF ABS(X-A)+ABS(Y-B)=0 THEN 500\n350 REM PRINT INFO\n360 GOSUB 610\n370 PRINT\n380 NEXT K\n410 PRINT\n420 PRINT \"SORRY, THAT'S\";N;\"GUESSES.\"\n430 PRINT \"THE HURKLE IS AT \";A;\",\";B\n440 PRINT\n450 PRINT \"LET'S PLAY AGAIN, HURKLE IS HIDING.\"\n460 PRINT\n470 GOTO 285\n500 REM\n510 PRINT\n520 PRINT \"YOU FOUND HIM IN\";K;\"GUESSES!\"\n540 GOTO 440\n610 PRINT \"GO \";\n620 IF Y=B THEN 670\n630 IF Y<B THEN 660\n640 PRINT \"SOUTH\";\n650 GOTO 670\n660 PRINT \"NORTH\";\n670 IF X=A THEN 720\n680 IF X<A THEN 710\n690 PRINT \"WEST\";\n700 GOTO 720\n710 PRINT \"EAST\";\n720 PRINT\n730 RETURN\n999 END\n"
  },
  {
    "path": "51_Hurkle/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "51_Hurkle/java/src/Hurkle.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of Hurkle\n * <p>\n * Based on the Basic game of Hurkle here\n * https://github.com/coding-horror/basic-computer-games/blob/main/51%20Hurkle/hurkle.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Hurkle {\n\n    public static final int GRID_SIZE = 10;\n    public static final int MAX_GUESSES = 5;\n\n    private enum GAME_STATE {\n        STARTING,\n        START_GAME,\n        GUESSING,\n        PLAY_AGAIN,\n        GAME_OVER\n    }\n\n    private GAME_STATE gameState;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private int guesses;\n\n    // hurkle position\n    private int hurkleXPos;\n    private int hurkleYPos;\n\n    // player guess\n    private int playerGuessXPos;\n    private int playerGuessYPos;\n\n    public Hurkle() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    intro();\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Start the game, set the number of players, names and round\n                case START_GAME:\n\n                    hurkleXPos = randomNumber();\n                    hurkleYPos = randomNumber();\n\n                    guesses = 1;\n                    gameState = GAME_STATE.GUESSING;\n\n                    break;\n\n                // Guess an x,y position of the hurkle\n                case GUESSING:\n                    String guess = displayTextAndGetInput(\"GUESS #\" + guesses + \"? \");\n                    playerGuessXPos = getDelimitedValue(guess, 0);\n                    playerGuessYPos = getDelimitedValue(guess, 1);\n                    if (foundHurkle()) {\n                        gameState = GAME_STATE.PLAY_AGAIN;\n                    } else {\n                        showDirectionOfHurkle();\n                        guesses++;\n                        if (guesses > MAX_GUESSES) {\n                            System.out.println(\"SORRY, THAT'S \"\n                                    + MAX_GUESSES + \" GUESSES.\");\n                            System.out.println(\"THE HURKLE IS AT \"\n                                    + hurkleXPos + \",\" + hurkleYPos);\n                            System.out.println();\n                            gameState = GAME_STATE.PLAY_AGAIN;\n                        }\n                    }\n\n                    break;\n\n                case PLAY_AGAIN:\n                    System.out.println(\"LET'S PLAY AGAIN, HURKLE IS HIDING.\");\n                    System.out.println();\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n            }\n            // Effectively an endless loop because the game never quits as per\n            // the original basic code.\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void showDirectionOfHurkle() {\n        System.out.print(\"GO \");\n        if (playerGuessYPos == hurkleYPos) {\n            // don't print North or South because the player has chosen the\n            // same y grid pos as the hurkle\n        } else if (playerGuessYPos < hurkleYPos) {\n            System.out.print(\"NORTH\");\n        } else if (playerGuessYPos > hurkleYPos) {\n            System.out.print(\"SOUTH\");\n        }\n\n        if (playerGuessXPos == hurkleXPos) {\n            // don't print East or West because the player has chosen the\n            // same x grid pos as the hurkle\n        } else if (playerGuessXPos < hurkleXPos) {\n            System.out.print(\"EAST\");\n        } else if (playerGuessXPos > hurkleXPos) {\n            System.out.print(\"WEST\");\n        }\n        System.out.println();\n    }\n\n    private boolean foundHurkle() {\n        if ((playerGuessXPos - hurkleXPos)\n                - (playerGuessYPos - hurkleYPos) == 0) {\n            System.out.println(\"YOU FOUND HIM IN \" + guesses + \" GUESSES.\");\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Display info about the game\n     */\n    private void intro() {\n        System.out.println(\"HURKLE\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"A HURKLE IS HIDING ON A \" + GRID_SIZE + \" BY \"\n                + GRID_SIZE + \" GRID. HOMEBASE\");\n        System.out.println(\"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\");\n        System.out.println(\"AND ANY POINT ON THE GRID IS DESIGNATED BY A\");\n        System.out.println(\"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\");\n        System.out.println(\"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\");\n        System.out.println(\"IS THE VERTICAL POSITION. YOU MUST TRY TO\");\n        System.out.println(\"GUESS THE HURKLE'S GRIDPOINT. YOU GET \"\n                + MAX_GUESSES + \" TRIES.\");\n        System.out.println(\"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\");\n        System.out.println(\"DIRECTION TO GO TO LOOK FOR THE HURKLE.\");\n    }\n\n    /**\n     * Generate random number\n     * Used to create one part of an x,y grid position\n     *\n     * @return random number\n     */\n    private int randomNumber() {\n        return (int) (Math.random()\n                * (GRID_SIZE) + 1);\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Accepts a string delimited by comma's and returns the pos'th delimited\n     * value (starting at count 0).\n     *\n     * @param text - text with values separated by comma's\n     * @param pos  - which position to return a value for\n     * @return the int representation of the value\n     */\n    private int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        return Integer.parseInt(tokens[pos]);\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/java/src/HurkleGame.java",
    "content": "public class HurkleGame {\n\n    public static void main(String[] args) {\n        Hurkle hurkle = new Hurkle();\n        hurkle.play();\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "51_Hurkle/javascript/hurkle.html",
    "content": "<html>\n<head>\n<title>HURKLE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"hurkle.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "51_Hurkle/javascript/hurkle.js",
    "content": "// BATNUM\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"HURKLE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    n = 5;\n    g = 10;\n    print(\"\\n\");\n    print(\"A HURKLE IS HIDING ON A \" + g + \" BY \" + g + \" GRID. HOMEBASE\\n\");\n    print(\"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\\n\");\n    print(\"AND ANY POINT ON THE GRID IS DESIGNATED BY A\\n\");\n    print(\"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\\n\");\n    print(\"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\\n\");\n    print(\"IS THE VERTICAL POSITION. YOU MUST TRY TO\\n\");\n    print(\"GUESS THE HURKLE'S GRIDPOINT. YOU GET \" + n + \" TRIES.\\n\");\n    print(\"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\\n\");\n    print(\"DIRECTION TO GO TO LOOK FOR THE HURKLE.\\n\");\n    print(\"\\n\");\n    while (1) {\n        a = Math.floor(g * Math.random());\n        b = Math.floor(g * Math.random());\n        for (k = 1; k <= n; k++) {\n            print(\"GUESS #\" + k + \" \");\n            str = await input();\n            x = parseInt(str);\n            y = parseInt(str.substr(str.indexOf(\",\") + 1));\n            if (x == a && y == b) {\n                print(\"\\n\");\n                print(\"YOU FOUND HIM IN \" + k + \" GUESSES!\\n\");\n                break;\n            }\n            print(\"GO \");\n            if (y < b) {\n                print(\"NORTH\");\n            } else if (y > b) {\n                print(\"SOUTH\");\n            }\n            if (x < a) {\n                print(\"EAST\\n\");\n            } else {\n                print(\"WEST\\n\");\n            }\n        }\n        if (k > n) {\n            print(\"\\n\");\n            print(\"SORRY, THAT'S \" + n + \" GUESSES.\\n\");\n            print(\"THE HURKLE IS AT \" + a + \",\" + b + \"\\n\");\n        }\n        print(\"\\n\");\n        print(\"LET'S PLAY AGAIN, HURKLE IS HIDING.\\n\");\n        print(\"\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "51_Hurkle/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "51_Hurkle/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "51_Hurkle/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "51_Hurkle/perl/hurkle.pl",
    "content": "#!/usr/bin/perl\r\n\r\nuse strict;\r\nuse warnings;\r\n\r\n# global variables\r\n\r\nmy($GRID)  = 10;\r\nmy($TRIES) = 5;\r\n\r\n\r\n# main program starts here\r\n\r\n# print instructions\r\nprint <<HERE;\r\n                    Hurkle\r\n    Creative Computing  Morristown, New Jersey\r\n\r\nA Hurkle is hiding on a ${GRID} by ${GRID} grid. Homebase\r\non the grid is point 0,0 in the southwest corner,\r\nand any point on the grid is designated by a\r\npair of whole numbers seperated by a comma. The first\r\nnumber is the horizontal position and the second number\r\nis the vertical position. You must try to\r\nguess the Hurkle's gridpoint. You get ${TRIES} tries.\r\nAfter each try, I will tell you the approximate\r\ndirection to go to look for the Hurkle.\r\n\r\nHERE\r\n\r\n# The PLAY block is a complete game from start\r\n# to finish. The continue block prints the\r\n# \"let's play again\" message and then a new\r\n# game is started.\r\nPLAY: while (1) {\r\n    my($H1) = int(rand $GRID);\r\n    my($H2) = int(rand $GRID);\r\n\r\n    for my $i (1 .. $TRIES) {\r\n        printf(\" Guess # %D ? \", $i);\r\n\r\n        my($G1,$G2);\r\n        # The CHECK loop will execute while we\r\n        # attempt to collect valid input from\r\n        # the player\r\n        CHECK: while (1) {\r\n\r\n            chomp(my $in = <STDIN>);\r\n            # Use a regex to attempt to parse out\r\n            # two integers separated by a comma.\r\n            if ($in =~ m{(\\d+)\\s*,\\s*(\\d+)}) {\r\n                $G1 = $1; $G2 = $2;\r\n                last CHECK;\r\n            }\r\n            # Input not accepted, please try again\r\n            print \"Please enter two numbers separated by a comma ? \";\r\n        }\r\n\r\n        if (abs($H1 - $G1) + abs($H2 - $G2) != 0) {\r\n\r\n            # print directional info\r\n            printf(\"Go %s%s\\n\\n\",\r\n                ($G2 == $H2 ? '' : $G2 < $H2 ? 'north' : 'south'),\r\n                ($G1 == $H1 ? '' : $G1 < $H1 ? 'east'  : 'west' ),\r\n            );\r\n        } else {\r\n            # win!\r\n            printf(\"\\nYou found him in %d tries!\\n\", $i);\r\n            # move to the continue block\r\n            next PLAY;\r\n        }\r\n    } # tries loop\r\n\r\n    # No more guesses\r\n    printf(\"Sorry, that's %d guesses.\\n\", $TRIES);\r\n    printf(\"The Hurkle is at %d, %d\\n\", $H1, $H2);\r\n}\r\n\r\n# Execution comes here either from the \"next PLAY\"\r\n# statement, or by the PLAY block naturally ending\r\n# after the player has lost.\r\ncontinue {\r\n    print \"\\nLet's play again. Hurkle is hiding.\\n\\n\";\r\n}\r\n"
  },
  {
    "path": "51_Hurkle/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "51_Hurkle/python/hurkle.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"Ported to Python by @iamtraction\"\"\"\n\nfrom random import random\n\n\ndef direction(A, B, X, Y) -> None:\n    \"\"\"Print the direction hint for finding the hurkle.\"\"\"\n\n    print(\"GO \", end=\"\")\n    if Y < B:\n        print(\"NORTH\", end=\"\")\n    elif Y > B:\n        print(\"SOUTH\", end=\"\")\n\n    if X < A:\n        print(\"EAST\", end=\"\")\n    elif X > A:\n        print(\"WEST\", end=\"\")\n\n    print()\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"HURKLE\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n\n    print(\"\\n\\n\\n\")\n\n    N = 5\n    G = 10\n\n    print()\n    print(\"A HURKLE IS HIDING ON A\", G, \"BY\", G, \"GRID. HOMEBASE\")\n    print(\"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\")\n    print(\"AND ANY POINT ON THE GRID IS DESIGNATED BY A\")\n    print(\"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\")\n    print(\"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\")\n    print(\"IS THE VERTICAL POSITION. YOU MUST TRY TO\")\n    print(\"GUESS THE HURKLE'S GRIDPOINT. YOU GET\", N, \"TRIES.\")\n    print(\"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\")\n    print(\"DIRECTION TO GO TO LOOK FOR THE HURKLE.\")\n    print()\n\n    while True:\n        A = int(G * random())\n        B = int(G * random())\n\n        for k in range(0, N):\n            print(\"\\nGUESS #\" + str(k))\n\n            # read coordinates in `X, Y` format, split the string\n            # at `,`, and then parse the coordinates to `int` and\n            # store them in `X` and `Y` respectively.\n            [X, Y] = [int(c) for c in input(\"X,Y? \").split(\",\")]\n\n            if abs(X - A) + abs(Y - B) == 0:\n                print(\"\\nYOU FOUND HIM IN\", k + 1, \"GUESSES!\")\n                break\n            else:\n                direction(A, B, X, Y)\n                continue\n\n        print(\"\\n\\nLET'S PLAY AGAIN, HURKLE IS HIDING.\\n\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "51_Hurkle/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "51_Hurkle/ruby/hurkle.rb",
    "content": "MAX_GUESSES = 5\nGRID_SIZE = 10\n\nclass Point < Object\n  attr_accessor :x\n  attr_accessor :y\n\n  def initialize(text=\"\")\n    x, y = text.split(\",\").map(&:strip)\n    @x = (x || rand(GRID_SIZE).floor).to_i\n    @y = (y || rand(GRID_SIZE).floor).to_i\n  end\n\n  def to_s\n    \"#{@x}, #{@y}\"\n  end\n\n  def ==(other_point)\n    @x == other_point.x && @y == other_point.y\n  end\n\n  def direction_to(other_point)\n    (  @y < other_point.y ? \"NORTH\" : \"SOUTH\" unless @y == other_point.y ).to_s +\n      (@x < other_point.x ? \"EAST\"  : \"WEST\"  unless @x == other_point.x ).to_s\n  end\nend\n\ndef main\n  say_introduction\n\n  loop do\n    hurkle_point = Point.new\n    found = false\n    (1..MAX_GUESSES).each do |guess_num|\n      found = guess(hurkle_point, guess_num)\n      break if found\n    end\n    say_failure(hurkle_point) if not found\n    say_play_again\n  end\n\nend\n\ndef say_introduction\n  puts \" \" * 33 + \"HURKLE\"\n  puts \" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n  3.times { puts }\n  puts\n  puts \"A HURKLE IS HIDING ON A #{GRID_SIZE} BY #{GRID_SIZE} GRID. HOMEBASE\"\n  puts \"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\"\n  puts \"AND ANY POINT ON THE GRID IS DESIGNATED BY A\"\n  puts \"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\"\n  puts \"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\"\n  puts \"IS THE VERTICAL POSITION. YOU MUST TRY TO\"\n  puts \"GUESS THE HURKLE'S GRIDPOINT. YOU GET #{MAX_GUESSES} TRIES.\"\n  puts \"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\"\n  puts \"DIRECTION TO GO TO LOOK FOR THE HURKLE.\"\n  puts\nend\n\ndef guess(hurkle_point, guess_num)\n  print \"GUESS # #{guess_num} ? \"\n  guess_point = Point.new(gets.chomp)\n  if guess_point == hurkle_point\n    say_success(guess_num)\n    true\n  else\n    say_where_to_go(hurkle_point, guess_point)\n    false\n  end\nend\n\ndef say_success(guess_num)\n  puts\n  puts \"YOU FOUND IT IN #{guess_num} GUESSES!\"\nend\n\ndef say_where_to_go(hurkle_point, guess_point)\n  puts \"GO #{guess_point.direction_to(hurkle_point)}\"\n  puts\nend\n\ndef say_failure(hurkle_point)\n  puts\n  puts \"SORRY, THAT'S \" + MAX_GUESSES.to_s + \" GUESSES.\"\n  puts \"THE HURKLE IS AT #{hurkle_point}\"\nend\n\ndef say_play_again\n  puts\n  puts \"LET'S PLAY AGAIN, HURKLE IS HIDING.\"\n  puts\nend\n\nmain\n"
  },
  {
    "path": "51_Hurkle/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "51_Hurkle/rust/src/game.rs",
    "content": "use std::io;\n\nuse rand::Rng;\n\ntype Position = (u8, u8);\n\npub struct Game {\n    hurkle: Position,\n    tries: u8,\n}\n\nimpl Game {\n    pub fn new() -> Self {\n        let x: u8 = rand::thread_rng().gen_range(1..=10);\n        let y: u8 = rand::thread_rng().gen_range(1..=10);\n        let hurkle = (x, y);\n\n        Game { hurkle, tries: 0 }\n    }\n\n    pub fn update(&mut self) -> bool {\n        if self.tries >= 5 {\n            println!(\"SORRY, THAT'S {} GUESSES.\", self.tries);\n            println!(\"THE HURKLE IS AT {}, {}\", self.hurkle.0, self.hurkle.1);\n            return true;\n        }\n        self.tries += 1;\n        self.process_guess(self.get_guess())\n    }\n\n    fn get_guess(&self) -> Position {\n        let mut pos = (0, 0);\n\n        'guess: loop {\n            println!(\"GUESS # {}?\", self.tries);\n\n            let mut input = String::new();\n\n            io::stdin()\n                .read_line(&mut input)\n                .expect(\"**Failed to read line**\");\n\n            let input: Vec<&str> = input.trim().split(\",\").collect();\n\n            let mut is_y = false;\n            for a in input {\n                match a.parse::<u8>() {\n                    Ok(a) => {\n                        if a > 10 || a == 0 {\n                            println!(\"GUESS AXIS CANNOT BE ZERO OR LARGER THAN TEN!\");\n                            break;\n                        }\n                        if is_y {\n                            pos.1 = a;\n                            break 'guess;\n                        } else {\n                            pos.0 = a;\n                            is_y = true;\n                        }\n                    }\n                    Err(e) => println!(\"{} - TRY AGAIN!\", e.to_string().to_uppercase()),\n                }\n            }\n        }\n\n        pos\n    }\n\n    fn process_guess(&self, p: Position) -> bool {\n        if p == self.hurkle {\n            println!(\"\\nYOU FOUND HIM IN {} GUESSES!\", self.tries);\n            return true;\n        }\n\n        let (x, y) = (p.0, p.1);\n        let (hx, hy) = (self.hurkle.0, self.hurkle.1);\n\n        let mut dir_x = \"WEST\";\n        let mut dir_y = \"SOUTH\";\n\n        let mut set_y_dir = || {\n            if y < hy {\n                dir_y = \"NORTH\";\n            } else {\n                dir_y = \"\";\n            }\n        };\n\n        if x > hx {\n            set_y_dir();\n        } else if x < hx {\n            dir_x = \"EAST\";\n            set_y_dir();\n        } else {\n            dir_x = \"\";\n            set_y_dir();\n        }\n\n        println!(\"GO {}{}\\n\", dir_y, dir_x);\n\n        false\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/rust/src/main.rs",
    "content": "use game::Game;\n\nmod game;\n\nfn main() {\n    println!(\"\\n\\n\\t\\tHURKLE\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n\n    println!(\"A HURKLE IS HIDING ON A 10 BY 10 GRID. HOMEBASE\");\n    println!(\"ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\");\n    println!(\"AND ANY POINT ON THE GRID IS DESIGNATED BY A\");\n    println!(\"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\");\n    println!(\"NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\");\n    println!(\"IS THE VERTICAL POSITION. YOU MUST TRY TO\");\n    println!(\"GUESS THE HURKLE'S GRIDPOINT. YOU GET 5 TRIES.\");\n    println!(\"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\");\n    println!(\"DIRECTION TO GO TO LOOK FOR THE HURKLE.\\n\");\n\n    loop {\n        let mut game = Game::new();\n\n        loop {\n            if game.update() {\n                println!(\"\\nLET'S PLAY AGAIN. HURKLE IS HIDING.\");\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "51_Hurkle/vbnet/Hurkle.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Hurkle\", \"Hurkle.vbproj\", \"{63674AC0-0FE6-467F-B2D0-016105155ADE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{63674AC0-0FE6-467F-B2D0-016105155ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{63674AC0-0FE6-467F-B2D0-016105155ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{63674AC0-0FE6-467F-B2D0-016105155ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{63674AC0-0FE6-467F-B2D0-016105155ADE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "51_Hurkle/vbnet/Hurkle.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Hurkle</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "51_Hurkle/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "52_Kinema/README.md",
    "content": "### Kinema\n\nThis program tests your fundamental knowledge of kinematics. It presents a simple problem: a ball is thrown straight up into the air at some random velocity. You then must answer three questions about the flight of the ball:\n1. How high will it go?\n2. How long until it returns to earth?\n3. What will be its velocity after a random number of seconds?\n\nThe computer evaluates your performance; within 15% of the correct answer is considered close enough. After each run, the computer gives you another problem until you interrupt it.\n\nKINEMA was shorted from the original Huntington Computer Project Program, KINERV, by Richard Pav of Patchogue High School, Patchogue, New York.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=95)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=110)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "52_Kinema/csharp/Kinema.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "52_Kinema/csharp/Kinema.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Kinema\", \"Kinema.csproj\", \"{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "52_Kinema/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "52_Kinema/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "52_Kinema/java/src/Kinema.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Kinema\n * <p>\n * Based on the Basic game of Kinema here\n * https://github.com/coding-horror/basic-computer-games/blob/main/52%20Kinema/kinema.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Kinema {\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        STARTUP,\n        INIT,\n        HOW_HIGH,\n        SECONDS_TILL_IT_RETURNS,\n        ITS_VELOCITY,\n        RESULTS,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private int numberAnswersCorrect;\n\n    // How many meters per second a ball is thrown\n    private int velocity;\n\n    public Kinema() {\n        kbScanner = new Scanner(System.in);\n\n        gameState = GAME_STATE.STARTUP;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        double playerAnswer;\n        double correctAnswer;\n        do {\n            switch (gameState) {\n\n                case STARTUP:\n                    intro();\n                    gameState = GAME_STATE.INIT;\n                    break;\n\n                case INIT:\n                    numberAnswersCorrect = 0;\n\n                    // calculate a random velocity for the player to use in the calculations\n                    velocity = 5 + (int) (35 * Math.random());\n                    System.out.println(\"A BALL IS THROWN UPWARDS AT \" + velocity + \" METERS PER SECOND.\");\n                    gameState = GAME_STATE.HOW_HIGH;\n                    break;\n\n                case HOW_HIGH:\n\n                    playerAnswer = displayTextAndGetNumber(\"HOW HIGH WILL IT GO (IN METERS)? \");\n\n                    // Calculate the correct answer to how high it will go\n                    correctAnswer = 0.05 * Math.pow(velocity, 2);\n                    if (calculate(playerAnswer, correctAnswer)) {\n                        numberAnswersCorrect++;\n                    }\n                    gameState = GAME_STATE.ITS_VELOCITY;\n                    break;\n\n                case ITS_VELOCITY:\n\n                    playerAnswer = displayTextAndGetNumber(\"HOW LONG UNTIL IT RETURNS (IN SECONDS)? \");\n\n                    // Calculate current Answer for how long until it returns to the ground in seconds\n                    correctAnswer = (double) velocity / 5;\n                    if (calculate(playerAnswer, correctAnswer)) {\n                        numberAnswersCorrect++;\n                    }\n                    gameState = GAME_STATE.SECONDS_TILL_IT_RETURNS;\n                    break;\n\n                case SECONDS_TILL_IT_RETURNS:\n\n                    // Calculate random number of seconds for 3rd question\n                    double seconds = 1 + (Math.random() * (2 * velocity)) / 10;\n\n                    // Round to one decimal place.\n                    double scale = Math.pow(10, 1);\n                    seconds = Math.round(seconds * scale) / scale;\n\n                    playerAnswer = displayTextAndGetNumber(\"WHAT WILL ITS VELOCITY BE AFTER \" + seconds + \" SECONDS? \");\n\n                    // Calculate the velocity after the given number of seconds\n                    correctAnswer = velocity - (10 * seconds);\n                    if (calculate(playerAnswer, correctAnswer)) {\n                        numberAnswersCorrect++;\n                    }\n                    gameState = GAME_STATE.RESULTS;\n                    break;\n\n                case RESULTS:\n                    System.out.println(numberAnswersCorrect + \" RIGHT OUT OF 3\");\n                    if (numberAnswersCorrect > 1) {\n                        System.out.println(\" NOT BAD.\");\n                    }\n                    gameState = GAME_STATE.STARTUP;\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(33) + \"KINEMA\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n    }\n\n    private boolean calculate(double playerAnswer, double correctAnswer) {\n\n        boolean gotItRight = false;\n\n        if (Math.abs((playerAnswer - correctAnswer) / correctAnswer) < 0.15) {\n            System.out.println(\"CLOSE ENOUGH\");\n            gotItRight = true;\n        } else {\n            System.out.println(\"NOT EVEN CLOSE\");\n        }\n        System.out.println(\"CORRECT ANSWER IS \" + correctAnswer);\n        System.out.println();\n\n        return gotItRight;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to a Double\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private double displayTextAndGetNumber(String text) {\n        return Double.parseDouble(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n}\n"
  },
  {
    "path": "52_Kinema/java/src/KinemaGame.java",
    "content": "public class KinemaGame {\n    public static void main(String[] args) {\n\n        Kinema kinema = new Kinema();\n        kinema.play();\n    }\n}\n"
  },
  {
    "path": "52_Kinema/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "52_Kinema/javascript/kinema.html",
    "content": "<html>\n<head>\n<title>KINEMA</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"kinema.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "52_Kinema/javascript/kinema.js",
    "content": "// KINEMA\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar q;\n\nfunction evaluate_answer(str, a)\n{\n    g = parseFloat(str);\n    if (Math.abs((g - a) / a) < 0.15) {\n        print(\"CLOSE ENOUGH.\\n\");\n        q++;\n    } else {\n        print(\"NOT EVEN CLOSE....\\n\");\n    }\n    print(\"CORRECT ANSWER IS \" + a + \"\\n\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"KINEMA\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        q = 0;\n        v = 5 + Math.floor(35 * Math.random());\n        print(\"A BALL IS THROWN UPWARDS AT \" + v + \" METERS PER SECOND.\\n\");\n        print(\"\\n\");\n        a = 0.5 * Math.pow(v, 2);\n        print(\"HOW HIGH WILL IT GO (IN METERS)\");\n        str = await input();\n        evaluate_answer(str, a);\n        a = v / 5;\n        print(\"HOW LONG UNTIL IT RETURNS (IN SECONDS)\");\n        str = await input();\n        evaluate_answer(str, a);\n        t = 1 + Math.floor(2 * v * Math.random()) / 10;\n        a = v - 10 * t;\n        print(\"WHAT WILL ITS VELOCITY BE AFTER \" + t + \" SECONDS\");\n        str = await input();\n        evaluate_answer(str, a);\n        print(\"\\n\");\n        print(q + \" RIGHT OUT OF 3.\");\n        if (q < 2)\n            continue;\n        print(\"  NOT BAD.\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "52_Kinema/kinema.bas",
    "content": "10 PRINT TAB(33);\"KINEMA\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 PRINT\n105 PRINT\n106 Q=0\n110 V=5+INT(35*RND(1))\n111 PRINT \"A BALL IS THROWN UPWARDS AT\";V;\"METERS PER SECOND.\"\n112 PRINT\n115 A=.05*V^2\n116 PRINT \"HOW HIGH WILL IT GO (IN METERS)\";\n117 GOSUB 500\n120 A=V/5\n122 PRINT \"HOW LONG UNTIL IT RETURNS (IN SECONDS)\";\n124 GOSUB 500\n130 T=1+INT(2*V*RND(1))/10\n132 A=V-10*T\n134 PRINT \"WHAT WILL ITS VELOCITY BE AFTER\";T;\"SECONDS\";\n136 GOSUB 500\n140 PRINT\n150 PRINT Q;\"RIGHT OUT OF 3.\";\n160 IF Q<2 THEN 100\n170 PRINT \"  NOT BAD.\"\n180 GOTO 100\n500 INPUT G\n502 IF ABS((G-A)/A)<.15 THEN 510\n504 PRINT \"NOT EVEN CLOSE....\"\n506 GOTO 512\n510 PRINT \"CLOSE ENOUGH.\"\n511 Q=Q+1\n512 PRINT \"CORRECT ANSWER IS \";A\n520 PRINT\n530 RETURN\n999 END\n"
  },
  {
    "path": "52_Kinema/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "52_Kinema/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "52_Kinema/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "52_Kinema/perl/kinema.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 33 . \"KINEMA\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nwhile (1) {\n\tprint \"\\n\";\n\tprint \"\\n\";\n\tmy $Q=0;\n\tmy $V=5+int(35*rand(1));\n\tprint \"A BALL IS THROWN UPWARDS AT $V METERS PER SECOND.\\n\";\n\tprint \"\\n\";\n\n\tmy $A=.05*$V^2;\n\tprint \"HOW HIGH WILL IT GO (IN METERS)\";\n\t$Q+= &Input($A);\n\n\t$A=$V/5;\n\tprint \"HOW LONG UNTIL IT RETURNS (IN SECONDS)\";\n\t$Q+= &Input($A);\n\n\tmy $T=1+int(2*$V*rand(1))/10;\n\t$A=$V-10*$T;\n\tprint \"WHAT WILL ITS VELOCITY BE AFTER $T SECONDS\";\n\t$Q+= &Input($A);\n\n\tprint \"\\n\";\n\tprint \"$Q RIGHT OUT OF 3.\";\n\tif ($Q<2) { next; }\n\tprint \" NOT BAD.\\n\";\n\t}\n\nexit;\n\n\n#Line500:\nsub Input {\n\tmy ($A)= @_;\n\tmy $Point=0;\n\tprint \"? \"; chomp(my $G = <STDIN>);\n\tif (abs(($G-$A)/$A)<.15) {\n\t\tprint \"CLOSE ENOUGH.\\n\";\n\t\t$Point=1;\n\t\t} else {\n\t\tprint \"NOT EVEN CLOSE....\\n\";\n\t\t}\n\tprint \"CORRECT ANSWER IS $A\\n\";\n\tprint \"\\n\";\n\treturn $Point;\n\t}\n"
  },
  {
    "path": "52_Kinema/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "52_Kinema/python/kinema.py",
    "content": "\"\"\"\nKINEMA\n\nA kinematics physics quiz.\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\n\n# We approximate gravity from 9.8 meters/second squared to 10, which\n# is only off by about 2%. 10 is also a lot easier for people to use\n# for mental math.\n\ng = 10\n\n# We only expect the student to get within this percentage of the\n# correct answer. This isn't rocket science.\n\nEXPECTED_ACCURACY_PERCENT = 15\n\n\ndef do_quiz() -> None:\n    print()\n    print()\n    num_questions_correct = 0\n\n    # pick random initial velocity\n    v0 = random.randint(5, 40)\n    print(f\"A BALL IS THROWN UPWARDS AT {v0} METERS PER SECOND.\")\n    print()\n\n    answer = v0**2 / (2 * g)\n    num_questions_correct += ask_player(\"HOW HIGH WILL IT GO (IN METERS)?\", answer)\n\n    answer = 2 * v0 / g\n    num_questions_correct += ask_player(\n        \"HOW LONG UNTIL IT RETURNS (IN SECONDS)?\", answer\n    )\n\n    t = 1 + random.randint(0, 2 * v0) // g\n    answer = v0 - g * t\n    num_questions_correct += ask_player(\n        f\"WHAT WILL ITS VELOCITY BE AFTER {t} SECONDS?\", answer\n    )\n\n    print()\n    print(f\"{num_questions_correct} right out of 3.\")\n    if num_questions_correct >= 2:\n        print(\"  NOT BAD.\")\n\n\ndef ask_player(question: str, answer) -> int:\n    print(question)\n    player_answer = float(input())\n\n    accuracy_frac = EXPECTED_ACCURACY_PERCENT / 100.0\n    if abs((player_answer - answer) / answer) < accuracy_frac:\n        print(\"CLOSE ENOUGH.\")\n        score = 1\n    else:\n        print(\"NOT EVEN CLOSE....\")\n        score = 0\n    print(f\"CORRECT ANSWER IS {answer}\")\n    print()\n    return score\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"KINEMA\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    while True:\n        do_quiz()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "52_Kinema/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "52_Kinema/ruby/kinema.rb",
    "content": "#!/usr/bin/env ruby\n\n# Kinema\n# reinterpreted from BASIC by stephan.com\n\nEPSILON = 0.15\n\ndef close?(guess, answer)\n  (guess-answer).abs < answer * EPSILON\nend\n\ndef ask(text, answer)\n  puts text\n  guess = gets.strip.to_f\n  if close?(guess, answer)\n    puts 'Close enough'\n    @score += 1\n  else\n    puts 'Not even close....'\n  end\n\n  puts \"Correct answer is #{answer}\"\nend\n\nputs 'Kinema'.center(80)\nputs 'Adapted by stephan.com'.center(80)\nputs; puts; puts;\n\nloop do\n  puts; puts\n  @score = 0\n  v = 5 + rand(35)\n\n  puts \"A ball is thrown upwards at #{v} meters per second\"\n\n  ask 'How high will it go? (in meters)', 0.05 * v * v\n  ask 'How long until it returns? (in seconds)', v/5.0\n\n  t = 1 + rand(2*v)/10.0\n  ask \"What will its velocity be after #{t} seconds?\", v - 10 * t\n  puts\n  print \"#{@score} right out of 3.\"\n  print \" not bad\" if @score > 1\n  puts\nend\n"
  },
  {
    "path": "52_Kinema/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nrand = \"0.9.0\""
  },
  {
    "path": "52_Kinema/rust/src/main.rs",
    "content": "/** KINEMA BY RICHARD PAV\n * https://github.com/coding-horror/basic-computer-games/blob/main/52_Kinema/kinema.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * As a faithful translation, many of the code here are done in an unrecommended way by\n *  today's standards.\n * \n * ATTENTION: The original code has mathematical imprecision and uses simplifications\n * instead of the real formulation, which could lead to incorrect results. I have solved\n * this issue, but kept the old lines. To compile the original version, just uncomment the \n * code with the OLD label and comment the lines with the NEW label.\n * example: gravity is now 9.81 instead of 10; Inputs and outputs are now float not integers...\n * \n * FORMULATION\n * A BALL IS THROWN UPWARDS AT 9,36 METERS PER SECOND.\n * HOW HIGH WILL IT GO (IN METERS)? (9,36 ^2) / (2 * 9,81) = 4,465321101\n * HOW LONG UNTIL IT RETURNS (IN SECONDS)? 2*(9,36 / 9,81) = 1,908256881\n * WHAT WILL ITS VELOCITY BE AFTER 1,09 SECONDS? 9,36- 9,81 * 1,09 = −1,3329\n * \n * 17/02/25\n*/\n\nuse std::io::Write;\nuse rand::Rng;\n\nfn subroutine(a: f64, q: &mut i32) {\n    std::io::stdout().flush().unwrap();\n    //500 INPUT G\n    let mut input = String::new();\n    let g;\n    loop {\n        std::io::stdin().read_line(&mut input).unwrap();\n        match input.trim().parse::<f64>() {\n            Ok(e) => { g = e; break; },\n            Err(_) => { print!(\"\\nINVALID. TRY AGAIN: \"); continue; },\n        };\n    }\n    //502 IF ABS((G-A)/A)<.15 THEN 510\n    if f64::abs((g-a)/a) < 0.15 {\n        //510 PRINT \"CLOSE ENOUGH.\"        \n        print!(\"CLOSE ENOUGH.\");\n        //511 Q=Q+1\n        *q = *q + 1;\n    }\n    else {\n        //504 PRINT \"NOT EVEN CLOSE....\"\n        print!(\"NOT EVEN CLOSE...\");\n        //506 GOTO 512\n    }\n    //512 PRINT \"CORRECT ANSWER IS \";A\n    print!(\"\\nCORRECT ANSWER IS {a:.2}\\n\");\n    //520 PRINT\n    //530 RETURN\n}\n\nfn main() {\n    let mut rng = rand::rng();\n\n    //10 PRINT TAB(33);\"KINEMA\"\n    //20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    //30 PRINT: PRINT: PRINT\n    //100 PRINT\n    //105 PRINT\n    print!(\"{}KINEMA\\n{}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\\n\", \n        \" \".repeat(33),\n        \" \".repeat(15)\n    );\n    loop {\n        //106 Q=0\n        let mut q = 0;\n        //110 V=5+INT(35*RND(1))\n        let v: f64 = 5.0 + 35.0 * rng.random_range(0.0..1.0);\n        //111 PRINT \"A BALL IS THROWN UPWARDS AT\";V;\"METERS PER SECOND.\"\n        //112 PRINT\n        print!(\"\\nA BALL IS THROWN UPWARDS AT {v:.2} METERS PER SECOND.\\n\");\n        //115 A=.05*V^2\n        //let a = 0.05 * v.powf(2.0); // OLD\n        let mut a = v.powf(2.0) / (2.0 * 9.81); // NEW\n        //116 PRINT \"HOW HIGH WILL IT GO (IN METERS)\";\n        print!(\"\\nHOW HIGH WILL IT GO (IN METERS)? \");\n        \n        //117 GOSUB 500\n        subroutine(a, &mut q);\n        \n        //120 A=V/5\n        //a = v / 5.0; // OLD\n        a = 2.0 * v / 9.81; // NEW\n        //122 PRINT \"HOW LONG UNTIL IT RETURNS (IN SECONDS)\";\n        print!(\"\\nHOW LONG UNTIL IT RETURNS (IN SECONDS)? \");\n        //124 GOSUB 500\n        subroutine(a, &mut q);\n\n        //130 T=1+INT(2*V*RND(1))/10\n        let t = 1.0 + (2.0 * v * rng.random_range(0.0..1.0) / 10.0);\n        //132 A=V-10*T\n        a = v + (-9.81 * t);\n        //134 PRINT \"WHAT WILL ITS VELOCITY BE AFTER\";T;\"SECONDS\";\n        print!(\"\\nWHAT WILL ITS VELOCITY BE AFTER {t:.2} SECONDS? \");\n\n        //136 GOSUB 500\n        subroutine(a, &mut q);\n\n        //140 PRINT\n        //150 PRINT Q;\"RIGHT OUT OF 3.\";\n        print!(\"\\n{q} RIGHT OUT OF 3.\\n\");\n        //160 IF Q<2 THEN 100\n        if q < 2 {\n            continue;\n        }\n        //170 PRINT \"  NOT BAD.\"\n        //print!(\"  NOT BAD.\");\n        //180 GOTO 100\n    }\n    //999 END\n}\n"
  },
  {
    "path": "52_Kinema/vbnet/Kinema.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Kinema\", \"Kinema.vbproj\", \"{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "52_Kinema/vbnet/Kinema.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Kinema</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "52_Kinema/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "53_King/README.md",
    "content": "## King\n\nThis is one of the most comprehensive, difficult, and interesting games. (If you've never played one of these games, start with HAMMURABI.)\n\nIn this game, you are Premier of Setats Detinu, a small communist island 30 by 70 miles long. Your job is to decide upon the budget of your country and distribute money to your country from the communal treasury.\n\nThe money system is Rollods; each person needs 100 Rallods per year to survive. Your country's income comes from farm produce and tourists visiting your magnificent forests, hunting, fishing, etc. Part of your land is farm land but it also has an excellent mineral content and may be sold to foreign industry for strip mining. Industry import and support their own workers. Crops cost between 10 and 15 Rallods per square mile to plant, cultivate, and harvest. Your goal is to complete an eight-year term of office without major mishap. A word of warning: it isn't easy!\n\nThe author of this program is James A. Storer who wrote it while a student at Lexington High School.\n\n⚠️ This game includes references to suicide or self-harm.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=96)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=111)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\nImplementers should be aware that this game contains bugs.\n\n### Bug 1\n\nOn basic line 1450\n\n    1450 V3=INT(A+V3)\n    1451 A=INT(A+V3)\n\n...where A is the current treasury, and V3 is initially zero.\nThis would mean that the treasury doubles at the end of the first year, and all calculations for an increase in the treasury due to tourism are discarded.\nPossibly, this made the game more playable, although impossible for the player to understand why the treasury was increasing?\n\nA quick fix for this bug in the original code would be\n\n    1450 V3=ABS(INT(V1-V2))\n    1451 A=INT(A+V3)\n\n...judging from the description of tourist income on basic line 1410\n\n    1410 PRINT \" YOU MADE\";ABS(INT(V1-V2));\"RALLODS FROM TOURIST TRADE.\"\n\n### Bug 2\n\nOn basic line 1330 following was the variable T1 never assigned:\n\n    1330 PRINT \" YOU HARVESTED \";INT(J-U2);\"SQ. MILES OF CROPS.\"\n    1340 IF U2=0 THEN 1370\n    1344 IF T1>=2 THEN 1370\n    1350 PRINT \"   (DUE TO \";\n    1355 IF T1=0 THEN 1365\n    1360 PRINT \"INCREASED \";\n\nLikely it should be the difference of the current years crop loss compared to the\nlast years crop loss.\n\n### Bug 3\n\nOn basic line 1997 it is:\n\n    1997 PRINT \"   AND 10,000 SQ. MILES OF FOREST LAND.\"\n\nbut it should be:\n\n    1997 PRINT \"   AND 1,000 SQ. MILES OF FOREST LAND.\"\n\n### Bug 4\n\nOn basic line 1310 we see this:\n\n    1310 IF C=0 THEN 1324\n    1320 PRINT \"OF \";INT(J);\"SQ. MILES PLANTED,\";\n    1324 ...\n\nbut it should probably be:\n\n    1310 IF J=0 THEN 1324\n\n### Bug 5\n\nOn basic line 1390 the income from tourism is calculated:\n\n```\n1390 A=INT(A+Q)\n1400 V1=INT(((B-P1)*22)+(RND(1)*500))\n1405 V2=INT((2000-D)*15)\n1410 PRINT \" YOU MADE\";ABS(INT(V1-V2));\"RALLODS FROM TOURIST TRADE.\"\n```\n\nIt is very easily possible that `V2` is larger than `V1` e.g. if all of the land has been sold. In the original game this does not make a difference because of Bug 1 (see above).\n\nHowever, judging by how `V1` and `V2` are handled in the code, it looks like `V1` is the basic income from tourism and `V2` is a deduction for pollution. When `ABS(INT(V1-V2))` is used as earnings from tourism, the player actually _gets_ money for a large enough pollution. So a better solution would be to let `V1 - V2` cap out at 0, so once the pollution is large enough, there is no income from tourists anymore.\n"
  },
  {
    "path": "53_King/csharp/Country.cs",
    "content": "namespace King;\n\ninternal class Country\n{\n    private const int InitialLand = 1000;\n\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    private float _rallods;\n    private float _countrymen;\n    private float _foreigners;\n    private float _arableLand;\n    private float _industryLand;\n\n    public Country(IReadWrite io, IRandom random)\n        : this(\n            io,\n            random,\n            (int)(60000 + random.NextFloat(1000) - random.NextFloat(1000)),\n            (int)(500 + random.NextFloat(10) - random.NextFloat(10)),\n            0,\n            InitialLand)\n    {\n    }\n\n    public Country(IReadWrite io, IRandom random, float rallods, float countrymen, float foreigners, float land)\n    {\n        _io = io;\n        _random = random;\n        _rallods = rallods;\n        _countrymen = countrymen;\n        _foreigners = foreigners;\n        _arableLand = land;\n    }\n\n    public string GetStatus(int landValue, int plantingCost) \n        => Resource.Status(_rallods, _countrymen, _foreigners, _arableLand, landValue, plantingCost);\n    \n    public float Countrymen => _countrymen;\n    public float Workers => _foreigners;\n    public bool HasWorkers => _foreigners > 0;\n    private float FarmLand => _arableLand;\n    public bool HasRallods => _rallods > 0;\n    public float Rallods => _rallods;\n    public float IndustryLand => InitialLand - _arableLand;\n    public int PreviousTourismIncome { get; private set; }\n\n    public bool SellLand(int landValue, out float landSold)\n    {\n        if (_io.TryReadValue(\n                SellLandPrompt, \n                out landSold, \n                new ValidityTest(v => v <= FarmLand, () => SellLandError(FarmLand))))\n        {\n            _arableLand = (int)(_arableLand - landSold);\n            _rallods = (int)(_rallods + landSold * landValue);\n            return true;\n        }\n\n        return false;\n    }\n\n    public bool DistributeRallods(out float rallodsGiven)\n    {\n        if (_io.TryReadValue(\n                GiveRallodsPrompt,\n                out rallodsGiven, \n                new ValidityTest(v => v <= _rallods, () => GiveRallodsError(_rallods))))\n        {\n            _rallods = (int)(_rallods - rallodsGiven);\n            return true;\n        }\n\n        return false;\n    }\n\n    public bool PlantLand(int plantingCost, out float landPlanted)\n    {\n        if (_io.TryReadValue(\n                PlantLandPrompt, \n                out landPlanted, \n                new ValidityTest(v => v <= _countrymen * 2, PlantLandError1),\n                new ValidityTest(v => v <= FarmLand, PlantLandError2(FarmLand)),\n                new ValidityTest(v => v * plantingCost <= _rallods, PlantLandError3(_rallods))))\n        {\n            _rallods -= (int)(landPlanted * plantingCost);\n            return true;\n        }\n\n        return false;\n    }\n\n    public bool ControlPollution(out float rallodsSpent)\n    {\n        if (_io.TryReadValue(\n                PollutionPrompt,\n                out rallodsSpent, \n                new ValidityTest(v => v <= _rallods, () => PollutionError(_rallods))))\n        {\n            _rallods = (int)(_rallods - rallodsSpent);\n            return true;\n        }\n\n        return false;\n    }\n\n    public bool TrySpend(float amount, float landValue)\n    {\n        if (_rallods >= amount)\n        {\n            _rallods -= amount;\n            return true;\n        }\n        \n        _arableLand = (int)(_arableLand - (int)(amount - _rallods) / landValue);\n        _rallods = 0;\n        return false;\n    }\n\n    public void RemoveTheDead(int deaths) => _countrymen = (int)(_countrymen - deaths);\n\n    public void Migration(int migration) => _countrymen = (int)(_countrymen + migration);\n\n    public void AddWorkers(int newWorkers) => _foreigners = (int)(_foreigners + newWorkers);\n\n    public void SellCrops(int income) => _rallods = (int)(_rallods + income);\n\n    public void EntertainTourists(int income)\n    {\n        PreviousTourismIncome = income;\n        _rallods = (int)(_rallods + income);\n    }\n}\n"
  },
  {
    "path": "53_King/csharp/Game.cs",
    "content": "namespace King;\n\ninternal class Game\n{\n    const int TermOfOffice = 8;\n\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    public void Play()\n    {\n        _io.Write(Title);\n\n        var reign = SetUpReign();\n        if (reign != null)\n        {\n            while (reign.PlayYear());\n        }\n\n        _io.WriteLine();\n        _io.WriteLine();\n    }\n\n    private Reign? SetUpReign()\n    {\n        var response = _io.ReadString(InstructionsPrompt).ToUpper();\n\n        if (response.Equals(\"Again\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            return _io.TryReadGameData(_random, out var reign) ? reign : null;\n        }\n        \n        if (!response.StartsWith(\"N\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            _io.Write(InstructionsText(TermOfOffice));\n        }\n\n        _io.WriteLine();\n        return new Reign(_io, _random);\n    }\n}\n"
  },
  {
    "path": "53_King/csharp/IOExtensions.cs",
    "content": "using System.Diagnostics.CodeAnalysis;\nusing static King.Resources.Resource;\n\nnamespace King;\n\ninternal static class IOExtensions\n{\n    internal static bool TryReadGameData(this IReadWrite io, IRandom random, [NotNullWhen(true)] out Reign? reign)\n    {\n        if (io.TryReadValue(SavedYearsPrompt, v => v < Reign.MaxTerm, SavedYearsError(Reign.MaxTerm), out var years) &&\n            io.TryReadValue(SavedTreasuryPrompt, out var rallods) &&\n            io.TryReadValue(SavedCountrymenPrompt, out var countrymen) &&\n            io.TryReadValue(SavedWorkersPrompt, out var workers) &&\n            io.TryReadValue(SavedLandPrompt, v => v is > 1000 and <= 2000, SavedLandError, out var land))\n        {\n            reign = new Reign(io, random, new Country(io, random, rallods, countrymen, workers, land), years + 1);\n            return true;\n        }\n\n        reign = default;\n        return false;\n    }\n\n    internal static bool TryReadValue(this IReadWrite io, string prompt, out float value, params ValidityTest[] tests)\n    {\n        while (true)\n        {\n            var response = value = io.ReadNumber(prompt);\n            if (response == 0) { return false; }\n            if (tests.All(test => test.IsValid(response, io))) { return true; }\n        } \n    }\n\n    internal static bool TryReadValue(this IReadWrite io, string prompt, out float value)\n        => io.TryReadValue(prompt, _ => true, \"\", out value);\n    \n    internal static bool TryReadValue(\n        this IReadWrite io,\n        string prompt,\n        Predicate<float> isValid,\n        string error,\n        out float value)\n        => io.TryReadValue(prompt, isValid, () => error, out value);\n\n    internal static bool TryReadValue(\n        this IReadWrite io,\n        string prompt,\n        Predicate<float> isValid,\n        Func<string> getError,\n        out float value)\n    {\n        while (true)\n        {\n            value = io.ReadNumber(prompt);\n            if (value < 0) { return false; }\n            if (isValid(value)) { return true; }\n            \n            io.Write(getError());\n        }\n    }\n}\n"
  },
  {
    "path": "53_King/csharp/King.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "53_King/csharp/King.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"King\", \"King.csproj\", \"{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "53_King/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using King.Resources;\nglobal using static King.Resources.Resource;\nusing King;\n\nnew Game(new ConsoleIO(), new RandomNumberGenerator()).Play();\n"
  },
  {
    "path": "53_King/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "53_King/csharp/Reign.cs",
    "content": "namespace King;\n\ninternal class Reign\n{\n    public const int MaxTerm = 8;\n\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    private readonly Country _country;\n    private float _yearNumber;\n\n    public Reign(IReadWrite io, IRandom random)\n        : this(io, random, new Country(io, random), 1)\n    {\n    }\n\n    public Reign(IReadWrite io, IRandom random, Country country, float year)\n    {\n        _io = io;\n        _random = random;\n        _country = country;\n        _yearNumber = year;\n    }\n\n    public bool PlayYear()\n    {\n        var year = new Year(_country, _random, _io);\n\n        _io.Write(year.Status);\n\n        var result = year.GetPlayerActions() ?? year.EvaluateResults() ?? IsAtEndOfTerm();\n        if (result.IsGameOver)\n        {\n            _io.WriteLine(result.Message);\n            return false;\n        }\n\n        return true;\n    }\n\n    private Result IsAtEndOfTerm() \n        => _yearNumber == MaxTerm \n            ? Result.GameOver(EndCongratulations(MaxTerm)) \n            : Result.Continue;\n}\n"
  },
  {
    "path": "53_King/csharp/Resources/DeathsPollution.txt",
    "content": " {0} countrymen died of carbon-monoxide and dust inhalation"
  },
  {
    "path": "53_King/csharp/Resources/DeathsStarvation.txt",
    "content": " {0} countrymen died of starvation"
  },
  {
    "path": "53_King/csharp/Resources/Emigration.txt",
    "content": " {0} countrymen left the island."
  },
  {
    "path": "53_King/csharp/Resources/EndAlso.txt",
    "content": "also had your left eye gouged out!\n;have also gained a very bad reputation.\n;have also been declared national fink.\n"
  },
  {
    "path": "53_King/csharp/Resources/EndCongratulations.txt",
    "content": "\n\nCongratulations!!!!!!!!!!!!!!!!!!\nYou have successfully completed your {0} year term\nof office. You were, of course, extremely lucky, but\nnevertheless, it's quite an achievement. Goodbye and good\nluck - you'll probably need it if you're the type that\nplays this game.\n\n\n"
  },
  {
    "path": "53_King/csharp/Resources/EndConsequences.txt",
    "content": "You have been thrown out of office and are now\nresiding in prison.;\nYou have been assassinated.\n"
  },
  {
    "path": "53_King/csharp/Resources/EndForeignWorkers.txt",
    "content": "\n\nThe number of foreign workers has exceeded the number\nof countrymen. As a minority, they have revolted and\ntaken over the country.\n{0}\n\n"
  },
  {
    "path": "53_King/csharp/Resources/EndManyDead.txt",
    "content": "{0} countrymen died in one year!!!!!\ndue to this extreme mismanagement, you have not only\nbeen impeached and thrown out of office, but you\n{1}\n\n"
  },
  {
    "path": "53_King/csharp/Resources/EndMoneyLeftOver.txt",
    "content": "\nMoney was left over in the treasury which you did\nnot spend. As a result, some of your countrymen died\nof starvation. The public is enraged and you have\nbeen forced to resign.\n\n\n"
  },
  {
    "path": "53_King/csharp/Resources/EndOneThirdDead.txt",
    "content": "\n\nOver one third of the population has died since you\nwere elected to office. The people (remaining)\nhate your guts.\n{0}\n\n"
  },
  {
    "path": "53_King/csharp/Resources/FuneralExpenses.txt",
    "content": "   You were forced to spend {0} rallods on funeral expenses"
  },
  {
    "path": "53_King/csharp/Resources/GiveRallodsError.txt",
    "content": "   Think again. You've only got {0}  rallods in the treasury.\n"
  },
  {
    "path": "53_King/csharp/Resources/GiveRallodsPrompt.txt",
    "content": "How many rallods will you distribute among your countrymen"
  },
  {
    "path": "53_King/csharp/Resources/Goodbye.txt",
    "content": "Goodbye.\n(If you wish to continue this game at a later date, answer\n'again' when asked if you want instructions at the start\nof the game).\n"
  },
  {
    "path": "53_King/csharp/Resources/Harvest.txt",
    "content": " you harvested  {0} sq. miles of crops.\n{1}making {2} rallods.\n"
  },
  {
    "path": "53_King/csharp/Resources/HarvestReason.txt",
    "content": "   (Due to increased air and water pollution from foreign industry.)\n"
  },
  {
    "path": "53_King/csharp/Resources/Immigration.txt",
    "content": " {0} countrymen came to the island."
  },
  {
    "path": "53_King/csharp/Resources/InstructionsPrompt.txt",
    "content": "Do you want instructions"
  },
  {
    "path": "53_King/csharp/Resources/InstructionsText.txt",
    "content": "\n\n\nCongratulations! You've just been elected Premier of Setats\nDetinu, a small communist island 30 by 70 miles long. Your\njob is to decide upon the country's budget and distribute\nmoney to your countrymen from the communal treasury.\nThe money system is rallods, and each person needs 100\nrallods per year to survive. Your country's income comes\nfrom farm produce and tourists visiting your magnificent\nforests, hunting, fishing, etc. Half your land if farm land\nwhich also has an excellent mineral content and may be sold\nto foreign industry (strip mining) who import and support\ntheir own workers. Crops cost between 10 and 15 rallods per\nsquare mile to plant.\nYour goal is to complete your {0} year term of office.\nGood luck!\n"
  },
  {
    "path": "53_King/csharp/Resources/InsufficientReserves.txt",
    "content": ""
  },
  {
    "path": "53_King/csharp/Resources/LandPlanted.txt",
    "content": "Of  {0} sq. miles planted,"
  },
  {
    "path": "53_King/csharp/Resources/PlantLandError1.txt",
    "content": "   Sorry, but each countryman can only plant 2 sq. miles."
  },
  {
    "path": "53_King/csharp/Resources/PlantLandError2.txt",
    "content": "   Sorry, but you've only {0} sq. miles of farm land."
  },
  {
    "path": "53_King/csharp/Resources/PlantLandError3.txt",
    "content": "   Think again, You've only {0}  rallods left in the treasury.\n"
  },
  {
    "path": "53_King/csharp/Resources/PlantLandPrompt.txt",
    "content": "How many square miles do you wish to plant"
  },
  {
    "path": "53_King/csharp/Resources/PollutionError.txt",
    "content": "   Think again. You only have  {0}  rallods remaining.\n"
  },
  {
    "path": "53_King/csharp/Resources/PollutionPrompt.txt",
    "content": "How many rallods do you wish to spend on pollution control"
  },
  {
    "path": "53_King/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace King.Resources;\n\ninternal static class Resource\n{\n    private static bool _sellLandErrorShown;\n\n    public static Stream Title => GetStream();\n    \n    public static string InstructionsPrompt => GetString();\n    public static string InstructionsText(int years) => string.Format(GetString(), years);\n\n    public static string Status(\n        float rallods,\n        float countrymen,\n        float workers,\n        float land,\n        float landValue,\n        float plantingCost)\n        => string.Format(\n            workers == 0 ? StatusWithWorkers : StatusSansWorkers,\n            rallods,\n            (int)countrymen,\n            (int)workers,\n            (int)land,\n            landValue,\n            plantingCost);\n\n    private static string StatusWithWorkers => GetString();\n    private static string StatusSansWorkers => GetString();\n\n    public static string SellLandPrompt => GetString();\n    public static string SellLandError(float farmLand)\n    {\n        var error = string.Format(GetString(), farmLand, _sellLandErrorShown ? \"\" : SellLandErrorReason);\n        _sellLandErrorShown = true;\n        return error;\n    }\n    private static string SellLandErrorReason => GetString();\n\n    public static string GiveRallodsPrompt => GetString();\n    public static string GiveRallodsError(float rallods) => string.Format(GetString(), rallods);\n\n    public static string PlantLandPrompt => GetString();\n    public static string PlantLandError1 => GetString();\n    public static string PlantLandError2(float farmLand) => string.Format(GetString(), farmLand);\n    public static string PlantLandError3(float rallods) => string.Format(GetString(), rallods);\n\n    public static string PollutionPrompt => GetString();\n    public static string PollutionError(float rallods) => string.Format(GetString(), rallods);\n\n    public static string DeathsStarvation(float deaths) => string.Format(GetString(), (int)deaths);\n    public static string DeathsPollution(int deaths) => string.Format(GetString(), deaths);\n    public static string FuneralExpenses(int expenses) => string.Format(GetString(), expenses);\n    public static string InsufficientReserves => GetString();\n\n    public static string WorkerMigration(int newWorkers) => string.Format(GetString(), newWorkers);\n    public static string Migration(int migration) \n        => string.Format(migration < 0 ? Emigration : Immigration, Math.Abs(migration));\n    public static string Emigration => GetString();\n    public static string Immigration => GetString();\n\n    public static string LandPlanted(float landPlanted) \n        => landPlanted > 0 ? string.Format(GetString(), (int)landPlanted) : \"\";\n    public static string Harvest(int yield, int income, bool hasIndustry) \n        => string.Format(GetString(), yield, HarvestReason(hasIndustry), income);\n    private static string HarvestReason(bool hasIndustry) => hasIndustry ? GetString() : \"\";\n\n    public static string TourismEarnings(int income) => string.Format(GetString(), income);\n    public static string TourismDecrease(IRandom random) => string.Format(GetString(), TourismReason(random));\n    private static string TourismReason(IRandom random) => GetStrings()[random.Next(5)];\n\n    private static string EndAlso(IRandom random)\n        => random.Next(10) switch\n        {\n            <= 3 => GetStrings()[0],\n            <= 6 => GetStrings()[1],\n            _ => GetStrings()[2]\n        };\n\n    public static string EndCongratulations(int termLength) => string.Format(GetString(), termLength);\n    private static string EndConsequences(IRandom random) => GetStrings()[random.Next(2)];\n    public static string EndForeignWorkers(IRandom random) => string.Format(GetString(), EndConsequences(random));\n    public static string EndManyDead(int deaths, IRandom random) => string.Format(GetString(), deaths, EndAlso(random));\n    public static string EndMoneyLeftOver() => GetString();\n    public static string EndOneThirdDead(IRandom random) => string.Format(GetString(), EndConsequences(random));\n    \n    public static string SavedYearsPrompt => GetString();\n    public static string SavedYearsError(int years) => string.Format(GetString(), years);\n    public static string SavedTreasuryPrompt => GetString();\n    public static string SavedCountrymenPrompt => GetString();\n    public static string SavedWorkersPrompt => GetString();\n    public static string SavedLandPrompt => GetString();\n    public static string SavedLandError => GetString();\n\n    public static string Goodbye => GetString();\n\n    private static string[] GetStrings([CallerMemberName] string? name = null) => GetString(name).Split(';');\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "53_King/csharp/Resources/SavedCountrymenPrompt.txt",
    "content": "How many countrymen"
  },
  {
    "path": "53_King/csharp/Resources/SavedLandError.txt",
    "content": "   Come on, you started with 1000 sq. miles of farm land\n   and 10,000 sq. miles of forest land\n"
  },
  {
    "path": "53_King/csharp/Resources/SavedLandPrompt.txt",
    "content": "How many square miles of land"
  },
  {
    "path": "53_King/csharp/Resources/SavedTreasuryPrompt.txt",
    "content": "How much did you have in the treasury"
  },
  {
    "path": "53_King/csharp/Resources/SavedWorkersPrompt.txt",
    "content": "How many workers"
  },
  {
    "path": "53_King/csharp/Resources/SavedYearsError.txt",
    "content": "   Come on, your term in office is only {0} years.\n"
  },
  {
    "path": "53_King/csharp/Resources/SavedYearsPrompt.txt",
    "content": "How many years had you been in office when interrupted"
  },
  {
    "path": "53_King/csharp/Resources/SellLandError.txt",
    "content": "*** Think again. You only have {0} square miles of farm land.\n{1}"
  },
  {
    "path": "53_King/csharp/Resources/SellLandErrorReason.txt",
    "content": "\n(Foreign industry will only buy farm land because\nforest land is uneconomical to strip mine due to trees,\nthicker top soil, etc.)\n"
  },
  {
    "path": "53_King/csharp/Resources/SellLandPrompt.txt",
    "content": "How many square miles do you wish to sell to industry"
  },
  {
    "path": "53_King/csharp/Resources/StatusSansWorkers.txt",
    "content": "\nYou now have  {0}  rallods in the treasury.\n {1} countrymen, and {3} sq. miles of land.\nThis year industry will buy land for {4} rallods per square mile.\nLand currently costs {5} rallods per square mile to plant.\n\n"
  },
  {
    "path": "53_King/csharp/Resources/StatusWithWorkers.txt",
    "content": "\nYou now have  {0}  rallods in the treasury.\n {1} countrymen,  {2} foreign workers and {3} sq. miles of land.\nThis year industry will buy land for {4} rallods per square mile.\nLand currently costs {5} rallods per square mile to plant.\n\n"
  },
  {
    "path": "53_King/csharp/Resources/Title.txt",
    "content": "                                  King\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "53_King/csharp/Resources/TourismDecrease.txt",
    "content": "   Decrease because {0}"
  },
  {
    "path": "53_King/csharp/Resources/TourismEarnings.txt",
    "content": " You made {0} rallods from tourist trade."
  },
  {
    "path": "53_King/csharp/Resources/TourismReason.txt",
    "content": "fish population has dwindled due to water pollution.\n;air pollution is killing game bird population.\n;mineral baths are being ruined by water pollution.\n;unpleasant smog is discouraging sun bathers.\n;hotels are looking shabby due to smog grit.\n"
  },
  {
    "path": "53_King/csharp/Resources/WorkerMigration.txt",
    "content": " {0} workers came to the country and"
  },
  {
    "path": "53_King/csharp/Result.cs",
    "content": "namespace King;\n\ninternal record struct Result (bool IsGameOver, string Message)\n{\n    internal static Result GameOver(string message) => new(true, message);\n    internal static Result Continue => new(false, \"\");\n}\n"
  },
  {
    "path": "53_King/csharp/ValidityTest.cs",
    "content": "namespace King;\n\ninternal class ValidityTest\n{\n    private readonly Predicate<float> _isValid;\n    private readonly Func<string> _getError;\n\n    public ValidityTest(Predicate<float> isValid, string error)\n        : this(isValid, () => error)\n    {\n    }\n\n    public ValidityTest(Predicate<float> isValid, Func<string> getError)\n    {\n        _isValid = isValid;\n        _getError = getError;\n    }\n\n    public bool IsValid(float value, IReadWrite io)\n    {\n        if (_isValid(value)) { return true; }\n        \n        io.Write(_getError());\n        return false;\n    }\n}"
  },
  {
    "path": "53_King/csharp/Year.cs",
    "content": "using System.Text;\n\nnamespace King;\n\ninternal class Year\n{\n    private readonly Country _country;\n    private readonly IRandom _random;\n    private readonly IReadWrite _io;\n    private readonly int _plantingCost;\n    private readonly int _landValue;\n\n    private float _landSold;\n    private float _rallodsDistributed;\n    private float _landPlanted;\n    private float _pollutionControlCost;\n\n    private float _citizenSupport;\n    private int _deaths;\n    private float _starvationDeaths;\n    private int _pollutionDeaths;\n    private int _migration;\n\n    public Year(Country country, IRandom random, IReadWrite io)\n    {\n        _country = country;\n        _random = random;\n        _io = io;\n        \n        _plantingCost = random.Next(10, 15);\n        _landValue = random.Next(95, 105);\n    }\n\n    public string Status => _country.GetStatus(_landValue, _plantingCost);\n\n    public Result? GetPlayerActions()\n    {\n        var playerSoldLand = _country.SellLand(_landValue, out _landSold);\n        var playerDistributedRallods = _country.DistributeRallods(out _rallodsDistributed);\n        var playerPlantedLand = _country.HasRallods && _country.PlantLand(_plantingCost, out _landPlanted);\n        var playerControlledPollution = _country.HasRallods && _country.ControlPollution(out _pollutionControlCost);\n\n        return playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution\n            ? null\n            : Result.GameOver(Goodbye);\n    }\n\n    public Result? EvaluateResults()\n    {\n        var rallodsUnspent = _country.Rallods;\n\n        _io.WriteLine();\n        _io.WriteLine();\n\n        return EvaluateDeaths() \n            ?? EvaluateMigration() \n            ?? EvaluateAgriculture()\n            ?? EvaluateTourism()\n            ?? DetermineResult(rallodsUnspent);\n    }\n\n    public Result? EvaluateDeaths()\n    {\n        var supportedCountrymen = _rallodsDistributed / 100;\n        _citizenSupport = supportedCountrymen - _country.Countrymen;\n        _starvationDeaths = -_citizenSupport;\n        if (_starvationDeaths > 0)\n        {\n            if (supportedCountrymen < 50) { return Result.GameOver(EndOneThirdDead(_random)); }\n            _io.WriteLine(DeathsStarvation(_starvationDeaths));\n        }\n\n        var pollutionControl = _pollutionControlCost >= 25 ? _pollutionControlCost / 25 : 1;\n        _pollutionDeaths = (int)(_random.Next((int)_country.IndustryLand) / pollutionControl);\n        if (_pollutionDeaths > 0)\n        {\n            _io.WriteLine(DeathsPollution(_pollutionDeaths));\n        }\n\n        _deaths = (int)(_starvationDeaths + _pollutionDeaths);\n        if (_deaths > 0)\n        {\n            var funeralCosts = _deaths * 9;\n            _io.WriteLine(FuneralExpenses(funeralCosts));\n\n            if (!_country.TrySpend(funeralCosts, _landValue))\n            {\n                _io.WriteLine(InsufficientReserves);\n            }\n\n            _country.RemoveTheDead(_deaths);\n        }\n\n        return null;\n    }\n\n    private Result? EvaluateMigration()\n    {\n        if (_landSold > 0)\n        {\n            var newWorkers = (int)(_landSold + _random.NextFloat(10) - _random.NextFloat(20));\n            if (!_country.HasWorkers) { newWorkers += 20; }\n            _io.Write(WorkerMigration(newWorkers));\n            _country.AddWorkers(newWorkers);\n        }\n\n        _migration = \n            (int)(_citizenSupport / 10 + _pollutionControlCost / 25 - _country.IndustryLand / 50 - _pollutionDeaths / 2);\n        _io.WriteLine(Migration(_migration));\n        _country.Migration(_migration);\n\n        return null;\n    }\n\n    private Result? EvaluateAgriculture()\n    {\n        var ruinedCrops = (int)Math.Min(_country.IndustryLand * (_random.NextFloat() + 1.5f) / 2, _landPlanted);\n        var yield = (int)(_landPlanted - ruinedCrops);\n        var income = (int)(yield * _landValue / 2f);\n\n        _io.Write(LandPlanted(_landPlanted));\n        _io.Write(Harvest(yield, income, _country.IndustryLand > 0));\n\n        _country.SellCrops(income);\n\n        return null;\n    }\n\n    private Result? EvaluateTourism()\n    {\n        var reputationValue = (int)((_country.Countrymen - _migration) * 22 + _random.NextFloat(500));\n        var industryAdjustment = (int)(_country.IndustryLand * 15);\n        var tourismIncome = Math.Abs(reputationValue - industryAdjustment);\n\n        _io.WriteLine(TourismEarnings(tourismIncome));\n        if (industryAdjustment > 0 && tourismIncome < _country.PreviousTourismIncome)\n        {\n            _io.Write(TourismDecrease(_random));\n        }\n\n        _country.EntertainTourists(tourismIncome);\n\n        return null;\n    }\n\n    private Result? DetermineResult(float rallodsUnspent)\n    {\n        if (_deaths > 200) { return Result.GameOver(EndManyDead(_deaths, _random)); }\n        if (_country.Countrymen < 343) { return Result.GameOver(EndOneThirdDead(_random)); }\n        if (rallodsUnspent / 100 > 5 && _starvationDeaths >= 2) { return Result.GameOver(EndMoneyLeftOver()); }\n        if (_country.Workers > _country.Countrymen) { return Result.GameOver(EndForeignWorkers(_random)); }\n        return null;\n    }\n}\n"
  },
  {
    "path": "53_King/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "53_King/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "53_King/javascript/king.html",
    "content": "<html>\n<head>\n<title>KING</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"king.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "53_King/javascript/king.js",
    "content": "// KING\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nfunction hate_your_guts()\n{\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"OVER ONE THIRD OF THE POPULATION HAS DIED SINCE YOU\\n\");\n    print(\"WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\\n\");\n    print(\"HATE YOUR GUTS.\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"KING\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    str = await input();\n    n5 = 8;\n    if (str == \"AGAIN\") {\n        while (1) {\n            print(\"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED\");\n            x5 = parseInt(await input());\n            if (x5 == 0)\n                return;\n            if (x5 < 8)\n                break;\n            print(\"   COME ON, YOUR TERM IN OFFICE IS ONLY \" + n5 + \" YEARS.\\n\");\n        }\n        print(\"HOW MUCH DID YOU HAVE IN THE TREASURY\");\n        a = parseInt(await input());\n        if (a < 0)\n            return;\n        print(\"HOW MANY COUNTRYMEN\");\n        b = parseInt(await input());\n        if (b < 0)\n            return;\n        print(\"HOW MANY WORKERS\");\n        c = parseInt(await input());\n        if (c < 0)\n            return;\n        while (1) {\n            print(\"HOW MANY SQUARE MILES OF LAND\");\n            d = parseInt(await input());\n            if (d < 0)\n                return;\n            if (d > 1000 && d <= 2000)\n                break;\n            print(\"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\\n\");\n            print(\"   AND 10,000 SQ. MILES OF FOREST LAND.\\n\");\n        }\n    } else {\n        if (str.substr(0, 1) != \"N\") {\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\\n\");\n            print(\"DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\\n\");\n            print(\"JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\\n\");\n            print(\"MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\\n\");\n            print(\"THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\\n\");\n            print(\"RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\\n\");\n            print(\"FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\\n\");\n            print(\"FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\\n\");\n            print(\"WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\\n\");\n            print(\"TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\\n\");\n            print(\"THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\\n\");\n            print(\"SQUARE MILE TO PLANT.\\n\");\n            print(\"YOUR GOAL IS TO COMPLETE YOUR \" + n5 + \" YEAR TERM OF OFFICE.\\n\");\n            print(\"GOOD LUCK!\\n\");\n        }\n        print(\"\\n\");\n        a = Math.floor(60000 + (1000 * Math.random()) - (1000 * Math.random()));\n        b = Math.floor(500 + (10 * Math.random()) - (10 * Math.random()));\n        c = 0;\n        d = 2000;\n        x5 = 0;\n    }\n    v3 = 0;\n    b5 = 0;\n    x = false;\n    while (1) {\n        w = Math.floor(10 * Math.random() + 95);\n        print(\"\\n\");\n        print(\"YOU NOW HAVE \" + a + \" RALLODS IN THE TREASURY.\\n\");\n        print(b + \" COUNTRYMEN, \");\n        v9 = Math.floor(((Math.random() / 2) * 10 + 10));\n        if (c != 0)\n            print(c + \" FOREIGN WORKERS, \");\n        print(\"AND \" + Math.floor(d) + \" SQ. MILES OF LAND.\\n\");\n        print(\"THIS YEAR INDUSTRY WILL BUY LAND FOR \" + w + \" \");\n        print(\"RALLODS PER SQUARE MILE.\\n\");\n        print(\"LAND CURRENTLY COSTS \" + v9 + \" RALLODS PER SQUARE MILE TO PLANT.\\n\");\n        print(\"\\n\");\n        while (1) {\n            print(\"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY\");\n            h = parseInt(await input());\n            if (h < 0)\n                continue;\n            if (h <= d - 1000)\n                break;\n            print(\"***  THINK AGAIN. YOU ONLY HAVE \" + (d - 1000) + \" SQUARE MILES OF FARM LAND.\\n\");\n            if (x == false) {\n                print(\"\\n\");\n                print(\"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\\n\");\n                print(\"FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\\n\");\n                print(\"THICKER TOP SOIL, ETC.)\\n\");\n                x = true;\n            }\n        }\n        d = Math.floor(d - h);\n        a = Math.floor(a + (h * w));\n        while (1) {\n            print(\"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN\");\n            i = parseInt(await input());\n            if (i < 0)\n                continue;\n            if (i < a)\n                break;\n            if (i == a) {\n                j = 0;\n                k = 0;\n                a = 0;\n                break;\n            }\n            print(\"   THINK AGAIN. YOU'VE ONLY \" + a + \" RALLODS IN THE TREASURY\\n\");\n        }\n        if (a) {\n            a = Math.floor(a - i);\n            while (1) {\n                print(\"HOW MANY SQUARE MILES DO YOU WISH TO PLANT\");\n                j = parseInt(await input());\n                if (j < 0)\n                    continue;\n                if (j <= b * 2) {\n                    if (j <= d - 1000) {\n                        u1 = Math.floor(j * v9);\n                        if (u1 > a) {\n                            print(\"   THINK AGAIN. YOU'VE ONLY \" + a + \" RALLODS LEFT IN THE TREASURY.\\n\");\n                            continue;\n                        } else if (u1 == a) {\n                            k = 0;\n                            a = 0;\n                        }\n                        break;\n                    }\n                    print(\"   SORRY, BUT YOU'VE ONLY \" + (d - 1000) + \" SQ. MILES OF FARM LAND.\\n\");\n                    continue;\n                }\n                print(\"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\\n\");\n            }\n        }\n        if (a) {\n            a -= u1;\n            while (1) {\n                print(\"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL\");\n                k = parseInt(await input());\n                if (k < 0)\n                    continue;\n                if (k <= a)\n                    break;\n                print(\"   THINK AGAIN. YOU ONLY HAVE \" + a + \" RALLODS REMAINING.\\n\");\n            }\n        }\n        if (h == 0 && i == 0 && j == 0 && k == 0) {\n            print(\"GOODBYE.\\n\");\n            print(\"(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\\n\");\n            print(\"'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\\n\");\n            print(\"OF THE GAME).\\n\");\n            return;\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        a = Math.floor(a - k);\n        a4 = a;\n        if (Math.floor(i / 100 - b) < 0) {\n            if (i / 100 < 50) {\n                hate_your_guts();\n                break;\n            }\n            print(Math.floor(b - (i / 100)) + \" COUNTRYMEN DIED OF STARVATION\\n\");\n        }\n        f1 = Math.floor(Math.random() * (2000 - d));\n        if (k >= 25)\n            f1 = Math.floor(f1 / (k / 25));\n        if (f1 > 0)\n            print(f1 + \" COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\\n\");\n        funeral = false;\n        if (Math.floor((i / 100) - b) >= 0) {\n            if (f1 > 0) {\n                print(\"   YOU WERE FORCED TO SPEND \" + Math.floor(f1 * 9) + \" RALLODS ON \");\n                print(\"FUNERAL EXPENSES.\\n\");\n                b5 = f1;\n                a = Math.floor(a - (f1 * 9));\n                funeral = true;\n            }\n        } else {\n            print(\"   YOU WERE FORCED TO SPEND \" + Math.floor((f1 + (b - (i / 100))) * 9));\n            print(\" RALLODS ON FUNERAL EXPENSES.\\n\");\n            b5 = Math.floor(f1 + (b - (i / 100)));\n            a = Math.floor(a - ((f1 + (b - (i / 100))) * 9));\n            funeral = true;\n        }\n        if (funeral) {\n            if (a < 0) {\n                print(\"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\\n\");\n                d = Math.floor(d + (a / w));\n                a = 0;\n            }\n            b = Math.floor(b - b5);\n        }\n        c1 = 0;\n        if (h != 0) {\n            c1 = Math.floor(h + (Math.random() * 10) - (Math.random() * 20));\n            if (c <= 0)\n                c1 += 20;\n            print(c1 + \" WORKERS CAME TO THE COUNTRY AND \");\n        }\n        p1 = Math.floor(((i / 100 - b) / 10) + (k / 25) - ((2000 - d) / 50) - (f1 / 2));\n        print(Math.abs(p1) + \" COUNTRYMEN \");\n        if (p1 >= 0)\n            print(\"CAME TO\");\n        else\n            print(\"LEFT\");\n        print(\" THE ISLAND.\\n\");\n        b = Math.floor(b + p1);\n        c = Math.floor(c + c1);\n        u2 = Math.floor(((2000 - d) * ((Math.random() + 1.5) / 2)));\n        if (c != 0) {\n            print(\"OF \" + Math.floor(j) + \" SQ. MILES PLANTED,\");\n        }\n        if (j <= u2)\n            u2 = j;\n        print(\" YOU HARVESTED \" + Math.floor(j - u2) + \" SQ. MILES OF CROPS.\\n\");\n        if (u2 != 0 && t1 < 2) {\n            print(\"   (DUE TO \");\n            if (t1 != 0)\n                print(\"INCREASED \");\n            print(\"AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\\n\");\n        }\n        q = Math.floor((j - u2) * (w / 2));\n        print(\"MAKING \" + q + \" RALLODS.\\n\");\n        a = Math.floor(a + q);\n        v1 = Math.floor(((b - p1) * 22) + (Math.random() * 500));\n        v2 = Math.floor((2000 - d) * 15);\n        print(\" YOU MADE \" + Math.abs(Math.floor(v1 - v2)) + \" RALLODS FROM TOURIST TRADE.\\n\");\n        if (v2 != 0 && v1 - v2 < v3) {\n            print(\"   DECREASE BECAUSE \");\n            g1 = 10 * Math.random();\n            if (g1 <= 2)\n                print(\"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\\n\");\n            else if (g1 <= 4)\n                print(\"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\\n\");\n            else if (g1 <= 6)\n                print(\"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\\n\");\n            else if (g1 <= 8)\n                print(\"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\\n\");\n            else if (g1 <= 10)\n                print(\"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\\n\");\n        }\n        v3 = Math.floor(a + v3);    // Probable bug from original game\n        a = Math.floor(a + v3);\n        if (b5 > 200) {\n            print(\"\\n\");\n            print(\"\\n\");\n            print(b5 + \" COUNTRYMEN DIED IN ONE YEAR!!!!!\\n\");\n            print(\"DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\\n\");\n            print(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\\n\");\n            m6 = Math.floor(Math.random() * 10);\n            if (m6 <= 3)\n                print(\"ALSO HAD YOUR LEFT EYE GOUGED OUT!\\n\");\n            else if (m6 <= 6)\n                print(\"HAVE ALSO GAINED A VERY BAD REPUTATION.\\n\");\n            else\n                print(\"HAVE ALSO BEEN DECLARED NATIONAL FINK.\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            return;\n        }\n        if (b < 343) {\n            hate_your_guts();\n            break;\n        }\n        if (a4 / 100 > 5 && b5 - f1 >= 2) {\n            print(\"\\n\");\n            print(\"MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\\n\");\n            print(\"NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\\n\");\n            print(\"OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\\n\");\n            print(\"BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\\n\");\n            print(\"THE CHOICE IS YOURS.\\n\");\n            print(\"IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\\n\");\n            print(\"BEFORE PROCEEDING.\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            return;\n        }\n        if (c > b) {\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\\n\");\n            print(\"OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\\n\");\n            print(\"TAKEN OVER THE COUNTRY.\\n\");\n            break;\n        }\n        if (n5 - 1 == x5) {\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"CONGRATULATIONS!!!!!!!!!!!!!!!!!!\\n\");\n            print(\"YOU HAVE SUCCESFULLY COMPLETED YOUR \" + n5 + \" YEAR TERM\\n\");\n            print(\"OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\\n\");\n            print(\"NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\\n\");\n            print(\"LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\\n\");\n            print(\"PLAYS THIS GAME.\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            return;\n        }\n        x5++;\n        b5 = 0;\n    }\n    if (Math.random() <= 0.5) {\n        print(\"YOU HAVE BEEN ASSASSINATED.\\n\");\n    } else {\n        print(\"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\\n\");\n        print(\"RESIDING IN PRISON.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "53_King/king.bas",
    "content": "1 PRINT TAB(34);\"KING\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"DO YOU WANT INSTRUCTIONS\";\n5 INPUT Z$\n6 N5=8\n10 IF LEFT$(Z$,1)=\"N\" THEN 47\n11 IF Z$=\"AGAIN\" THEN 1960\n12 PRINT:PRINT:PRINT\n20 PRINT \"CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\"\n22 PRINT \"DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\"\n24 PRINT \"JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\"\n26 PRINT \"MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\"\n28 PRINT \"THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\"\n30 PRINT \"RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\"\n32 PRINT \"FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\"\n34 PRINT \"FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\"\n36 PRINT \"WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\"\n38 PRINT \"TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\"\n40 PRINT \"THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\"\n42 PRINT \"SQUARE MILE TO PLANT.\"\n44 PRINT \"YOUR GOAL IS TO COMPLETE YOUR\";N5;\"YEAR TERM OF OFFICE.\"\n46 PRINT \"GOOD LUCK!\"\n47 PRINT\n50 A=INT(60000+(1000*RND(1))-(1000*RND(1)))\n55 B=INT(500+(10*RND(1))-(10*RND(1)))\n65 D=2000\n100 W=INT(10*RND(1)+95)\n102 PRINT\n105 PRINT \"YOU NOW HAVE \";A;\" RALLODS IN THE TREASURY.\"\n110 PRINT INT(B);:PRINT \"COUNTRYMEN, \";\n115 V9=INT(((RND(1)/2)*10+10))\n120 IF C=0 THEN 140\n130 PRINT INT(C);\"FOREIGN WORKERS, \";\n140 PRINT \"AND\";INT(D);\"SQ. MILES OF LAND.\"\n150 PRINT \"THIS YEAR INDUSTRY WILL BUY LAND FOR\";W;\n152 PRINT \"RALLODS PER SQUARE MILE.\"\n155 PRINT \"LAND CURRENTLY COSTS\";V9;\"RALLODS PER SQUARE MILE TO PLANT.\"\n162 PRINT\n200 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY\";\n210 INPUT H\n215 IF H<0 THEN 200\n220 IF H<=D-1000 THEN 300\n230 PRINT \"***  THINK AGAIN. YOU ONLY HAVE\";D-1000;\"SQUARE MILES OF FARM LAND.\"\n240 IF X<>0 THEN 200\n250 PRINT:PRINT \"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\"\n260 PRINT \"FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\"\n270 PRINT \"THICKER TOP SOIL, ETC.)\"\n280 X=1\n299 GOTO 200\n300 D=INT(D-H)\n310 A=INT(A+(H*W))\n320 PRINT \"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN\";\n340 INPUT I\n342 IF I<0 THEN 320\n350 IF I<A THEN 400\n360 IF I=A THEN 380\n370 PRINT \"   THINK AGAIN. YOU'VE ONLY\";A;\" RALLODS IN THE TREASURY\"\n375 GOTO 320\n380 J=0\n390 K=0\n395 A=0\n399 GOTO 1000\n400 A=INT(A-I)\n410 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO PLANT\";\n420 INPUT J\n421 IF J<0 THEN 410\n422 IF J<=B*2 THEN 426\n423 PRINT \"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\"\n424 GOTO 410\n426 IF J<=D-1000 THEN 430\n427 PRINT \"   SORRY, BUT YOU'VE ONLY\";D-1000;\"SQ. MILES OF FARM LAND.\"\n428 GOTO 410\n430 U1=INT(J*V9)\n435 IF U1<A THEN 500\n440 IF U1=A THEN 490\n450 PRINT \"   THINK AGAIN. YOU'VE ONLY\";A;\" RALLODS LEFT IN THE TREASURY.\"\n460 GOTO 410\n490 K=0\n495 A=0\n499 GOTO 1000\n500 A=A-U1\n510 PRINT \"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL\";\n520 INPUT K\n522 IF K<0 THEN 510\n530 IF K<=A THEN 1000\n540 PRINT \"   THINK AGAIN. YOU ONLY HAVE \";A;\" RALLODS REMAINING.\"\n550 GOTO 510\n600 IF H<>0 THEN 1002\n602 IF I<>0 THEN 1002\n604 IF J<>0 THEN 1002\n606 IF K<>0 THEN 1002\n609 PRINT\n612 PRINT \"GOODBYE.\"\n614 PRINT \"(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\"\n616 PRINT \"'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\"\n617 PRINT \"OF THE GAME).\"\n618 STOP\n1000 GOTO 600\n1002 PRINT\n1003 PRINT\n1010 A=INT(A-K)\n1020 A4=A\n1100 IF INT(I/100-B)>=0 THEN 1120\n1105 IF I/100<50 THEN 1700\n1110 PRINT INT(B-(I/100));\"COUNTRYMEN DIED OF STARVATION\"\n1120 F1=INT(RND(1)*(2000-D))\n1122 IF K<25 THEN 1130\n1125 F1=INT(F1/(K/25))\n1130 IF F1<=0 THEN 1150\n1140 PRINT F1;\"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\"\n1150 IF INT((I/100)-B)<0 THEN 1170\n1160 IF F1>0 THEN 1180\n1165 GOTO 1200\n1170 PRINT \"   YOU WERE FORCED TO SPEND\";INT((F1+(B-(I/100)))*9);\n1172 PRINT \"RALLODS ON FUNERAL EXPENSES\"\n1174 B5=INT(F1+(B-(I/100)))\n1175 A=INT(A-((F1+(B-(I/100)))*9))\n1176 GOTO 1185\n1180 PRINT \"   YOU WERE FORCED TO SPEND \";INT(F1*9);\"RALLODS ON \";\n1181 PRINT \"FUNERAL EXPENSES.\"\n1182 B5=F1\n1183 A=INT(A-(F1*9))\n1185 IF A>=0 THEN 1194\n1187 PRINT \"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\"\n1189 D=INT(D+(A/W))\n1190 A=0\n1194 B=INT(B-B5)\n1200 IF H=0 THEN 1250\n1220 C1=INT(H+(RND(1)*10)-(RND(1)*20))\n1224 IF C>0 THEN 1230\n1226 C1=C1+20\n1230 PRINT C1;\"WORKERS CAME TO THE COUNTRY AND\";\n1250 P1=INT(((I/100-B)/10)+(K/25)-((2000-D)/50)-(F1/2))\n1255 PRINT ABS(P1);\"COUNTRYMEN \";\n1260 IF P1<0 THEN 1275\n1265 PRINT \"CAME TO\";\n1270 GOTO 1280\n1275 PRINT \"LEFT\";\n1280 PRINT \" THE ISLAND.\"\n1290 B=INT(B+P1)\n1292 C=INT(C+C1)\n1305 U2=INT(((2000-D)*((RND(1)+1.5)/2)))\n1310 IF C=0 THEN 1324\n1320 PRINT \"OF \";INT(J);\"SQ. MILES PLANTED,\";\n1324 IF J>U2 THEN 1330\n1326 U2=J\n1330 PRINT \" YOU HARVESTED \";INT(J-U2);\"SQ. MILES OF CROPS.\"\n1340 IF U2=0 THEN 1370\n1344 IF T1>=2 THEN 1370\n1350 PRINT \"   (DUE TO \";\n1355 IF T1=0 THEN 1365\n1360 PRINT \"INCREASED \";\n1365 PRINT \"AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\"\n1370 Q=INT((J-U2)*(W/2))\n1380 PRINT \"MAKING\";INT(Q);\"RALLODS.\"\n1390 A=INT(A+Q)\n1400 V1=INT(((B-P1)*22)+(RND(1)*500))\n1405 V2=INT((2000-D)*15)\n1410 PRINT \" YOU MADE\";ABS(INT(V1-V2));\"RALLODS FROM TOURIST TRADE.\"\n1420 IF V2=0 THEN 1450\n1425 IF V1-V2>=V3 THEN 1450\n1430 PRINT \"   DECREASE BECAUSE \";\n1435 G1=10*RND(1)\n1440 IF G1<=2 THEN 1460\n1442 IF G1<=4 THEN 1465\n1444 IF G1<=6 THEN 1470\n1446 IF G1<=8 THEN 1475\n1448 IF G1<=10 THEN 1480\n1450 V3=INT(A+V3)\n1451 A=INT(A+V3)\n1452 GOTO 1500\n1460 PRINT \"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\"\n1462 GOTO 1450\n1465 PRINT \"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\"\n1467 GOTO 1450\n1470 PRINT \"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\"\n1472 GOTO 1450\n1475 PRINT \"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\"\n1477 GOTO 1450\n1480 PRINT \"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\"\n1482 GOTO 1450\n1500 IF B5>200 THEN 1600\n1505 IF B<343 THEN 1700\n1510 IF (A4/100)>5 THEN 1800\n1515 IF C>B THEN 1550\n1520 IF N5-1=X5 THEN 1900\n1545 GOTO 2000\n1550 PRINT\n1552 PRINT\n1560 PRINT \"THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\"\n1562 PRINT \"OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\"\n1564 PRINT \"TAKEN OVER THE COUNTRY.\"\n1570 IF RND(1)<=.5 THEN 1580\n1574 PRINT \"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\"\n1576 PRINT \"RESIDING IN PRISON.\"\n1578 GOTO 1590\n1580 PRINT \"YOU HAVE BEEN ASSASSINATED.\"\n1590 PRINT\n1592 PRINT\n1596 STOP\n1600 PRINT\n1602 PRINT\n1610 PRINT B5;\"COUNTRYMEN DIED IN ONE YEAR!!!!!\"\n1615 PRINT \"DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\"\n1620 PRINT \"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\"\n1622 M6=INT(RND(1)*10)\n1625 IF M6<=3 THEN 1670\n1630 IF M6<=6 THEN 1680\n1635 IF M6<=10 THEN 1690\n1670 PRINT \"ALSO HAD YOUR LEFT EYE GOUGED OUT!\"\n1672 GOTO 1590\n1680 PRINT \"HAVE ALSO GAINED A VERY BAD REPUTATION.\"\n1682 GOTO 1590\n1690 PRINT \"HAVE ALSO BEEN DECLARED NATIONAL FINK.\"\n1692 GOTO 1590\n1700 PRINT\n1702 PRINT\n1710 PRINT \"OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\"\n1715 PRINT \"WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\"\n1720 PRINT \"HATE YOUR GUTS.\"\n1730 GOTO 1570\n1800 IF B5-F1<2 THEN 1515\n1807 PRINT\n1815 PRINT \"MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\"\n1820 PRINT \"NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\"\n1825 PRINT \"OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\"\n1830 PRINT \"BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\"\n1835 PRINT \"THE CHOICE IS YOURS.\"\n1840 PRINT \"IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\"\n1845 PRINT \"BEFORE PROCEEDING.\"\n1850 GOTO 1590\n1900 PRINT\n1902 PRINT\n1920 PRINT \"CONGRATULATIONS!!!!!!!!!!!!!!!!!!\"\n1925 PRINT \"YOU HAVE SUCCESFULLY COMPLETED YOUR\";N5;\"YEAR TERM\"\n1930 PRINT \"OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\"\n1935 PRINT \"NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\"\n1940 PRINT \"LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\"\n1945 PRINT \"PLAYS THIS GAME.\"\n1950 GOTO 1590\n1960 PRINT \"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED\";\n1961 INPUT X5\n1962 IF X5<0 THEN 1590\n1963 IF X5<8 THEN 1969\n1965 PRINT \"   COME ON, YOUR TERM IN OFFICE IS ONLY\";N5;\"YEARS.\"\n1967 GOTO 1960\n1969 PRINT \"HOW MUCH DID YOU HAVE IN THE TREASURY\";\n1970 INPUT A\n1971 IF A<0 THEN 1590\n1975 PRINT \"HOW MANY COUNTRYMEN\";\n1976 INPUT B\n1977 IF B<0 THEN 1590\n1980 PRINT \"HOW MANY WORKERS\";\n1981 INPUT C\n1982 IF C<0 THEN 1590\n1990 PRINT \"HOW MANY SQUARE MILES OF LAND\";\n1991 INPUT D\n1992 IF D<0 THEN 1590\n1993 IF D>2000 THEN 1996\n1994 IF D>1000 THEN 100\n1996 PRINT \"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\"\n1997 PRINT \"   AND 10,000 SQ. MILES OF FOREST LAND.\"\n1998 GOTO 1990\n2000 X5=X5+1\n2020 B5=0\n2040 GOTO 100\n2046 END\n"
  },
  {
    "path": "53_King/king_variable_update.bas",
    "content": "1 PRINT TAB(34);\"KING\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"DO YOU WANT INSTRUCTIONS\";\n5 INPUT Z$\n6 YEARS_REQUIRED=8\n10 IF LEFT$(Z$,1)=\"N\" THEN 47\n    11 IF Z$=\"AGAIN\" THEN 1960\n    12 PRINT:PRINT:PRINT\n    20 PRINT \"CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\"\n    22 PRINT \"DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\"\n    24 PRINT \"JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\"\n    26 PRINT \"MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\"\n    28 PRINT \"THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\"\n    30 PRINT \"RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\"\n    32 PRINT \"FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\"\n    34 PRINT \"FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\"\n    36 PRINT \"WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\"\n    38 PRINT \"TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\"\n    40 PRINT \"THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\"\n    42 PRINT \"SQUARE MILE TO PLANT.\"\n    44 PRINT \"YOUR GOAL IS TO COMPLETE YOUR\";YEARS_REQUIRED;\"YEAR TERM OF OFFICE.\"\n    46 PRINT \"GOOD LUCK!\"\n\n47 PRINT\n\n50 RALLODS=INT(60000+(1000*RND(1))-(1000*RND(1)))\n55 COUNTRYMEN=INT(500+(10*RND(1))-(10*RND(1)))\n65 LANDAREA=2000\n100 LANDPRICE=INT(10*RND(1)+95)\n102 PRINT\n105 PRINT \"YOU NOW HAVE \";RALLODS;\" RALLODS IN THE TREASURY.\"\n110 PRINT INT(COUNTRYMEN);:PRINT \"COUNTRYMEN, \";\n115 COST_TO_PLANT=INT(((RND(1)/2)*10+10))\n120 IF FOREIGN_WORKERS=0 THEN 140\n130 PRINT INT(FOREIGN_WORKERS);\"FOREIGN WORKERS, \";\n140 PRINT \"AND\";INT(LANDAREA);\"SQ. MILES OF LAND.\"\n150 PRINT \"THIS YEAR INDUSTRY WILL BUY LAND FOR\";LANDPRICE;\n152 PRINT \"RALLODS PER SQUARE MILE.\"\n155 PRINT \"LAND CURRENTLY COSTS\";COST_TO_PLANT;\"RALLODS PER SQUARE MILE TO PLANT.\"\n162 PRINT\n\n200 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY\";\n210 INPUT SELL_TO_INDUSTRY\n215 IF SELL_TO_INDUSTRY<0 THEN 200\n220 IF SELL_TO_INDUSTRY<=LANDAREA-1000 THEN 300\n230 PRINT \"***  THINK AGAIN. YOU ONLY HAVE\";LANDAREA-1000;\"SQUARE MILES OF FARM LAND.\"\n\n240 IF EXPLANATION_GIVEN THEN 200\n    250 PRINT:PRINT \"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\"\n    260 PRINT \"FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\"\n    270 PRINT \"THICKER TOP SOIL, ETC.)\"\n    280 EXPLANATION_GIVEN=TRUE\n299 GOTO 200\n\n300 LANDAREA=INT(LANDAREA-SELL_TO_INDUSTRY)\n310 RALLODS=INT(RALLODS+(SELL_TO_INDUSTRY*LANDPRICE))\n320 PRINT \"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN\";\n340 INPUT WELFARE\n342 IF WELFARE<0 THEN 320\n350 IF WELFARE<RALLODS THEN 400\n360 IF WELFARE=RALLODS THEN 380\n370 PRINT \"   THINK AGAIN. YOU'VE ONLY\";RALLODS;\" RALLODS IN THE TREASURY\"\n375 GOTO 320\n\n380 PLANTING_AREA=0\n390 MONEY_SPENT_ON_POLLUTION_CONTROL=0\n395 RALLODS=0\n399 GOTO 600\n\n400 RALLODS=INT(RALLODS-WELFARE)\n\n410 PRINT \"HOW MANY SQUARE MILES DO YOU WISH TO PLANT\";\n420 INPUT PLANTING_AREA\n421 IF PLANTING_AREA<0 THEN 410\n422 IF PLANTING_AREA<=COUNTRYMEN*2 THEN 426\n423 PRINT \"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\"\n424 GOTO 410\n\n426 IF PLANTING_AREA<=LANDAREA-1000 THEN 430\n427 PRINT \"   SORRY, BUT YOU'VE ONLY\";LANDAREA-1000;\"SQ. MILES OF FARM LAND.\"\n428 GOTO 410\n\n430 MONEY_SPENT_ON_PLANTING=INT(PLANTING_AREA*COST_TO_PLANT)\n435 IF MONEY_SPENT_ON_PLANTING<RALLODS THEN 500\n440 IF MONEY_SPENT_ON_PLANTING=RALLODS THEN 490\n450 PRINT \"   THINK AGAIN. YOU'VE ONLY\";RALLODS;\" RALLODS LEFT IN THE TREASURY.\"\n460 GOTO 410\n\n490 MONEY_SPENT_ON_POLLUTION_CONTROL=0\n495 RALLODS=0\n499 GOTO 600\n\n500 RALLODS=RALLODS-MONEY_SPENT_ON_PLANTING\n\n510 PRINT \"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL\";\n520 INPUT MONEY_SPENT_ON_POLLUTION_CONTROL\n\n522 IF MONEY_SPENT_ON_POLLUTION_CONTROL<0 THEN 510\n530 IF MONEY_SPENT_ON_POLLUTION_CONTROL<=RALLODS THEN 1000\n540 PRINT \"   THINK AGAIN. YOU ONLY HAVE \";RALLODS;\" RALLODS REMAINING.\"\n550 GOTO 510\n\n600 IF SELL_TO_INDUSTRY<>0 THEN 1002\n602 IF WELFARE<>0 THEN 1002\n604 IF PLANTING_AREA<>0 THEN 1002\n606 IF MONEY_SPENT_ON_POLLUTION_CONTROL<>0 THEN 1002\n\n609 PRINT\n612 PRINT \"GOODBYE.\"\n614 PRINT \"(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\"\n616 PRINT \"'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\"\n617 PRINT \"OF THE GAME).\"\n618 STOP\n\n1000 GOTO 600\n\n1002 PRINT\n1003 PRINT\n\n1010 RALLODS=INT(RALLODS-MONEY_SPENT_ON_POLLUTION_CONTROL)\n1020 ORIGINAL_RALLODS=RALLODS\n\n1100 IF INT(WELFARE/100-COUNTRYMEN)>=0 THEN 1120\n1105 IF WELFARE/100<50 THEN 1700\n1110 PRINT INT(COUNTRYMEN-(WELFARE/100));\"COUNTRYMEN DIED OF STARVATION\"\n\n1120 POLLUTION_DEATHS=INT(RND(1)*(2000-LANDAREA))\n1122 IF MONEY_SPENT_ON_POLLUTION_CONTROL<25 THEN 1130\n1125 POLLUTION_DEATHS=INT(POLLUTION_DEATHS/(MONEY_SPENT_ON_POLLUTION_CONTROL/25))\n\n1130 IF POLLUTION_DEATHS<=0 THEN 1150\n1140 PRINT POLLUTION_DEATHS;\"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\"\n\n1150 IF INT((WELFARE/100)-COUNTRYMEN)<0 THEN 1170\n1160 IF POLLUTION_DEATHS>0 THEN 1180\n1165 GOTO 1200\n\n1170 PRINT \"   YOU WERE FORCED TO SPEND\";INT((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9);\n1172 PRINT \"RALLODS ON FUNERAL EXPENSES\"\n1174 DEATHS=INT(POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))\n1175 RALLODS=INT(RALLODS-((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9))\n1176 GOTO 1185\n\n1180 PRINT \"   YOU WERE FORCED TO SPEND \";INT(POLLUTION_DEATHS*9);\"RALLODS ON \";\n1181 PRINT \"FUNERAL EXPENSES.\"\n1182 DEATHS=POLLUTION_DEATHS\n1183 RALLODS=INT(RALLODS-(POLLUTION_DEATHS*9))\n\n1185 IF RALLODS>=0 THEN 1194\n1187 PRINT \"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\"\n1189 LANDAREA=INT(LANDAREA+(RALLODS/LANDPRICE))\n1190 RALLODS=0\n\n1194 COUNTRYMEN=INT(COUNTRYMEN-DEATHS)\n\n1200 IF SELL_TO_INDUSTRY=0 THEN 1250\n1220 NEW_FOREIGNERS=INT(SELL_TO_INDUSTRY+(RND(1)*10)-(RND(1)*20))\n1224 IF FOREIGN_WORKERS>0 THEN 1230\n1226 NEW_FOREIGNERS=NEW_FOREIGNERS+20\n\n1230 PRINT NEW_FOREIGNERS;\"WORKERS CAME TO THE COUNTRY AND\";\n\n1250 IMMIGRATION=INT(((WELFARE/100-COUNTRYMEN)/10)+(MONEY_SPENT_ON_POLLUTION_CONTROL/25)-((2000-LANDAREA)/50)-(POLLUTION_DEATHS/2))\n1255 PRINT ABS(IMMIGRATION);\"COUNTRYMEN \";\n1260 IF IMMIGRATION<0 THEN 1275\n1265 PRINT \"CAME TO\";\n1270 GOTO 1280\n1275 PRINT \"LEFT\";\n1280 PRINT \" THE ISLAND.\"\n1290 COUNTRYMEN=INT(COUNTRYMEN+IMMIGRATION)\n\n\n1292 FOREIGN_WORKERS=INT(FOREIGN_WORKERS+NEW_FOREIGNERS)\n\n1305 CROP_LOSS=INT(((2000-LANDAREA)*((RND(1)+1.5)/2)))\n1310 IF FOREIGN_WORKERS=0 THEN 1324\n1320 PRINT \"OF \";INT(PLANTING_AREA);\"SQ. MILES PLANTED,\";\n1324 IF PLANTING_AREA>CROP_LOSS THEN 1330\n1326 CROP_LOSS=PLANTING_AREA\n1330 PRINT \" YOU HARVESTED \";INT(PLANTING_AREA-CROP_LOSS);\"SQ. MILES OF CROPS.\"\n1340 IF CROP_LOSS=0 THEN 1370\n1344 IF T1>=2 THEN 1370\n1350 PRINT \"   (DUE TO \";\n1355 IF T1=0 THEN 1365\n1360 PRINT \"INCREASED \";\n1365 PRINT \"AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\"\n1370 AGRICULTURAL_INCOME=INT((PLANTING_AREA-CROP_LOSS)*(LANDPRICE/2))\n1380 PRINT \"MAKING\";INT(AGRICULTURAL_INCOME);\"RALLODS.\"\n1390 RALLODS=INT(RALLODS+AGRICULTURAL_INCOME)\n\nREM I think tourism calculations are actually wrong in the original code!\n\n1400 V1=INT(((COUNTRYMEN-IMMIGRATION)*22)+(RND(1)*500))\n1405 V2=INT((2000-LANDAREA)*15)\n1410 PRINT \" YOU MADE\";ABS(INT(V1-V2));\"RALLODS FROM TOURIST TRADE.\"\n1420 IF V2=0 THEN 1450\n1425 IF V1-V2>=V3 THEN 1450\n1430 PRINT \"   DECREASE BECAUSE \";\n1435 G1=10*RND(1)\n1440 IF G1<=2 THEN 1460\n1442 IF G1<=4 THEN 1465\n1444 IF G1<=6 THEN 1470\n1446 IF G1<=8 THEN 1475\n1448 IF G1<=10 THEN 1480\n1450 V3=INT(RALLODS+V3)\n1451 RALLODS=INT(RALLODS+V3)\n1452 GOTO 1500\n1460 PRINT \"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\"\n1462 GOTO 1450\n1465 PRINT \"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\"\n1467 GOTO 1450\n1470 PRINT \"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\"\n1472 GOTO 1450\n1475 PRINT \"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\"\n1477 GOTO 1450\n1480 PRINT \"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\"\n1482 GOTO 1450\n1500 IF DEATHS>200 THEN 1600\n1505 IF COUNTRYMEN<343 THEN 1700\n1510 IF (ORIGINAL_RALLODS/100)>5 THEN 1800\n1515 IF FOREIGN_WORKERS>COUNTRYMEN THEN 1550\n1520 IF YEARS_REQUIRED-1=X5 THEN 1900\n1545 GOTO 2000\n1550 PRINT\n1552 PRINT\n1560 PRINT \"THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\"\n1562 PRINT \"OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\"\n1564 PRINT \"TAKEN OVER THE COUNTRY.\"\n1570 IF RND(1)<=.5 THEN 1580\n1574 PRINT \"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\"\n1576 PRINT \"RESIDING IN PRISON.\"\n1578 GOTO 1590\n1580 PRINT \"YOU HAVE BEEN ASSASSINATED.\"\n1590 PRINT\n1592 PRINT\n1596 STOP\n1600 PRINT\n1602 PRINT\n1610 PRINT DEATHS;\"COUNTRYMEN DIED IN ONE YEAR!!!!!\"\n1615 PRINT \"DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\"\n1620 PRINT \"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\"\n1622 M6=INT(RND(1)*10)\n1625 IF M6<=3 THEN 1670\n1630 IF M6<=6 THEN 1680\n1635 IF M6<=10 THEN 1690\n1670 PRINT \"ALSO HAD YOUR LEFT EYE GOUGED OUT!\"\n1672 GOTO 1590\n1680 PRINT \"HAVE ALSO GAINED A VERY BAD REPUTATION.\"\n1682 GOTO 1590\n1690 PRINT \"HAVE ALSO BEEN DECLARED NATIONAL FINK.\"\n1692 GOTO 1590\n\n1700 PRINT\n1702 PRINT\n1710 PRINT \"OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\"\n1715 PRINT \"WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\"\n1720 PRINT \"HATE YOUR GUTS.\"\n1730 GOTO 1570\n1800 IF DEATHS-POLLUTION_DEATHS<2 THEN 1515\n1807 PRINT\n1815 PRINT \"MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\"\n1820 PRINT \"NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\"\n1825 PRINT \"OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\"\n1830 PRINT \"BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\"\n1835 PRINT \"THE CHOICE IS YOURS.\"\n1840 PRINT \"IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\"\n1845 PRINT \"BEFORE PROCEEDING.\"\n1850 GOTO 1590\n1900 PRINT\n1902 PRINT\n1920 PRINT \"CONGRATULATIONS!!!!!!!!!!!!!!!!!!\"\n1925 PRINT \"YOU HAVE SUCCESFULLY COMPLETED YOUR\";YEARS_REQUIRED;\"YEAR TERM\"\n1930 PRINT \"OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\"\n1935 PRINT \"NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\"\n1940 PRINT \"LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\"\n1945 PRINT \"PLAYS THIS GAME.\"\n1950 GOTO 1590\n\n1960 PRINT \"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED\";\n1961 INPUT X5\n1962 IF X5<0 THEN 1590\n1963 IF X5<8 THEN 1969\n1965 PRINT \"   COME ON, YOUR TERM IN OFFICE IS ONLY\";YEARS_REQUIRED;\"YEARS.\"\n1967 GOTO 1960\n1969 PRINT \"HOW MUCH DID YOU HAVE IN THE TREASURY\";\n1970 INPUT RALLODS\n1971 IF RALLODS<0 THEN 1590\n1975 PRINT \"HOW MANY COUNTRYMEN\";\n1976 INPUT COUNTRYMEN\n1977 IF COUNTRYMEN<0 THEN 1590\n1980 PRINT \"HOW MANY WORKERS\";\n1981 INPUT FOREIGN_WORKERS\n1982 IF FOREIGN_WORKERS<0 THEN 1590\n1990 PRINT \"HOW MANY SQUARE MILES OF LAND\";\n1991 INPUT LANDAREA\n1992 IF LANDAREA<0 THEN 1590\n1993 IF LANDAREA>2000 THEN 1996\n1994 IF LANDAREA>1000 THEN 100\n1996 PRINT \"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\"\n1997 PRINT \"   AND 10,000 SQ. MILES OF FOREST LAND.\"\n1998 GOTO 1990\n\n2000 X5=X5+1\n2020 DEATHS=0\n2040 GOTO 100\n2046 END\n"
  },
  {
    "path": "53_King/kotlin/King.kt",
    "content": "package king53\n\nimport kotlin.math.abs\nimport kotlin.random.Random\nimport kotlin.system.exitProcess\n\nlateinit var gameState: GameState\nconst val KEEP_ORIGINAL_BUGS = false\nconst val KEEP_ORIGINAL_SUICIDE_REFERENCE = false\n\nval rnd: Double get() = Random.nextDouble()\nfun tab(i: Int) = \" \".repeat(i)\nclass EndOfInputException : Throwable()\n\nfun main() {\n    header()\n\n    print(\"DO YOU WANT INSTRUCTIONS? \")\n    readLine()?.apply {\n        gameState = if (startsWith(\"AGAIN\")) loadOldGame() else GameState()\n        if (startsWith(\"Y\")) instructions(gameState.yearsRequired)\n    }\n        ?: throw EndOfInputException()\n\n    with(gameState) {\n        do {\n\n            recalculateLandCost()\n            displayStatus()\n            inputLandSale()\n            performLandSale()\n            inputWelfare()\n            performWelfare()\n            inputPlantingArea()\n            performPlanting()\n            inputPollutionControl()\n            if (zeroInput()) {\n                displayExitMessage()\n                exitProcess(0)\n            }\n            val yearResult = simulateOneYear().also {\n                it.displayConsequences()\n            }\n        } while (yearResult == YearOutcome.ContinueNextYear)\n    }\n}\n\nprivate fun header() {\n    println(\"${tab(34)}KING\")\n    println(\"${tab(14)}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    println()\n    println()\n    println()\n}\n\nfun instructions(yearsRequired: Int) {\n    println(\n        \"\"\"\n\n\n        CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\n        DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\n        JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\n        MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\n        THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\n        RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\n        FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\n        FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\n        WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\n        TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\n        THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\n        SQUARE MILE TO PLANT.\n        YOUR GOAL IS TO COMPLETE YOUR $yearsRequired YEAR TERM OF OFFICE.\n        GOOD LUCK!\n        \"\"\".trimIndent()\n    )\n}\n\nfun loadOldGame(): GameState = GameState().apply {\n\n    do {\n        var retry = false\n        print(\"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? \")\n        currentYear = validatedInput { it > 0 }\n\n        if (currentYear >= yearsRequired) {\n            println(\"   COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.\")\n            retry = true\n        }\n\n    } while (retry)\n\n    print(\"HOW MUCH DID YOU HAVE IN THE TREASURY? \")\n    rallods = validatedInput { it >= 0 }\n\n    print(\"HOW MANY COUNTRYMEN? \")\n    countrymen = validatedInput { it >= 0 }\n\n    print(\"HOW MANY WORKERS? \")\n    foreignWorkers = validatedInput { it >= 0 }\n\n    do {\n        var retry = false\n        print(\"HOW MANY SQUARE MILES OF LAND? \")\n        landArea = validatedInput { it >= 0 }\n\n        if (landArea > 2000 || landArea <= 1000) {\n            println(\"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\")\n            println(\"   AND 10,000 SQ. MILES OF FOREST LAND.\")\n            retry = true\n        }\n    } while (retry)\n\n}\n\n\n/**\n * Possible outcomes for a year.\n */\nsealed class YearOutcome {\n\n    /**\n     * Display output for the end of the year, for each different possible\n     * year outcome.\n     */\n    open fun displayConsequences() {\n        // Default display nothing\n    }\n\n    fun finalFate() {\n        if (rnd < .5) {\n            println(\"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\")\n            println(\"RESIDING IN PRISON.\")\n        } else {\n            println(\"YOU HAVE BEEN ASSASSINATED.\")\n        }\n        println()\n        println()\n    }\n\n    object ContinueNextYear : YearOutcome()\n\n    class Win(private val yearsRequired: Int) : YearOutcome() {\n        override fun displayConsequences() {\n            // The misspelling of \"successfully\" is in the original code.\n            println(\n                \"\"\"\n\n                CONGRATULATIONS!!!!!!!!!!!!!!!!!!\n                YOU HAVE SUCCESFULLY COMPLETED YOUR $yearsRequired YEAR TERM\n                OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\n                NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\n                LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\n                PLAYS THIS GAME.\n\n\n            \"\"\".trimIndent()\n            )\n        }\n    }\n\n    class ExtremeMismanagement(private val death: Int) : YearOutcome() {\n        override fun displayConsequences() {\n            println()\n            println(\"$death COUNTRYMEN DIED IN ONE YEAR!!!!!\")\n            println(\"DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\")\n            println(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\")\n            println(\n                when ((rnd * 10.0).toInt()) {\n                    in 0..3 -> \"ALSO HAD YOUR LEFT EYE GOUGED OUT!\"\n                    in 4..6 -> \"HAVE ALSO GAINED A VERY BAD REPUTATION.\"\n                    else -> \"HAVE ALSO BEEN DECLARED NATIONAL FINK.\"\n                }\n            )\n        }\n    }\n\n    object TooManyPeopleDead : YearOutcome() {\n        // The mistyping of \"population\" is in the original game.\n        override fun displayConsequences() {\n            println(\n                \"\"\"\n\n\n            OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\n            WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\n            HATE YOUR GUTS.\n        \"\"\".trimIndent()\n            )\n            finalFate()\n        }\n    }\n\n    object AntiImmigrationRevolution : YearOutcome() {\n        override fun displayConsequences() {\n            println(\n                \"\"\"\n            THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\n            OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\n            TAKEN OVER THE COUNTRY.\n        \"\"\".trimIndent()\n            )\n            finalFate()\n        }\n    }\n\n    object StarvationWithFullTreasury : YearOutcome() {\n        override fun displayConsequences() {\n            println(\n                if (KEEP_ORIGINAL_SUICIDE_REFERENCE) {\n                    \"\"\"\n                    MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\n                    NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\n                    OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\n                    BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\n                    THE CHOICE IS YOURS.\n                    IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\n                    BEFORE PROCEEDING.\n                \"\"\".trimIndent()\n                } else {\n                    \"\"\"\n                    MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\n                    NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\n                    OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\n                    BEEN FORCED TO RESIGN.\n                    PLEASE TURN OFF YOUR COMPUTER AND SURRENDER IT TO\n                    THE NEAREST POLICE STATION.\n                \"\"\".trimIndent()\n                }\n            )\n        }\n    }\n\n}\n\n/**\n * Record data, allow data input, and process the simulation for the game.\n */\nclass GameState(val yearsRequired: Int = 8) {\n\n    /**\n     * The current year. Years start with zero, but we never\n     * output the current year.\n     */\n    var currentYear = 0\n\n    /**\n     * Keep track of each year's crop loss, so we can report increases.\n     */\n    private var lastYearsCropLoss: Int = 0\n\n    /**\n     * Number of countrymen who have died of either pollution\n     * or starvation this year.\n     *  It costs 9 rallods to bury a body.\n     *  If you lose 200 people in one year, you will throw an {@see ExtremeMismanagementException}\n     */\n    private var death = 0\n\n    /**\n     * Last year's tourist numbers. Use this to check whether the number\n     * of tourists has gone up or down each year.\n     */\n    private var tourists = 0\n\n    private var moneySpentOnPollutionControl = 0\n\n    private var moneySpentOnPlanting = 0\n    /**\n     * Current stock of rallods.\n     * Player starts with between 59000 and 61000 rallods, but\n     * mostly distributed close to 60000. 75% of the time it's\n     * between 59500 and 60500.\n     */\n    var rallods = (60000.0 + (1000.0 * rnd) - (1000.0 * rnd)).toInt()\n\n    /**\n     * Population.\n     * Initial population is about 500.\n     * 75% of the time it's between 495 and 505.\n     */\n    var countrymen = (500 + (10 * rnd) - (10 * rnd)).toInt()\n\n    /**\n     * Land sale price is evenly between 95 and 104 rallods per\n     * square mile.\n     * Price doesn't change over the course of the game.\n     */\n    private var landPrice = (10 * rnd + 95).toInt()\n\n    private var plantingArea = 0\n\n    private var welfareThisYear = 0\n    /**\n     * Land area in square miles. Arable land is 1000 square miles less.\n     * Almost all calculations use landArea-1000 because only arable\n     * land is of any use.\n     */\n    var landArea = 2000\n\n    /**\n     * Number of foreigners brought in by companies to whom you\n     * have sold land. If this gets higher than your population, there will\n     * be a revolution.\n     */\n    var foreignWorkers = 0\n\n    /**\n     * Planting cost is recalculated every year.\n     */\n    private var costToPlant: Int = 1\n\n    /**\n     * There is a brief explanation of land selling only\n     * on the first turn.\n     */\n    private var explanationOfSellingGiven = false\n\n    private var sellThisYear: Int = 0\n\n    /**\n     * Planting cost is recalculated every year\n     * at between 10 and 14 rallods.\n     */\n    fun recalculateLandCost() {\n        costToPlant = ((rnd / 2.0) * 10.0 + 10.0).toInt()\n    }\n\n    /**\n     * Show the current status of the world.\n     */\n    fun displayStatus() {\n        println()\n        println(\"YOU NOW HAVE $rallods RALLODS IN THE TREASURY.\")\n        print(\"$countrymen COUNTRYMEN, \")\n        if (foreignWorkers != 0) {\n            println(\"$foreignWorkers FOREIGN WORKERS, \")\n        }\n        println(\"AND $landArea SQ. MILES OF LAND.\")\n        println(\"THIS YEAR INDUSTRY WILL BUY LAND FOR $landPrice\")\n        println(\"RALLODS PER SQUARE MILE.\")\n        println(\"LAND CURRENTLY COSTS $costToPlant RALLODS PER SQUARE MILE TO PLANT.\")\n    }\n\n    fun displayExitMessage() {\n        println()\n        println(\"GOODBYE.\")\n        println(\"(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\")\n        println(\"'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\")\n        println(\"OF THE GAME).\")\n    }\n\n    fun performLandSale() {\n        landArea -= sellThisYear\n        rallods += sellThisYear * landPrice\n    }\n\n    fun performPlanting() {\n        rallods -= moneySpentOnPlanting\n    }\n\n    fun performWelfare() {\n        rallods -= welfareThisYear\n    }\n\n    /**\n     * Ask how much land we want to sell. Immediately get the money.\n     * The player has to do the calculations to work out how much\n     * money that makes.\n     */\n    fun inputLandSale() {\n        do {\n            print(\"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? \")\n            sellThisYear = numberInput()\n            if (sellThisYear > landArea - 1000) {\n                println(\"***  THINK AGAIN. YOU ONLY HAVE ${landArea - 1000} SQUARE MILES OF FARM LAND.\")\n                if (!explanationOfSellingGiven) {\n                    println()\n                    println(\"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\")\n                    println(\"FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\")\n                    println(\"THICKER TOP SOIL, ETC.)\")\n                    explanationOfSellingGiven = true\n                }\n            }\n        } while (sellThisYear < 0 || sellThisYear > landArea - 1000)\n    }\n\n\n    /**\n     * Input the value of `welfareThisYear`\n     */\n    fun inputWelfare() {\n        do {\n            var retry = false\n            print(\"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? \")\n            welfareThisYear = numberInput()\n\n            if (welfareThisYear > rallods) {\n                println(\"   THINK AGAIN. YOU'VE ONLY $rallods RALLODS IN THE TREASURY\")\n                retry = true\n            }\n\n            if (welfareThisYear < 0) {\n                retry = true\n            }\n        } while (retry)\n    }\n\n    /**\n     * Get the number of square miles to plant this year.\n     * Validate the response:\n     *  Each countryman can only plant 2 square miles.\n     *  You can only plant on arable land.\n     *  You may not spend more on planting than your treasury.\n     */\n    fun inputPlantingArea() {\n        if (welfareThisYear == rallods) {\n            plantingArea = 0\n        } else {\n            do {\n                var retry = false\n                print(\"HOW MANY SQUARE MILES DO YOU WISH TO PLANT? \")\n                plantingArea = numberInput()\n                val moneySpentOnPlanting = plantingArea * costToPlant\n\n                if (plantingArea < 0) {\n                    retry = true\n                } else if (plantingArea >= 0 && plantingArea > countrymen * 2) {\n                    println(\"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\")\n                    retry = true\n                } else if (plantingArea > landArea - 1000) {\n                    println(\"   SORRY, BUT YOU'VE ONLY ${landArea - 1000} SQ. MILES OF FARM LAND.\")\n                    retry = true\n                } else if (moneySpentOnPlanting > rallods) {\n                    println(\"   THINK AGAIN. YOU'VE ONLY $rallods RALLODS LEFT IN THE TREASURY.\")\n                    retry = true\n                }\n            } while (retry)\n        }\n\n    }\n\n    /**\n     * Enter amount for pollution control.\n     * Validate that this does not exceed treasury.\n     */\n    fun inputPollutionControl() {\n        do {\n            var retry = false\n            print(\"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? \")\n            moneySpentOnPollutionControl = numberInput()\n\n            if (rallods < 0) {\n                retry = true\n            } else if (moneySpentOnPollutionControl > rallods) {\n                println(\"   THINK AGAIN. YOU ONLY HAVE $rallods RALLODS REMAINING.\")\n                retry = true\n            }\n\n        } while (retry)\n    }\n\n    /**\n     * @return true if all data entered so far has been zero.\n     */\n    fun zeroInput() = sellThisYear == 0 &&\n            welfareThisYear == 0 &&\n            plantingArea == 0 &&\n            moneySpentOnPollutionControl == 0\n\n    fun simulateOneYear(): YearOutcome {\n        rallods -= moneySpentOnPollutionControl\n        val rallodsAfterPollutionControl = rallods\n\n        var starvationDeaths = 0\n        if (welfareThisYear / 100.0 - countrymen < 0) {\n\n            /*\n            Wait, WHAT?\n            If you spend less than 5000 rallods on welfare, no matter the current size of the\n            population, then you will end the game, with the game claiming that too many\n            people have died, without showing exactly how many have died?\n\n            https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1105%20IF%20I/100%3C50%20THEN%201700\n             */\n            if (welfareThisYear / 100.0 < 50)\n                return YearOutcome.TooManyPeopleDead\n\n            starvationDeaths = (countrymen - (welfareThisYear / 100.0)).toInt()\n            println(\"$starvationDeaths COUNTRYMEN DIED OF STARVATION\")\n        }\n\n        var pollutionDeaths = (rnd * (2000 - landArea)).toInt()\n        if (moneySpentOnPollutionControl >= 25) {\n            pollutionDeaths = (pollutionDeaths / (moneySpentOnPollutionControl / 25.0)).toInt()\n        }\n\n        if (pollutionDeaths > 0) {\n            println(\"$pollutionDeaths COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\")\n        }\n\n        death = pollutionDeaths + starvationDeaths\n        if (death > 0) {\n            println(\"   YOU WERE FORCED TO SPEND ${death * 9}\")\n            println(\"RALLODS ON FUNERAL EXPENSES\")\n            rallods -= death * 9\n        }\n\n        if (rallods < 0) {\n            println(\"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\")\n            landArea += rallods / landPrice\n            rallods = 1\n        }\n\n        countrymen -= death\n\n        val newForeigners =\n            if (sellThisYear > 0) {\n                (sellThisYear + rnd * 10.0 + rnd * 20.0).toInt() + (if (foreignWorkers <= 0) 20 else 0)\n            } else 0\n\n        /*\n        Immigration is calculated as\n            One for every thousand rallods more welfare than strictly required\n            minus one for every 10 starvation deaths\n            plus One for every 25 rallods spent on pollution control\n            plus one for every 50 square miles of arable land\n            minus one for every 2 pollution deaths\n         */\n        val immigration = (\n                (welfareThisYear / 100.0 - countrymen) / 10.0 +\n                        moneySpentOnPollutionControl / 25.0 -\n                        (2000 - landArea) / 50.0 -\n                        pollutionDeaths / 2.0\n                ).toInt()\n        println(\n            \"$newForeigners WORKERS CAME TO THE COUNTRY AND\" +\n                    \" ${abs(immigration)} COUNTRYMEN ${if (immigration < 0) \"LEFT\" else \"CAME TO\"}\" +\n                    \" THE ISLAND.\"\n        )\n\n        countrymen += immigration\n        foreignWorkers += newForeigners\n\n        /*\n        Crop loss is between 75% and 125% of the land sold to industry,\n        due to the pollution that industry causes.\n        Money spent on pollution control reduces pollution deaths among\n        the population, but does not affect crop losses.\n         */\n        var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt()\n        if (foreignWorkers > 0)\n            print(\"OF $plantingArea SQ. MILES PLANTED,\")\n        if (plantingArea <= cropLoss)\n            cropLoss = plantingArea\n        val cropLossWorse = cropLoss > lastYearsCropLoss\n        lastYearsCropLoss = cropLoss\n        println(\" YOU HARVESTED ${plantingArea - cropLoss} SQ. MILES OF CROPS.\")\n\n        if (cropLoss > 0) {\n            println(\"   (DUE TO ${if (cropLossWorse) \"INCREASED \" else \"\"}AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY)\")\n        }\n\n        val agriculturalIncome = ((plantingArea - cropLoss) * landPrice / 2.0).toInt()\n        println(\"MAKING $agriculturalIncome RALLODS.\")\n        rallods += agriculturalIncome\n\n        val v1 = (((countrymen - immigration) * 22.0) + rnd * 500).toInt()\n        val v2 = ((2000.0 - landArea) * 15.0).toInt()\n        println(\" YOU MADE ${abs(v1 - v2)} RALLODS FROM TOURIST TRADE.\")\n        if (v2 != 0 && v1 - v2 < tourists) {\n            print(\"   DECREASE BECAUSE \")\n            println(\n                when ((10 * rnd).toInt()) {\n                    in 0..2 -> \"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\"\n                    in 3..4 -> \"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\"\n                    in 5..6 -> \"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\"\n                    in 7..8 -> \"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\"\n                    else -> \"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\"\n                }\n            )\n        }\n\n        /*\n         The original code was incorrect.\n         If v3 starts at 0, for example, our money doubles, when we\n         have already been told that \"YOU MADE ${abs(v1 - v2)} RALLODS\n         FROM TOURIST TRADE\"\n\n        See the original code\n            1450 V3=INT(A+V3)\n            1451 A=INT(A+V3)\n\n            https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1450%20V3%3DINT,INT(A%2BV3)\n         */\n        if (KEEP_ORIGINAL_BUGS) {\n            tourists += rallods\n        } else {\n            tourists = abs(v1 - v2)\n        }\n        rallods += tourists\n\n        return if (death > 200)\n            YearOutcome.ExtremeMismanagement(death)\n        else if (countrymen < 343)\n            YearOutcome.TooManyPeopleDead\n        else if (rallodsAfterPollutionControl / 100 > 5 && death - pollutionDeaths >= 2)\n            YearOutcome.StarvationWithFullTreasury\n        else if (foreignWorkers > countrymen)\n            YearOutcome.AntiImmigrationRevolution\n        else {\n            if (currentYear++ > yearsRequired)\n                YearOutcome.Win(yearsRequired)\n            else\n                YearOutcome.ContinueNextYear\n        }\n\n    }\n}\n\nprivate fun numberInput() = try {\n    readLine()?.toInt() ?: throw EndOfInputException()\n} catch (r: NumberFormatException) {\n    0\n}\n\nclass DataEntryValidationException : Throwable()\nprivate fun validatedInput(predicate : (Int)->Boolean) =\n    numberInput().apply { if (!predicate(this)) throw DataEntryValidationException() }\n"
  },
  {
    "path": "53_King/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "53_King/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "53_King/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "53_King/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n\n\n## Porting notes\n\nVariables:\n\n* A: Available rallods (money)\n* B: Current countrymen\n* C: foreign_workers\n* C1: foreign_workers_influx\n* D: Available land (farmland=D-1000)\n* F1: polution_deaths (last round)\n* B5: died_contrymen (starvation + pollution)\n* H: sm_sell_to_industry\n* I: distributed_rallods\n* J: planted_sq in a round\n* K: pollution_control_spendings in a round\n* X5: years in office\n* N5: YEARS_IN_TERM - how many years one term in office has\n* P1: population_change (positive means people come, negative means people leave)\n* W: land_buy_price\n* V9: planting_cost\n* U2: crop_loss\n* V1-V2: Earnings from tourist trade\n* V3: tourism_earnings\n* T1: crop_loss_last_year\n* W: land_buy_price\n* X: only show an error message once\n\nFunctions:\n\n* `RND(1)`: `random.random()`\n* `INT(...)`: `int(...)`\n* `ABS(...)`: `abs(...)`\n\nBugs: See [53 King README](../README.md)\n\nImplicit knowledge:\n\n* `COST_OF_LIVING`: One countryman needs 100 for food. Otherwise they will die of starvation\n* `COST_OF_FUNERAL`: A funeral costs 9\n"
  },
  {
    "path": "53_King/python/king.py",
    "content": "\"\"\"\nKING\n\nA strategy game where the player is the king.\n\nPorted to Python by Martin Thoma in 2022\n\"\"\"\n\nimport sys\nfrom dataclasses import dataclass\nfrom random import randint, random\n\nFOREST_LAND = 1000\nINITIAL_LAND = FOREST_LAND + 1000\nCOST_OF_LIVING = 100\nCOST_OF_FUNERAL = 9\nYEARS_IN_TERM = 8\nPOLLUTION_CONTROL_FACTOR = 25\n\n\ndef ask_int(prompt) -> int:\n    while True:\n        try:\n            return int(input(prompt))\n        except ValueError:\n            continue\n\n\n@dataclass\nclass GameState:\n    rallods: int = -1\n    countrymen: int = -1\n    land: int = INITIAL_LAND\n    foreign_workers: int = 0\n    years_in_office: int = 0\n\n    # previous year stats\n    crop_loss_last_year: int = 0\n\n    # current year stats\n    died_contrymen: int = 0\n    pollution_deaths: int = 0\n    population_change: int = 0\n\n    # current year - market situation (in rallods per square mile)\n    planting_cost: int = -1\n    land_buy_price: int = -1\n\n    tourism_earnings: int = 0\n\n    def set_market_conditions(self) -> None:\n        self.land_buy_price = randint(95, 105)\n        self.planting_cost = randint(10, 15)\n\n    @property\n    def farmland(self) -> int:\n        return self.land - FOREST_LAND\n\n    @property\n    def settled_people(self) -> int:\n        return self.countrymen - self.population_change\n\n    def sell_land(self, amount: int) -> None:\n        assert amount <= self.farmland\n        self.land -= amount\n        self.rallods += self.land_buy_price * amount\n\n    def distribute_rallods(self, distribute: int) -> None:\n        self.rallods -= distribute\n\n    def spend_pollution_control(self, spend: int) -> None:\n        self.rallods -= spend\n\n    def plant(self, sq_to_plant: int) -> None:\n        self.rallods -= sq_to_plant * self.planting_cost\n\n    def print_status(self) -> None:\n        print(f\"\\n\\nYOU NOW HAVE {self.rallods} RALLODS IN THE TREASURY.\")\n        print(f\"{int(self.countrymen)} COUNTRYMEN, \", end=\"\")\n        if self.foreign_workers > 0:\n            print(f\"{int(self.foreign_workers)} FOREIGN WORKERS, \", end=\"\")\n        print(f\"AND {self.land} SQ. MILES OF LAND.\")\n        print(\n            f\"THIS YEAR INDUSTRY WILL BUY LAND FOR {self.land_buy_price} \"\n            \"RALLODS PER SQUARE MILE.\"\n        )\n        print(\n            f\"LAND CURRENTLY COSTS {self.planting_cost} RALLODS \"\n            \"PER SQUARE MILE TO PLANT.\\n\"\n        )\n\n    def handle_deaths(\n        self, distributed_rallods: int, pollution_control_spendings: int\n    ) -> None:\n        starved_countrymen = max(\n            0, int(self.countrymen - distributed_rallods / COST_OF_LIVING)\n        )\n\n        if starved_countrymen > 0:\n            print(f\"{starved_countrymen} COUNTRYMEN DIED OF STARVATION\")\n\n        self.pollution_deaths = int(random() * (INITIAL_LAND - self.land))\n        if pollution_control_spendings >= POLLUTION_CONTROL_FACTOR:\n            self.pollution_deaths = int(\n                self.pollution_deaths\n                / (pollution_control_spendings / POLLUTION_CONTROL_FACTOR)\n            )\n        if self.pollution_deaths > 0:\n            print(\n                f\"{self.pollution_deaths} COUNTRYMEN DIED OF CARBON-MONOXIDE \"\n                f\"AND DUST INHALATION\"\n            )\n\n        self.died_contrymen = starved_countrymen + self.pollution_deaths\n        if self.died_contrymen > 0:\n            funeral_cost = self.died_contrymen * COST_OF_FUNERAL\n            print(f\"   YOU WERE FORCED TO SPEND {funeral_cost} RALLODS ON \")\n            print(\"FUNERAL EXPENSES.\")\n            self.rallods -= funeral_cost\n            if self.rallods < 0:\n                print(\"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\")\n                self.land += int(self.rallods / self.land_buy_price)\n                self.rallods = 0\n            self.countrymen -= self.died_contrymen\n\n    def handle_tourist_trade(self) -> None:\n        V1 = int(self.settled_people * 22 + random() * 500)\n        V2 = int((INITIAL_LAND - self.land) * 15)\n        tourist_trade_earnings = 0\n        if V1 > V2:\n            tourist_trade_earnings = V1 - V2\n        print(f\" YOU MADE {tourist_trade_earnings} RALLODS FROM TOURIST TRADE.\")\n        if V2 != 0 and not (V1 - V2 >= self.tourism_earnings):\n            print(\"   DECREASE BECAUSE \", end=\"\")\n            reason = randint(0, 10)\n            if reason <= 2:\n                print(\"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\")\n            elif reason <= 4:\n                print(\"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\")\n            elif reason <= 6:\n                print(\"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\")\n            elif reason <= 8:\n                print(\"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\")\n            else:\n                print(\"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\")\n\n        # NOTE: The following two lines had a bug in the original game:\n        self.tourism_earnings = abs(int(V1 - V2))\n        self.rallods += self.tourism_earnings\n\n    def handle_harvest(self, planted_sq: int) -> None:\n        crop_loss = int((INITIAL_LAND - self.land) * ((random() + 1.5) / 2))\n        if self.foreign_workers != 0:\n            print(f\"OF {planted_sq} SQ. MILES PLANTED,\")\n        if planted_sq <= crop_loss:\n            crop_loss = planted_sq\n        harvested = int(planted_sq - crop_loss)\n        print(f\" YOU HARVESTED {harvested} SQ. MILES OF CROPS.\")\n        unlucky_harvesting_worse = crop_loss - self.crop_loss_last_year\n        if crop_loss != 0:\n            print(\"   (DUE TO \", end=\"\")\n            if unlucky_harvesting_worse > 2:\n                print(\"INCREASED \", end=\"\")\n            print(\"AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\")\n        revenue = int((planted_sq - crop_loss) * (self.land_buy_price / 2))\n        print(f\"MAKING {revenue} RALLODS.\")\n        self.crop_loss_last_year = crop_loss\n        self.rallods += revenue\n\n    def handle_foreign_workers(\n        self,\n        sm_sell_to_industry: int,\n        distributed_rallods: int,\n        polltion_control_spendings: int,\n    ) -> None:\n        foreign_workers_influx = 0\n        if sm_sell_to_industry != 0:\n            foreign_workers_influx = int(\n                sm_sell_to_industry + (random() * 10) - (random() * 20)\n            )\n            if self.foreign_workers <= 0:\n                foreign_workers_influx += 20\n            print(f\"{foreign_workers_influx} WORKERS CAME TO THE COUNTRY AND\")\n\n        surplus_distributed = distributed_rallods / COST_OF_LIVING - self.countrymen\n        population_change = int(\n            (surplus_distributed / 10)\n            + (polltion_control_spendings / POLLUTION_CONTROL_FACTOR)\n            - ((INITIAL_LAND - self.land) / 50)\n            - (self.died_contrymen / 2)\n        )\n        print(f\"{abs(population_change)} COUNTRYMEN \", end=\"\")\n        if population_change < 0:\n            print(\"LEFT \", end=\"\")\n        else:\n            print(\"CAME TO \", end=\"\")\n        print(\"THE ISLAND\")\n        self.countrymen += population_change\n        self.foreign_workers += foreign_workers_influx\n\n    def handle_too_many_deaths(self) -> None:\n        print(f\"\\n\\n\\n{self.died_contrymen} COUNTRYMEN DIED IN ONE YEAR!!!!!\")\n        print(\"\\n\\n\\nDUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\")\n        print(\"BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\")\n        message = randint(0, 10)\n        if message <= 3:\n            print(\"ALSO HAD YOUR LEFT EYE GOUGED OUT!\")\n        if message <= 6:\n            print(\"HAVE ALSO GAINED A VERY BAD REPUTATION.\")\n        if message <= 10:\n            print(\"HAVE ALSO BEEN DECLARED NATIONAL FINK.\")\n        sys.exit()\n\n    def handle_third_died(self) -> None:\n        print()\n        print()\n        print(\"OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\")\n        print(\"WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\")\n        print(\"HATE YOUR GUTS.\")\n        self.end_game()\n\n    def handle_money_mismanagement(self) -> None:\n        print()\n        print(\"MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\")\n        print(\"NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\")\n        print(\"OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\")\n        print(\"BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\")\n        print(\"THE CHOICE IS YOURS.\")\n        print(\"IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\")\n        print(\"BEFORE PROCEEDING.\")\n        sys.exit()\n\n    def handle_too_many_foreigners(self) -> None:\n        print(\"\\n\\nTHE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\")\n        print(\"OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\")\n        print(\"TAKEN OVER THE COUNTRY.\")\n        self.end_game()\n\n    def end_game(self) -> None:\n        if random() <= 0.5:\n            print(\"YOU HAVE BEEN ASSASSINATED.\")\n        else:\n            print(\"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\")\n            print(\"RESIDING IN PRISON.\")\n        sys.exit()\n\n    def handle_congratulations(self) -> None:\n        print(\"\\n\\nCONGRATULATIONS!!!!!!!!!!!!!!!!!!\")\n        print(f\"YOU HAVE SUCCESFULLY COMPLETED YOUR {YEARS_IN_TERM} YEAR TERM\")\n        print(\"OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\")\n        print(\"NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\")\n        print(\"LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\")\n        print(\"PLAYS THIS GAME.\")\n        sys.exit()\n\n\ndef print_header() -> None:\n    print(\" \" * 34 + \"KING\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef print_instructions() -> None:\n    print(\n        f\"\"\"\\n\\n\\nCONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\nDETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\nJOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\nMONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\nTHE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS {COST_OF_LIVING}\nRALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\nFROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\nFORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\nWHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\nTO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\nTHEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\nSQUARE MILE TO PLANT.\nYOUR GOAL IS TO COMPLETE YOUR {YEARS_IN_TERM} YEAR TERM OF OFFICE.\nGOOD LUCK!\"\"\"\n    )\n\n\ndef ask_how_many_sq_to_plant(state: GameState) -> int:\n    while True:\n        sq = ask_int(\"HOW MANY SQUARE MILES DO YOU WISH TO PLANT? \")\n        if sq < 0:\n            continue\n        elif sq > 2 * state.countrymen:\n            print(\"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\")\n        elif sq > state.farmland:\n            print(\n                f\"   SORRY, BUT YOU ONLY HAVE {state.farmland} \"\n                \"SQ. MILES OF FARM LAND.\"\n            )\n        elif sq * state.planting_cost > state.rallods:\n            print(\n                f\"   THINK AGAIN. YOU'VE ONLY {state.rallods} RALLODS \"\n                \"LEFT IN THE TREASURY.\"\n            )\n        else:\n            return sq\n\n\ndef ask_pollution_control(state: GameState) -> int:\n    while True:\n        rallods = ask_int(\n            \"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? \"\n        )\n        if rallods > state.rallods:\n            print(f\"   THINK AGAIN. YOU ONLY HAVE {state.rallods} RALLODS REMAINING.\")\n        elif rallods < 0:\n            continue\n        else:\n            return rallods\n\n\ndef ask_sell_to_industry(state: GameState) -> int:\n    had_first_err = False\n    first = \"\"\"(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\nFOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\nTHICKER TOP SOIL, ETC.)\"\"\"\n    err = f\"\"\"***  THINK AGAIN. YOU ONLY HAVE {state.farmland} SQUARE MILES OF FARM LAND.\"\"\"\n    while True:\n        sm = input(\"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? \")\n        try:\n            sm_sell = int(sm)\n        except ValueError:\n            if not had_first_err:\n                print(first)\n                had_first_err = True\n            print(err)\n            continue\n        if sm_sell > state.farmland:\n            print(err)\n        elif sm_sell < 0:\n            continue\n        else:\n            return sm_sell\n\n\ndef ask_distribute_rallods(state: GameState) -> int:\n    while True:\n        rallods = ask_int(\n            \"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? \"\n        )\n        if rallods < 0:\n            continue\n        elif rallods > state.rallods:\n            print(\n                f\"   THINK AGAIN. YOU'VE ONLY {state.rallods} RALLODS IN THE TREASURY\"\n            )\n        else:\n            return rallods\n\n\ndef resume() -> GameState:\n    while True:\n        years = ask_int(\"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? \")\n        if years < 0:\n            sys.exit()\n        if years >= YEARS_IN_TERM:\n            print(f\"   COME ON, YOUR TERM IN OFFICE IS ONLY {YEARS_IN_TERM} YEARS.\")\n        else:\n            break\n    treasury = ask_int(\"HOW MUCH DID YOU HAVE IN THE TREASURY? \")\n    if treasury < 0:\n        sys.exit()\n    countrymen = ask_int(\"HOW MANY COUNTRYMEN? \")\n    if countrymen < 0:\n        sys.exit()\n    workers = ask_int(\"HOW MANY WORKERS? \")\n    if workers < 0:\n        sys.exit()\n    while True:\n        land = ask_int(\"HOW MANY SQUARE MILES OF LAND? \")\n        if land < 0:\n            sys.exit()\n        if land > INITIAL_LAND:\n            farm_land = INITIAL_LAND - FOREST_LAND\n            print(f\"   COME ON, YOU STARTED WITH {farm_land:,} SQ. MILES OF FARM LAND\")\n            print(f\"   AND {FOREST_LAND:,} SQ. MILES OF FOREST LAND.\")\n        if land > FOREST_LAND:\n            break\n    return GameState(\n        rallods=treasury,\n        countrymen=countrymen,\n        foreign_workers=workers,\n        years_in_office=years,\n    )\n\n\ndef main() -> None:\n    print_header()\n    want_instructions = input(\"DO YOU WANT INSTRUCTIONS? \").upper()\n    if want_instructions == \"AGAIN\":\n        state = resume()\n    else:\n        state = GameState(\n            rallods=randint(59000, 61000),\n            countrymen=randint(490, 510),\n            planting_cost=randint(10, 15),\n        )\n    if want_instructions != \"NO\":\n        print_instructions()\n\n    while True:\n        state.set_market_conditions()\n        state.print_status()\n\n        # Users actions\n        sm_sell_to_industry = ask_sell_to_industry(state)\n        state.sell_land(sm_sell_to_industry)\n\n        distributed_rallods = ask_distribute_rallods(state)\n        state.distribute_rallods(distributed_rallods)\n\n        planted_sq = ask_how_many_sq_to_plant(state)\n        state.plant(planted_sq)\n        polltion_control_spendings = ask_pollution_control(state)\n        state.spend_pollution_control(polltion_control_spendings)\n\n        # Run the year\n        state.handle_deaths(distributed_rallods, polltion_control_spendings)\n        state.handle_foreign_workers(\n            sm_sell_to_industry, distributed_rallods, polltion_control_spendings\n        )\n        state.handle_harvest(planted_sq)\n        state.handle_tourist_trade()\n\n        if state.died_contrymen > 200:\n            state.handle_too_many_deaths()\n        if state.countrymen < 343:\n            state.handle_third_died()\n        elif (\n            state.rallods > 500\n            and state.died_contrymen - state.pollution_deaths >= 2\n        ):\n            state.handle_money_mismanagement()\n        if state.foreign_workers > state.countrymen:\n            state.handle_too_many_foreigners()\n        elif YEARS_IN_TERM - 1 == state.years_in_office:\n            state.handle_congratulations()\n        else:\n            state.years_in_office += 1\n            state.died_contrymen = 0\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "53_King/python/king_variable_update.py",
    "content": ""
  },
  {
    "path": "53_King/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "53_King/rust/Cargo.toml",
    "content": "[package]\nname = \"king\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nfastrand = \"^2.0.0\"\n"
  },
  {
    "path": "53_King/rust/README.md",
    "content": "King\n====\n\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [rust](https://www.rust-lang.org/).\n\nPorting Notes\n-------------\n\n### Floats\n\nThe original code implicitly uses floating point numbers in many places which are explicitly cast to integers. In this port, I avoided using floats and tried to replicate the behaviour using just integers. It is possible that I missed some places where rounding a value would have made a difference. If you find such a bug, please notify me or make implement a fix yourself.\n\n### Signed Numbers\n\nI used unsigned integers for most of the program because it was easier than to check for negative values all the time. Unfortunately, that made the code a bit whacky in one or two places.\n\nSince I only allow input of positive numbers, it is not possible to exit the game when entering the stats to resume a game, which would be possible by entering negative numbers in the original game.\n\n### Bugs\n\nI tried to fix all bugs listed in the [main README for King](../README.md). I have tested this implementation a bit but not extensively, so there may be some portation bugs. If you find them, you are free to fix them.\n\nFuture Development\n------------------\n\nI plan to add some tests and tidy up the code a bit, but this version should be feature-complete.\n"
  },
  {
    "path": "53_King/rust/src/main.rs",
    "content": "#![forbid(unsafe_code)]\n\nuse fastrand::Rng;\nuse std::io;\nuse std::io::{stdin, stdout, BufRead, Write};\n\n// global variable `N5` in the original game\nconst TERM_LENGTH: u32 = 8;\n\nfn main() {\n    let mut rng = Rng::new();\n    let mut input = stdin().lock();\n    let mut state = intro(&mut input, &mut rng).expect(\"input error\");\n\n    loop {\n        let land_price = 95 + rng.u32(0..10);\n        let plant_price = 10 + rng.u32(0..5);\n        print_state(&state, land_price, plant_price);\n        state = match next_round(&mut input, &mut rng, &state, land_price, plant_price)\n            .expect(\"input error\")\n        {\n            RoundEnd::Next(s) => s,\n            RoundEnd::GameOver(msg) => {\n                println!(\"{}\", msg);\n                return;\n            }\n        }\n    }\n}\n\n// The game is round based (one round per in-game year).\n// This struct represents the state before each round\n#[derive(Clone, PartialEq, Eq, Debug)]\nstruct State {\n    // global variable `A` in the original game (currency: \"rallods\")\n    money: u32,\n    // global variable `B` in the original game\n    countrymen: u32,\n    // global variable `C` in the original game\n    foreign_workers: u32,\n    // global variable `D` in the original game\n    land: u32,\n    // global variable `X5` in original game\n    year_in_office: u32,\n    // global variable `X` in original game\n    show_land_hint: bool,\n    // global variable `V3` in original game\n    previous_tourist_trade: u32,\n}\n\n#[derive(Clone, PartialEq, Eq, Debug)]\nenum RoundEnd {\n    GameOver(String),\n    Next(State),\n}\n\nfn init_state(rng: &mut Rng) -> State {\n    State {\n        // the original formula for random values used floating point numbers.\n        // e.g. `INT(60000+(1000*RND(1))-(1000*RND(1)))`\n        // I want to avoid floats unless necessary. These values generated here should be close\n        // enough to the original distribution\n        money: 60000 + rng.u32(0..1000) - rng.u32(0..1000),\n        countrymen: 500 + rng.u32(0..10) - rng.u32(0..10),\n        foreign_workers: 0,\n        land: 2000,\n        year_in_office: 0,\n        show_land_hint: true,\n        previous_tourist_trade: 0,\n    }\n}\n\nfn print_state(state: &State, land_price: u32, plant_price: u32) {\n    print!(\n        r\"\nYOU NOW HAVE {} RALLODS IN THE TREASURY.\n {} COUNTRYMEN, \",\n        state.money, state.countrymen\n    );\n    if state.foreign_workers > 0 {\n        print!(\"{} FOREIGN WORKERS, \", state.foreign_workers)\n    }\n    println!(\n        r\"AND {} SQ. MILES OF LAND.\nTHIS YEAR INDUSTRY WILL BUY LAND FOR {} RALLODS PER SQUARE MILE.\nLAND CURRENTLY COSTS {} RALLODS PER SQUARE MILE TO PLANT.\n\",\n        state.land, land_price, plant_price\n    );\n}\n\n// print the intro, optional instructions or a previous savegame\nfn intro<R: BufRead>(mut input: R, rng: &mut Rng) -> io::Result<State> {\n    println!(\"⚠️ This game includes references to suicide or self-harm.\");\n    println!(\"                                  KING\");\n    println!(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\");\n    print!(\"DO YOU WANT INSTRUCTIONS?? \");\n    // In the original game, all inputs were made in the same line as the previous output.\n    // I try to replicate this behaviour here, but if I do not print a line break, the stdout buffer\n    // will not be flushed and the user may not see the input prompt before the input.\n    // this means in these cases I have to explicitly flush stdout.\n    stdout().flush()?;\n    let mut buf = String::with_capacity(16);\n    input.read_line(&mut buf)?;\n    buf.make_ascii_lowercase();\n    match buf.trim() {\n        \"n\" => Ok(init_state(rng)),\n        \"again\" => {\n            let year_in_office = read_and_verify_int(\n                &mut input,\n                &mut buf,\n                \"HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED?? \",\n                |v| {\n                    if v < 8 {\n                        Ok(v)\n                    } else {\n                        Err(format!(\n                            \"   COME ON, YOUR TERM IN OFFICE IS ONLY {} YEARS.\",\n                            TERM_LENGTH\n                        ))\n                    }\n                },\n            )?;\n            // The original game exits here when you enter a negative number for any of\n            // the following values. This looks like intentional behaviour. However, to replicate that\n            // I would have to change everything to signed number which I do not want right now.\n            print!(\"HOW MUCH DID YOU HAVE IN THE TREASURY?? \");\n            stdout().flush()?;\n            let money = read_int(&mut input, &mut buf)?;\n            print!(\"HOW MANY COUNTRYMEN?? \");\n            stdout().flush()?;\n            let countrymen = read_int(&mut input, &mut buf)?;\n            print!(\"HOW MANY WORKERS?? \");\n            stdout().flush()?;\n            let foreign_workers = read_int(&mut input, &mut buf)?;\n            let land = read_and_verify_int(\n                &mut input,\n                &mut buf,\n                \"HOW MANY SQUARE MILES OF LAND?? \",\n                |v| {\n                    if !(1000..=2000).contains(&v) {\n                        // Note: the original says \"10,000 SQ. MILES OF FOREST LAND\", but this is\n                        // inconsistent and listed as Bug 3 in the README.md\n                        Err(\"   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\\n   AND 1000 SQ. MILES OF FOREST LAND.\".to_owned())\n                    } else {\n                        Ok(v)\n                    }\n                },\n            )?;\n            Ok(State {\n                money,\n                countrymen,\n                foreign_workers,\n                land,\n                year_in_office,\n                show_land_hint: true,\n                previous_tourist_trade: 0,\n            })\n        }\n        _ => {\n            println!(\n                r\"\nCONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\nDETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\nJOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\nMONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\nTHE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\nRALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\nFROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\nFORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\nWHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\nTO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\nTHEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\nSQUARE MILE TO PLANT.\nYOUR GOAL IS TO COMPLETE YOUR {} YEAR TERM OF OFFICE.\nGOOD LUCK!\n\",\n                TERM_LENGTH\n            );\n            Ok(init_state(rng))\n        }\n    }\n}\n\nstatic POLLUTION: &[&str] = &[\n    \"FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\",\n    \"AIR POLLUTION IS KILLING GAME BIRD POPULATION.\",\n    \"MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\",\n    \"UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\",\n    \"HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\",\n];\n\nfn next_round<R: BufRead>(\n    mut input: R,\n    rng: &mut Rng,\n    state: &State,\n    land_price: u32,\n    plant_price: u32,\n) -> io::Result<RoundEnd> {\n    let mut buf = String::with_capacity(16);\n    let mut show_land_hint = state.show_land_hint;\n    // global variable `H` in the original game\n    let land_sold = read_and_verify_int(\n        &mut input,\n        &mut buf,\n        \"HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY?? \",\n        |v| {\n            if v + 1000 <= state.land {\n                Ok(v)\n            } else if show_land_hint {\n                show_land_hint = false;\n                Err(format!(\n                    r\"***  THINK AGAIN. YOU ONLY HAVE {} SQUARE MILES OF FARM LAND.\n(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\nFOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\nTHICKER TOP SOIL, ETC.)\",\n                    state.land - 1000\n                ))\n            } else {\n                Err(format!(\n                    r\"***  THINK AGAIN. YOU ONLY HAVE {} SQUARE MILES OF FARM LAND.\\n\",\n                    state.land - 1000\n                ))\n            }\n        },\n    )?;\n\n    let land = state.land - land_sold;\n    let money = state.money + land_sold * land_price;\n\n    // global variable `I` in the original game\n    let money_distributed = read_and_verify_int(\n        &mut input,\n        &mut buf,\n        \"HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN?? \",\n        |v| {\n            if v <= money {\n                Ok(v)\n            } else {\n                Err(format!(\n                    \"   THINK AGAIN. YOU'VE ONLY {} RALLODS IN THE TREASURY\",\n                    money\n                ))\n            }\n        },\n    )?;\n    let money = money - money_distributed;\n\n    // global variable `J` in the original game\n    let land_planted = if money > 0 {\n        read_and_verify_int(\n            &mut input,\n            &mut buf,\n            \"HOW MANY SQUARE MILES DO YOU WISH TO PLANT?? \",\n            |v| {\n                if v > 2 * state.countrymen {\n                    Err(\"   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\".to_owned())\n                } else if v + 1000 > land {\n                    Err(format!(\n                        \"   SORRY, BUT YOU'VE ONLY {} SQ. MILES OF FARM LAND.\",\n                        land - 1000\n                    ))\n                } else if v * plant_price > money {\n                    Err(format!(\n                        \"   THINK AGAIN. YOU'VE ONLY {} RALLODS LEFT IN THE TREASURY.\",\n                        money\n                    ))\n                } else {\n                    Ok(v)\n                }\n            },\n        )?\n    } else {\n        0\n    };\n    let money = money - land_planted * plant_price;\n\n    // global variable `K` in the original game\n    let pollution_control = if money > 0 {\n        read_and_verify_int(\n            &mut input,\n            &mut buf,\n            \"HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL?? \",\n            |v| {\n                if v <= money {\n                    Ok(v)\n                } else {\n                    Err(format!(\n                        \"   THINK AGAIN. YOU ONLY HAVE {} RALLODS REMAINING.\",\n                        money\n                    ))\n                }\n            },\n        )?\n    } else {\n        0\n    };\n    let money = money - pollution_control;\n\n    if land_sold == 0 && money_distributed == 0 && land_planted == 0 && pollution_control == 0 {\n        return Ok(RoundEnd::GameOver(\n            r\"\nGOODBYE.\n(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\n'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\nOF THE GAME).\"\n                .to_owned(),\n        ));\n    }\n\n    println!(\"\\n\\n\");\n\n    let money_after_expenses = money;\n\n    let starvation_deaths = state.countrymen.saturating_sub(money_distributed / 100);\n    if starvation_deaths > 0 {\n        println!(\"{starvation_deaths} COUNTRYMEN DIED OF STARVATION\");\n    }\n\n    // the original was using `RND(1)` as factor, but I do not want to deal with floats.\n    // this solution should do the same in the range of numbers we expect\n    let pollution = ((2000 - land) * rng.u32(0..=2000)) / 2000;\n    let pollution_deaths = if pollution_control >= 25 {\n        pollution / (pollution_control / 25)\n    } else {\n        pollution\n    };\n\n    if pollution_deaths > 0 {\n        println!(\n            \"{} COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\",\n            pollution_deaths\n        );\n    }\n\n    let (money, land) = if pollution_deaths + starvation_deaths > 0 {\n        let funeral_costs = (pollution_deaths + starvation_deaths) * 9;\n        println!(\"   YOU WERE FORCED TO SPEND {funeral_costs} RALLODS ON FUNERAL EXPENSES\");\n        if funeral_costs > money {\n            println!(\"   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\");\n            (\n                0,\n                // I only handle integers here, but I think the basic code implicitly turns integers\n                // to floats on division. So in order to round up to the next full land unit, I have\n                // to do this weird modulo stuff here\n                land - funeral_costs / land_price\n                    + if funeral_costs % land_price == 0 {\n                        0\n                    } else {\n                        1\n                    },\n            )\n        } else {\n            (money - funeral_costs, land)\n        }\n    } else {\n        (money, land)\n    };\n\n    let mut countrymen = state\n        .countrymen\n        .saturating_sub(starvation_deaths)\n        .saturating_sub(pollution_deaths);\n\n    let tourist_trade_positive = countrymen * 22 + rng.u32(0..500);\n    let tourist_trade_negative = (2000 - land) * 15;\n\n    let new_foreign_workers: i32 = if land_sold > 0 {\n        land_sold as i32 + rng.i32(0..10) - rng.i32(0..20)\n            + if state.foreign_workers == 0 { 20 } else { 0 }\n    } else {\n        0\n    };\n    // In theory, we could come up with negative foreign workers here (and in the original game)\n    // This does not seem to be right, so let's cap them at 0\n    let foreign_workers = if new_foreign_workers < 0 {\n        state\n            .foreign_workers\n            .saturating_sub(new_foreign_workers.unsigned_abs())\n    } else {\n        state.foreign_workers + new_foreign_workers as u32\n    };\n    print!(\" {new_foreign_workers} WORKERS CAME TO THE COUNTRY AND \");\n\n    let countryman_migration = (money_distributed as i32 / 100 - countrymen as i32) / 10\n        + pollution_control as i32 / 25\n        - (2000 - land as i32) / 50\n        - pollution_deaths as i32 / 2;\n\n    if countryman_migration < 0 {\n        println!(\"{} COUNTRYMEN LEFT THE ISLAND\", countryman_migration.abs());\n        countrymen = countrymen.saturating_sub(countryman_migration.unsigned_abs())\n    } else {\n        println!(\"{countryman_migration} COUNTRYMEN CAME TO THE ISLAND\");\n        countrymen += countryman_migration as u32\n    }\n\n    let harvest_lost = ((2000 - land) * (rng.u32(0..2000) + 3000)) / 4000;\n    // in the original game, this checked for foreign_workers == 0 instead of land_planted == 0\n    // this is documented as Bug 4 in the README.md\n    if land_planted == 0 {\n        print!(\"OF {land_planted} SQ. MILES PLANTED,\");\n    }\n    println!(\n        \" YOU HARVESTED {} SQ. MILES OF CROPS.\",\n        land_planted.saturating_sub(harvest_lost)\n    );\n\n    if harvest_lost > 0 {\n        // There was a bug here in the original code (Bug 2 in README.md).\n        // Based on the variable `V1`, the word `INCREASED` was inserted.\n        // However, no value was ever assigned to `V1`. Since the pollution comes from land that has\n        // been sold, I used the land difference to check whether the pollution increased.\n        if state.land < land {\n            println!(\"   (DUE TO INCREASED AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\");\n        } else {\n            println!(\"   (DUE TO AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\");\n        }\n    }\n\n    let crop_winnings = land_planted.saturating_sub(harvest_lost) * land_price / 2;\n    println!(\"MAKING {crop_winnings} RALLODS.\");\n    let money = money + crop_winnings;\n\n    // In the original game, there are two bugs here (documented as Bug 1 and Bug 5 in the README.md)\n    // The first one made the game ignore the income from tourists and duplicated the money that was\n    // left at this point (the \"DECREASE BECAUSE\"-message would never have been shown).\n    // The second bug made the tourist trade profitable again is the pollution was too high (i.e.\n    // if `tourist_trade_positive` was less than `tourist_trade_negative`\n    let tourist_trade = tourist_trade_positive.saturating_sub(tourist_trade_negative);\n    println!(\" YOU MADE {tourist_trade} RALLODS FROM TOURIST TRADE.\");\n    if tourist_trade < state.previous_tourist_trade {\n        println!(\n            \"   DECREASE BECAUSE {}\",\n            POLLUTION[rng.usize(0..POLLUTION.len())]\n        );\n    }\n    let money = money + tourist_trade;\n\n    if starvation_deaths + pollution_deaths > 200 {\n        let reason = rng.u8(0..10);\n        return Ok(RoundEnd::GameOver(format!(\n            r\"\n\n {} COUNTRYMEN DIED IN ONE YEAR!!!!!\nDUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY\nBEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU\n{}\n\",\n            starvation_deaths + pollution_deaths,\n            // The reasons are not equally probable in the original game.\n            // I wonder if this was intentional.\n            if reason <= 3 {\n                \"ALSO HAD YOUR LEFT EYE GOUGED OUT!\"\n            } else if reason <= 6 {\n                \"HAVE ALSO GAINED A VERY BAD REPUTATION.\"\n            } else {\n                \"HAVE ALSO BEEN DECLARED NATIONAL FINK.\"\n            }\n        )));\n    }\n    if countrymen < 343 {\n        // This is not entirely fair, it is possible that some of them just left, not died.\n        // Also: the initial number of countrymen varies a bit, but this boundary is fix, so it is\n        // not always a third\n        return Ok(RoundEnd::GameOver(format!(\n            r\"\n\nOVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU\nWERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\nHATE YOUR GUTS.\n{}\n\",\n            departure_flavour(rng)\n        )));\n    }\n    if money_after_expenses / 100 > 5 && starvation_deaths >= 2 {\n        return Ok(RoundEnd::GameOver(\n            r\"\nMONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID\nNOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED\nOF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE\nBEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.\nTHE CHOICE IS YOURS.\nIF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER\nBEFORE PROCEEDING.\n\"\n            .to_owned(),\n        ));\n    }\n    if foreign_workers > countrymen {\n        return Ok(RoundEnd::GameOver(format!(\n            r\"\n\nTHE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER\nOF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND\nTAKEN OVER THE COUNTRY.\n{}\n\",\n            departure_flavour(rng)\n        )));\n    }\n    if state.year_in_office + 1 >= TERM_LENGTH {\n        return Ok(RoundEnd::GameOver(format!(\n            r\"\n\nCONGRATULATIONS!!!!!!!!!!!!!!!!!!\nYOU HAVE SUCCESFULLY COMPLETED YOUR {} YEAR TERM\nOF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT\nNEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD\nLUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT\nPLAYS THIS GAME.\n\",\n            TERM_LENGTH\n        )));\n    }\n\n    Ok(RoundEnd::Next(State {\n        money,\n        countrymen,\n        foreign_workers,\n        land,\n        year_in_office: state.year_in_office + 1,\n        show_land_hint,\n        previous_tourist_trade: tourist_trade,\n    }))\n}\n\nfn departure_flavour(rng: &mut Rng) -> &'static str {\n    if rng.bool() {\n        \"YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\\nRESIDING IN PRISON.\\n\"\n    } else {\n        \"YOU HAVE BEEN ASSASSINATED.\\n\"\n    }\n}\n\nfn read_int<R: BufRead>(mut input: R, buf: &mut String) -> io::Result<u32> {\n    loop {\n        buf.clear();\n        input.read_line(buf)?;\n        let line = buf.trim();\n        // This is implicit behaviour in the original code: empty input is equal to 0\n        if line.is_empty() {\n            return Ok(0);\n        }\n        if let Ok(n) = line.parse::<u32>() {\n            return Ok(n);\n        } else {\n            print!(\"??REENTER\\n?? \");\n            stdout().flush()?;\n        }\n    }\n}\n\nfn read_and_verify_int<R: BufRead, Verify>(\n    mut input: R,\n    buf: &mut String,\n    prompt: &str,\n    mut verify: Verify,\n) -> io::Result<u32>\nwhere\n    Verify: FnMut(u32) -> Result<u32, String>,\n{\n    loop {\n        print!(\"{}\", prompt);\n        stdout().flush()?;\n        let v = read_int(&mut input, buf)?;\n        match verify(v) {\n            Ok(v) => {\n                return Ok(v);\n            }\n            Err(msg) => {\n                println!(\"{}\", msg);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "53_King/vbnet/King.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"King\", \"King.vbproj\", \"{043D7CC7-1FFC-438E-BB00-31CB467BEB73}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "53_King/vbnet/King.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>King</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "53_King/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "54_Letter/README.md",
    "content": "### Letter\n\nLETTER is similar to the game GUESS in which you guess a number chosen by the computer; in this program, the computer picks a random letter of the alphabet and you must guess which one it is using the clues provided as you go along. It should not take you more than five guesses to get the mystery letter.\n\nThe program which appears here is loosely based on the original written by Bob Albrect of People’s Computer Company.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=99)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=114)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "54_Letter/csharp/Game.cs",
    "content": "﻿namespace Letter\n{\n    internal static class Game\n    {\n        /// <summary>\n        /// Maximum number of guesses.\n        /// Note the program doesn't enforce this - it just displays a message if this is exceeded.\n        /// </summary>\n        private const int MaximumGuesses = 5;\n\n        /// <summary>\n        /// Main game loop.\n        /// </summary>\n        public static void Play()\n        {\n            DisplayIntroductionText();\n\n            // Keep playing forever, or until the user quits.\n            while (true)\n            {\n                PlayRound();\n            }\n        }\n\n        /// <summary>\n        /// Play a single round.\n        /// </summary>\n        internal static void PlayRound()\n        {\n            var gameState = new GameState();\n            DisplayRoundIntroduction();\n\n            char letterInput = '\\0'; // Set the initial character to something that's not A-Z.\n            while (letterInput != gameState.Letter)\n            {\n                letterInput = GetCharacterFromKeyboard();\n                gameState.GuessesSoFar++;\n                DisplayGuessResult(gameState.Letter, letterInput);\n            }\n            DisplaySuccessMessage(gameState);\n        }\n\n        /// <summary>\n        /// Display an introduction when the game loads.\n        /// </summary>\n        internal static void DisplayIntroductionText()\n        {\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"LETTER\");\n            Console.WriteLine(\"Creative Computing, Morristown, New Jersey.\");\n            Console.WriteLine(\"\");\n\n            Console.ForegroundColor = ConsoleColor.DarkGreen;\n            Console.WriteLine(\"Letter Guessing Game\");\n            Console.WriteLine(\"I'll think of a letter of the alphabet, A to Z.\");\n            Console.WriteLine(\"Try to guess my letter and I'll give you clues\");\n            Console.WriteLine(\"as to how close you're getting to my letter.\");\n            Console.WriteLine(\"\");\n\n            Console.ResetColor();\n        }\n\n        /// <summary>\n        /// Display introductionary text for each round.\n        /// </summary>\n        internal static void DisplayRoundIntroduction()\n        {\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"O.K., I have a letter. Start guessing.\");\n\n            Console.ResetColor();\n        }\n\n        /// <summary>\n        /// Display text depending whether the guess is lower or higher.\n        /// </summary>\n        internal static void DisplayGuessResult(char letterToGuess, char letterInput)\n        {\n            Console.BackgroundColor = ConsoleColor.White;\n            Console.ForegroundColor = ConsoleColor.Black;\n            Console.Write(\" \" + letterInput + \" \");\n\n            Console.ResetColor();\n            Console.ForegroundColor = ConsoleColor.Gray;\n            Console.Write(\" \");\n            if (letterInput != letterToGuess)\n            {\n                if (letterInput > letterToGuess)\n                {\n                    Console.WriteLine(\"Too high. Try a lower letter\");\n                }\n                else\n                {\n                    Console.WriteLine(\"Too low. Try a higher letter\");\n                }\n            }\n            Console.ResetColor();\n        }\n\n        /// <summary>\n        /// Display success, and the number of guesses.\n        /// </summary>\n        internal static void DisplaySuccessMessage(GameState gameState)\n        {\n            Console.ForegroundColor = ConsoleColor.Green;\n            Console.WriteLine($\"You got it in {gameState.GuessesSoFar} guesses!!\");\n            if (gameState.GuessesSoFar > MaximumGuesses)\n            {\n                Console.ForegroundColor = ConsoleColor.Red;\n                Console.WriteLine($\"But it shouldn't take more than {MaximumGuesses} guesses!\");\n            }\n            else\n            {\n                Console.WriteLine(\"Good job !!!!!\");\n            }\n            Console.ForegroundColor = ConsoleColor.Yellow;\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"Let's play again.....\");\n\n            Console.ResetColor();\n        }\n\n        /// <summary>\n        /// Get valid input from the keyboard: must be an alpha character. Converts to upper case if necessary.\n        /// </summary>\n        internal static char GetCharacterFromKeyboard()\n        {\n            char letterInput;\n            do\n            {\n                var keyPressed = Console.ReadKey(true);\n                letterInput = Char.ToUpper(keyPressed.KeyChar); // Convert to upper case immediately.\n            } while (!Char.IsLetter(letterInput)); // If the input is not a letter, wait for another letter to be pressed.\n            return letterInput;\n        }\n    }\n}\n"
  },
  {
    "path": "54_Letter/csharp/GameState.cs",
    "content": "﻿namespace Letter\n{\n    /// <summary>\n    /// Holds the current state.\n    /// </summary>\n    internal class GameState\n    {\n        /// <summary>\n        /// Initialise the game state with a random letter.\n        /// </summary>\n        public GameState()\n        {\n            Letter = GetRandomLetter();\n            GuessesSoFar = 0;\n        }\n\n        /// <summary>\n        /// The letter that the user is guessing.\n        /// </summary>\n        public char Letter { get; set; }\n\n        /// <summary>\n        /// The number of guesses the user has had so far.\n        /// </summary>\n        public int GuessesSoFar { get; set; }\n\n        /// <summary>\n        /// Get a random character (A-Z) for the user to guess.\n        /// </summary>\n        internal static char GetRandomLetter()\n        {\n            var random = new Random();\n            var randomNumber = random.Next(0, 26);\n            return (char)('A' + randomNumber);\n        }\n    }\n}\n"
  },
  {
    "path": "54_Letter/csharp/Letter.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "54_Letter/csharp/Letter.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Letter\", \"Letter.csproj\", \"{8BE20DCF-A729-46ED-92EA-55866844EB93}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8BE20DCF-A729-46ED-92EA-55866844EB93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8BE20DCF-A729-46ED-92EA-55866844EB93}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8BE20DCF-A729-46ED-92EA-55866844EB93}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8BE20DCF-A729-46ED-92EA-55866844EB93}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "54_Letter/csharp/Program.cs",
    "content": "﻿using Letter;\n\nGame.Play();\n"
  },
  {
    "path": "54_Letter/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "54_Letter/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "54_Letter/java/src/Letter.java",
    "content": "import java.awt.*;\nimport java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Letter\n * <p>\n * Based on the Basic game of Letter here\n * https://github.com/coding-horror/basic-computer-games/blob/main/54%20Letter/letter.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Letter {\n\n    public static final int OPTIMAL_GUESSES = 5;\n    public static final int ASCII_A = 65;\n    public static final int ALL_LETTERS = 26;\n\n    private enum GAME_STATE {\n        STARTUP,\n        INIT,\n        GUESSING,\n        RESULTS,\n        GAME_OVER\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // Players guess count;\n    private int playerGuesses;\n\n    // Computers ascii code for a random letter between A..Z\n    private int computersLetter;\n\n    public Letter() {\n\n        gameState = GAME_STATE.STARTUP;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTUP:\n                    intro();\n                    gameState = GAME_STATE.INIT;\n                    break;\n\n                case INIT:\n                    playerGuesses = 0;\n                    computersLetter = ASCII_A + (int) (Math.random() * ALL_LETTERS);\n                    System.out.println(\"O.K., I HAVE A LETTER.  START GUESSING.\");\n                    gameState = GAME_STATE.GUESSING;\n                    break;\n\n                // Player guesses the number until they get it or run out of guesses\n                case GUESSING:\n                    String playerGuess = displayTextAndGetInput(\"WHAT IS YOUR GUESS? \").toUpperCase();\n\n                    // Convert first character of input string to ascii\n                    int toAscii = playerGuess.charAt(0);\n                    playerGuesses++;\n                    if (toAscii == computersLetter) {\n                        gameState = GAME_STATE.RESULTS;\n                        break;\n                    }\n\n                    if (toAscii > computersLetter) {\n                        System.out.println(\"TOO HIGH.  TRY A LOWER LETTER.\");\n                    } else {\n                        System.out.println(\"TOO LOW.  TRY A HIGHER LETTER.\");\n                    }\n                    break;\n\n                // Play again, or exit game?\n                case RESULTS:\n                    System.out.println();\n                    System.out.println(\"YOU GOT IT IN \" + playerGuesses + \" GUESSES!!\");\n                    if (playerGuesses <= OPTIMAL_GUESSES) {\n                        System.out.println(\"GOOD JOB !!!!!\");\n                        // Original game beeped 15 tims if you guessed in the optimal guesses or less\n                        // Changed this to do a single beep only\n                        Toolkit.getDefaultToolkit().beep();\n                    } else {\n                        // Took more than optimal number of guesses\n                        System.out.println(\"BUT IT SHOULDN'T TAKE MORE THAN \" + OPTIMAL_GUESSES + \" GUESSES!\");\n                    }\n                    System.out.println();\n                    System.out.println(\"LET'S PLAN AGAIN.....\");\n                    gameState = GAME_STATE.INIT;\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    public void intro() {\n        System.out.println(simulateTabs(33) + \"LETTER\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"LETTER GUESSING GAME\");\n        System.out.println();\n        System.out.println(\"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\");\n        System.out.println(\"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\");\n        System.out.println(\"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\");\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n}\n"
  },
  {
    "path": "54_Letter/java/src/LetterGame.java",
    "content": "public class LetterGame {\n\n    public static void main(String[] args) {\n\n        Letter letter = new Letter();\n        letter.play();\n    }\n}\n"
  },
  {
    "path": "54_Letter/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "54_Letter/javascript/letter.html",
    "content": "<html>\n<head>\n<title>LETTER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"letter.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "54_Letter/javascript/letter.js",
    "content": "// LETTER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"LETTER\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"LETTER GUESSING GAME\\n\");\n    print(\"\\n\");\n    print(\"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\\n\");\n    print(\"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\\n\");\n    print(\"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\\n\");\n    while (1) {\n        l = 65 + Math.floor(26 * Math.random());\n        g = 0;\n        print(\"\\n\");\n        print(\"O.K., I HAVE A LETTER.  START GUESSING.\\n\");\n        while (1) {\n\n            print(\"\\n\");\n            print(\"WHAT IS YOUR GUESS\");\n            g++;\n            str = await input();\n            a = str.charCodeAt(0);\n            print(\"\\n\");\n            if (a == l)\n                break;\n            if (a < l) {\n                print(\"TOO LOW.  TRY A HIGHER LETTER.\\n\");\n            } else {\n                print(\"TOO HIGH.  TRY A LOWER LETTER.\\n\");\n            }\n        }\n        print(\"\\n\");\n        print(\"YOU GOT IT IN \" + g + \" GUESSES!!\\n\");\n        if (g > 5) {\n            print(\"BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\\n\");\n        } else {\n            print(\"GOOD JOB !!!!!\\n\");\n        }\n        print(\"\\n\");\n        print(\"LET'S PLAY AGAIN.....\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "54_Letter/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "54_Letter/letter.bas",
    "content": "10 PRINT TAB(33);\"LETTER\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"LETTER GUESSING GAME\": PRINT\n210 PRINT \"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\"\n220 PRINT \"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\"\n230 PRINT \"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\"\n310 L=65+INT(RND(1)*26)\n320 G=0\n340 PRINT: PRINT \"O.K., I HAVE A LETTER.  START GUESSING.\"\n410 PRINT: PRINT \"WHAT IS YOUR GUESS\";\n420 G=G+1\n430 INPUT A$: A=ASC(A$): PRINT\n440 IF A=L THEN 500\n450 IF A>L THEN 480\n460 PRINT \"TOO LOW.  TRY A HIGHER LETTER.\": GOTO 410\n480 PRINT \"TOO HIGH.  TRY A LOWER LETTER.\": GOTO 410\n500 PRINT: PRINT \"YOU GOT IT IN\";G;\"GUESSES!!\"\n504 IF G<=5 THEN 508\n506 PRINT \"BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\": GOTO 515\n508 PRINT \"GOOD JOB !!!!!\"\n510 FOR N=1 TO 15: PRINT CHR$(7);: NEXT N\n515 PRINT\n520 PRINT \"LET'S PLAY AGAIN.....\"\n530 GOTO 310\n999 END\n"
  },
  {
    "path": "54_Letter/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "54_Letter/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "54_Letter/perl/letter.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x33 . \"LETTER\\n\";\nprint ' 'x15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"LETTER GUESSING GAME\\n\\n\";\nprint \"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\\n\";\nprint \"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\\n\";\nprint \"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\\n\";\n\nwhile (1) {\n\tmy $letter = 65 + int(rand(26));\n\tmy $guesses = 0;\n\tprint \"\\nO.K., I HAVE A LETTER. START GUESSING.\\n\";\n\n\tmy $answer;\n\tdo {\n\t\tprint \"\\nWHAT IS YOUR GUESS? \";\n\t\t$guesses++;\n\t\tchomp($answer = <STDIN>);\n\t\t$answer = ord($answer);\n\t\tprint \"\\n\";\n\t\tprint \"TOO LOW. TRY A HIGHER LETTER.\\n\" if $answer < $letter;\n\t\tprint \"TOO HIGH. TRY A LOWER LETTER.\\n\" if $answer > $letter;\n\t} until($answer eq $letter);\n\n\tprint \"\\nYOU GOT IT IN $guesses GUESSES!!\\n\";\n\n\tif ($guesses <= 5) {\n\t\tprint \"GOOD JOB !!!!!\\n\";\n\t\tprint chr(7) x 15; # ASCII Bell\n\t} else {\n\t\tprint \"BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\\n\";\n\t}\n\n\tprint \"\\nLET'S PLAY AGAIN.....\\n\";\n}\n\nexit;\n"
  },
  {
    "path": "54_Letter/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "54_Letter/python/letter.py",
    "content": "\"\"\"\nLETTER\n\nA letter guessing game.\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\n\n# The original code printed character 7, the \"BELL\" character 15 times\n# when the player won. Many modern systems do not support this, and in\n# any case, it can quickly become annoying, so it is disabled here.\n\nBELLS_ON_SUCCESS = False\n\n\ndef print_instructions() -> None:\n    print(\"LETTER GUESSING GAME\")\n    print()\n    print(\"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\")\n    print(\"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\")\n    print(\"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\")\n\n\ndef play_game() -> None:\n    target_value = random.randint(ord(\"A\"), ord(\"Z\"))\n    num_guesses = 0\n    print()\n    print(\"O.K., I HAVE A LETTER.  START GUESSING.\")\n    print()\n    while True:\n        print(\"WHAT IS YOUR GUESS?\")\n        num_guesses += 1\n        guess = ord(input())\n        print()\n        if guess == target_value:\n            print()\n            print(f\"YOU GOT IT IN {num_guesses} GUESSES!!\")\n            if num_guesses > 5:\n                print(\"BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\")\n                # goto 515\n            print(\"GOOD JOB !!!!!\")\n\n            if BELLS_ON_SUCCESS:\n                bell_str = chr(7) * 15\n                print(bell_str)\n\n            print()\n            print(\"LET'S PLAY AGAIN.....\")\n            return\n        elif guess > target_value:\n            print(\"TOO HIGH. TRY A LOWER LETTER.\")\n            continue\n        else:\n            print(\"TOO LOW. TRY A HIGHER LETTER.\")\n            continue\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"LETTER\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    print_instructions()\n\n    while True:\n        play_game()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "54_Letter/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "54_Letter/ruby/letter.rb",
    "content": "#!/usr/bin/env ruby\n\n# Kinema\n# reinterpreted from BASIC by stephan.com\n\nputs 'Letter'.center(80)\nputs 'Adapted by stephan.com'.center(80)\nputs \"\\n\\n\\n\"\n\nputs \"Letter guessing game\\n\\n\"\n\nputs \"I'll think of a letter of the alphabet, A to Z.\"\nputs \"Try to guess my letter and I'll give you clues\"\nputs \"as to how close you're getting to my letter.\"\n\ndef win(turns)\n  puts \"\\nyou got it in #{turns} guesses!!\"\n  return puts \"but it shouldn't take more than 5 guesses!\" if turns > 5\n\n  puts \"good job !!!!!\\a\\a\\a\"\nend\n\ndef play\n  letter = ('A'..'Z').to_a.sample\n  guess = nil\n  turn = 0\n\n  puts \"\\nO.K., I have a letter.  Start guessing.\"\n\n  until guess == letter\n    puts \"\\nWhat is your guess?\"\n\n    guess = gets.strip.chars.first.upcase\n    turn += 1\n\n    puts 'Too low.  Try a higher letter.' if guess < letter\n    puts 'Too high.  Try a lower letter.' if guess > letter\n  end\n  win(turn)\nend\n\nloop do\n  play\n  puts \"\\nlet's play again.....\"\nend\n"
  },
  {
    "path": "54_Letter/rust/Cargo.toml",
    "content": "[package]\nname = \"letter\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.4\"\n\n"
  },
  {
    "path": "54_Letter/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "54_Letter/rust/src/main.rs",
    "content": "use rand::Rng;\nuse std::cmp::Ordering;\nuse std::io;\n\nfn main() {\n    println!(\n        \"{: >40}\\n{: >57}\\n\\n\\n\",\n        \"LETTER\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    println!(\"LETTER GUESSING GAME\\n\");\n    println!(\"I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\");\n    println!(\"TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\");\n    println!(\"AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\");\n\n    loop {\n        let gen_character = rand::thread_rng().gen_range('A'..='Z'); // generates a random character between A and Z\n        let gen_character = String::from(gen_character);\n        println!(\"\\nO.K., I HAVE A LETTER.  START GUESSING.\");\n        for i in 0..999999 {\n            println!(\"\\nWHAT IS YOUR GUESS?\");\n\n            let mut guess = String::new();\n\n            io::stdin()\n                .read_line(&mut guess)\n                .expect(\"Failed to read the line\");\n            println!(\"{}\", gen_character);\n            let guess = guess.trim().to_ascii_uppercase();\n            match guess.cmp(&gen_character) {\n                Ordering::Less => println!(\"\\nTOO LOW.  TRY A HIGHER LETTER.\"),\n                Ordering::Greater => println!(\"\\nTOO HIGH.  TRY A LOWER LETTER.\"),\n                Ordering::Equal => {\n                    println!(\"\\nYOU GOT IT IN {} GUESSES!!\", i + 1);\n                    if i >= 4 {\n                        println!(\"BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\\n\");\n                    } else {\n                        println!(\"{}\", std::iter::repeat(\"💖\").take(15).collect::<String>());\n                        println!(\"GOOD JOB !!!!!\");\n                    }\n                    break;\n                }\n            }\n        }\n        println!(\"\\nLET'S PLAY AGAIN.....\");\n    }\n}\n"
  },
  {
    "path": "54_Letter/vbnet/Letter.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Letter\", \"Letter.vbproj\", \"{15392FFC-0EBB-4CA3-970F-8AC32DE84724}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "54_Letter/vbnet/Letter.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Letter</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "54_Letter/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "55_Life/README.md",
    "content": "### Life\n\nThe Game of Life was originally described in _Scientific American_, October 1970, in an article by Martin Gardner. The game itself was originated by John Conway of Gonville and Caius College, University of Cambridge England.\n\nIn the “manual” game, organisms exist in the form of counters (chips or checkers) on a large checkerboard and die or reproduce according to some simple genetic rules. Conway’s criteria for choosing his genetic laws were carefully delineated as follows:\n1. There should be no initial pattern for which there is a simple proof that the population can grow without limit.\n2. There should be simple initial patterns that apparently do grow without limit.\n3. There should be simple initial patterns that grow and change for a considerable period of time before coming to an end in three possible ways:\n    1. Fading away completely (from overcrowding or from becoming too sparse)\n    2. Settling into a stable configuration that remains unchanged thereafter\n    3. Entering an oscillating phase in which they repeat an endless cycle of two or more periods\n\nIn brief, the rules should be such as to make the behavior of the population relatively unpredictable. Conway’s genetic laws are delightfully simple. First note that each cell of the checkerboard (assumed to be an infinite plane) has eight neighboring cells, four adjacent orthogonally, four adjacent diagonally. The rules are:\n1. Survivals. Every counter with two or three neighboring counters survives for the next generation.\n2. Deaths. Each counter with four or more neighbors dies (is removed) from overpopulation. Every counter with one neighbor or none dies from isolation.\n3. Births. Each empty cell adjacent to exactly three neighbors — no more — is a birth cell. A counter is placed on it at the next move.\n\nIt is important to understand that all births and deaths occur simultaneously. Together they constitute a single generation or, as we shall call it, a “move” in the complete “life history” of the initial configuration.\n\nYou will find the population constantly undergoing unusual, sometimes beautiful and always unexpected change. In a few cases the society eventually dies out (all counters vanishing), although this may not happen until after a great many generations. Most starting patterns either reach stable figures — Conway calls them “still lifes” — that cannot change or patterns that oscillate forever. Patterns with no initial symmetry tend to become symmetrical. Once this happens the symmetry cannot be lost, although it may increase in richness.\n\nConway used a DEC PDP-7 with a graphic display to observe long-lived populations. You’ll probably find this more enjoyable to watch on a CRT than a hard-copy terminal.\n\nSince MITS 8K BASIC does not have LINE INPUT, to enter leading blanks in the patter, type a “.” at the start of the line. This will be converted to a space by BASIC, but it permits you to type leading spaces. Typing DONE indicates that you are finished entering the pattern. See sample run.\n\nClark Baker of Project DELTA originally wrote this version of LIFE which was further modified by Steve North of Creative Computing.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=100)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=115)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n\n#### Porting Notes\n\n- To make sense of the code, it's important to understand what the values in the A(X,Y) array mean:\n  - 0: dead cell\n  - 1: live cell\n  - 2: currently live, but dead next cycle\n  - 3: currently dead, but alive next cycle\n\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "55_Life/csharp/.gitignore",
    "content": "\n# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode\n# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,rider,visualstudio,visualstudiocode\n\n### DotnetCore ###\n# .NET Core build folders\nbin/\nobj/\n\n# Common node modules locations\n/node_modules\n/wwwroot/node_modules\n\n### Rider ###\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/**/usage.statistics.xml\n.idea/**/dictionaries\n.idea/**/shelf\n\n# AWS User-specific\n.idea/**/aws.xml\n\n# Generated files\n.idea/**/contentModel.xml\n\n# Sensitive or high-churn files\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n.idea/**/dbnavigator.xml\n\n# Gradle\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# Gradle and Maven with auto-import\n# When using Gradle or Maven with auto-import, you should exclude module files,\n# since they will be recreated, and may cause churn.  Uncomment if using\n# auto-import.\n# .idea/artifacts\n# .idea/compiler.xml\n# .idea/jarRepositories.xml\n# .idea/modules.xml\n# .idea/*.iml\n# .idea/modules\n# *.iml\n# *.ipr\n\n# CMake\ncmake-build-*/\n\n# Mongo Explorer plugin\n.idea/**/mongoSettings.xml\n\n# File-based project format\n*.iws\n\n# IntelliJ\nout/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# SonarLint plugin\n.idea/sonarlint/\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Editor-based Rest Client\n.idea/httpRequests\n\n# Android studio 3.1+ serialized cache file\n.idea/caches/build_file_checksums.ser\n\n### VisualStudioCode ###\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n!.vscode/*.code-snippets\n\n# Local History for Visual Studio Code\n.history/\n\n# Built Visual Studio Code Extensions\n*.vsix\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n.ionide\n\n# Support for Project snippet scope\n\n### VisualStudio ###\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Ww][Ii][Nn]32/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# ASP.NET Scaffolding\nScaffoldingReadMe.txt\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.tlog\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio 6 auto-generated project file (contains which files were open etc.)\n*.vbp\n\n# Visual Studio 6 workspace and project file (working project files containing files to include in project)\n*.dsw\n*.dsp\n\n# Visual Studio 6 technical files\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# Visual Studio History (VSHistory) files\n.vshistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n# Fody - auto-generated XML schema\nFodyWeavers.xsd\n\n# VS Code files for those working on multiple tools\n*.code-workspace\n\n# Local History for Visual Studio Code\n\n# Windows Installer files from build outputs\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# JetBrains Rider\n*.sln.iml\n\n### VisualStudio Patch ###\n# Additional files built by Visual Studio\n\n# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode\n"
  },
  {
    "path": "55_Life/csharp/Life.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <OutputType>Exe</OutputType>\n        <TargetFramework>net6.0</TargetFramework>\n        <Nullable>enable</Nullable>\n    </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "55_Life/csharp/Life.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Life\", \"Life.csproj\", \"{28B02688-78D1-4B3E-B998-BCC78C292D03}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "55_Life/csharp/Program.cs",
    "content": "﻿using System.Text;\n\nconst int maxWidth = 70;\nconst int maxHeight = 24;\n\nConsole.WriteLine(\"ENTER YOUR PATTERN:\");\nvar pattern = new Pattern(ReadPattern(limitHeight: maxHeight).ToArray());\n\nvar minX = 10 - pattern.Height / 2;\nvar minY = 34 - pattern.Width / 2;\nvar maxX = maxHeight - 1;\nvar maxY = maxWidth - 1;\n\nvar matrix = new Matrix(height: maxHeight, width: maxWidth);\nvar simulation = InitializeSimulation(pattern, matrix);\n\nPrintHeader();\nProcessSimulation();\n\nIEnumerable<string> ReadPattern(int limitHeight)\n{\n    for (var i = 0; i < limitHeight; i++)\n    {\n        var input = Console.ReadLine();\n        if (input.ToUpper() == \"DONE\")\n        {\n            break;\n        }\n\n        // In the original version, BASIC would trim the spaces in the beginning of an input, so the original\n        // game allowed you to input an '.' before the spaces to circumvent this limitation. This behavior was\n        // kept for compatibility.\n        if (input.StartsWith('.'))\n            yield return input.Substring(1, input.Length - 1);\n\n        yield return input;\n    }\n}\n\nvoid PrintHeader()\n{\n    void PrintCentered(string text)\n    {\n        const int pageWidth = 64;\n\n        var spaceCount = (pageWidth - text.Length) / 2;\n        Console.Write(new string(' ', spaceCount));\n        Console.WriteLine(text);\n    }\n\n    PrintCentered(\"LIFE\");\n    PrintCentered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    Console.WriteLine();\n    Console.WriteLine();\n    Console.WriteLine();\n}\n\nSimulation InitializeSimulation(Pattern pattern, Matrix matrixToInitialize) {\n    var newSimulation = new Simulation();\n\n    // transcribes the pattern to the middle of the simulation and counts initial population\n    for (var x = 0; x < pattern.Height; x++)\n    {\n        for (var y = 0; y < pattern.Width; y++)\n        {\n            if (pattern.Content[x][y] == ' ')\n                continue;\n\n            matrixToInitialize[minX + x, minY + y] = CellState.Stable;\n            newSimulation.IncreasePopulation();\n        }\n    }\n\n    return newSimulation;\n}\n\nTimeSpan GetPauseBetweenIterations()\n{\n    if (args.Length != 2) return TimeSpan.Zero;\n\n    var parameter = args[0].ToLower();\n    if (parameter.Contains(\"wait\"))\n    {\n        var value = args[1];\n        if (int.TryParse(value, out var sleepMilliseconds))\n            return TimeSpan.FromMilliseconds(sleepMilliseconds);\n    }\n\n    return TimeSpan.Zero;\n}\n\nvoid ProcessSimulation()\n{\n    var pauseBetweenIterations = GetPauseBetweenIterations();\n    var isInvalid = false;\n\n    while (true)\n    {\n        var invalidText = isInvalid ? \"INVALID!\" : \"\";\n        Console.WriteLine($\"GENERATION: {simulation.Generation}\\tPOPULATION: {simulation.Population} {invalidText}\");\n\n        simulation.StartNewGeneration();\n\n        var nextMinX = maxHeight - 1;\n        var nextMinY = maxWidth - 1;\n        var nextMaxX = 0;\n        var nextMaxY = 0;\n\n        var matrixOutput = new StringBuilder();\n\n        // prints the empty lines before search area\n        for (var x = 0; x < minX; x++)\n        {\n            matrixOutput.AppendLine();\n        }\n\n        // refreshes the matrix and updates search area\n        for (var x = minX; x <= maxX; x++)\n        {\n            var printedLine = Enumerable.Repeat(' ', maxWidth).ToList();\n            for (var y = minY; y <= maxY; y++)\n            {\n                if (matrix[x, y] == CellState.Dying)\n                {\n                    matrix[x, y] = CellState.Empty;\n                    continue;\n                }\n                if (matrix[x, y] == CellState.New)\n                {\n                    matrix[x, y] = CellState.Stable;\n                }\n                else if (matrix[x, y] != CellState.Stable)\n                {\n                    continue;\n                }\n\n                printedLine[y] = '*';\n\n                nextMinX = Math.Min(x, nextMinX);\n                nextMaxX = Math.Max(x, nextMaxX);\n                nextMinY = Math.Min(y, nextMinY);\n                nextMaxY = Math.Max(y, nextMaxY);\n            }\n\n            matrixOutput.AppendLine(string.Join(separator: null, values: printedLine));\n        }\n\n        // prints empty lines after search area\n        for (var x = maxX + 1; x < maxHeight; x++)\n        {\n            matrixOutput.AppendLine();\n        }\n        Console.Write(matrixOutput);\n\n        void UpdateSearchArea()\n        {\n            minX = nextMinX;\n            maxX = nextMaxX;\n            minY = nextMinY;\n            maxY = nextMaxY;\n\n            const int limitX = 21;\n            const int limitY = 67;\n\n            if (minX < 2)\n            {\n                minX = 2;\n                isInvalid = true;\n            }\n\n            if (maxX > limitX)\n            {\n                maxX = limitX;\n                isInvalid = true;\n            }\n\n            if (minY < 2)\n            {\n                minY = 2;\n                isInvalid = true;\n            }\n\n            if (maxY > limitY)\n            {\n                maxY = limitY;\n                isInvalid = true;\n            }\n        }\n        UpdateSearchArea();\n\n        for (var x = minX - 1; x <= maxX + 1; x++)\n        {\n            for (var y = minY - 1; y <= maxY + 1; y++)\n            {\n                int CountNeighbors()\n                {\n                    var neighbors = 0;\n                    for (var i = x - 1; i <= x + 1; i++)\n                    {\n                        for (var j = y - 1; j <= y + 1; j++)\n                        {\n                            if (matrix[i, j] == CellState.Stable || matrix[i, j] == CellState.Dying)\n                                neighbors++;\n                        }\n                    }\n\n                    return neighbors;\n                }\n\n                var neighbors = CountNeighbors();\n                if (matrix[x, y] == CellState.Empty)\n                {\n                    if (neighbors == 3)\n                    {\n                        matrix[x, y] = CellState.New;\n                        simulation.IncreasePopulation();\n                    }\n                }\n                else if (neighbors is < 3 or > 4)\n                {\n                    matrix[x, y] = CellState.Dying;\n                }\n                else\n                {\n                    simulation.IncreasePopulation();\n                }\n            }\n        }\n\n        // expands search area to accommodate new cells\n        minX--;\n        minY--;\n        maxX++;\n        maxY++;\n\n        if (pauseBetweenIterations > TimeSpan.Zero)\n            Thread.Sleep(pauseBetweenIterations);\n    }\n}\n\npublic class Pattern\n{\n    public string[] Content { get; }\n    public int Height { get; }\n    public int Width { get; }\n\n    public Pattern(IReadOnlyCollection<string> patternLines)\n    {\n        Height = patternLines.Count;\n        Width = patternLines.Max(x => x.Length);\n        Content = NormalizeWidth(patternLines);\n    }\n\n    private string[] NormalizeWidth(IReadOnlyCollection<string> patternLines)\n    {\n        return patternLines\n            .Select(x => x.PadRight(Width, ' '))\n            .ToArray();\n    }\n}\n\n/// <summary>\n/// Indicates the state of a given cell in the simulation.\n/// </summary>\ninternal enum CellState\n{\n    Empty = 0,\n    Stable = 1,\n    Dying = 2,\n    New = 3\n}\n\npublic class Simulation\n{\n    public int Generation { get; private set; }\n\n    public int Population { get; private set; }\n\n    public void StartNewGeneration()\n    {\n        Generation++;\n        Population = 0;\n    }\n\n    public void IncreasePopulation()\n    {\n        Population++;\n    }\n}\n\n/// <summary>\n/// This class was created to aid debugging, through the implementation of the ToString() method.\n/// </summary>\nclass Matrix\n{\n    private readonly CellState[,] _matrix;\n\n    public Matrix(int height, int width)\n    {\n        _matrix = new CellState[height, width];\n    }\n\n    public CellState this[int x, int y]\n    {\n        get => _matrix[x, y];\n        set => _matrix[x, y] = value;\n    }\n\n    public override string ToString()\n    {\n        var stringBuilder = new StringBuilder();\n        for (var x = 0; x < _matrix.GetLength(0); x++)\n        {\n            for (var y = 0; y < _matrix.GetLength(1); y++)\n            {\n                var character = _matrix[x, y] == 0 ? \" \": ((int)_matrix[x, y]).ToString();\n                stringBuilder.Append(character);\n            }\n\n            stringBuilder.AppendLine();\n        }\n        return stringBuilder.ToString();\n    }\n}\n"
  },
  {
    "path": "55_Life/csharp/README.md",
    "content": "# Life\n\nAn implementation of John Conway's popular cellular automaton, also know as **Conway's Game of Life**. The original source was downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html).\n\nPorted by Dyego Alekssander Maas.\n\n## How to run\n\nThis program requires you to install [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0). After installed, you just need to run `dotnet run` from this directory in the terminal.\n\n## Know more about Conway's Game of Life\n\nYou can find more about Conway's Game of Life on this page of the [Cornell Math Explorers' Club](http://pi.math.cornell.edu/~lipa/mec/lesson6.html), alongside many examples of patterns you can try.\n\n### Optional parameters\n\nOptionally, you can run this program with the `--wait 1000` argument, the number being the time in milliseconds\nthat the application will pause between each iteration. This is enables you to watch the simulation unfolding. By default, there is no pause between iterations.\n\nThe complete command would be `dotnet run --wait 1000`.\n\n## Entering patterns\n\nOnce running the game, you are expected to enter a pattern. This pattern consists of multiple lines of text with either **spaces** or **some character**, usually an asterisk (`*`).\n\nSpaces represent empty cells. Asterisks represent alive cells.\n\nAfter entering the pattern, you need to enter the word \"DONE\". It is not case sensitive. An example of pattern would be:\n\n```\n *\n***\nDONE\n```\n\n### Some patterns you could try\n\n```\n *\n***\n```\n\n```\n*\n***\n```\n\n```\n**\n**\n```\n\n```\n  *\n *\n*\n```\n\nThis one is known as **glider**:\n\n```\n***\n*\n *\n```\n\n## Instructions to the port\n\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "55_Life/java/README.md",
    "content": "# Game of Life - Java version\n\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n\n## Requirements\n\n* Requires Java 17 (or later)\n\n## Notes\n\nThe Java version of Game of Life tries to mimics the behaviour of the BASIC version.\nHowever, the Java code does not have much in common with the original.\n\n**Differences in behaviour:**\n* Input supports the ```.``` character, but it's optional.\n* Evaluation of ```DONE``` input string is case insensitive.\n* Run with the ```-s``` command line argument to halt the program after each generation, and continue when ```ENTER``` is pressed.\n"
  },
  {
    "path": "55_Life/java/src/java/Life.java",
    "content": "import java.util.ArrayList;\nimport java.util.List;\nimport java.util.Scanner;\n\n/**\n * The Game of Life class.<br>\n * <br>\n * Mimics the behaviour of the BASIC version, however the Java code does not have much in common with the original.\n * <br>\n * Differences in behaviour:\n * <ul>\n *     <li>Input supports the \".\" character, but it's optional.</li>\n *     <li>Input regarding the \"DONE\" string is case insensitive.</li>\n * </ul>\n */\npublic class Life {\n\n    private static final byte DEAD  = 0;\n    private static final byte ALIVE = 1;\n    private static final String NEWLINE = \"\\n\";\n\n    private final Scanner consoleReader = new Scanner(System.in);\n\n    private final byte[][] matrix = new byte[21][67];\n    private int generation = 0;\n    private int population = 0;\n    boolean stopAfterGen = false;\n    boolean invalid = false;\n\n    /**\n     * Constructor.\n     *\n     * @param args the command line arguments\n     */\n    public Life(String[] args) {\n        parse(args);\n    }\n\n    private void parse(String[] args) {\n        for (String arg : args) {\n            if (\"-s\".equals(arg)) {\n                stopAfterGen = true;\n                break;\n            }\n        }\n    }\n\n    /**\n     * Starts the game.\n     */\n    public void start() {\n        printGameHeader();\n        readPattern();\n        while (true) {\n            printGeneration();\n            advanceToNextGeneration();\n            if (stopAfterGen) {\n                System.out.print(\"PRESS ENTER TO CONTINUE\");\n                consoleReader.nextLine();\n            }\n        }\n    }\n\n    private void advanceToNextGeneration() {\n        // store all cell transitions in a list, i.e. if a dead cell becomes alive, or a living cell dies\n        List<Transition> transitions = new ArrayList<>();\n        // there's still room for optimization: instead of iterating over all cells in the matrix,\n        // we could consider only the section containing the pattern(s), as in the BASIC version\n        for (int y = 0; y < matrix.length; y++) {\n            for (int x = 0; x < matrix[y].length; x++) {\n                int neighbours = countNeighbours(y, x);\n                if (matrix[y][x] == ALIVE) {\n                    if (neighbours < 2 || neighbours > 3) {\n                        transitions.add(new Transition(y, x, DEAD));\n                        population--;\n                    }\n                } else { // cell is dead\n                    if (neighbours == 3) {\n                        if (x < 2 || x > 67 || y < 2 || y > 21) {\n                            invalid = true;\n                        }\n                        transitions.add(new Transition(y, x, ALIVE));\n                        population++;\n                    }\n                }\n            }\n        }\n        // apply all transitions to the matrix\n        transitions.forEach(t -> matrix[t.y()][t.x()] = t.newState());\n        generation++;\n    }\n\n    private int countNeighbours(int y, int x) {\n        int neighbours = 0;\n        for (int row = Math.max(y - 1, 0); row <= Math.min(y + 1, matrix.length - 1); row++) {\n            for (int col = Math.max(x - 1, 0); col <= Math.min(x + 1, matrix[row].length - 1); col++) {\n                if (row == y && col == x) {\n                    continue;\n                }\n                if (matrix[row][col] == ALIVE) {\n                    neighbours++;\n                }\n            }\n        }\n        return neighbours;\n    }\n\n    private void readPattern() {\n        System.out.println(\"ENTER YOUR PATTERN:\");\n        List<String> lines = new ArrayList<>();\n        String line;\n        int maxLineLength = 0;\n        boolean reading = true;\n        while (reading) {\n            System.out.print(\"? \");\n            line = consoleReader.nextLine();\n            if (line.equalsIgnoreCase(\"done\")) {\n                reading = false;\n            } else {\n                // optional support for the '.' that is needed in the BASIC version\n                lines.add(line.replace('.', ' '));\n                maxLineLength = Math.max(maxLineLength, line.length());\n            }\n        }\n        fillMatrix(lines, maxLineLength);\n    }\n\n    private void fillMatrix(List<String> lines, int maxLineLength) {\n        float xMin = 33 - maxLineLength / 2f;\n        float yMin = 11 - lines.size() / 2f;\n        for (int y = 0; y < lines.size(); y++) {\n            String line = lines.get(y);\n            for (int x = 1; x <= line.length(); x++) {\n                if (line.charAt(x-1) == '*') {\n                    matrix[floor(yMin + y)][floor(xMin + x)] = ALIVE;\n                    population++;\n                }\n            }\n        }\n    }\n\n    private int floor(float f) {\n        return (int) Math.floor(f);\n    }\n\n    private void printGameHeader() {\n        printIndented(34, \"LIFE\");\n        printIndented(15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println(NEWLINE.repeat(3));\n    }\n\n    private void printIndented(int spaces, String str) {\n        System.out.println(\" \".repeat(spaces) + str);\n    }\n\n    private void printGeneration() {\n        printGenerationHeader();\n        for (int y = 0; y < matrix.length; y++) {\n            for (int x = 0; x < matrix[y].length; x++) {\n                System.out.print(matrix[y][x] == 1 ? \"*\" : \" \");\n            }\n            System.out.println();\n        }\n    }\n\n    private void printGenerationHeader() {\n        String invalidText = invalid ? \"INVALID!\" : \"\";\n        System.out.printf(\"GENERATION: %-13d POPULATION: %d %s\\n\", generation, population, invalidText);\n    }\n\n    /**\n     * Main method that starts the program.\n     *\n     * @param args the command line arguments:\n     *             <pre>-s: Stop after each generation (press enter to continue)</pre>\n     * @throws Exception if something goes wrong.\n     */\n    public static void main(String[] args) throws Exception {\n        new Life(args).start();\n    }\n\n}\n\n/**\n * Represents a state change for a single cell within the matrix.\n *\n * @param y the y coordinate (row) of the cell\n * @param x the x coordinate (column) of the cell\n * @param newState the new state of the cell (either DEAD or ALIVE)\n */\nrecord Transition(int y, int x, byte newState) { }\n"
  },
  {
    "path": "55_Life/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "55_Life/javascript/life.html",
    "content": "<html>\n<head>\n<title>LIFE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"life.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "55_Life/javascript/life.js",
    "content": "// LIFE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar bs = [];\nvar a = [];\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"LIFE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"ENTER YOUR PATTERN:\\n\");\n    x1 = 1;\n    y1 = 1;\n    x2 = 24;\n    y2 = 70;\n    for (c = 1; c <= 24; c++) {\n        bs[c] = \"\";\n        a[c] = [];\n        for (d = 1; d <= 70; d++)\n            a[c][d] = 0;\n    }\n    c = 1;\n    while (1) {\n        bs[c] = await input();\n        if (bs[c] == \"DONE\") {\n            bs[c] = \"\";\n            break;\n        }\n        if (bs[c].substr(0, 1) == \".\")\n            bs[c] = \" \" + bs[c].substr(1);\n        c++;\n    }\n    c--;\n    l = 0;\n    for (x = 1; x <= c - 1; x++) {\n        if (bs[x].length > l)\n            l = bs[x].length;\n    }\n    x1 = 11 - (c >> 1);\n    y1 = 33 - (l >> 1);\n    p = 0;\n    for (x = 1; x <= c; x++) {\n        for (y = 1; y <= bs[x].length; y++) {\n            if (bs[x][y - 1] != \" \") {\n                a[x1 + x][y1 + y] = 1;\n                p++;\n            }\n        }\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    i9 = false;\n    g = 0;\n    while (g < 100) {\n        print(\"GENERATION: \" + g + \" POPULATION: \" + p + \" \");\n        if (i9)\n            print(\"INVALID!\");\n        x3 = 24;\n        y3 = 70;\n        x4 = 1;\n        y4 = 1;\n        p = 0;\n        g++;\n        for (x = 1; x <= x1 - 1; x++)\n            print(\"\\n\");\n        for (x = x1; x <= x2; x++) {\n            print(\"\\n\");\n            str = \"\";\n            for (y = y1; y <= y2; y++) {\n                if (a[x][y] == 2) {\n                    a[x][y] = 0;\n                    continue;\n                } else if (a[x][y] == 3) {\n                    a[x][y] = 1;\n                } else if (a[x][y] != 1) {\n                    continue;\n                }\n                while (str.length < y)\n                    str += \" \";\n                str += \"*\";\n                if (x < x3)\n                    x3 = x;\n                if (x > x4)\n                    x4 = x;\n                if (y < y3)\n                    y3 = y;\n                if (y > y4)\n                    y4 = y;\n            }\n            print(str);\n        }\n        for (x = x2 + 1; x <= 24; x++)\n            print(\"\\n\");\n        x1 = x3;\n        x2 = x4;\n        y1 = y3;\n        y2 = y4;\n        if (x1 < 3) {\n            x1 = 3;\n            i9 = true;\n        }\n        if (x2 > 22) {\n            x2 = 22;\n            i9 = true;\n        }\n        if (y1 < 3) {\n            y1 = 3;\n            i9 = true;\n        }\n        if (y2 > 68) {\n            y2 = 68;\n            i9 = true;\n        }\n        p = 0;\n        for (x = x1 - 1; x <= x2 + 1; x++) {\n            for (y = y1 - 1; y <= y2 + 1; y++) {\n                c = 0;\n                for (i = x - 1; i <= x + 1; i++) {\n                    for (j = y - 1; j <= y + 1; j++) {\n                        if (a[i][j] == 1 || a[i][j] == 2)\n                            c++;\n                    }\n                }\n                if (a[x][y] == 0) {\n                    if (c == 3) {\n                        a[x][y] = 3;\n                        p++;\n                    }\n                } else {\n                    if (c < 3 || c > 4) {\n                        a[x][y] = 2;\n                    } else {\n                        p++;\n                    }\n                }\n            }\n        }\n        x1--;\n        y1--;\n        x2++;\n        y2++;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "55_Life/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "55_Life/life.bas",
    "content": "2 PRINT TAB(34);\"LIFE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n8 PRINT \"ENTER YOUR PATTERN:\"\n9 X1=1: Y1=1: X2=24: Y2=70\n10 DIM A(24,70),B$(24)\n20 C=1\n30 INPUT B$(C)\n40 IF B$(C)=\"DONE\" THEN B$(C)=\"\": GOTO 80\n50 IF LEFT$(B$(C),1)=\".\" THEN B$(C)=\" \"+RIGHT$(B$(C),LEN(B$(C))-1)\n60 C=C+1\n70 GOTO 30\n80 C=C-1: L=0\n90 FOR X=1 TO C-1\n100 IF LEN(B$(X))>L THEN L=LEN(B$(X))\n110 NEXT X\n120 X1=11-C/2\n130 Y1=33-L/2\n140 FOR X=1 TO C\n150 FOR Y=1 TO LEN(B$(X))\n160 IF MID$(B$(X),Y,1)<>\" \" THEN A(X1+X,Y1+Y)=1:P=P+1\n170 NEXT Y\n180 NEXT X\n200 PRINT:PRINT:PRINT\n210 PRINT \"GENERATION:\";G,\"POPULATION:\";P;: IF I9 THEN PRINT \"INVALID!\";\n215 X3=24:Y3=70:X4=1: Y4=1: P=0\n220 G=G+1\n225 FOR X=1 TO X1-1: PRINT: NEXT X\n230 FOR X=X1 TO X2\n240 PRINT\n250 FOR Y=Y1 TO Y2\n253 IF A(X,Y)=2 THEN A(X,Y)=0:GOTO 270\n256 IF A(X,Y)=3 THEN A(X,Y)=1:GOTO 261\n260 IF A(X,Y)<>1 THEN 270\n261 PRINT TAB(Y);\"*\";\n262 IF X<X3 THEN X3=X\n264 IF X>X4 THEN X4=X\n266 IF Y<Y3 THEN Y3=Y\n268 IF Y>Y4 THEN Y4=Y\n270 NEXT Y\n290 NEXT X\n295 FOR X=X2+1 TO 24: PRINT: NEXT X\n299 X1=X3: X2=X4: Y1=Y3: Y2=Y4\n301 IF X1<3 THEN X1=3:I9=-1\n303 IF X2>22 THEN X2=22:I9=-1\n305 IF Y1<3 THEN Y1=3:I9=-1\n307 IF Y2>68 THEN Y2=68:I9=-1\n309 P=0\n500 FOR X=X1-1 TO X2+1\n510 FOR Y=Y1-1 TO Y2+1\n520 C=0\n530 FOR I=X-1 TO X+1\n540 FOR J=Y-1 TO Y+1\n550 IF A(I,J)=1 OR A(I,J)=2 THEN C=C+1\n560 NEXT J\n570 NEXT I\n580 IF A(X,Y)=0 THEN 610\n590 IF C<3 OR C>4 THEN A(X,Y)=2: GOTO 600\n595 P=P+1\n600 GOTO 620\n610 IF C=3 THEN A(X,Y)=3:P=P+1\n620 NEXT Y\n630 NEXT X\n635 X1=X1-1:Y1=Y1-1:X2=X2+1:Y2=Y2+1\n640 GOTO 210\n650 END\n"
  },
  {
    "path": "55_Life/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "55_Life/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "55_Life/perl/life.pl",
    "content": "#!/usr/bin/perl\n#use strict;\n\nprint ' 'x 34 . \"LIFE\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"ENTER YOUR PATTERN; \\n\";\n$X1=1; $Y1=1; $X2=24; $Y2=70;\n@A;\n$C=1;\n\n@B;\nLine30:\nprint \"? \"; chomp($B[$C] = uc(<STDIN>));\nif ($B[$C] eq \"DONE\") { $B[$C]=\"\"; goto Line80; }\n$B[$C]=~ s/\\./ /g;\n$C=$C+1;\ngoto Line30;\n\n\nLine80:\n\n$C=$C-1; $L=0; $G=0;\nfor ($X=1; $X<=$C-1; $X++) {\n\tif (length($B[$X])>$L) { $L=length($B[$X]); }\n\t}\n\n$X1=11-$C/2;\n$Y1=33-$L/2;\nfor ($X=1; $X<=$C; $X++) {\n\tfor ($Y=1; $Y<=length($B[$X]); $Y++) {\n\t\tif (substr($B[$X],$Y-1,1) ne \" \") { $A[$X1+$X][$Y1+$Y]=1; $P=$P+1; }\n\t\t}\n\t}\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\n\nLine210:\nprint \"GENERATION: \".$G.\"\\t\\tPOPULATION: \".$P; if ($I9) { print \"\\tINVALID!\"; }\nprint \"\\n\";\n$X3=24; $Y3=70; $X4=1; $Y4=1; $P=0;\n$G=$G+1;\nfor ($X=1; $X<=$X1-1; $X++) { print \"\\n\"; }\nfor ($X=$X1; $X<=$X2; $X++) {\n\t$Row= \" \"x 80;\n\tfor ($Y=$Y1; $Y<=$Y2; $Y++) {\n\t\tif ($A[$X][$Y]==2) { $A[$X][$Y]=0; goto Line270; }\n\t\tif ($A[$X][$Y]==3) { $A[$X][$Y]=1; goto Line261; }\n\t\tif ($A[$X][$Y]!=1) { goto Line270; }\n\n\t\tLine261:\n\t\tsubstr($Row, $Y, 1, \"*\");\n\t\tif ($X<$X3) { $X3=$X; }\n\t\tif ($X>$X4) { $X4=$X; }\n\t\tif ($Y<$Y3) { $Y3=$Y; }\n\t\tif ($Y>$Y4) { $Y4=$Y; }\n\n\t\tLine270:\n\t\t}\n\tprint \"$Row\\n\";\n\t}\n\nfor ($X=$X2+1; $X<=24; $X++) { print \"\\n\"; }\n$X1=$X3; $X2=$X4; $Y1=$Y3; $Y2=$Y4;\nif ($X1<3) { $X1=3; $I9=-1; }\nif ($X2>22) { $X2=22; $I9=-1; }\nif ($Y1<3) { $Y1=3; $I9=-1; }\nif ($Y2>68) { $Y2=68; $I9=-1; }\n$P=0;\n\nfor ($X=$X1-1; $X<=$X2+1; $X++) {\n\tfor ($Y=$Y1-1; $Y<=$Y2+1; $Y++) {\n\t\t$C=0;\n\t\tfor ($I=$X-1; $I<=$X+1; $I++) {\n\t\t\tfor ($J=$Y-1; $J<=$Y+1; $J++) {\n\t\t\t\tif ($A[$I][$J]==1 || $A[$I][$J]==2) { $C=$C+1; }\n\t\t\t\t}\n\t\t\t}\n\t\tif ($A[$X][$Y]==0) { goto Line610; }\n\t\tif ($C<3 || $C>4) { $A[$X][$Y]=2; goto Line600; }\n\t\t$P=$P+1;\n\n\t\tLine600:\n\t\tgoto Line620;\n\n\t\tLine610:\n\t\tif ($C==3) { $A[$X][$Y]=3; $P=$P+1; }\n\n\t\tLine620:\n\t\t}\n\t}\n$X1=$X1-1; $Y1=$Y1-1; $X2=$X2+1; $Y2=$Y2+1;\ngoto Line210;\nexit;\n"
  },
  {
    "path": "55_Life/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "55_Life/python/life.py",
    "content": "\"\"\"\nLIFE\n\nAn implementation of John Conway's popular cellular automaton\n\nPorted by Dave LeCompte\n\"\"\"\n\nfrom typing import Dict\n\nPAGE_WIDTH = 64\n\nMAX_WIDTH = 70\nMAX_HEIGHT = 24\n\n\ndef print_centered(msg) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n\ndef get_pattern() -> Dict[int, str]:\n    print(\"ENTER YOUR PATTERN:\")\n    c = 0\n\n    pattern: Dict[int, str] = {}\n    while True:\n        line = input()\n        if line == \"DONE\":\n            return pattern\n\n        # BASIC input would strip of leading whitespace.\n        # Python input does not. The following allows you to start a\n        # line with a dot to disable the whitespace stripping. This is\n        # unnecessary for Python, but for historical accuracy, it's\n        # staying in.\n\n        if line[0] == \".\":\n            line = f\" {line[1:]}\"\n        pattern[c] = line\n        c += 1\n\n\ndef main() -> None:\n    print_header(\"LIFE\")\n\n    pattern = get_pattern()\n\n    pattern_height = len(pattern)\n    pattern_width = 0\n    for _line_num, line in pattern.items():\n        pattern_width = max(pattern_width, len(line))\n\n    min_x = 11 - pattern_height // 2\n    min_y = 33 - pattern_width // 2\n    max_x = MAX_HEIGHT - 1\n    max_y = MAX_WIDTH - 1\n\n    a = [[0 for _ in range(MAX_WIDTH)] for _ in range(MAX_HEIGHT)]\n    p = 0\n    g = 0\n    invalid = False\n\n    # line 140\n    # transcribe the input pattern into the active array\n    for x in range(0, pattern_height):\n        for y in range(0, len(pattern[x])):\n            if pattern[x][y] != \" \":\n                a[min_x + x][min_y + y] = 1\n                p += 1\n\n    print()\n    print()\n    print()\n    while True:\n        inv_str = \"INVALID!\" if invalid else \"\"\n        print(f\"GENERATION: {g}\\tPOPULATION: {p} {inv_str}\")\n\n        next_min_x = MAX_HEIGHT - 1\n        next_min_y = MAX_WIDTH - 1\n        next_max_x = 0\n        next_max_y = 0\n\n        p = 0\n        g += 1\n        for _ in range(min_x):\n            print()\n\n        for x in range(min_x, max_x + 1):\n            print()\n            line_list = [\" \"] * MAX_WIDTH\n            for y in range(min_y, max_y + 1):\n                if a[x][y] == 2:\n                    a[x][y] = 0\n                    continue\n                elif a[x][y] == 3:\n                    a[x][y] = 1\n                elif a[x][y] != 1:\n                    continue\n\n                line_list[y] = \"*\"\n\n                next_min_x = min(x, next_min_x)\n                next_max_x = max(x, next_max_x)\n                next_min_y = min(y, next_min_y)\n                next_max_y = max(y, next_max_y)\n\n            print(\"\".join(line_list))\n\n        # line 295\n        for _ in range(max_x + 1, MAX_HEIGHT):\n            print()\n\n        print()\n\n        min_x = next_min_x\n        max_x = next_max_x\n        min_y = next_min_y\n        max_y = next_max_y\n\n        if min_x < 3:\n            min_x = 3\n            invalid = True\n        if max_x > 22:\n            max_x = 22\n            invalid = True\n        if min_y < 3:\n            min_y = 3\n            invalid = True\n        if max_y > 68:\n            max_y = 68\n            invalid = True\n\n        # line 309\n        p = 0\n\n        for x in range(min_x - 1, max_x + 2):\n            for y in range(min_y - 1, max_y + 2):\n                count = 0\n                for i in range(x - 1, x + 2):\n                    for j in range(y - 1, y + 2):\n                        if a[i][j] in [1, 2]:\n                            count += 1\n                if a[x][y] == 0:\n                    if count == 3:\n                        a[x][y] = 3\n                        p += 1\n                elif (count < 3) or (count > 4):\n                    a[x][y] = 2\n                else:\n                    p += 1\n\n        # line 635\n        min_x = min_x - 1\n        min_y = min_y - 1\n        max_x = max_x + 1\n        max_y = max_y + 1\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "55_Life/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "55_Life/ruby/life.rb",
    "content": "#!ruby\n\n# The Pattern class encapsulates everything we would want to know about a\n# pattern in our Game of Life: its size, its current pattern of alive and\n# dead cells, which generation it's on and how long it can run, and how\n# to accept input for itself, print itself, and most importantly iterate\n# from one generation to the next.\n\nPATTERN_WIDTH = 80\nPATTERN_HEIGHT = 24\n\nclass Pattern\n\n  # Begin with a totally empty/dead pattern of fixed size at generation 0.\n\n  def initialize(max_generations: 10)\n    @max_generations = max_generations\n    @generation = 0\n    @population = nil\n    @counter = Array.new(PATTERN_HEIGHT) { Array.new(PATTERN_WIDTH, 0) }\n    @invalid = false\n  end\n\n  # Take input from the console and enter it into the pattern.\n\n  def get_input\n    input = []\n    done = false\n\n    # Accept the input from the user on the console\n\n    loop do\n      print \"? \"\n      line = gets.chomp\n      break if line == 'DONE'\n      line.gsub!(/^\\./, ' ')\n      input << line\n    end\n\n    # Emit some blank space\n    (1..10).each { puts }\n\n    # Center the input in the two-dimensional array\n    input_width = input.map { |line| line.length }.max\n    width_offset = ((PATTERN_WIDTH - input_width) / 2).floor\n    height_offset = ((PATTERN_HEIGHT - input.count) / 2).floor\n    # TODO emit error if width > PATTERN_WIDTH or line count > PATTERN_HEIGHT\n\n    # Start by setting each element to 0 if dead or a 1 if alive\n\n    input.each_index do |y|\n      line = input[y].ljust(input_width)\n      y_offset = y + height_offset\n      @counter[y_offset] = [\n        [0] * width_offset,\n        line.split(\"\").map { |char| char == ' ' ? 0 : 1 },\n        [0] * PATTERN_WIDTH\n      ].flatten.take(PATTERN_WIDTH)\n    end\n\n    @population = @counter.flatten.sum\n  end\n\n  # Emit the pattern to the console.\n\n  def display\n    puts \"GENERATION:#{@generation}\\tPOPULATION:#{@population}\"\n    puts \"INVALID!\"if @invalid\n\n    @counter.each do |row|\n      puts row.map { |cell| ((cell == 0 || cell == 2) ? ' ' : 'X') }.join('')\n    end\n  end\n\n  # Iterate from one generation to the next, returning true if the\n  # game of life should continue, and false if it should terminate.\n\n  def iterate\n    @generation = @generation + 1\n    return false if @generation > @max_generations\n\n    # Update the counter array with new values.\n    # First, change each 2 (dying) to a 0 (dead)\n    # and each 3 (born) to a 1 (alive)\n    @counter.map! { |row| row.map! { |cell| cell >= 2 ? cell-2 : cell } }\n\n    # Now for each cell, count its neighbors and update it\n\n    @population = 0\n    @counter.each_index do |rownum|\n      @counter[rownum].each_index do |colnum|\n        cell_value = @counter[rownum][colnum]\n\n        # If any cell on the border is set, our small algorithm is not\n        # smart enough to correctly check its neighbors, so sadly our\n        # pattern becomes invalid. We keep going though\n\n        @invalid = true if cell_value > 0 && (\n          rownum == 0 || rownum == PATTERN_HEIGHT-1 || colnum == 0 || colnum == PATTERN_WIDTH-1\n        )\n\n        # Count the cell's neighbors (not including itself)\n\n        neighbors = @counter[rownum-1..rownum+1].map { |row| row[colnum-1..colnum+1] }.flatten\n        neighbor_count = neighbors.inject(0) do |sum, value|\n          sum += (value == 1 || value == 2) ? 1 : 0\n        end\n        neighbor_count = neighbor_count - cell_value\n\n        # Update this cell based on its neighbor count, either leaving it\n        # as a 0 or 1, or setting it to 2 (dying) or 3 (being born)\n\n        if cell_value == 0\n          if neighbor_count == 3\n            cell_value = 3\n            @population = @population + 1\n          end\n        elsif neighbor_count < 2 || neighbor_count > 3\n          cell_value = 2\n        else\n          @population = @population + 1\n        end\n        @counter[rownum][colnum] = cell_value\n\n      end\n    end\n\n    # If every cell is dead, we are done. Otherwise, keep going up to the\n    # maximum number of generations\n\n    @population > 0\n  end\n\nend\n\n# The following program code makes use of the Pattern class to create,\n# iterate on, and display the Game of Life.\n\ndef display_banner\n  puts \" \" * 34 + \"LIFE\"\n  puts \" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n  puts\n  puts \"PLEASE ENTER YOUR STARTING PATTERN, USING SPACE FOR AN EMPTY CELL\"\n  puts \"AND AN 'X' FOR A FILLED CELL. YOUR PATTERN MAY BE UP TO #{PATTERN_HEIGHT} ROWS\"\n  puts \"OF UP TO #{PATTERN_WIDTH} COLUMNS EACH. TYPE 'DONE' WHEN DONE.\"\n  puts \"ENTER YOUR PATTERN:\"\nend\n\ndef main\n\n  display_banner\n\n  pattern = Pattern.new\n  pattern.get_input\n  pattern.display\n  pattern.display while pattern.iterate\n\nend\n\nmain\n"
  },
  {
    "path": "55_Life/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "55_Life/rust/README.md",
    "content": "# Conway's Life\n\nOriginal from David Ahl's _Basic Computer Games_, downloaded from http://www.vintage-basic.net/games.html.\n\nPorted to Rust by Jon Fetter-Degges\n\nDeveloped and tested on Rust 1.64.0\n\n## How to Run\n\nInstall Rust using the instructions at [rust-lang.org](https://www.rust-lang.org/tools/install).\n\nAt a command or shell prompt in the `rust` subdirectory, enter `cargo run`.\n\n## Differences from Original Behavior\n\n* The simulation stops if all cells die.\n* `.` at the beginning of an input line is supported but optional.\n* Input of more than 66 columns is rejected. Input will automatically terminate after 20 rows. Beyond these bounds, the original\nimplementation would have marked the board as invalid, and beyond 68 cols/24 rows it would have had an out of bounds array access.\n* The check for the string \"DONE\" at the end of input is case-independent.\n* The program pauses for half a second between each generation.\n"
  },
  {
    "path": "55_Life/rust/src/main.rs",
    "content": "// Rust implementation of the \"Basic Computer Games\" version of Conway's Life\n//\n// Jon Fetter-Degges\n// October 2022\n\n// I am a Rust newbie. Corrections and suggestions are welcome.\n\nuse std::{cmp, fmt, io, thread, time};\n\n// The BASIC implementation uses integers to represent the state of each cell: 1 is\n// alive, 2 is about to die, 3 is about to be born, 0 is dead. Here, we'll use an enum\n// instead.\n// Deriving Copy (which requires Clone) allows us to use this enum value in assignments,\n// and deriving Eq (or PartialEq) allows us to use the == operator. These need to be\n// explicitly specified because some enums may have associated data that makes copies and\n// comparisons more complicated or expensive.\n#[derive(Clone, Copy, PartialEq, Eq)]\nenum CellState {\n    Empty,\n    Alive,\n    AboutToDie,\n    AboutToBeBorn,\n}\n\n// Support direct printing of the cell. In this program cells will only be Alive or Empty\n// when they are printed.\nimpl fmt::Display for CellState {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let rep = match *self {\n            CellState::Empty => ' ',\n            CellState::Alive => '*',\n            CellState::AboutToDie => 'o',\n            CellState::AboutToBeBorn => '.',\n        };\n        write!(f, \"{}\", rep)\n    }\n}\n\n// Following the BASIC implementation, we will bound the board at 24 rows x 70 columns.\n// The board is an array of CellState. Using an array of arrays gives us bounds checking\n// in both dimensions.\nconst HEIGHT: usize = 24;\nconst WIDTH: usize = 70;\n\nstruct Board {\n    cells: [[CellState; WIDTH]; HEIGHT],\n    min_row: usize,\n    max_row: usize,\n    min_col: usize,\n    max_col: usize,\n    population: usize,\n    generation: usize,\n    invalid: bool,\n}\n\nimpl Board {\n    fn new() -> Board {\n        Board {\n            cells: [[CellState::Empty; WIDTH]; HEIGHT],\n            min_row: 0,\n            max_row: 0,\n            min_col: 0,\n            max_col: 0,\n            population: 0,\n            generation: 0,\n            invalid: false,\n        }\n    }\n}\n\nfn main() {\n    println!(); println!(); println!();\n    println!(\"{:33}{}\", \" \", \"Life\");\n    println!(\"{:14}{}\", \" \", \"Creative Computing  Morristown, New Jersey\");\n    println!(\"Enter your pattern: \");\n    let mut board = parse_pattern(get_pattern());\n    loop {\n        finish_cell_transitions(&mut board);\n        print_board(&board);\n        mark_cell_transitions(&mut board);\n        if board.population == 0 {\n            break; // this isn't in the original implementation but it seemed better than\n                   // spewing blank screens\n        }\n        delay();\n    }\n}\n\nfn get_pattern() -> Vec<Vec<char>> {\n    let max_line_len = WIDTH - 4;\n    let max_line_count = HEIGHT - 4;\n    let mut lines = Vec::new();\n    loop {\n        let mut line = String::new();\n        // read_line reads into the buffer (appending if it's not empty). It returns the\n        // number of characters read, including the newline. This will be 0 on EOF.\n        // unwrap() will panic and terminate the program if there is an error reading\n        // from stdin. That's reasonable behavior in this case.\n        let nread = io::stdin().read_line(&mut line).unwrap();\n        let line = line.trim_end();\n        if nread == 0 || line.eq_ignore_ascii_case(\"DONE\") {\n            return lines;\n        }\n        // Handle Unicode by converting the string to a vector of characters up front. We\n        // do this here because we check the number of characters several times, so we\n        // might as well just do the Unicode parsing once.\n        let line = Vec::from_iter(line.chars());\n        if line.len() > max_line_len {\n            println!(\"Line too long - the maximum is {max_line_len} characters.\");\n            continue;\n        }\n        lines.push(line);\n        if lines.len() == max_line_count {\n            println!(\"Maximum line count reached. Starting simulation.\");\n            return lines;\n        }\n    }\n}\n\nfn parse_pattern(rows: Vec<Vec<char>>) -> Board {\n    // This function assumes that the input pattern in rows is in-bounds. If the pattern\n    // is too large, this function will panic. get_pattern checks the size of the input,\n    // so it is safe to call this function with its results.\n\n    let mut board = Board::new();\n\n    // The BASIC implementation puts the pattern roughly in the center of the board,\n    // assuming that there are no blank rows at the beginning or end, or blanks entered\n    // at the beginning or end of every row. It wouldn't be hard to check for that, but\n    // for now we'll preserve the original behavior.\n    let nrows = rows.len();\n    // If rows is empty, the call to max will return None. The unwrap_or then provides a\n    // default value\n    let ncols = rows.iter().map(|l| l.len()).max().unwrap_or(0);\n\n    // The min and max values here are unsigned. If nrows >= 24 or ncols >= 68, these\n    // assignments will panic - they do not wrap around unless we use a function with\n    // that specific behavior. Again, we expect bounds checking on the input before this\n    // function is called.\n    board.min_row = 11 - nrows / 2;\n    board.min_col = 33 - ncols / 2;\n    board.max_row = board.min_row + nrows - 1;\n    board.max_col = board.min_col + ncols - 1;\n\n    // Loop over the rows provided. enumerate() augments the iterator with an index.\n    for (row_index, pattern) in rows.iter().enumerate() {\n        let row = board.min_row + row_index;\n        // Now loop over the non-empty cells in the current row. filter_map takes a\n        // closure that returns an Option. If the Option is None, filter_map filters out\n        // that entry from the for loop. If it's Some(x), filter_map executes the loop\n        // body with the value x.\n        for col in pattern.iter().enumerate().filter_map(|(col_index, chr)| {\n            if *chr == ' ' || (*chr == '.' && col_index == 0) {\n                None\n            } else {\n                Some(board.min_col + col_index)\n            }\n        }) {\n            board.cells[row][col] = CellState::Alive;\n            board.population += 1;\n        }\n    }\n\n    board\n}\n\nfn finish_cell_transitions(board: &mut Board) {\n    // In the BASIC implementation, this happens in the same loop that prints the board.\n    // We're breaking it out to improve separation of concerns.\n    let mut min_row = HEIGHT - 1;\n    let mut max_row = 0usize;\n    let mut min_col = WIDTH - 1;\n    let mut max_col = 0usize;\n    for row_index in board.min_row-1..=board.max_row+1 {\n        let mut any_alive_this_row = false;\n        for col_index in board.min_col-1..=board.max_col+1 {\n            let cell = &mut board.cells[row_index][col_index];\n            if *cell == CellState::AboutToBeBorn {\n                *cell = CellState::Alive;\n                board.population += 1;\n            } else if *cell == CellState::AboutToDie {\n                *cell = CellState::Empty;\n                board.population -= 1;\n            }\n            if *cell == CellState::Alive {\n                any_alive_this_row = true;\n                min_col = cmp::min(min_col, col_index);\n                max_col = cmp::max(max_col, col_index);\n            }\n        }\n        if any_alive_this_row {\n            min_row = cmp::min(min_row, row_index);\n            max_row = cmp::max(max_row, row_index);\n    }\n    }\n    // If anything is alive within two cells of the boundary, mark the board invalid and\n    // clamp the bounds. We need a two-cell margin because we'll count neighbors on cells\n    // one space outside the min/max, and when we count neighbors we go out by an\n    // additional space.\n    if min_row < 2 {\n        min_row = 2;\n        board.invalid = true;\n    }\n    if max_row > HEIGHT - 3 {\n        max_row = HEIGHT - 3;\n        board.invalid = true;\n    }\n    if min_col < 2 {\n        min_col = 2;\n        board.invalid = true;\n    }\n    if max_col > WIDTH - 3 {\n        max_col = WIDTH - 3;\n        board.invalid = true;\n    }\n\n    board.min_row = min_row;\n    board.max_row = max_row;\n    board.min_col = min_col;\n    board.max_col = max_col;\n}\n\nfn print_board(board: &Board) {\n    println!(); println!(); println!();\n    print!(\"Generation: {}  Population: {}\", board.generation, board.population);\n    if board.invalid {\n        print!(\"  Invalid!\");\n    }\n    println!();\n    for row_index in 0..HEIGHT {\n        for col_index in 0..WIDTH {\n            // This print uses the Display implementation for cell_state, above.\n            print!(\"{}\", board.cells[row_index][col_index]);\n        }\n        println!();\n    }\n}\n\nfn count_neighbors(board: &Board, row_index: usize, col_index: usize) -> i32 {\n    // Simply loop over all the immediate neighbors of a cell. We assume that the row and\n    // column indices are not on (or outside) the boundary of the arrays; if they are,\n    // the function will panic instead of going out of bounds.\n    let mut count = 0;\n    for i in row_index-1..=row_index+1 {\n        for j in col_index-1..=col_index+1 {\n            if i == row_index && j == col_index {\n                continue;\n            }\n            if board.cells[i][j] == CellState::Alive || board.cells[i][j] == CellState::AboutToDie {\n                count += 1;\n            }\n        }\n    }\n    count\n}\n\nfn mark_cell_transitions(board: &mut Board) {\n    for row_index in board.min_row-1..=board.max_row+1 {\n        for col_index in board.min_col-1..=board.max_col+1 {\n            let neighbors = count_neighbors(board, row_index, col_index);\n            // Borrow a mutable reference to the array cell\n            let this_cell_state = &mut board.cells[row_index][col_index];\n            *this_cell_state = match *this_cell_state {\n                CellState::Empty if neighbors == 3 => CellState::AboutToBeBorn,\n                CellState::Alive if !(2..=3).contains(&neighbors) => CellState::AboutToDie,\n                _ => *this_cell_state,\n            }\n        }\n    }\n    board.generation += 1;\n}\n\nfn delay() {\n    thread::sleep(time::Duration::from_millis(500));\n}\n"
  },
  {
    "path": "55_Life/vbnet/Life.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Life\", \"Life.vbproj\", \"{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "55_Life/vbnet/Life.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Life</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "55_Life/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "56_Life_for_Two/README.md",
    "content": "### Life for Two\n\nLIFE-2 is based on Conway’s game of Life. You must be familiar with the rules of LIFE before attempting to play LIFE-2.\n\nThere are two players; the game is played on a 5x5 board and each player has a symbol to represent his own pieces of ‘life.’ Live cells belonging to player 1 are represented by `*` and live cells belonging to player 2 are represented by the symbol `#`.\n\nThe # and * are regarded as the same except when deciding whether to generate a live cell. An empty cell having two `#` and one `*` for neighbors will generate a `#`, i.e. the live cell generated belongs to the player who has the majority of the 3 live cells surrounding the empty cell where life is to be generated, for example:\n\n```\n|   | 1 | 2 | 3 | 4 | 5 |\n|:-:|:-:|:-:|:-:|:-:|:-:|\n| 1 |   |   |   |   |   |\n| 2 |   |   | * |   |   |\n| 3 |   |   |   | # |   |\n| 4 |   |   | # |   |   |\n| 5 |   |   |   |   |   |\n```\n\nA new cell will be generated at (3,3) which will be a `#` since there are two `#` and one `*` surrounding. The board will then become:\n```\n|   | 1 | 2 | 3 | 4 | 5 |\n|:-:|:-:|:-:|:-:|:-:|:-:|\n| 1 |   |   |   |   |   |\n| 2 |   |   |   |   |   |\n| 3 |   |   | # | # |   |\n| 4 |   |   |   |   |   |\n| 5 |   |   |   |   |   |\n```\nOn the first move each player positions 3 pieces of life on the board by typing in the co-ordinates of the pieces. (In the event of the same cell being chosen by both players that cell is left empty.)\n\nThe board is then adjusted to the next generation and printed out.\n\nOn each subsequent turn each player places one piece on the board, the object being to annihilate his opponent’s pieces. The board is adjusted for the next generation and printed out after both players have entered their new piece.\n\nThe game continues until one player has no more live pieces. The computer will then print out the board and declare the winner.\n\nThe idea for this game, the game itself, and the above write-up were written by Brian Wyvill of Bradford University in Yorkshire, England.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=102)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=117)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\nNote: The original program has a bug. The instructions say that if both players\nenter the same cell that the cell is set to 0 or empty. However, the original\nBasic program tells the player \"ILLEGAL COORDINATES\" and makes another cell be entered,\ngiving a slightly unfair advantage to the 2nd player.\n\nThe Perl verson of the program fixes the bug and follows the instructions.\n\nNote: The original code had \"GOTO 800\" but label 800 didn't exist; it should have gone to label 999.\nThe Basic program has been fixed.\n\nNote: The Basic program is written to assume it's being played on a Teletype, i.e. output is printed\non paper. To play on a terminal the input must not be echoed, which can be a challenge to do portably\nand without tying the solution to a specific OS. Some versions may tell you how to do this, others might not.\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Board.cs",
    "content": "using System.Collections;\nusing System.Text;\n\nnamespace LifeforTwo;\n\ninternal class Board : IEnumerable<Coordinates>\n{\n    private readonly Piece[,] _cells = new Piece[7, 7];\n    private readonly Dictionary<int, int> _cellCounts = \n        new() { [Piece.None] = 0, [Piece.Player1] = 0, [Piece.Player2] = 0 };\n\n    public Piece this[Coordinates coordinates]\n    {\n        get => this[coordinates.X, coordinates.Y];\n        set => this[coordinates.X, coordinates.Y] = value;\n    }\n\n    private Piece this[int x, int y]\n    {\n        get => _cells[x, y];\n        set\n        {\n            if (!_cells[x, y].IsEmpty) { _cellCounts[_cells[x, y]] -= 1; }\n            _cells[x, y] = value;\n            _cellCounts[value] += 1;\n        }\n    }\n\n    public int Player1Count => _cellCounts[Piece.Player1];\n    public int Player2Count => _cellCounts[Piece.Player2];\n\n    internal bool IsEmptyAt(Coordinates coordinates) => this[coordinates].IsEmpty;\n\n    internal void ClearCell(Coordinates coordinates) => this[coordinates] = Piece.NewNone();\n    internal void AddPlayer1Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer1();\n    internal void AddPlayer2Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer2();\n\n    public override string ToString()\n    {\n        var builder = new StringBuilder();\n\n        for (var y = 0; y <= 6; y++)\n        {\n            builder.AppendLine();\n            for (var x = 0; x <= 6; x++)\n            {\n                builder.Append(GetCellDisplay(x, y));\n            }\n        }\n\n        return builder.ToString();\n    }\n\n    private string GetCellDisplay(int x, int y) =>\n        (x, y) switch\n        {\n            (0 or 6, _) => $\" {y % 6} \",\n            (_, 0 or 6) => $\" {x % 6} \",\n            _ => $\" {this[x, y]} \"\n        };\n\n    public IEnumerator<Coordinates> GetEnumerator()\n    {\n        for (var x = 1; x <= 5; x++)\n        {\n            for (var y = 1; y <= 5; y++)\n            {\n                yield return new(x, y);\n            }\n        }\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n}\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Coordinates.cs",
    "content": "namespace LifeforTwo;\n\ninternal record Coordinates (int X, int Y)\n{\n    public static bool TryCreate((float X, float Y) values, out Coordinates coordinates)\n    {\n        if (values.X <= 0 || values.X > 5 || values.Y <= 0 || values.Y > 5)\n        {\n            coordinates = new(0, 0);\n            return false;\n        }\n\n        coordinates = new((int)values.X, (int)values.Y);\n        return true;\n    }\n\n    public static Coordinates operator +(Coordinates coordinates, int value) =>\n        new (coordinates.X + value, coordinates.Y + value);\n\n    public IEnumerable<Coordinates> GetNeighbors()\n    {\n        yield return new(X - 1, Y);\n        yield return new(X + 1, Y);\n        yield return new(X, Y - 1);\n        yield return new(X, Y + 1);\n        yield return new(X - 1, Y - 1);\n        yield return new(X + 1, Y - 1);\n        yield return new(X - 1, Y + 1);\n        yield return new(X + 1, Y + 1);\n    }\n}\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Game.cs",
    "content": "internal class Game\n{\n    private readonly IReadWrite _io;\n\n    public Game(IReadWrite io)\n    {\n        _io = io;\n    }\n\n    public void Play()\n    {\n        _io.Write(Streams.Title);\n\n        var life = new Life(_io);\n\n        _io.Write(life.FirstGeneration);\n\n        foreach (var generation in life)\n        {\n            _io.WriteLine();\n            _io.Write(generation);\n        }\n\n        _io.WriteLine(life.Result ?? \"No result\");\n    }\n}\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Generation.cs",
    "content": "internal class Generation\n{\n    private readonly Board _board;\n\n    public Generation(Board board)\n    {\n        _board = board;\n        CountNeighbours();\n    }\n\n    public Board Board => _board;\n\n    public int Player1Count => _board.Player1Count;\n    public int Player2Count => _board.Player2Count;\n\n    public string? Result => \n        (Player1Count, Player2Count) switch\n        {\n            (0, 0) => Strings.Draw,\n            (_, 0) => string.Format(Formats.Winner, 1),\n            (0, _) => string.Format(Formats.Winner, 2),\n            _ => null\n        };\n\n    public static Generation Create(IReadWrite io)\n    {\n        var board = new Board();\n\n        SetInitialPieces(1, coord => board.AddPlayer1Piece(coord));\n        SetInitialPieces(2, coord => board.AddPlayer2Piece(coord));\n\n        return new Generation(board);\n\n        void SetInitialPieces(int player, Action<Coordinates> setPiece)\n        {\n            io.WriteLine(Formats.InitialPieces, player);\n            for (var i = 1; i <= 3; i++)\n            {\n                setPiece(io.ReadCoordinates(board));\n            }\n        }\n    }\n\n    public Generation CalculateNextGeneration()\n    {\n        var board = new Board();\n\n        foreach (var coordinates in _board)\n        {\n            board[coordinates] = _board[coordinates].GetNext();\n        }\n\n        return new(board);\n    }\n    \n    public void AddPieces(IReadWrite io)\n    {\n        var player1Coordinate = io.ReadCoordinates(1, _board);\n        var player2Coordinate = io.ReadCoordinates(2, _board);\n\n        if (player1Coordinate == player2Coordinate)\n        {\n            io.Write(Streams.SameCoords);\n            // This is a bug existing in the original code. The line should be _board[_coordinates[_player]] = 0;\n            _board.ClearCell(player1Coordinate + 1);\n        }\n        else\n        {\n            _board.AddPlayer1Piece(player1Coordinate);\n            _board.AddPlayer2Piece(player2Coordinate);\n        }\n    }\n\n    private void CountNeighbours()\n    {\n        foreach (var coordinates in _board)\n        {\n            var piece = _board[coordinates];\n            if (piece.IsEmpty) { continue; }\n\n            foreach (var neighbour in coordinates.GetNeighbors())\n            {\n                _board[neighbour] = _board[neighbour].AddNeighbour(piece);\n            }\n        }\n    }\n\n    public override string ToString() => _board.ToString();\n}"
  },
  {
    "path": "56_Life_for_Two/csharp/IOExtensions.cs",
    "content": "internal static class IOExtensions\n{\n    internal static Coordinates ReadCoordinates(this IReadWrite io, int player, Board board)\n    {\n        io.Write(Formats.Player, player);\n        return io.ReadCoordinates(board);\n    }\n\n    internal static Coordinates ReadCoordinates(this IReadWrite io, Board board)\n    {\n        while (true)\n        {\n            io.WriteLine(\"X,Y\");\n            var values = io.Read2Numbers(\"&&&&&&\\r\");\n            if (Coordinates.TryCreate(values, out var coordinates) && board.IsEmptyAt(coordinates))\n            {\n                return coordinates;\n            }\n            io.Write(Streams.IllegalCoords);\n        }\n    }\n}"
  },
  {
    "path": "56_Life_for_Two/csharp/Life.cs",
    "content": "using System.Collections;\n\ninternal class Life : IEnumerable<Generation>\n{\n    private readonly IReadWrite _io;\n\n    public Life(IReadWrite io)\n    {\n        _io = io;\n        FirstGeneration = Generation.Create(io);\n    }\n\n    public Generation FirstGeneration { get; }\n    public string? Result { get; private set; }\n    \n    public IEnumerator<Generation> GetEnumerator()\n    {\n        var current = FirstGeneration;\n        while (current.Result is null)\n        {\n            current = current.CalculateNextGeneration();\n            yield return current;\n\n            if (current.Result is null) { current.AddPieces(_io); }\n        }\n\n        Result = current.Result;\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); \n}"
  },
  {
    "path": "56_Life_for_Two/csharp/LifeforTwo.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "56_Life_for_Two/csharp/LifeforTwo.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"LifeforTwo\", \"LifeforTwo.csproj\", \"{B2BFE429-A4BC-4CEA-881E-32382182EA32}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Piece.cs",
    "content": "using System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace LifeforTwo;\n\npublic struct Piece\n{\n    public const int None = 0x0000;\n    public const int Player1 = 0x0100;\n    public const int Player2 = 0x1000;\n    private const int PieceMask = Player1 | Player2;\n    private const int NeighbourValueOffset = 8;\n\n    private static readonly ImmutableHashSet<int> _willBePlayer1 = \n        new[] { 0x0003, 0x0102, 0x0103, 0x0120, 0x0130, 0x0121, 0x0112, 0x0111, 0x0012 }.ToImmutableHashSet();\n    private static readonly ImmutableHashSet<int> _willBePlayer2 = \n        new[] { 0x0021, 0x0030, 0x1020, 0x1030, 0x1011, 0x1021, 0x1003, 0x1002, 0x1012 }.ToImmutableHashSet();\n\n    private int _value;\n\n    private Piece(int value) => _value = value;\n\n    public int Value => _value & PieceMask;\n    public bool IsEmpty => (_value & PieceMask) == None;\n\n    public static Piece NewNone() => new(None);\n    public static Piece NewPlayer1() => new(Player1);\n    public static Piece NewPlayer2() => new(Player2);\n\n    public Piece AddNeighbour(Piece neighbour)\n    {\n        _value += neighbour.Value >> NeighbourValueOffset;\n        return this;\n    }\n\n    public Piece GetNext() => new(\n        _value switch\n        {\n            _ when _willBePlayer1.Contains(_value) => Player1,\n            _ when _willBePlayer2.Contains(_value) => Player2,\n            _ => None\n        });\n\n    public override string ToString() =>\n        (_value & PieceMask) switch\n        {\n            Player1 => \"*\",\n            Player2 => \"#\",\n            _ => \" \"\n        };\n\n    public static implicit operator Piece(int value) => new(value);\n    public static implicit operator int(Piece piece) => piece.Value;\n}"
  },
  {
    "path": "56_Life_for_Two/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using static LifeforTwo.Resources.Resource;\nglobal using LifeforTwo;\n\nnew Game(new ConsoleIO()).Play();\n"
  },
  {
    "path": "56_Life_for_Two/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/Draw.txt",
    "content": "\nA draw"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/IllegalCoords.txt",
    "content": "Illegal coords. Retype\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/InitialPieces.txt",
    "content": "\nPlayer {0}  - 3 live pieces"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/Player.txt",
    "content": "\n\nPlayer {0} "
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace LifeforTwo.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Title => GetStream();\n        public static Stream IllegalCoords => GetStream();\n        public static Stream SameCoords => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string InitialPieces => GetString();\n        public static string Player => GetString();\n        public static string Winner => GetString();\n    }\n\n    internal static class Strings\n    {\n        public static string Draw => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/SameCoords.txt",
    "content": "Same coord.  Set to 0\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/Title.txt",
    "content": "                                 Life2\n               Creative Computing  Morristown, New Jersey\n\n\n\n          U.B. Life Game\n"
  },
  {
    "path": "56_Life_for_Two/csharp/Resources/Winner.txt",
    "content": "\nPlayer {0} is the winner"
  },
  {
    "path": "56_Life_for_Two/java/LifeForTwo.java",
    "content": "import java.util.*;\nimport java.util.stream.IntStream;\n\n/**\n * Life for Two\n * <p>\n * The original BASIC program uses a grid with an extras border of cells all around,\n * probably to simplify calculations and manipulations. This java program has the exact\n * grid size and instead uses boundary check conditions in the logic.\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class LifeForTwo {\n\n    final static int GRID_SIZE = 5;\n\n    //Pair of offset which when added to the current cell's coordinates,\n    // give the coordinates of the neighbours\n    final static int[] neighbourCellOffsets = {\n            -1, 0,\n            1, 0,\n            0, -1,\n            0, 1,\n            -1, -1,\n            1, -1,\n            -1, 1,\n            1, 1\n    };\n\n    //The best term that I could come with to describe these numbers was 'masks'\n    //They act like indicators to decide which player won the cell. The value is the score of the cell after all the\n    // generation calculations.\n    final static List<Integer> maskPlayer1 = List.of(3, 102, 103, 120, 130, 121, 112, 111, 12);\n    final static List<Integer> maskPlayer2 = List.of(21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012);\n\n    public static void main(String[] args) {\n        printIntro();\n        Scanner scan = new Scanner(System.in);\n        scan.useDelimiter(\"\\\\D\");\n\n        int[][] grid = new int[GRID_SIZE][GRID_SIZE];\n\n        initializeGrid(grid);\n\n        //Read the initial 3 moves for each player\n        for (int b = 1; b <= 2; b++) {\n            System.out.printf(\"\\nPLAYER %d - 3 LIVE PIECES.%n\", b);\n            for (int k1 = 1; k1 <= 3; k1++) {\n                var player1Coordinates = readUntilValidCoordinates(scan, grid);\n                grid[player1Coordinates.x - 1][player1Coordinates.y - 1] = (b == 1 ? 3 : 30);\n            }\n        }\n\n        printGrid(grid);\n\n        calculatePlayersScore(grid); //Convert 3, 30 to 100, 1000\n\n        resetGridForNextGen(grid);\n        computeCellScoresForOneGen(grid);\n\n        var playerScores = calculatePlayersScore(grid);\n        resetGridForNextGen(grid);\n\n        boolean gameOver = false;\n        while (!gameOver) {\n            printGrid(grid);\n            if (playerScores.getPlayer1Score() == 0 && playerScores.getPlayer2Score() == 0) {\n                System.out.println(\"\\nA DRAW\");\n                gameOver = true;\n            } else if (playerScores.getPlayer2Score() == 0) {\n                System.out.println(\"\\nPLAYER 1 IS THE WINNER\");\n                gameOver = true;\n            } else if (playerScores.getPlayer1Score() == 0) {\n                System.out.println(\"\\nPLAYER 2 IS THE WINNER\");\n                gameOver = true;\n            } else {\n                System.out.print(\"PLAYER 1 \");\n                Coordinate player1Move = readCoordinate(scan);\n                System.out.print(\"PLAYER 2 \");\n                Coordinate player2Move = readCoordinate(scan);\n                if (!player1Move.equals(player2Move)) {\n                    grid[player1Move.x - 1][player1Move.y - 1] = 100;\n                    grid[player2Move.x - 1][player2Move.y - 1] = 1000;\n                }\n                //In the original, B is assigned 99 when both players choose the same cell\n                //and that is used to control the flow\n                computeCellScoresForOneGen(grid);\n                playerScores = calculatePlayersScore(grid);\n                resetGridForNextGen(grid);\n            }\n        }\n\n    }\n\n    private static void initializeGrid(int[][] grid) {\n        for (int[] row : grid) {\n            Arrays.fill(row, 0);\n        }\n    }\n\n    private static void computeCellScoresForOneGen(int[][] grid) {\n        for (int i = 0; i < GRID_SIZE; i++) {\n            for (int j = 0; j < GRID_SIZE; j++) {\n                if (grid[i][j] >= 100) {\n                    calculateScoreForOccupiedCell(grid, i, j);\n                }\n            }\n        }\n    }\n\n    private static Scores calculatePlayersScore(int[][] grid) {\n        int m2 = 0;\n        int m3 = 0;\n        for (int i = 0; i < GRID_SIZE; i++) {\n            for (int j = 0; j < GRID_SIZE; j++) {\n                if (grid[i][j] < 3) {\n                    grid[i][j] = 0;\n                } else {\n                    if (maskPlayer1.contains(grid[i][j])) {\n                        m2++;\n                    } else if (maskPlayer2.contains(grid[i][j])) {\n                        m3++;\n                    }\n                }\n            }\n        }\n        return new Scores(m2, m3);\n    }\n\n    private static void resetGridForNextGen(int[][] grid) {\n        for (int i = 0; i < GRID_SIZE; i++) {\n            for (int j = 0; j < GRID_SIZE; j++) {\n                if (grid[i][j] < 3) {\n                    grid[i][j] = 0;\n                } else {\n                    if (maskPlayer1.contains(grid[i][j])) {\n                        grid[i][j] = 100;\n                    } else if (maskPlayer2.contains(grid[i][j])) {\n                        grid[i][j] = 1000;\n                    } else {\n                        grid[i][j] = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    private static void calculateScoreForOccupiedCell(int[][] grid, int i, int j) {\n        var b = 1;\n        if (grid[i][j] > 999) {\n            b = 10;\n        }\n        for (int k = 0; k < 15; k += 2) {\n            //check bounds\n            var neighbourX = i + neighbourCellOffsets[k];\n            var neighbourY = j + neighbourCellOffsets[k + 1];\n            if (neighbourX >= 0 && neighbourX < GRID_SIZE &&\n                    neighbourY >= 0 && neighbourY < GRID_SIZE) {\n                grid[neighbourX][neighbourY] = grid[neighbourX][neighbourY] + b;\n            }\n\n        }\n    }\n\n    private static void printGrid(int[][] grid) {\n        System.out.println();\n        printRowEdge();\n        System.out.println();\n        for (int i = 0; i < grid.length; i++) {\n            System.out.printf(\"%d \", i + 1);\n            for (int j = 0; j < grid[i].length; j++) {\n                System.out.printf(\" %c \", mapChar(grid[i][j]));\n            }\n            System.out.printf(\" %d\", i + 1);\n            System.out.println();\n        }\n        printRowEdge();\n        System.out.println();\n    }\n\n    private static void printRowEdge() {\n        System.out.print(\"0 \");\n        IntStream.range(1, GRID_SIZE + 1).forEach(i -> System.out.printf(\" %s \", i));\n        System.out.print(\" 0\");\n    }\n\n    private static char mapChar(int i) {\n        if (i == 3 || i == 100) {\n            return '*';\n        }\n        if (i == 30 || i == 1000) {\n            return '#';\n        }\n        return ' ';\n    }\n\n    private static Coordinate readUntilValidCoordinates(Scanner scanner, int[][] grid) {\n        boolean coordinateInRange = false;\n        Coordinate coordinate = null;\n        while (!coordinateInRange) {\n            coordinate = readCoordinate(scanner);\n            if (coordinate.x <= 0 || coordinate.x > GRID_SIZE\n                    || coordinate.y <= 0 || coordinate.y > GRID_SIZE\n                    || grid[coordinate.x - 1][coordinate.y - 1] != 0) {\n                System.out.println(\"ILLEGAL COORDS. RETYPE\");\n            } else {\n                coordinateInRange = true;\n            }\n        }\n        return coordinate;\n    }\n\n    private static Coordinate readCoordinate(Scanner scanner) {\n        Coordinate coordinate = null;\n        int x, y;\n        boolean valid = false;\n\n        System.out.println(\"X,Y\");\n        System.out.print(\"XXXXXX\\r\");\n        System.out.print(\"$$$$$$\\r\");\n        System.out.print(\"&&&&&&\\r\");\n\n        while (!valid) {\n            try {\n                System.out.print(\"? \");\n                y = scanner.nextInt();\n                x = scanner.nextInt();\n                valid = true;\n                coordinate = new Coordinate(x, y);\n            } catch (InputMismatchException e) {\n                System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n                valid = false;\n            } finally {\n                scanner.nextLine();\n            }\n        }\n        return coordinate;\n    }\n\n    private static void printIntro() {\n        System.out.println(\"                                LIFE2\");\n        System.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println(\"\\n\\n\");\n\n        System.out.println(\"\\tU.B. LIFE GAME\");\n    }\n\n    private static class Coordinate {\n        private final int x, y;\n\n        public Coordinate(int x, int y) {\n            this.x = x;\n            this.y = y;\n        }\n\n        public int getX() {\n            return x;\n        }\n\n        public int getY() {\n            return y;\n        }\n\n        @Override\n        public String toString() {\n            return \"Coordinate{\" +\n                    \"x=\" + x +\n                    \", y=\" + y +\n                    '}';\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n            Coordinate that = (Coordinate) o;\n            return x == that.x && y == that.y;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(x, y);\n        }\n    }\n\n    private static class Scores {\n        private final int player1Score;\n        private final int player2Score;\n\n        public Scores(int player1Score, int player2Score) {\n            this.player1Score = player1Score;\n            this.player2Score = player2Score;\n        }\n\n        public int getPlayer1Score() {\n            return player1Score;\n        }\n\n        public int getPlayer2Score() {\n            return player2Score;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "56_Life_for_Two/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "56_Life_for_Two/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "56_Life_for_Two/javascript/lifefortwo.html",
    "content": "<html>\n<head>\n<title>LIFE FOR TWO</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"lifefortwo.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "56_Life_for_Two/javascript/lifefortwo.js",
    "content": "// LIFE FOR TWO\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar na = [];\nvar ka = [, 3,102,103,120,130,121,112,111,12,\n          21,30,1020,1030,1011,1021,1003,1002,1012];\nvar aa = [,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1];\nvar xa = [];\nvar ya = [];\nvar j;\nvar k;\nvar m2;\nvar m3;\n\nfunction show_data()\n{\n    k = 0;\n    m2 = 0;\n    m3 = 0;\n    for (j = 0; j <= 6; j++) {\n        print(\"\\n\");\n        for (k = 0; k <= 6; k++) {\n            if (j == 0 || j == 6) {\n                if (k == 6)\n                    print(\" 0 \");\n                else\n                    print(\" \" + k + \" \");\n            } else if (k == 0 || k == 6) {\n                if (j == 6)\n                    print(\" 0\\n\");\n                else\n                    print(\" \" + j + \" \");\n            } else {\n                if (na[j][k] >= 3) {\n                    for (o1 = 1; o1 <= 18; o1++) {\n                        if (na[j][k] == ka[o1])\n                            break;\n                    }\n                    if (o1 <= 18) {\n                        if (o1 <= 9) {\n                            na[j][k] = 100;\n                            m2++;\n                            print(\" * \");\n                        } else {\n                            na[j][k] = 1000;\n                            m3++;\n                            print(\" # \");\n                        }\n                    } else {\n                        na[j][k] = 0;\n                        print(\"   \");\n                    }\n                } else {\n                    na[j][k] = 0;\n                    print(\"   \");\n                }\n            }\n        }\n    }\n}\n\nfunction process_board()\n{\n    for (j = 1; j <= 5; j++) {\n        for (k = 1; k <= 5; k++) {\n            if (na[j][k] > 99) {\n                b = 1;\n                if (na[j][k] > 999)\n                    b = 10;\n                for (o1 = 1; o1 <= 15; o1 += 2) {\n                    na[j + aa[o1]][k + aa[o1 + 1]] = na[j + aa[o1]][k + aa[o1 + 1]] + b;\n                }\n            }\n        }\n    }\n    show_data();\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"LIFE2\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(tab(10) + \"U.B. LIFE GAME\\n\");\n    m2 = 0;\n    m3 = 0;\n    for (j = 0; j <= 6; j++) {\n        na[j] = [];\n        for (k = 0; k <= 6; k++)\n            na[j][k] = 0;\n    }\n    for (b = 1; b <= 2; b++) {\n        p1 = (b == 2) ? 30 : 3;\n        print(\"\\n\");\n        print(\"PLAYER \" + b + \" - 3 LIVE PIECES.\\n\");\n        for (k1 = 1; k1 <= 3; k1++) {\n            while (1) {\n                print(\"X,Y\\n\");\n                str = await input();\n                ya[b] = parseInt(str);\n                xa[b] = parseInt(str.substr(str.indexOf(\",\") + 1));\n                if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)\n                    break;\n                print(\"ILLEGAL COORDS. RETYPE\\n\");\n            }\n            if (b != 1) {\n                if (xa[1] == xa[2] && ya[1] == ya[2]) {\n                    print(\"SAME COORD.  SET TO 0\\n\");\n                    na[xa[b] + 1][ya[b] + 1] = 0;\n                    b = 99;\n                }\n            }\n            na[xa[b]][ya[b]] = p1;\n        }\n    }\n    show_data();\n    while (1) {\n        print(\"\\n\");\n        process_board();\n        if (m2 == 0 && m3 == 0) {\n            print(\"\\n\");\n            print(\"A DRAW\\n\");\n            break;\n        }\n        if (m3 == 0) {\n            print(\"\\n\");\n            print(\"PLAYER 1 IS THE WINNER\\n\");\n            break;\n        }\n        if (m2 == 0) {\n            print(\"\\n\");\n            print(\"PLAYER 2 IS THE WINNER\\n\");\n            break;\n        }\n        for (b = 1; b <= 2; b++) {\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"PLAYER \" + b + \" \");\n            while (1) {\n                print(\"X,Y\\n\");\n                str = await input();\n                ya[b] = parseInt(str);\n                xa[b] = parseInt(str.substr(str.indexOf(\",\") + 1));\n                if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)\n                    break;\n                print(\"ILLEGAL COORDS. RETYPE\\n\");\n            }\n            if (b != 1) {\n                if (xa[1] == xa[2] && ya[1] == ya[2]) {\n                    print(\"SAME COORD.  SET TO 0\\n\");\n                    na[xa[b] + 1][ya[b] + 1] = 0;\n                    b = 99;\n                }\n            }\n            if (b == 99)\n                break;\n        }\n        if (b <= 2) {\n            na[x[1]][y[1]] = 100;\n            na[x[2]][y[2]] = 1000;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "56_Life_for_Two/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "56_Life_for_Two/lifefortwo.bas",
    "content": "2 PRINT TAB(33);\"LIFE2\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n7 DIM N(6,6),K(18),A(16),X(2),Y(2)\n8 DATA 3,102,103,120,130,121,112,111,12\n9 DATA 21,30,1020,1030,1011,1021,1003,1002,1012\n10 FOR M=1 TO 18: READ K(M): NEXT M\n13 DATA -1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1\n14 FOR O1= 1 TO 16: READ A(O1): NEXT O1\n20 GOTO 500\n50 FOR J=1 TO 5\n51 FOR K=1 TO 5\n55 IF N(J,K)>99 THEN GOSUB 200\n60 NEXT K\n65 NEXT J\n90 K=0: M2=0: M3=0\n99 FOR J=0 TO 6: PRINT\n100 FOR K=0 TO 6\n101 IF J<>0 THEN IF J<>6 THEN 105\n102 IF K=6 THEN PRINT 0;: GOTO 125\n103 PRINT K;: GOTO 120\n105 IF K<>0 THEN IF K<>6 THEN 110\n106 IF J=6 THEN PRINT 0: GOTO 126\n107 PRINT J;: GOTO 120\n110 GOSUB 300\n120 NEXT K\n125 NEXT J\n126 RETURN\n200 B=1: IF N(J,K)>999 THEN B=10\n220 FOR O1= 1 TO 15 STEP 2\n230 N(J+A(O1),K+A(O1+1))=N(J+A(O1),K+A(O1+1))+B\n231 NEXT O1\n239 RETURN\n300 IF N(J,K)<3 THEN 399\n305 FOR O1=1 TO 18\n310 IF N(J,K)=K(O1) THEN 350\n315 NEXT O1\n320 GOTO 399\n350 IF O1>9 THEN 360\n351 N(J,K)=100: M2=M2+1: PRINT \" * \";\n355 RETURN\n360 N(J,K)=1000: M3=M3+1: PRINT \" # \";\n365 RETURN\n399 N(J,K)=0: PRINT \"   \";: RETURN\n500 PRINT TAB(10);\"U.B. LIFE GAME\"\n505 M2=0: M3=0\n510 FOR J=1 TO 5\n511 FOR K=1 TO 5\n515 N(J,K)=0\n516 NEXT K\n517 NEXT J\n519 FOR B=1 TO 2: P1=3: IF B=2 THEN P1=30\n520 PRINT:PRINT \"PLAYER\";B;\" - 3 LIVE PIECES.\"\n535 FOR K1=1 TO 3: GOSUB 700\n540 N(X(B),Y(B))=P1: NEXT K1\n542 NEXT B\n559 GOSUB 90\n560 PRINT: GOSUB 50\n570 IF M2=0 THEN IF M3=0 THEN 574\n571 IF M3=0 THEN B=1: GOTO 575\n572 IF M2=0 THEN B=2: GOTO 575\n573 GOTO 580\n574 PRINT: PRINT \"A DRAW\":GOTO 999\n575 PRINT: PRINT \"PLAYER\";B;\"IS THE WINNER\":GOTO 999\n580 FOR B=1 TO 2: PRINT: PRINT: PRINT \"PLAYER\";B;: GOSUB 700\n581 IF B=99 THEN 560\n582 NEXT B\n586 N(X(1),Y(1))=100: N(X(2),Y(2))=1000\n596 GOTO 560\n700 PRINT \"X,Y\":PRINT\"XXXXXX\";CHR$(13);\"$$$$$$\";CHR$(13);\"&&&&&&\";\n701 PRINT CHR$(13);: INPUT Y(B),X(B)\n705 IF X(B)<=5 THEN IF X(B)>0 THEN 708\n706 GOTO 750\n708 IF Y(B)<=5 THEN IF Y(B)>0 THEN 715\n710 GOTO 750\n715 IF N(X(B),Y(B))<>0 THEN 750\n720 IF B=1 THEN RETURN\n725 IF X(1)=X(2) THEN IF Y(1)=Y(2) THEN 740\n730 RETURN\n740 PRINT \"SAME COORD.  SET TO 0\"\n741 N(X(B)+1,Y(B)+1)=0: B=99: RETURN\n750 PRINT \"ILLEGAL COORDS. RETYPE\": GOTO 700\n999 END\n"
  },
  {
    "path": "56_Life_for_Two/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "56_Life_for_Two/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nNote: The original program has a bug (see the README in the above dir). This Perl version fixes it.\n\nNote: For input, the X value is to the right while the Y value is down.\nTherefore, the top right cell is \"5,1\", not \"1,5\".\n\nThe original program was made to be played on a Teletype, i.e. a printer on paper.\nThat allowed the program to \"black out\" the input line to hide a user's input from his/her\nopponent, assuming the opponent was at least looking away. To do the equivalent on a\nterminal would require a Perl module that isn't installed by default (i.e. it is not\npart of CORE and would also require a C compiler to install), nor do I want to issue a\nshell command to \"stty\" to hide the input because that would restrict the game to Linux/Unix.\nThis means it would have to be played on the honor system.\n\nHowever, if you want to try it, install the module \"Term::ReadKey\" (\"sudo cpan -i Term::ReadKey\"\nif on Linux/Unix and you have root access). If the code finds that module, it will automatically\nuse it and hide the input ... and restore echoing input again when the games ends. If the module\nis not found, input will be visible.\n"
  },
  {
    "path": "56_Life_for_Two/perl/lifefortwo.pl",
    "content": "#!/usr/bin/perl\n\n# Life_For_Two program in Perl\n#   Required extensive restructuring to remove all of the GOTO's.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# try to load module to hide input, set RKey to true if found\nmy $Rkey = eval { require Term::ReadKey } // 0;\nEND { Term::ReadKey::ReadMode('normal') if ($Rkey); }\n\n# globals\nmy @Board;      # 2D board\nmy @X;          # ?\nmy @Y;          # ?\nmy $Player;     # 1 or 2\nmy $M2 = 0;     # ?\nmy $M3 = 0;     # ?\n\n# add 0 on front to make data 1 based\nmy @K = (0,3,102,103,120,130,121,112,111,12,21,30,1020,1030,1011,1021,1003,1002,1012);\nmy @A = (0,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1);\n\nprint \"\\n\";\nprint \" \" x 33, \"LIFE2\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\nprint \" \" x 10, \"U.B. LIFE GAME\\n\";\nfor my $j (1 .. 5) { for my $k (1 .. 5) { $Board[$j][$k] = 0; } }\n\nfor (1 .. 2)\n{\n    $Player = $_; # if we make $Player the loop var, the global isn't set\n    my $p1 = ($Player == 2) ? 30 : 3;\n    print \"\\nPLAYER $Player - 3 LIVE PIECES.\\n\";\n    for (1 .. 3)\n    {\n        get_input();\n        $Board[$X[$Player]][$Y[$Player]] = $p1 if ($Player != 99);\n    }\n}\nprint_board(); # print board after initial input\n\nwhile (1)\n{\n    print \"\\n\";\n    calc_board();  # calc new positions\n    print_board(); # print current board after calc\n\n    if ($M2 == 0 && $M3 == 0)\n    {\n        print \"\\nA DRAW\\n\";\n        last;\n    }\n    if ($M3 == 0)\n    {\n        win(1);\n        last;\n    }\n    if ($M2 == 0)\n    {\n        win(2);\n        last;\n    }\n\n    for (1 .. 2)\n    {\n        $Player = $_; # if we make $Player the loop var, the global isn't set\n        print \"\\n\\nPLAYER $Player \";\n        get_input();\n        last if ($Player == 99);\n    }\n    next if ($Player == 99);\n\n    $Board[$X[1]][$Y[1]] = 100;\n    $Board[$X[2]][$Y[2]] = 1000;\n}\nexit(0);\n\n###########################################################\n\nsub win\n{\n    my $p = shift;\n    print \"\\nPLAYER $p IS THE WINNER\\n\";\n}\n\nsub calc_board\n{\n    for my $j (1 .. 5)\n    {\n        for my $k (1 .. 5)\n        {\n            if ($Board[$j][$k] > 99)\n            {\n                $Player = $Board[$j][$k] > 999 ? 10 : 1;\n                for (my $c = 1 ; $c <= 15 ; $c += 2)\n                {\n                    $Board[$j+$A[$c]][$k+$A[$c+1]] = ($Board[$j+$A[$c]][$k+$A[$c+1]] // 0) + $Player;\n                }\n            }\n        }\n    }\n}\n\nsub print_board\n{\n    $M2 = 0;\n    $M3 = 0;\n    for my $j (0 .. 6)\n    {\n        print \"\\n\";\n        for my $k (0 .. 6)\n        {\n            if ($j != 0 && $j != 6)\n            {\n                if ($k != 0 && $k != 6)\n                {\n                    print_row($j, $k);\n                    next;\n                }\n                if ($j == 6)\n                {\n                    print \"0\\n\";\n                    return;\n                }\n                print \" $j \";\n            }\n            else\n            {\n                if ($k == 6)\n                {\n                    print \" 0 \";\n                    last;\n                }\n                print \" $k \";\n            }\n        }\n    }\n}\n\nsub print_row\n{\n    my ($j, $k) = @_;\n\n    if ($Board[$j][$k] >= 3)\n    {\n        my $c;\n        for $c (1 .. 18)\n        {\n            if ($Board[$j][$k] == $K[$c])\n            {\n                if ($c <= 9)\n                {\n                    $Board[$j][$k] = 100;\n                    $M2++;\n                    print \" * \";\n                }\n                else\n                {\n                    $Board[$j][$k] = 1000;\n                    $M3++;\n                    print \" # \";\n                }\n                return;\n            }\n        }\n    }\n    $Board[$j][$k] = 0;\n    print \"   \";\n}\n\nsub get_input\n{\n    while (1)\n    {\n        print \"X,Y\\n\";\n        my $ans;\n\n        if ($Rkey)\n        {\n            # code to hide input\n            Term::ReadKey::ReadMode('noecho');\n            $ans = Term::ReadKey::ReadLine(0);\n            Term::ReadKey::ReadMode('restore');\n            print \"\\n\"; # do this since the one entered was hidden\n        }\n        else\n        {\n            # normal, input visible\n            chomp($ans = <>);\n        }\n\n        ($Y[$Player], $X[$Player]) = split(/[,\\s]+/, $ans, 2);\n        if ($X[$Player] > 5 || $X[$Player] < 1 || $Y[$Player] > 5 || $Y[$Player] < 1)\n        {\n            print \"ILLEGAL COORDS. RETYPE\\n\";\n            next;\n        }\n        # this tells you the cell was already taken not zero it out, bug!\n        #if ($Board[$X[$Player]][$Y[$Player]] != 0)\n        #{\n        #    print \"ILLEGAL COORDS. RETYPE\\n\";\n        #    next;\n        #}\n        last;\n    }\n\n    return if ($Player == 1 || $X[1] != $X[2] || $Y[1] != $Y[2]);\n\n    print \"SAME COORD.  SET TO 0\\n\";\n    $Board[$X[$Player]+1][$Y[$Player]+1] = 0;\n    $Player = 99;\n}\n"
  },
  {
    "path": "56_Life_for_Two/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "56_Life_for_Two/python/life_for_two.py",
    "content": "'''\r\nLIFE FOR TWO\r\n\r\nCompetitive Game of Life (two or more players).\r\n\r\nPorted by Sajid Sarker (2022).\r\n'''\r\n\r\n# Global Variable Initialisation\r\n# Initialise the board\r\ngn = [[0 for _ in range(6)] for _ in range(6)]\r\ngx = [0 for _ in range(3)]\r\ngy = [0 for _ in range(3)]\r\ngk = [0, 3, 102, 103, 120, 130, 121,\r\n      112, 111, 12, 21, 30, 1020, 1030,\r\n      1011, 1021, 1003, 1002, 1012]\r\nga = [0, -1, 0, 1, 0, 0, -1, 0, 1, -1, -1, 1, -1, -1, 1, 1, 1]\r\nm2 = 0\r\nm3 = 0\r\n\r\n\r\n# Helper Functions\r\ndef tab(number) -> str:\r\n    t = \"\"\r\n    while len(t) < number:\r\n        t += \" \"\r\n    return t\r\n\r\n\r\ndef display_header() -> None:\r\n    print(f\"{tab(33)}LIFE2\")\r\n    print(f\"{tab(15)}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\r\n    print(f\"{tab(10)}U.B. LIFE GAME\")\r\n\r\n\r\n# Board Functions\r\ndef setup_board() -> None:\r\n    # Players add symbols to initially setup the board\r\n    for b in range(1, 3):\r\n        p1 = 3 if b != 2 else 30\r\n        print(f\"\\nPLAYER {b} - 3 LIVE PIECES.\")\r\n        for _ in range(1, 4):\r\n            query_player(b)\r\n            gn[gx[b]][gy[b]] = p1\r\n\r\n\r\ndef modify_board() -> None:\r\n    # Players take turns to add symbols and modify the board\r\n    for b in range(1, 3):\r\n        print(f\"PLAYER {b} \")\r\n        query_player(b)\r\n        if b == 99:\r\n            break\r\n    if b <= 2:\r\n        gn[gx[1]][gy[1]] = 100\r\n        gn[gx[2]][gy[2]] = 1000\r\n\r\n\r\ndef simulate_board() -> None:\r\n    # Simulate the board for one step\r\n    for j in range(1, 6):\r\n        for k in range(1, 6):\r\n            if gn[j][k] > 99:\r\n                b = 1 if gn[j][k] <= 999 else 10\r\n                for o1 in range(1, 16, 2):\r\n                    gn[j + ga[o1] - 1][k + ga[o1 + 1] - 1] += b\r\n                    # gn[j+ga[o1]][k+ga[o1+1]-1] = gn[j+ga[o1]][k+ga[o1+1]]+b\r\n\r\n\r\ndef display_board() -> None:\r\n    # Draws the board with all symbols\r\n    m2, m3 = 0, 0\r\n    for j in range(7):\r\n        print(\"\")\r\n        for k in range(7):\r\n            if j in [0, 6]:\r\n                if k != 6:\r\n                    print(f\" {str(k)} \", end=\"\")\r\n                else:\r\n                    print(\" 0 \", end=\"\")\r\n            elif k in [0, 6]:\r\n                print(f\" {str(j)} \", end=\"\")\r\n            elif gn[j][k] < 3:\r\n                gn[j][k] = 0\r\n                print(\"   \", end=\"\")\r\n            else:\r\n                for o1 in range(1, 19):\r\n                    if gn[j][k] == gk[o1]:\r\n                        break\r\n                if o1 <= 18:\r\n                    if o1 > 9:\r\n                        gn[j][k] = 1000\r\n                        m3 += 1\r\n                        print(\" # \", end=\"\")\r\n                    else:\r\n                        gn[j][k] = 100\r\n                        m2 += 1\r\n                        print(\" * \", end=\"\")\r\n                else:\r\n                    gn[j][k] = 0\r\n                    print(\"   \", end=\"\")\r\n\r\n\r\n# Player Functions\r\ndef query_player(b) -> None:\r\n    # Query player for symbol placement coordinates\r\n    while True:\r\n        print(\"X,Y\\nXXXXXX\\n$$$$$$\\n&&&&&&\")\r\n        a_ = input(\"??\")\r\n        b_ = input(\"???\")\r\n        x_ = [int(num) for num in a_.split() if num.isdigit()]\r\n        y_ = [int(num) for num in b_.split() if num.isdigit()]\r\n        x_ = [0] if not x_ else x_\r\n        y_ = [0] if not y_ else y_\r\n        gx[b] = y_[0]\r\n        gy[b] = x_[0]\r\n        if gx[b] in range(1, 6)\\\r\n                and gy[b] in range(1, 6)\\\r\n                and gn[gx[b]][gy[b]] == 0:\r\n            break\r\n        print(\"ILLEGAL COORDS. RETYPE\")\r\n    if b != 1:\r\n        if gx[1] == gx[2] and gy[1] == gy[2]:\r\n            print(\"SAME COORD. SET TO 0\")\r\n            gn[gx[b] + 1][gy[b] + 1] = 0\r\n            b = 99\r\n\r\n\r\n# Game Functions\r\ndef check_winner(m2, m3) -> None:\r\n    # Check if the game has been won\r\n    if m2 == 0 and m3 == 0:\r\n        print(\"\\nA DRAW\\n\")\r\n        return\r\n    if m3 == 0:\r\n        print(\"\\nPLAYER 1 IS THE WINNER\\n\")\r\n        return\r\n    if m2 == 0:\r\n        print(\"\\nPLAYER 2 IS THE WINNER\\n\")\r\n        return\r\n\r\n\r\n# Program Flow\r\ndef main() -> None:\r\n    display_header()\r\n    setup_board()\r\n    display_board()\r\n    while True:\r\n        print(\"\\n\")\r\n        simulate_board()\r\n        display_board()\r\n        check_winner(m2, m3)\r\n        modify_board()\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n"
  },
  {
    "path": "56_Life_for_Two/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "56_Life_for_Two/vbnet/LifeforTwo.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"LifeforTwo\", \"LifeforTwo.vbproj\", \"{571A55BD-86BA-4DD2-9769-B258E7654586}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{571A55BD-86BA-4DD2-9769-B258E7654586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{571A55BD-86BA-4DD2-9769-B258E7654586}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{571A55BD-86BA-4DD2-9769-B258E7654586}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{571A55BD-86BA-4DD2-9769-B258E7654586}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "56_Life_for_Two/vbnet/LifeforTwo.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>LifeforTwo</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "56_Life_for_Two/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "57_Literature_Quiz/README.md",
    "content": "### Literature Quiz\n\nThis is a simple CAI-type program which presents four multiple-choice questions from children’s literature. Running the program is self-explanatory.\n\nThe program was written by Pamela McGinley while at DEC.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=104)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=117)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "57_Literature_Quiz/csharp/LiteratureQuiz.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "57_Literature_Quiz/csharp/LiteratureQuiz.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"LiteratureQuiz\", \"LiteratureQuiz.csproj\", \"{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "57_Literature_Quiz/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "57_Literature_Quiz/csharp/litquiz.cs",
    "content": "using System;\n\nnamespace litquiz\n{\n    class litquiz\n    {\n        public static int Score = 0;\n\n\n        public static void Main(string[] args)\n        {\n\n            //Print the title and intro\n\n            Console.WriteLine(\"                         LITERATURE QUIZ\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE\");\n            Console.WriteLine();\n            Console.WriteLine(\"THIS IS A MULTIPLE-CHOICE QUIZ\");\n            Console.WriteLine(\"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\");\n            Console.WriteLine();\n            Console.WriteLine(\"GOOD LUCK!\");\n            Console.WriteLine();\n            Console.WriteLine();\n            One();\n\n\n\n        }\n\n        public static void One() {\n            Console.WriteLine(\"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\");\n            Console.WriteLine(\"1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO\");\n\n            string answerOne;\n            answerOne = Console.ReadLine();\n\n            if(answerOne == \"4\")\n            {\n                Console.WriteLine(\"VERY GOOD! HERE'S ANOTHER.\");\n                Score = Score + 1;\n                Two();\n            }\n            else\n            {\n                Console.WriteLine(\"SORRY...FIGARO WAS HIS NAME.\");\n                Two();\n            }\n\n        }\n\n        public static void Two()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\");\n            Console.WriteLine(\"1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S\");\n\n            string answerTwo;\n            answerTwo = Console.ReadLine();\n\n            if(answerTwo == \"2\")\n            {\n                Console.WriteLine(\"PRETTY GOOD!\");\n                Score = Score + 1;\n                Three();\n            }\n            else\n            {\n                Console.WriteLine(\"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\");\n                Three();\n            }\n        }\n\n        public static void Three()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\");\n            Console.WriteLine(\"1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO\");\n\n            string answerThree;\n            answerThree = Console.ReadLine();\n\n            if(answerThree == \"4\")\n            {\n                Console.WriteLine(\"YEA!  YOU'RE A REAL LITERATURE GIANT.\");\n                Score = Score + 1;\n                Four();\n            }\n            else\n            {\n                Console.WriteLine(\"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\");\n                Four();\n            }\n\n\n\n\n        }\n\n        public static void Four()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\");\n            Console.WriteLine(\"1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY\");\n\n            string answerFour;\n            answerFour = Console.ReadLine();\n\n            if(answerFour == \"3\")\n            {\n                Console.WriteLine(\"GOOD MEMORY!\");\n                Score = Score + 1;\n                End();\n            }\n            else\n            {\n                Console.WriteLine(\"OH, COME ON NOW...IT WAS SNOW WHITE.\");\n                End();\n            }\n\n        }\n\n        public static void End()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n            if(Score == 4)\n            {\n                Console.WriteLine(\"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\");\n                Console.WriteLine(\"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\");\n                Console.WriteLine(\"LITERATURE (HA, HA, HA)\");\n                return;\n            }\n            else if(Score < 2)\n            {\n                Console.WriteLine(\"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\");\n                Console.WriteLine(\"NURSERY SCHOOL FOR YOU, MY FRIEND.\");\n                return;\n            }\n            else\n            {\n                Console.WriteLine(\"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\");\n                Console.WriteLine(\"READING THE NURSERY GREATS.\");\n                return;\n            }\n        }\n\n\t}\n}\n"
  },
  {
    "path": "57_Literature_Quiz/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "57_Literature_Quiz/java/src/LiteratureQuiz.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Literature Quiz\n * <p>\n * Based on the Basic game of Literature Quiz here\n * https://github.com/coding-horror/basic-computer-games/blob/main/57%20Literature%20Quiz/litquiz.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class LiteratureQuiz {\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        STARTUP,\n        QUESTIONS,\n        RESULTS,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n    // Players correct answers\n    private int correctAnswers;\n\n    public LiteratureQuiz() {\n\n        gameState = GAME_STATE.STARTUP;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTUP:\n                    intro();\n                    correctAnswers = 0;\n                    gameState = GAME_STATE.QUESTIONS;\n                    break;\n\n                // Ask the player four questions\n                case QUESTIONS:\n\n                    // Question 1\n                    System.out.println(\"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\");\n                    int question1Answer = displayTextAndGetNumber(\"1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO ? \");\n                    if (question1Answer == 3) {\n                        System.out.println(\"VERY GOOD!  HERE'S ANOTHER.\");\n                        correctAnswers++;\n                    } else {\n                        System.out.println(\"SORRY...FIGARO WAS HIS NAME.\");\n                    }\n\n                    System.out.println();\n\n                    // Question 2\n                    System.out.println(\"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\");\n                    int question2Answer = displayTextAndGetNumber(\"1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S ? \");\n                    if (question2Answer == 2) {\n                        System.out.println(\"PRETTY GOOD!\");\n                        correctAnswers++;\n                    } else {\n                        System.out.println(\"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\");\n                    }\n\n                    System.out.println();\n\n                    // Question 3\n                    System.out.println(\"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\");\n                    int question3Answer = displayTextAndGetNumber(\"1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO ? \");\n                    if (question3Answer == 4) {\n                        System.out.println(\"YEA!  YOU'RE A REAL LITERATURE GIANT.\");\n                        correctAnswers++;\n                    } else {\n                        System.out.println(\"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\");\n                    }\n\n                    System.out.println();\n\n                    // Question 4\n                    System.out.println(\"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\");\n                    int question4Answer = displayTextAndGetNumber(\"1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY ? \");\n                    if (question4Answer == 3) {\n                        System.out.println(\"GOOD MEMORY!\");\n                        correctAnswers++;\n                    } else {\n                        System.out.println(\"OH, COME ON NOW...IT WAS SNOW WHITE.\");\n                    }\n\n                    System.out.println();\n                    gameState = GAME_STATE.RESULTS;\n                    break;\n\n                // How did the player do?\n                case RESULTS:\n                    if (correctAnswers == 4) {\n                        // All correct\n                        System.out.println(\"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\");\n                        System.out.println(\"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\");\n                        System.out.println(\"LITERATURE (HA, HA, HA)\");\n                        // one or none correct\n                    } else if (correctAnswers < 2) {\n                        System.out.println(\"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\");\n                        System.out.println(\"NURSERY SCHOOL FOR YOU, MY FRIEND.\");\n                        // two or three correct\n                    } else {\n                        System.out.println(\"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\");\n                        System.out.println(\"READING THE NURSERY GREATS.\");\n                    }\n                    gameState = GAME_STATE.GAME_OVER;\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    public void intro() {\n        System.out.println(simulateTabs(25) + \"LITERATURE QUIZ\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"LITERATURE QUIZ\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\");\n        System.out.println(\"THIS IS A MULTIPLE-CHOICE QUIZ.\");\n        System.out.println(\"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\");\n        System.out.println();\n        System.out.println(\"GOOD LUCK!\");\n        System.out.println();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n}\n"
  },
  {
    "path": "57_Literature_Quiz/java/src/LiteratureQuizGame.java",
    "content": "public class LiteratureQuizGame {\n\n    public static void main(String[] args) {\n\n        LiteratureQuiz literatureQuiz = new LiteratureQuiz();\n        literatureQuiz.play();\n    }\n}\n"
  },
  {
    "path": "57_Literature_Quiz/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "57_Literature_Quiz/javascript/litquiz.html",
    "content": "<html>\n<head>\n<title>LITERATURE QUIZ</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"litquiz.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "57_Literature_Quiz/javascript/litquiz.js",
    "content": "// LITQUIZ\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(25) + \"LITERATURE QUIZ\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    r = 0;\n    print(\"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\\n\");\n    print(\"\\n\");\n    print(\"THIS IS A MULTIPLE-CHOICE QUIZ.\\n\");\n    print(\"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\\n\");\n    print(\"\\n\");\n    print(\"GOOD LUCK!\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\\n\");\n    print(\"1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO\\n\");\n    a = parseInt(await input());\n    if (a == 3) {\n        print(\"VERY GOOD!  HERE'S ANOTHER.\\n\");\n        r++;\n    } else {\n        print(\"SORRY...FIGARO WAS HIS NAME.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\\n\");\n    print(\"1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S\\n\");\n    a = parseInt(await input());\n    if (a == 2) {\n        print(\"PRETTY GOOD!\\n\");\n        r++;\n    } else {\n        print(\"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\\n\");\n    print(\"1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO\\n\");\n    a = parseInt(await input());\n    if (a == 4) {\n        print(\"YEA!  YOU'RE A REAL LITERATURE GIANT.\\n\");\n        r++;\n    } else {\n        print(\"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\\n\");\n    print(\"1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY\\n\");\n    a = parseInt(await input());\n    if (a == 3) {\n        print(\"GOOD MEMORY!\\n\");\n        r++;\n    } else {\n        print(\"OH, COME ON NOW...IT WAS SNOW WHITE.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    if (r == 4) {\n        print(\"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\\n\");\n        print(\"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\\n\");\n        print(\"LITERATURE (HA, HA, HA)\\n\");\n    } else if (r < 2) {\n        print(\"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\\n\");\n        print(\"NURSERY SCHOOL FOR YOU, MY FRIEND.\\n\");\n    } else {\n        print(\"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\\n\");\n        print(\"READING THE NURSERY GREATS.\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "57_Literature_Quiz/javascript/litquiz.mjs",
    "content": "#!/usr/bin/env node\n\nimport { println, input } from '../../00_Common/javascript/common.mjs';\n\nfunction printAlign(message = \"\", align = \"left\") {\n    // process.stdout.columns is the number of spaces per line in the terminal\n    const maxWidth = process.stdout.columns\n    if (align === \"center\") {\n        // calculate the amount of spaces required to center the message\n        const padColCount = Math.round((process.stdout.columns-message.length)/2);\n        const padding = padColCount <= 0 ? '' : ' '.repeat(padColCount);\n        println(padding, message);\n    } else if (align === \"right\") {\n        const padColCount = Math.round(process.stdout.columns-message.length);\n        const padding = padColCount <= 0 ? '' : ' '.repeat(padColCount);\n        println(padding, message);\n    } else {\n        println(message);\n    }\n}\n\nfunction equalIgnoreCase(correct, provided){\n    return correct.toString().toLowerCase() === provided.toString().toLowerCase()\n}\n\nasync function evaluateQuestion(question, answerOptions, correctAnswer, correctMessage, wrongMessage){\n    // ask the user to answer the given question\n    println(question);\n    println(answerOptions.map((answer, index) => `${index+1})${answer}`).join(', '));\n    // this is a blocking wait\n    const answer = await input('?')\n    const isCorrect = equalIgnoreCase(correctAnswer, answer)\n    println(isCorrect ? correctMessage : wrongMessage)\n    return isCorrect ? 1 : 0\n}\n\nasync function main(){\n    let score = 0\n\n    printAlign(\"LITERATURE QUIZ\", \"center\")\n    printAlign(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", \"center\")\n    println(\"\\n\\n\")\n\n    println(\"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\");\n    println();\n    println(\"THIS IS A MULTIPLE-CHOICE QUIZ.\");\n    println(\"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\");\n    println();\n    println(\"GOOD LUCK!\");\n    println(\"\\n\\n\");\n\n    score += await evaluateQuestion(\"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?\",\n        [ \"TIGGER\", \"CICERO\", \"FIGARO\", \"GUIPETTO\"], 3,\n        \"VERY GOOD!  HERE'S ANOTHER.\", \"SORRY...FIGARO WAS HIS NAME.\")\n    println()\n\n    score += await evaluateQuestion(\"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\",\n        [ \"MR. NIXON'S\", \"ELMER FUDD'S\", \"CLEM JUDD'S\", \"STROMBOLI'S\" ], 2,\n        \"PRETTY GOOD!\", \"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\")\n    println()\n\n    score += await evaluateQuestion(\"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\",\n        [ \"CICERO\", \"TRIXIA\", \"KING\", \"TOTO\" ], 4,\n        \"YEA!  YOU'RE A REAL LITERATURE GIANT.\",\n        \"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\")\n    println()\n\n    score += await evaluateQuestion(\"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\",\n        [ \"SLEEPING BEAUTY\", \"CINDERELLA\", \"SNOW WHITE\", \"WENDY\" ], 3,\n        \"GOOD MEMORY!\", \"OH, COME ON NOW...IT WAS SNOW WHITE.\")\n\n    println(\"\\n\")\n\n    if(score === 4) {\n        println(\"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\\n\"+\n        \"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\\n\"+\n        \"LITERATURE (HA, HA, HA)\")\n    } else if(score <= 2){\n        println(\"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\\n\" +\n        \"NURSERY SCHOOL FOR YOU, MY FRIEND.\")\n    } else {\n        println(\"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\\n\"+\n        \"READING THE NURSERY GREATS.\")\n    }\n}\n\nmain()\n"
  },
  {
    "path": "57_Literature_Quiz/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "57_Literature_Quiz/litquiz.bas",
    "content": "1 PRINT TAB(25);\"LITERATURE QUIZ\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n5 R=0\n10 PRINT \"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\"\n12 PRINT: PRINT \"THIS IS A MULTIPLE-CHOICE QUIZ.\"\n13 PRINT \"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\"\n15 PRINT: PRINT \"GOOD LUCK!\": PRINT: PRINT\n40 PRINT \"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\"\n42 PRINT \"1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO\";\n43 INPUT A: IF A=3 THEN 46\n44 PRINT \"SORRY...FIGARO WAS HIS NAME.\": GOTO 50\n46 PRINT \"VERY GOOD!  HERE'S ANOTHER.\"\n47 R=R+1\n50 PRINT: PRINT\n51 PRINT \"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\"\n52 PRINT \"1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S\";\n53 INPUT A: IF A=2 THEN 56\n54 PRINT \"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\": GOTO 60\n56 PRINT \"PRETTY GOOD!\"\n57 R=R+1\n60 PRINT: PRINT\n61 PRINT \"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\"\n62 PRINT \"1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO\";\n63 INPUT A: IF A=4 THEN 66\n64 PRINT \"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\": GOTO 70\n66 PRINT \"YEA!  YOU'RE A REAL LITERATURE GIANT.\"\n67 R=R+1\n70 PRINT:PRINT\n71 PRINT \"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\"\n72 PRINT \"1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY\";\n73 INPUT A: IF A=3 THEN 76\n74 PRINT \"OH, COME ON NOW...IT WAS SNOW WHITE.\"\n75 GOTO 80\n76 PRINT \"GOOD MEMORY!\"\n77 R=R+1\n80 PRINT:PRINT\n85 IF R=4 THEN 100\n90 IF R<2 THEN 200\n92 PRINT \"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\"\n94 PRINT \"READING THE NURSERY GREATS.\"\n96 STOP\n100 PRINT \"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\"\n110 PRINT \"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\"\n120 PRINT \"LITERATURE (HA, HA, HA)\"\n130 STOP\n200 PRINT \"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\"\n205 PRINT \"NURSERY SCHOOL FOR YOU, MY FRIEND.\"\n999 END\n"
  },
  {
    "path": "57_Literature_Quiz/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "57_Literature_Quiz/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "57_Literature_Quiz/perl/litquiz.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 25 . \"LITERATURE QUIZ\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\\n\";\nprint \"\\n\"; print \"THIS IS A MULTIPLE-CHOICE QUIZ.\\n\";\nprint \"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\\n\";\nprint \"\\n\"; print \"GOOD LUCK!\\n\";\nmy $R=0;\n\n\nprint \"\\n\"; print \"\\n\";\nprint \"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\\n\";\nprint \"1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO\";\nprint \"? \"; chomp(my $A = <STDIN>);\n\nif ($A eq 3) {\n\t$R++;\n\tprint \"VERY GOOD! HERE'S ANOTHER.\\n\";\n\t} else {\n\tprint \"SORRY...FIGARO WAS HIS NAME.\\n\";\n\t}\n\n\nprint \"\\n\"; print \"\\n\";\nprint \"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\\n\";\nprint \"1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S\";\nprint \"? \"; chomp($A = <STDIN>);\n\nif ($A eq 2) {\n\tprint \"PRETTY GOOD!\\n\";\n\t$R=$R+1;\n\t} else {\n\tprint \"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\\n\";\n\t}\n\n\nprint \"\\n\"; print \"\\n\";\nprint \"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\\n\";\nprint \"1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO\";\nprint \"? \"; chomp($A = <STDIN>);\nif ($A eq 4) {\n\tprint \"YEA! YOU'RE A REAL LITERATURE GIANT.\\n\";\n\t$R=$R+1;\n\t} else {\n\tprint \"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\\n\";\n\t}\n\n\nprint \"\\n\"; print \"\\n\";\nprint \"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\\n\";\nprint \"1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY\";\nprint \"? \"; chomp($A = <STDIN>);\nif ($A eq 3) {\n\tprint \"GOOD MEMORY!\\n\";\n\t$R=$R+1;\n\t} else {\n\tprint \"OH, COME ON NOW...IT WAS SNOW WHITE.\\n\";\n\t}\n\n\nprint \"\\n\"; print \"\\n\";\nif ($R eq 4) {\n\tprint \"WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY\\n\";\n\tprint \"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\\n\";\n\tprint \"LITERATURE (HA, HA, HA)\\n\";\n\texit\n\t}\nif ($R<2) {\n\tprint \"UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO\\n\";\n\tprint \"NURSERY SCHOOL FOR YOU, MY FRIEND.\\n\";\n\texit;\n\t}\n\nprint \"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\\n\";\nprint \"READING THE NURSERY GREATS.\\n\";\nexit;\n"
  },
  {
    "path": "57_Literature_Quiz/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "57_Literature_Quiz/python/litquiz.py",
    "content": "\"\"\"\nLITQUIZ\n\nA children's literature quiz\n\nPorted by Dave LeCompte\n\"\"\"\n\nfrom typing import List, NamedTuple\n\nPAGE_WIDTH = 64\n\n\nclass Question(NamedTuple):\n    question: str\n    answer_list: List[str]\n    correct_number: int\n    incorrect_message: str\n    correct_message: str\n\n    def ask(self) -> bool:\n        print(self.question)\n\n        options = [f\"{i+1}){self.answer_list[i]}\" for i in range(len(self.answer_list))]\n        print(\", \".join(options))\n\n        response = int(input())\n\n        if response == self.correct_number:\n            print(self.correct_message)\n            return True\n        else:\n            print(self.incorrect_message)\n            return False\n\n\nquestions = [\n    Question(\n        \"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?\",\n        [\"TIGGER\", \"CICERO\", \"FIGARO\", \"GUIPETTO\"],\n        3,\n        \"SORRY...FIGARO WAS HIS NAME.\",\n        \"VERY GOOD!  HERE'S ANOTHER.\",\n    ),\n    Question(\n        \"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\",\n        [\"MR. NIXON'S\", \"ELMER FUDD'S\", \"CLEM JUDD'S\", \"STROMBOLI'S\"],\n        2,\n        \"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\",\n        \"PRETTY GOOD!\",\n    ),\n    Question(\n        \"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED?\",\n        [\"CICERO\", \"TRIXIA\", \"KING\", \"TOTO\"],\n        4,\n        \"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\",\n        \"YEA!  YOU'RE A REAL LITERATURE GIANT.\",\n    ),\n    Question(\n        \"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE?\",\n        [\"SLEEPING BEAUTY\", \"CINDERELLA\", \"SNOW WHITE\", \"WENDY\"],\n        3,\n        \"OH, COME ON NOW...IT WAS SNOW WHITE.\",\n        \"GOOD MEMORY!\",\n    ),\n]\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((64 - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_instructions() -> None:\n    print(\"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\")\n    print()\n    print(\"THIS IS A MULTIPLE-CHOICE QUIZ.\")\n    print(\"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\")\n    print()\n    print(\"GOOD LUCK!\")\n    print()\n    print()\n\n\ndef main() -> None:\n    print_centered(\"LITERATURE QUIZ\")\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n    print_instructions()\n\n    score = 0\n\n    for q in questions:\n        if q.ask():\n            score += 1\n        print()\n        print()\n\n    if score == len(questions):\n        print(\"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\")\n        print(\"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\")\n        print(\"LITERATURE (HA, HA, HA)\")\n    elif score < len(questions) / 2:\n        print(\"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\")\n        print(\"NURSERY SCHOOL FOR YOU, MY FRIEND.\")\n    else:\n        print(\"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\")\n        print(\"READING THE NURSERY GREATS.\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "57_Literature_Quiz/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "57_Literature_Quiz/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "57_Literature_Quiz/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "57_Literature_Quiz/rust/src/main.rs",
    "content": "use std::io;\n\n\nfn print_instructions() {\n    println!(\"TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\");\n    println!();\n    println!(\"THIS IS A MULTIPLE-CHOICE QUIZ.\");\n    println!(\"TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\");\n    println!();\n    println!(\"GOOD LUCK!\");\n    println!();\n    println!();\n}\n\n\nfn print_center(text: String, width: usize) {\n    let pad_size;\n    if width > text.len() {\n        pad_size = (width - text.len()) / 2;\n    } else {\n        pad_size = 0;\n    }\n    println!(\"{}{}\", \" \".repeat(pad_size), text);\n}\n\n\nfn print_results(score: usize, number_of_questions: usize) {\n    if score == number_of_questions {\n        println!(\"WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\");\n        println!(\"YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\");\n        println!(\"LITERATURE (HA, HA, HA)\");\n    } else if score < number_of_questions / 2 {\n        println!(\"UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\");\n        println!(\"NURSERY SCHOOL FOR YOU, MY FRIEND.\");\n    } else {\n        println!(\"NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\");\n        println!(\"READING THE NURSERY GREATS.\");\n    }\n}\n\nfn main() {\n    let page_width: usize = 64;\n\n    struct Question<'a> {\n        question: &'a str,\n        choices: Vec<&'a str>,\n        answer: u8,\n        correct_response: &'a str,\n        wrong_response: &'a str,\n    }\n\n    impl Question<'_>{\n        fn ask(&self) -> bool {\n            println!(\"{}\", self.question);\n            for i in 0..4 {\n                print!(\"{}){}\", i+1, self.choices[i]);\n                if i != 3 { print!(\", \")};\n            }\n            println!(\"\");\n            let mut user_input: String = String::new();\n            io::stdin()\n                .read_line(&mut user_input)\n                .expect(\"Failed to read the line\");\n\n            if user_input.starts_with(&self.answer.to_string()) {\n                println!(\"{}\", self.correct_response);\n                true\n            } else {\n                println!(\"{}\", self.wrong_response);\n                false\n            }\n        }\n    }\n\n    let questions: Vec<Question> = vec![\n        Question{\n            question: \"IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?\",\n            choices: vec![\"TIGGER\", \"CICERO\", \"FIGARO\", \"GUIPETTO\"],\n            answer: 3,\n            wrong_response: \"SORRY...FIGARO WAS HIS NAME.\",\n            correct_response: \"VERY GOOD!  HERE'S ANOTHER.\",\n        },\n        Question{\n            question: \"FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\",\n            choices: vec![\"MR. NIXON'S\", \"ELMER FUDD'S\", \"CLEM JUDD'S\", \"STROMBOLI'S\"],\n            answer: 2,\n            wrong_response: \"TOO BAD...IT WAS ELMER FUDD'S GARDEN.\",\n            correct_response: \"PRETTY GOOD!\",\n        },\n        Question{\n            question: \"IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED?\",\n            choices: vec![\"CICERO\", \"TRIXIA\", \"KING\", \"TOTO\"],\n            answer: 4,\n            wrong_response: \"BACK TO THE BOOKS,...TOTO WAS HIS NAME.\",\n            correct_response: \"YEA!  YOU'RE A REAL LITERATURE GIANT.\",\n        },\n        Question{\n            question: \"WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE?\",\n            choices: vec![\"SLEEPING BEAUTY\", \"CINDERELLA\", \"SNOW WHITE\", \"WENDY\"],\n            answer: 3,\n            wrong_response: \"OH, COME ON NOW...IT WAS SNOW WHITE.\",\n            correct_response: \"GOOD MEMORY!\",\n        },    \n    ];\n    let number_of_questions: usize = questions.len();\n\n    print_center(\"LITERATURE QUIZ\".to_string(), page_width);\n    print_center(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".to_string(), page_width);\n    println!();\n    println!();\n    println!();\n    print_instructions();\n\n    let mut score = 0;\n    for question in questions {\n        if question.ask() {\n            score += 1;\n        }\n        println!();\n    }\n\n    print_results(score, number_of_questions);\n\n}\n\n\n\n"
  },
  {
    "path": "57_Literature_Quiz/vbnet/LiteratureQuiz.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"LiteratureQuiz\", \"LiteratureQuiz.vbproj\", \"{7897F5C5-055B-449D-9BD5-1F631DA87D06}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "57_Literature_Quiz/vbnet/LiteratureQuiz.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>LiteratureQuiz</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "57_Literature_Quiz/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "58_Love/README.md",
    "content": "### Love\n\nThis program is designed to reproduce Robert Indiana’s great art work “Love” with a message of your choice up to 60 characters long.\n\nThe love program was created by David Ahl.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=105)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=120)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "58_Love/csharp/Love.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources\\Intro.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "58_Love/csharp/Love.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Love\", \"Love.csproj\", \"{1C02A3CA-615B-42CF-B696-4514770CA67F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1C02A3CA-615B-42CF-B696-4514770CA67F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1C02A3CA-615B-42CF-B696-4514770CA67F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1C02A3CA-615B-42CF-B696-4514770CA67F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1C02A3CA-615B-42CF-B696-4514770CA67F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {F9C55508-108B-4EA1-ADD7-4BA8EC915E68}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "58_Love/csharp/LovePattern.cs",
    "content": "using System.IO;\nusing System.Text;\n\nnamespace Love;\n\ninternal class LovePattern\n{\n    private const int _lineLength = 60;\n    private readonly int[] _segmentLengths = new[] {\n        60, 1, 12, 26, 9, 12, 3, 8, 24, 17, 8, 4, 6, 23, 21, 6, 4, 6, 22, 12, 5,\n        6, 5, 4, 6, 21, 11, 8, 6, 4, 4, 6, 21, 10, 10, 5, 4, 4, 6, 21, 9, 11, 5,\n        4, 4, 6, 21, 8, 11, 6, 4, 4, 6, 21, 7, 11, 7, 4, 4, 6, 21, 6, 11, 8, 4,\n        4, 6, 19, 1, 1, 5, 11, 9, 4, 4, 6, 19, 1, 1, 5, 10, 10, 4, 4, 6, 18, 2,\n        1, 6, 8, 11, 4, 4, 6, 17, 3, 1, 7, 5, 13, 4, 4, 6, 15, 5, 2, 23, 5, 1,\n        29, 5, 17, 8, 1, 29, 9, 9, 12, 1, 13, 5, 40, 1, 1, 13, 5, 40, 1, 4, 6,\n        13, 3, 10, 6, 12, 5, 1, 5, 6, 11, 3, 11, 6, 14, 3, 1, 5, 6, 11, 3, 11,\n        6, 15, 2, 1, 6, 6, 9, 3, 12, 6, 16, 1, 1, 6, 6, 9, 3, 12, 6, 7, 1, 10,\n        7, 6, 7, 3, 13, 6, 6, 2, 10, 7, 6, 7, 3, 13, 14, 10, 8, 6, 5, 3, 14, 6,\n        6, 2, 10, 8, 6, 5, 3, 14, 6, 7, 1, 10, 9, 6, 3, 3, 15, 6, 16, 1, 1, 9,\n        6, 3, 3, 15, 6, 15, 2, 1, 10, 6, 1, 3, 16, 6, 14, 3, 1, 10, 10, 16, 6,\n        12, 5, 1, 11, 8, 13, 27, 1, 11, 8, 13, 27, 1, 60\n    };\n    private readonly StringBuilder _pattern = new();\n\n    public LovePattern(string message)\n    {\n        Fill(new SourceCharacters(_lineLength, message));\n    }\n\n    private void Fill(SourceCharacters source)\n    {\n        var lineLength = 0;\n\n        foreach (var segmentLength in _segmentLengths)\n        {\n            foreach (var character in source.GetCharacters(segmentLength))\n            {\n                _pattern.Append(character);\n            }\n            lineLength += segmentLength;\n            if (lineLength >= _lineLength)\n            {\n                _pattern.AppendLine();\n                lineLength = 0;\n            }\n        }\n    }\n\n    public override string ToString() =>\n        new StringBuilder()\n            .AppendLines(10)\n            .Append(_pattern)\n            .AppendLines(10)\n            .ToString();\n}\n"
  },
  {
    "path": "58_Love/csharp/Program.cs",
    "content": "﻿using Games.Common.IO;\nusing Love;\nusing Love.Resources;\n\nvar io = new ConsoleIO();\n\nio.Write(Resource.Streams.Intro);\n\nvar message = io.ReadString(\"Your message, please\");\n\nio.Write(new LovePattern(message));\n"
  },
  {
    "path": "58_Love/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "58_Love/csharp/Resources/Intro.txt",
    "content": "                                 Love\n               Creative Computing  Morristown, New Jersey\n\n\n\nA tribute to the great American artist, Robert Indiana.\nHis greatest work will be reproduced with a message of\nyour choice up to 60 characters.  If you can't think of\na message, simply type the word 'LOVE'\n\n"
  },
  {
    "path": "58_Love/csharp/Resources/Resource.cs",
    "content": "using System.IO;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Love.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Intro => GetStream();\n    }\n\n    private static Stream GetStream([CallerMemberName] string name = null)\n        => Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Love.Resources.{name}.txt\");\n}"
  },
  {
    "path": "58_Love/csharp/SourceCharacters.cs",
    "content": "using System;\n\nnamespace Love;\n\ninternal class SourceCharacters\n{\n    private readonly int _lineLength;\n    private readonly char[][] _chars;\n    private int _currentRow;\n    private int _currentIndex;\n\n    public SourceCharacters(int lineLength, string message)\n    {\n        _lineLength = lineLength;\n        _chars = new[] { new char[lineLength], new char[lineLength] };\n\n        for (int i = 0; i < lineLength; i++)\n        {\n            _chars[0][i] = message[i % message.Length];\n            _chars[1][i] = ' ';\n        }\n    }\n\n    public ReadOnlySpan<char> GetCharacters(int count)\n    {\n        var span = new ReadOnlySpan<char>(_chars[_currentRow], _currentIndex, count);\n\n        _currentRow = 1 - _currentRow;\n        _currentIndex += count;\n        if (_currentIndex >= _lineLength)\n        {\n            _currentIndex = _currentRow = 0;\n        }\n\n        return span;\n    }\n}\n"
  },
  {
    "path": "58_Love/csharp/StringBuilderExtensions.cs",
    "content": "using System.Text;\n\nnamespace Love;\n\ninternal static class StringBuilderExtensions\n{\n    internal static StringBuilder AppendLines(this StringBuilder builder, int count)\n    {\n        for (int i = 0; i < count; i++)\n        {\n            builder.AppendLine();\n        }\n\n        return builder;\n    }\n}\n"
  },
  {
    "path": "58_Love/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "58_Love/java/src/Love.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Love\n * <p>\n * Based on the Basic game of Love here\n * https://github.com/coding-horror/basic-computer-games/blob/main/58%20Love/love.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\npublic class Love {\n\n    // This is actually defined in the data, but made it a const for readability\n    public static final int ROW_LENGTH = 60;\n\n    // Contains the data to draw the picture\n    private final ArrayList<Integer> data;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    public Love() {\n        data = storeData();\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Show an intro, accept a message, then draw the picture.\n     */\n    public void process() {\n        intro();\n\n        int rowLength = data.get(0);\n\n        String message = displayTextAndGetInput(\"YOUR MESSAGE, PLEASE \");\n\n        // ensure the string is at least 60 characters\n        while (message.length() < rowLength) {\n            message += message;\n        }\n\n        // chop of any extra characters so its exactly ROW_LENGTH in length\n        if (message.length() > ROW_LENGTH) {\n            message = message.substring(0, ROW_LENGTH);\n        }\n\n        // Print header\n        System.out.println(message);\n\n        int pos = 1;  // don't read row length which is value in first element position\n\n        int runningLineTotal = 0;\n        StringBuilder lineText = new StringBuilder();\n        boolean outputChars = true;\n        while (true) {\n            int charsOrSpacesLength = data.get(pos);\n            if (charsOrSpacesLength == ROW_LENGTH) {\n                // EOF, so exit\n                break;\n            }\n            if (outputChars) {\n                // add characters from message string for charsOrSpacesLength characters\n                for (int i = 0; i < charsOrSpacesLength; i++) {\n                    lineText.append(message.charAt(i + runningLineTotal));\n                    // switch to spaces which will be in the next element of the arraylist\n                    outputChars = false;\n                }\n            } else {\n                // add charsOrSpacesLength spaces to the string\n                lineText.append(addSpaces(charsOrSpacesLength));\n                // Switch to chars to output on next loop\n                outputChars = true;\n            }\n\n            // We need to know when to print the string out\n            runningLineTotal += charsOrSpacesLength;\n\n            // Are we at end of line?  If so print and reset for next line\n            if (runningLineTotal >= ROW_LENGTH) {\n                System.out.println(lineText);\n                lineText = new StringBuilder();\n                runningLineTotal = 0;\n                outputChars = true;\n            }\n\n            // Move to next arraylist element\n            pos++;\n        }\n\n        // Print footer\n        System.out.println(message);\n\n    }\n\n    private void intro() {\n        System.out.println(addSpaces(33) + \"LOVE\");\n        System.out.println(addSpaces(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\");\n        System.out.println(\"HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\");\n        System.out.println(\"YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\");\n        System.out.println(\"A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\");\n        System.out.println();\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.nextLine();\n    }\n\n    /**\n     * Return a string of x spaces\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String addSpaces(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /**\n     * Original Basic program had the data in DATA format.  We're importing all the data into an array for ease of\n     * processing.\n     * Format of data is\n     * FIRST int of data is 60, which is the number of characters per line.\n     * LAST int of data is same as FIRST above.\n     * Then the data alternates between how many characters to print and how many spaces to print\n     * You need to keep a running total of the count of ints read and once this hits 60, its time to\n     * print and then reset count to zero.\n     *\n     * @return ArrayList of type Integer containing the data\n     */\n    private ArrayList<Integer> storeData() {\n\n        ArrayList<Integer> theData = new ArrayList<>();\n\n        theData.addAll(Arrays.asList(60, 1, 12, 26, 9, 12, 3, 8, 24, 17, 8, 4, 6, 23, 21, 6, 4, 6, 22, 12, 5, 6, 5));\n        theData.addAll(Arrays.asList(4, 6, 21, 11, 8, 6, 4, 4, 6, 21, 10, 10, 5, 4, 4, 6, 21, 9, 11, 5, 4));\n        theData.addAll(Arrays.asList(4, 6, 21, 8, 11, 6, 4, 4, 6, 21, 7, 11, 7, 4, 4, 6, 21, 6, 11, 8, 4));\n        theData.addAll(Arrays.asList(4, 6, 19, 1, 1, 5, 11, 9, 4, 4, 6, 19, 1, 1, 5, 10, 10, 4, 4, 6, 18, 2, 1, 6, 8, 11, 4));\n        theData.addAll(Arrays.asList(4, 6, 17, 3, 1, 7, 5, 13, 4, 4, 6, 15, 5, 2, 23, 5, 1, 29, 5, 17, 8));\n        theData.addAll(Arrays.asList(1, 29, 9, 9, 12, 1, 13, 5, 40, 1, 1, 13, 5, 40, 1, 4, 6, 13, 3, 10, 6, 12, 5, 1));\n        theData.addAll(Arrays.asList(5, 6, 11, 3, 11, 6, 14, 3, 1, 5, 6, 11, 3, 11, 6, 15, 2, 1));\n        theData.addAll(Arrays.asList(6, 6, 9, 3, 12, 6, 16, 1, 1, 6, 6, 9, 3, 12, 6, 7, 1, 10));\n        theData.addAll(Arrays.asList(7, 6, 7, 3, 13, 6, 6, 2, 10, 7, 6, 7, 3, 13, 14, 10, 8, 6, 5, 3, 14, 6, 6, 2, 10));\n        theData.addAll(Arrays.asList(8, 6, 5, 3, 14, 6, 7, 1, 10, 9, 6, 3, 3, 15, 6, 16, 1, 1));\n        theData.addAll(Arrays.asList(9, 6, 3, 3, 15, 6, 15, 2, 1, 10, 6, 1, 3, 16, 6, 14, 3, 1, 10, 10, 16, 6, 12, 5, 1));\n        theData.addAll(Arrays.asList(11, 8, 13, 27, 1, 11, 8, 13, 27, 1, 60));\n\n        return theData;\n    }\n\n    public static void main(String[] args) {\n\n        Love love = new Love();\n        love.process();\n    }\n}\n"
  },
  {
    "path": "58_Love/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "58_Love/javascript/love.html",
    "content": "<html>\n<head>\n<title>LOVE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"love.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "58_Love/javascript/love.js",
    "content": "// LOVE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar data = [60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5,\n            4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4,\n            4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4,\n            4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4,\n            4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8,\n            1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1,\n            5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1,\n            6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10,\n            7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10,\n            8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1,\n            9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1,\n            11,8,13,27,1,11,8,13,27,1,60];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"LOVE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\\n\");\n    print(\"HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\\n\");\n    print(\"YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\\n\");\n    print(\"A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\\n\");\n    print(\"\\n\");\n    print(\"YOUR MESSAGE, PLEASE\");\n    str = await input();\n    l = str.length;\n    ts = [];\n    for (i = 1; i <= 10; i++)\n        print(\"\\n\");\n    ts = \"\";\n    do {\n        ts += str;\n    } while (ts.length < 60) ;\n    pos = 0;\n    c = 0;\n    while (++c < 37) {\n        a1 = 1;\n        p = 1;\n        print(\"\\n\");\n        do {\n            a = data[pos++];\n            a1 += a;\n            if (p != 1) {\n                for (i = 1; i <= a; i++)\n                    print(\" \");\n                p = 1;\n            } else {\n                for (i = a1 - a; i <= a1 - 1; i++)\n                    print(ts[i]);\n                p = 0;\n            }\n        } while (a1 <= 60) ;\n    }\n    for (i = 1; i <= 10; i++)\n        print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "58_Love/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "58_Love/love.bas",
    "content": "2 PRINT TAB(33);\"LOVE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n20 PRINT \"A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\"\n30 PRINT \"HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\"\n40 PRINT \"YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\"\n50 PRINT \"A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\": PRINT\n60 INPUT \"YOUR MESSAGE, PLEASE\";A$: L=LEN(A$)\n70 DIM T$(120): FOR I=1 TO 10: PRINT: NEXT I\n100 FOR J=0 TO INT(60/L)\n110 FOR I=1 TO L\n120 T$(J*L+I)=MID$(A$,I,1)\n130 NEXT I: NEXT J\n140 C=0\n200 A1=1: P=1: C=C+1: IF C=37 THEN 999\n205 PRINT\n210 READ A: A1=A1+A: IF P=1 THEN 300\n240 FOR I=1 TO A: PRINT \" \";: NEXT I: P=1: GOTO 400\n300 FOR I=A1-A TO A1-1: PRINT T$(I);: NEXT I: P=0\n400 IF A1>60 THEN 200\n410 GOTO 210\n600 DATA 60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5\n610 DATA 4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4\n620 DATA 4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4\n630 DATA 4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4\n640 DATA 4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8\n650 DATA 1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1\n660 DATA 5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1\n670 DATA 6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10\n680 DATA 7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10\n690 DATA 8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1\n700 DATA 9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1\n710 DATA 11,8,13,27,1,11,8,13,27,1,60\n999 FOR I=1 TO 10: PRINT: NEXT I: END\n"
  },
  {
    "path": "58_Love/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "58_Love/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "58_Love/perl/love.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 33 . \"LOVE\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\nprint \"A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\\n\";\nprint \"HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\\n\";\nprint \"YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\\n\";\nprint \"A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\\n\"; print \"\\n\";\nprint \"YOUR MESSAGE, PLEASE? \"; chomp(my $A = <STDIN>);\nmy $L= length($A);\n\n\n#Original logic too fuzzy, remaked.\nmy $Width= 60;\nmy $Text= substr($A x ($Width/$L+1), 0, $Width);\nfor (my $I=1; $I<10; $I++) { print \"\\n\"; }\n\nmy @Data= (\n\t60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5,\n\t4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4,\n\t4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4,\n\t4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4,\n\t4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8,\n\t1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1,\n\t5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1,\n\t6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10,\n\t7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10,\n\t8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1,\n\t9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1,\n\t11,8,13,27,1,11,8,13,27,1,60\n\t);\n\n\nmy $Pos=0;\nmy $Toggle=1;\nforeach my $Size (@Data) {\n\tmy $Chunk= $Toggle ? substr($Text, $Pos, $Size) : \" \" x $Size;\n\tprint $Chunk;\n\t$Pos+= $Size;\n\t$Toggle= !$Toggle;\n\tif ($Pos>= $Width) {\n\t\tprint \"\\n\";\n\t\t$Toggle=1;\n\t\t$Pos=0;\n\t\t}\n\t}\n\nfor (my $I=1; $I<10; $I++) { print \"\\n\"; }\nexit;\n"
  },
  {
    "path": "58_Love/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "58_Love/python/love.py",
    "content": "\"\"\"\r\nLOVE\r\n\r\nFrom: BASIC Computer Games (1978)\r\n      Edited by David H. Ahl\r\n\r\n\"This program is designed to reproduce Robert Indiana's great art\r\n work 'Love' with a message of your choice up to 60 characters long.\r\n\r\n\"The [DATA variable is] an alternating count of the number\r\n of characters and blanks which form the design.  These data give\r\n the correct proportions for a standard 10 character per inch\r\n Teletype or line printer.\r\n\r\n\"The LOVE program was created by David Ahl.\"\r\n\r\n\r\nPython port by Jeff Jetton, 2019\r\n\"\"\"\r\n\r\n\r\n# Image data. Each top-level element is a row. Each row element\r\n# contains alternating character and blank run lengths.\r\nDATA = [\r\n    [\r\n        60,\r\n    ],\r\n    [1, 12, 26, 9, 12],\r\n    [3, 8, 24, 17, 8],\r\n    [4, 6, 23, 21, 6],\r\n    [4, 6, 22, 12, 5, 6, 5],\r\n    [4, 6, 21, 11, 8, 6, 4],\r\n    [4, 6, 21, 10, 10, 5, 4],\r\n    [4, 6, 21, 9, 11, 5, 4],\r\n    [4, 6, 21, 8, 11, 6, 4],\r\n    [4, 6, 21, 7, 11, 7, 4],\r\n    [4, 6, 21, 6, 11, 8, 4],\r\n    [4, 6, 19, 1, 1, 5, 11, 9, 4],\r\n    [4, 6, 19, 1, 1, 5, 10, 10, 4],\r\n    [4, 6, 18, 2, 1, 6, 8, 11, 4],\r\n    [4, 6, 17, 3, 1, 7, 5, 13, 4],\r\n    [4, 6, 15, 5, 2, 23, 5],\r\n    [1, 29, 5, 17, 8],\r\n    [1, 29, 9, 9, 12],\r\n    [1, 13, 5, 40, 1],\r\n    [1, 13, 5, 40, 1],\r\n    [4, 6, 13, 3, 10, 6, 12, 5, 1],\r\n    [5, 6, 11, 3, 11, 6, 14, 3, 1],\r\n    [5, 6, 11, 3, 11, 6, 15, 2, 1],\r\n    [6, 6, 9, 3, 12, 6, 16, 1, 1],\r\n    [6, 6, 9, 3, 12, 6, 7, 1, 10],\r\n    [7, 6, 7, 3, 13, 6, 6, 2, 10],\r\n    [7, 6, 7, 3, 13, 14, 10],\r\n    [8, 6, 5, 3, 14, 6, 6, 2, 10],\r\n    [8, 6, 5, 3, 14, 6, 7, 1, 10],\r\n    [9, 6, 3, 3, 15, 6, 16, 1, 1],\r\n    [9, 6, 3, 3, 15, 6, 15, 2, 1],\r\n    [10, 6, 1, 3, 16, 6, 14, 3, 1],\r\n    [10, 10, 16, 6, 12, 5, 1],\r\n    [11, 8, 13, 27, 1],\r\n    [11, 8, 13, 27, 1],\r\n    [\r\n        60,\r\n    ],\r\n]\r\n\r\n\r\n# Assume that the total length of the first element\r\n# is the line length used by every row\r\nROW_LEN = sum(DATA[0])\r\n\r\n\r\ndef main() -> None:\r\n    # Display intro text\r\n    print(\"\\n                  Love\")\r\n    print(\"Creative Computing  Morristown, New Jersey\")\r\n    print(\"\\n\\n\")\r\n    print(\"A tribute to the great American artist, Robert Indiana.\")\r\n    print(\"His great work will be reproduced with a message of\")\r\n    print(\"your choice up to 60 characters.  If you can't think of\")\r\n    print(\"a message, simple type the word 'love'\\n\")  # (sic)\r\n\r\n    # Get message from user\r\n    message = input(\"Your message, please? \")\r\n    if message == \"\":\r\n        message = \"LOVE\"\r\n\r\n    # Repeat the message until we get at least one line's worth\r\n    while len(message) < ROW_LEN:\r\n        message += message\r\n\r\n    # Display image\r\n    print(\"\\n\" * 9)\r\n    for row in DATA:\r\n        print_message = True\r\n        position = 0\r\n        line_text = \"\"\r\n        for length in row:\r\n            if print_message:\r\n                text = message[position : (position + length)]\r\n                print_message = False\r\n            else:\r\n                text = \" \" * length\r\n                print_message = True\r\n            line_text += text\r\n            position += length\r\n        print(line_text)\r\n\r\n    print()\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n\r\n\r\n######################################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   Not too different from the original, logic-wise. The image was\r\n#   originally encoded as a series of BASIC \"DATA\" lines. Here,\r\n#   we've converted it to a more Pythonic nested list structure.\r\n#   Other changes include reducing some of the vertical spacing\r\n#   (since we'll probably be showing this on a screen rather than\r\n#   the sort of tractor-feed printer the program was written for)\r\n#   and having the message default to LOVE when no input is given.\r\n#\r\n#   This program uses a simple version of run-length encoding to\r\n#   compress a 60 x 36 image (2,160 characters) into just 252 DATA\r\n#   values.  That's about an 8.5-to-1 data compression ratio,\r\n#   which is pretty good!\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   Process the user's message input to remove spaces and change\r\n#   to uppercase.\r\n#\r\n#   Encode other images in a similar fashion and let the user choose\r\n#   which one they'd like to use to display their message.\r\n#\r\n#   To help with the above step, create a program that reads in a\r\n#   text file of any sort of similar character/space art and produces\r\n#   the Python code to initialize the correct nested list of values.\r\n#\r\n#   For example, if the input file were:\r\n#\r\n#     *****\r\n#     *  **\r\n#     **  *\r\n#\r\n#   Your program would output:\r\n#\r\n#    ((5, ), (1, 1, 2), (2, 1, 1))\r\n#\r\n######################################################################\r\n"
  },
  {
    "path": "58_Love/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "58_Love/ruby/love.rb",
    "content": "data = [60, 1, 12, 26, 9, 12, 3, 8, 24, 17, 8, 4, 6, 23, 21, 6, 4, 6, 22, 12, 5, 6, 5,\n        4, 6, 21, 11, 8, 6, 4, 4, 6, 21, 10, 10, 5, 4, 4, 6, 21, 9, 11, 5, 4, 4, 6, 21,\n        8, 11, 6, 4, 4, 6, 21, 7, 11, 7, 4, 4, 6, 21, 6, 11, 8, 4, 4, 6, 19, 1, 1, 5,\n        11, 9, 4, 4, 6, 19, 1, 1, 5, 10, 10, 4, 4, 6, 18, 2, 1, 6, 8, 11, 4, 4, 6, 17,\n        3, 1, 7, 5, 13, 4, 4, 6, 15, 5, 2, 23, 5, 1, 29, 5, 17, 8, 1, 29, 9, 9, 12, 1,\n        13, 5, 40, 1, 1, 13, 5, 40, 1, 4, 6, 13, 3, 10, 6, 12, 5, 1, 5, 6, 11, 3, 11,\n        6, 14, 3, 1, 5, 6, 11, 3, 11, 6, 15, 2, 1, 6, 6, 9, 3, 12, 6, 16, 1, 1, 6, 6,\n        9, 3, 12, 6, 7, 1, 10, 7, 6, 7, 3, 13, 6, 6, 2, 10, 7, 6, 7, 3, 13, 14, 10, 8,\n        6, 5, 3, 14, 6, 6, 2, 10, 8, 6, 5, 3, 14, 6, 7, 1, 10, 9, 6, 3, 3, 15, 6, 16, 1,\n        1, 9, 6, 3, 3, 15, 6, 15, 2, 1, 10, 6, 1, 3, 16, 6, 14, 3, 1, 10, 10, 16, 6, 12,\n        5, 1, 11, 8, 13, 27, 1, 11, 8, 13, 27, 1, 60]\n\nputs 'LOVE'.center(60)\nputs 'stephan.com'.center(60)\nputs \"\\n\\n\"\n\nputs <<~EOLOVE\n  A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\n  HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\n  YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\n  A MESSAGE, SIMPLY TYPE THE WORD 'LOVE'\\n\nEOLOVE\n\nmessage = gets.strip\nmessage = 'love' if message.empty?\nl = message.length\n\nuntil data.empty?\n  puts\n  col = 0\n  p = true\n  while col < 60\n    run = data.shift\n\n    if p\n      run.times { |i| print message[(col + i) % l] }\n    else\n      print ' ' * run\n    end\n    p = !p\n    col += run\n  end\nend\n"
  },
  {
    "path": "58_Love/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "58_Love/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Jadi.\n"
  },
  {
    "path": "58_Love/rust/src/main.rs",
    "content": "use std::io;\r\n\r\nfn show_intro() {\r\n    // Displays the intro text\r\n    println!(\"\\n                  Love\");\r\n    println!(\"Creative Computing  Morristown, New Jersey\");\r\n    println!(\"\\n\\n\");\r\n    println!(\"A tribute to the great American artist, Robert Indiana.\");\r\n    println!(\"His great work will be reproduced with a message of\");\r\n    println!(\"your choice up to 60 characters.  If you can't think of\");\r\n    println!(\"a message, simple type the word 'love'\\n\"); // (sic)\r\n}\r\n\r\nfn main() {\r\n    enum PrintOrPass {\r\n        Print,\r\n        Pass,\r\n    }\r\n\r\n    let data = [\r\n        vec![60],\r\n        vec![1, 12, 26, 9, 12],\r\n        vec![3, 8, 24, 17, 8],\r\n        vec![4, 6, 23, 21, 6],\r\n        vec![4, 6, 22, 12, 5, 6, 5],\r\n        vec![4, 6, 21, 11, 8, 6, 4],\r\n        vec![4, 6, 21, 10, 10, 5, 4],\r\n        vec![4, 6, 21, 9, 11, 5, 4],\r\n        vec![4, 6, 21, 8, 11, 6, 4],\r\n        vec![4, 6, 21, 7, 11, 7, 4],\r\n        vec![4, 6, 21, 6, 11, 8, 4],\r\n        vec![4, 6, 19, 1, 1, 5, 11, 9, 4],\r\n        vec![4, 6, 19, 1, 1, 5, 10, 10, 4],\r\n        vec![4, 6, 18, 2, 1, 6, 8, 11, 4],\r\n        vec![4, 6, 17, 3, 1, 7, 5, 13, 4],\r\n        vec![4, 6, 15, 5, 2, 23, 5],\r\n        vec![1, 29, 5, 17, 8],\r\n        vec![1, 29, 9, 9, 12],\r\n        vec![1, 13, 5, 40, 1],\r\n        vec![1, 13, 5, 40, 1],\r\n        vec![4, 6, 13, 3, 10, 6, 12, 5, 1],\r\n        vec![5, 6, 11, 3, 11, 6, 14, 3, 1],\r\n        vec![5, 6, 11, 3, 11, 6, 15, 2, 1],\r\n        vec![6, 6, 9, 3, 12, 6, 16, 1, 1],\r\n        vec![6, 6, 9, 3, 12, 6, 7, 1, 10],\r\n        vec![7, 6, 7, 3, 13, 6, 6, 2, 10],\r\n        vec![7, 6, 7, 3, 13, 14, 10],\r\n        vec![8, 6, 5, 3, 14, 6, 6, 2, 10],\r\n        vec![8, 6, 5, 3, 14, 6, 7, 1, 10],\r\n        vec![9, 6, 3, 3, 15, 6, 16, 1, 1],\r\n        vec![9, 6, 3, 3, 15, 6, 15, 2, 1],\r\n        vec![10, 6, 1, 3, 16, 6, 14, 3, 1],\r\n        vec![10, 10, 16, 6, 12, 5, 1],\r\n        vec![11, 8, 13, 27, 1],\r\n        vec![11, 8, 13, 27, 1],\r\n        vec![60],\r\n    ];\r\n\r\n    const ROW_LEN: usize = 60;\r\n    show_intro();\r\n\r\n    let mut input: String = String::new();\r\n    io::stdin().read_line(&mut input).expect(\"No valid input\");\r\n    let input = if input.len() == 1 {\r\n        \"LOVE\"\r\n    } else {\r\n        input.trim()\r\n    };\r\n    // repeat the answer to fill the whole line, we will show chunks of this when needed\r\n    let input = input.repeat(ROW_LEN / (input.len()) + 1);\r\n\r\n    // Now lets display the Love\r\n    print!(\"{}\", \"\\n\".repeat(9));\r\n    for row in data {\r\n        let mut print_or_pass = PrintOrPass::Print;\r\n        let mut current_start = 0;\r\n        for count in row {\r\n            match print_or_pass {\r\n                PrintOrPass::Print => {\r\n                    print!(\"{}\", &input[current_start..count + current_start]);\r\n                    print_or_pass = PrintOrPass::Pass;\r\n                }\r\n                PrintOrPass::Pass => {\r\n                    print!(\"{}\", \" \".repeat(count));\r\n                    print_or_pass = PrintOrPass::Print;\r\n                }\r\n            }\r\n            current_start += count;\r\n        }\r\n        println!();\r\n    }\r\n}\r\n"
  },
  {
    "path": "58_Love/vbnet/Love.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Love\", \"Love.vbproj\", \"{440AD3C3-D842-4717-BB4D-C54463F59ECA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "58_Love/vbnet/Love.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Love</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "58_Love/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/README.md",
    "content": "### Lunar LEM Rocket\n\nThis game in its many different versions and names (ROCKET, LUNAR, LEM, and APOLLO) is by far and away the single most popular computer game. It exists in various versions that start you anywhere from 500 feet to 200 miles away from the moon, or other planets, too. Some allow the control of directional stabilization rockets and/or the retro rocket. The three versions presented here represent the most popular of the many variations.\n\nIn most versions of this game, the temptation is to slow up too soon and then have no fuel left for the lower part of the journey. This, of course, is disastrous (as you will find out when you land your own capsule)!\n\nLUNAR was originally in FOCAL by Jim Storer while a student at Lexington High School and subsequently converted to BASIC by David Ahl. ROCKET was written by Eric Peters at DEC and LEM by William Labaree II of Alexandria, Virginia.\n\nIn this program, you set the burn rate of the retro rockets (pounds of fuel per second) every 10 seconds and attempt to achieve a soft landing on the moon. 200 lbs/sec really puts the brakes on, and 0 lbs/sec is free fall. Ignition occurs a 8 lbs/sec, so _do not_ use burn rates between 1 and 7 lbs/sec. To make the landing more of a challenge, but more closely approximate the real Apollo LEM capsule, you should make the available fuel at the start (N) equal to 16,000 lbs, and the weight of the capsule (M) equal to 32,500 lbs.\n\n#### LEM\nThis is the most comprehensive of the three versions and permits you to control the time interval of firing, the thrust, and the attitude angle. It also allows you to work in the metric or English system of measurement. The instructions in the program dialog are very complete, so you shouldn’t have any trouble.\n\n#### ROCKET\nIn this version, you start 500 feet above the lunar surface and control the burn rate in 1-second bursts. Each unit of fuel slows your descent by 1 ft/sec. The maximum thrust of your engine is 30 ft/sec/sec.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=106)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=121)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n### lem.bas\n\n- The input validation on the thrust value (displayed as P, stored internally as F) appears to be incorrect.  It allows negative values up up to -95, but at -96 or more balks and calls it negative.  I suspect the intent was to disallow any value less than 0 (in keeping with the instructions), *or* nonzero values less than 10.\n\n- The physics calculations seem very sus.  If you enter \"1000,0,0\" (i.e. no thrust at all, integrating 1000 seconds at a time) four times in a row, you first fall, but then mysteriously gain vertical speed, and end up being lost in space.  This makes no sense.  A similar result happened when just periodically applying 10% thrust in an attempt to hover.\n\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n\n### LUNAR\n\nVariables:\n\n`A`: Altitude in miles.  Up is positive.\n`V`: Velocity in miles / sec.  Down is positive.\n\n`M`: Weight of capsule in pounds, both fuel and machine\n`N`: Empty weight of capsule in pounds.  So, weight of fuel is M - N.\n\n`G`: Gravity in miles / sec^2, down is positive.\n`Z`: Exhaust velocity in miles / sec\n\n`L`: time in seconds since start of simulation.\n`K`: Burn rate for this 10 second turn, pounds of fuel per sec\n`T`: Time left in this 10 second turn, in seconds.\n`S`: Burn time in this 10 second turn, input to subroutine 420.\n\nSubroutines:\n\n330, Apply updates from one call to subroutine 420.\n\n370, If you started descending and ended ascending, figure out whether you hit the surface in between.\n\n420, Compute new velocity and altitude using the Tsiolkovsky rocket equation for S seconds:\n\n`Q`: Fraction of initial mass that's burnt, i.e. 1 - mf / mo, exactly what we need for the Taylor series of `ln` in the rocket equation. Local to this subroutine.\n`J`: Final velocity after S seconds, down is positive.  Return value.\n`I`: Altitude after S seconds, up is positive.  Return value.\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"LunarLEMRocket\", \"LunarLEMRocket.csproj\", \"{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/javascript/lem.html",
    "content": "<html>\n<head>\n<title>LEM</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"lem.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/javascript/lem.js",
    "content": "// LEM\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"LEM\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    // ROCKT2 is an interactive game that simulates a lunar\n    // landing is similar to that of the Apollo program.\n    // There is absolutely no chance involved\n    zs = \"GO\";\n    b1 = 1;\n    while (1) {\n        m = 17.95;\n        f1 = 5.25;\n        n = 7.5;\n        r0 = 926;\n        v0 = 1.29;\n        t = 0;\n        h0 = 60;\n        r = r0 + h0;\n        a = -3,425;\n        r1 = 0;\n        a1 = 8.84361e-4;\n        r3 = 0;\n        a3 = 0;\n        m1 = 7.45;\n        m0 = m1;\n        b = 750;\n        t1 = 0;\n        f = 0;\n        p = 0;\n        n = 1;\n        m2 = 0;\n        s = 0;\n        c = 0;\n        if (zs == \"YES\") {\n            print(\"\\n\");\n            print(\"OK, DO YOU WANT THE COMPLETE INSTRUCTIONS OR THE INPUT -\\n\");\n            print(\"OUTPUT STATEMENTS?\\n\");\n            while (1) {\n                print(\"1=COMPLETE INSTRUCTIONS\\n\");\n                print(\"2=INPUT-OUTPUT STATEMENTS\\n\");\n                print(\"3=NEITHER\\n\");\n                b1 = parseInt(await input());\n                qs = \"NO\";\n                if (b1 == 1)\n                    break;\n                qs = \"YES\";\n                if (b1 == 2 || b1 == 3)\n                    break;\n            }\n        } else {\n            print(\"\\n\");\n            print(\"LUNAR LANDING SIMULATION\\n\");\n            print(\"\\n\");\n            print(\"HAVE YOU FLOWN AN APOLLO/LEM MISSION BEFORE\");\n            while (1) {\n                print(\" (YES OR NO)\");\n                qs = await input();\n                if (qs == \"YES\" || qs == \"NO\")\n                    break;\n                print(\"JUST ANSWER THE QUESTION, PLEASE, \");\n            }\n        }\n        if (qs == \"YES\") {\n            print(\"\\n\");\n            print(\"INPUT MEASUREMENT OPTION NUMBER\");\n        } else {\n            print(\"\\n\");\n            print(\"WHICH SYSTEM OF MEASUREMENT DO YOU PREFER?\\n\");\n            print(\" 1=METRIC     0=ENGLISH\\n\");\n            print(\"ENTER THE APPROPRIATE NUMBER\");\n        }\n        while (1) {\n            k = parseInt(await input());\n            if (k == 0 || k == 1)\n                break;\n            print(\"ENTER THE APPROPRIATE NUMBER\");\n        }\n        if (k == 1) {\n            z = 1852.8;\n            ms = \"METERS\";\n            g3 = 3.6;\n            ns = \" KILOMETERS\";\n            g5 = 1000;\n        } else {\n            z = 6080;\n            ms = \"FEET\";\n            g3 = 0.592;\n            ns = \"N.MILES\";\n            g5 = z;\n        }\n        if (b1 != 3) {\n            if (qs != \"YES\") {\n                print(\"\\n\");\n                print(\"  YOU ARE ON A LUNAR LANDING MISSION.  AS THE PILOT OF\\n\");\n                print(\"THE LUNAR EXCURSION MODULE, YOU WILL BE EXPECTED TO\\n\");\n                print(\"GIVE CERTAIN COMMANDS TO THE MODULE NAVIGATION SYSTEM.\\n\");\n                print(\"THE ON-BOARD COMPUTER WILL GIVE A RUNNING ACCOUNT\\n\");\n                print(\"OF INFORMATION NEEDED TO NAVIGATE THE SHIP.\\n\");\n                print(\"\\n\");\n                print(\"\\n\");\n                print(\"THE ATTITUDE ANGLE CALLED FOR IS DESCRIBED AS FOLLOWS.\\n\");\n                print(\"+ OR -180 DEGREES IS DIRECTLY AWAY FROM THE MOON\\n\");\n                print(\"-90 DEGREES IS ON A TANGENT IN THE DIRECTION OF ORBIT\\n\");\n                print(\"+90 DEGREES IS ON A TANGENT FROM THE DIRECTION OF ORBIT\\n\");\n                print(\"0 (ZERO) DEGREES IS DIRECTLY TOWARD THE MOON\\n\");\n                print(\"\\n\");\n                print(tab(30) + \"-180|+180\\n\");\n                print(tab(34) + \"^\\n\");\n                print(tab(27) + \"-90 < -+- > +90\\n\");\n                print(tab(34) + \"!\\n\");\n                print(tab(34) + \"0\\n\");\n                print(tab(21) + \"<<<< DIRECTION OF ORBIT <<<<\\n\");\n                print(\"\\n\");\n                print(tab(20) + \"------ SURFACE OF MOON ------\\n\");\n                print(\"\\n\");\n                print(\"\\n\");\n                print(\"ALL ANGLES BETWEEN -180 AND +180 DEGREES ARE ACCEPTED.\\n\");\n                print(\"\\n\");\n                print(\"1 FUEL UNIT = 1 SEC. AT MAX THRUST\\n\");\n                print(\"ANY DISCREPANCIES ARE ACCOUNTED FOR IN THE USE OF FUEL\\n\");\n                print(\"FOR AN ATTITUDE CHANGE.\\n\");\n                print(\"AVAILABLE ENGINE POWER: 0 (ZERO) AND ANY VALUE BETWEEN\\n\");\n                print(\"10 AND 100 PERCENT.\\n\");\n                print(\"\\n\");\n                print(\"NEGATIVE THRUST OR TIME IS PROHIBITED.\\n\");\n                print(\"\\n\");\n            }\n            print(\"\\n\");\n            print(\"INPUT: TIME INTERVAL IN SECONDS ------ (T)\\n\");\n            print(\"       PERCENTAGE OF THRUST ---------- (P)\\n\");\n            print(\"       ATTITUDE ANGLE IN DEGREES ----- (A)\\n\");\n            print(\"\\n\");\n            if (qs != \"YES\") {\n                print(\"FOR EXAMPLE:\\n\");\n                print(\"T,P,A? 10,65,-60\\n\");\n                print(\"TO ABORT THE MISSION AT ANY TIME, ENTER 0,0,0\\n\");\n                print(\"\\n\");\n            }\n            print(\"OUTPUT: TOTAL TIME IN ELAPSED SECONDS\\n\");\n            print(\"        HEIGHT IN \" + ms + \"\\n\");\n            print(\"        DISTANCE FROM LANDING SITE IN \" + ms + \"\\n\");\n            print(\"        VERTICAL VELOCITY IN \" + ms + \"/SECOND\\n\");\n            print(\"        HORIZONTAL VELOCITY IN \" + ms + \"/SECOND\\n\");\n            print(\"        FUEL UNITS REMAINING\\n\");\n            print(\"\\n\");\n        }\n        while (1) {\n            for (i = 1; i <= n; i++) {\n                if (m1 != 0) {\n                    m1 -= m2;\n                    if (m1 <= 0) {\n                        f = f * (1 + m1 / m2);\n                        m2 = m1 + m2;\n                        print(\"YOU ARE OUT OF FUEL.\\n\");\n                        m1 = 0;\n                    }\n                } else {\n                    f = 0;\n                    m2 = 0;\n                }\n                m = m - 0.5 * m2;\n                r4 = r3;\n                r3 = -0.5 * r0 * Math.pow(v0 / r, 2) + r * a1 * a1;\n                r2 = (3 * r3 - r4) / 2 + 0.00526 * f1 * f * c / m;\n                a4 = a3;\n                a3 = -2 * r1 * a1 / r;\n                a2 = (3 * a3 - a4) / 2 + 0.0056 * f1 * f * s / (m * r);\n                x = r1 * t1 + 0.5 * r2 * t1 * t1;\n                r = r + x;\n                h0 = h0 + x;\n                r1 = r1 + r2 * t1;\n                a = a + a1 * t1 + 0.5 * a2 * t1 * t1;\n                a1 = a1 + a2 * t1;\n                m = m - 0.5 * m2;\n                t = t + t1;\n                if (h0 < 3.287828e-4)\n                    break;\n            }\n            h = h0 * z;\n            h1 = r1 * z;\n            d = r0 * a * z;\n            d1 = r * a1 * z;\n            t2 = m1 * b / m0;\n            print(\" \" + t + \"\\t\" + h + \"\\t\" + d + \"\\t\" + h1 + \"\\t\" + d1 + \"\\t\" + t2 + \"\\n\");\n            if (h0 < 3.287828e-4) {\n                if (r1 < -8.21957e-4 || Math.abs(r * a1) > 4.93174e-4 || h0 < -3.287828e-4) {\n                    print(\"\\n\");\n                    print(\"CRASH !!!!!!!!!!!!!!!!\\n\");\n                    print(\"YOUR IMPACT CREATED A CRATER \" + Math.abs(h) + \" \" + ms + \" DEEP.\\n\");\n                    x1 = Math.sqrt(d1 * d1 + h1 * h1) * g3;\n                    print(\"AT CONTACT YOU WERE TRAVELING \" + x1 + \" \" + ns + \"/HR\\n\");\n                    break;\n                }\n                if (Math.abs(d) > 10 * z) {\n                    print(\"YOU ARE DOWN SAFELY - \\n\");\n                    print(\"\\n\");\n                    print(\"BUT MISSED THE LANDING SITE BY \" + Math.abs(d / g5) + \" \" + ns + \".\\n\");\n                    break;\n                }\n                print(\"\\n\");\n                print(\"TRANQUILITY BASE HERE -- THE EAGLE HAS LANDED.\\n\");\n                print(\"CONGRATULATIONS -- THERE WAS NO SPACECRAFT DAMAGE.\\n\");\n                print(\"YOU MAY NOW PROCEED WITH SURFACE EXPLORATION.\\n\");\n                break;\n            }\n            if (r0 * a > 164.474) {\n                print(\"\\n\");\n                print(\"YOU HAVE BEEN LOST IN SPACE WITH NO HOPE OF RECOVERY.\\n\");\n                break;\n            }\n            if (m1 > 0) {\n                while (1) {\n                    print(\"T,P,A\");\n                    str = await input();\n                    t1 = parseFloat(str);\n                    f = parseFloat(str.substr(str.indexOf(\",\") + 1));\n                    p = parseFloat(str.substr(str.lastIndexOf(\",\") + 1));\n                    f = f / 100;\n                    if (t1 < 0) {\n                        print(\"\\n\");\n                        print(\"THIS SPACECRAFT IS NOT ABLE TO VIOLATE THE SPACE-\");\n                        print(\"TIME CONTINUUM.\\n\");\n                        print(\"\\n\");\n                    } else if (t1 == 0) {\n                        break;\n                    } else if (Math.abs(f - 0.05) > 1 || Math.abs(f - 0.05) < 0.05) {\n                        print(\"IMPOSSIBLE THRUST VALUE \");\n                        if (f < 0) {\n                            print(\"NEGATIVE\\n\");\n                        } else if (f - 0.05 < 0.05) {\n                            print(\"TOO SMALL\\n\");\n                        } else {\n                            print(\"TOO LARGE\\n\");\n                        }\n                        print(\"\\n\");\n                    } else if (Math.abs(p) > 180) {\n                        print(\"\\n\");\n                        print(\"IF YOU WANT TO SPIN AROUND, GO OUTSIDE THE MODULE\\n\");\n                        print(\"FOR AN E.V.A.\\n\");\n                        print(\"\\n\");\n                    } else {\n                        break;\n                    }\n                }\n                if (t1 == 0) {\n                    print(\"\\n\");\n                    print(\"MISSION ABENDED\\n\");\n                    break;\n                }\n            } else {\n                t1 = 20;\n                f = 0;\n                p = 0;\n            }\n            n = 20;\n            if (t1 >= 400)\n                n = t1 / 20;\n            t1 = t1 / n;\n            p = p * 3.14159 / 180;\n            s = Math.sin(p);\n            c = Math.cos(p);\n            m2 = m0 * t1 * f / b;\n            r3 = -0.5 * r0 * Math.pow(v0 / r, 2) + r * a1 * a1;\n            a3 = -2 * r1 * a1 / r;\n        }\n        print(\"\\n\");\n        while (1) {\n            print(\"DO YOU WANT TO TRY IT AGAIN (YES/NO)?\\n\");\n            zs = await input();\n            if (zs == \"YES\" || zs == \"NO\")\n                break;\n        }\n        if (zs != \"YES\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"TOO BAD, THE SPACE PROGRAM HATES TO LOSE EXPERIENCED\\n\");\n    print(\"ASTRONAUTS.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/javascript/lunar.html",
    "content": "<html>\n<head>\n<title>LUNAR</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"lunar.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/javascript/lunar.js",
    "content": "// LUNAR\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar l;\nvar t;\nvar m;\nvar s;\nvar k;\nvar a;\nvar v;\nvar i;\nvar j;\nvar q;\nvar g;\nvar z;\nvar d;\n\nfunction formula_set_1()\n{\n    l = l + s;\n    t = t - s;\n    m = m - s * k;\n    a = i;\n    v = j;\n}\n\nfunction formula_set_2()\n{\n    q = s * k / m;\n    j = v + g * s + z * (-q - q * q / 2 - Math.pow(q, 3) / 3 - Math.pow(q, 4) / 4 - Math.pow(q, 5) / 5);\n    i = a - g * s * s / 2 - v * s + z * s * (q / 2 + Math.pow(q, 2) / 6 + Math.pow(q, 3) / 12 + Math.pow(q, 4) / 20 + Math.pow(q, 5) / 30);\n}\n\nfunction formula_set_3()\n{\n    while (s >= 5e-3) {\n        d = v + Math.sqrt(v * v + 2 * a * (g - z * k / m));\n        s = 2 * a / d;\n        formula_set_2();\n        formula_set_1();\n    }\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"LUNAR\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR\\n\");\n    print(\"LANDING CAPSULE.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY\\n\");\n    print(\"XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.\\n\");\n    while (1) {\n        print(\"\\n\");\n        print(\"SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN\\n\");\n        print(\"0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.\\n\");\n        print(\"SET NEW BURN RATE EVERY 10 SECONDS.\\n\");\n        print(\"\\n\");\n        print(\"CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,000 LBS.\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"GOOD LUCK\\n\");\n        l = 0;\n        print(\"\\n\");\n        print(\"SEC\\tMI + FT\\t\\tMPH\\tLB FUEL\\tBURN RATE\\n\");\n        print(\"\\n\");\n        a = 120;\n        v = 1;\n        m = 33000;\n        n = 16500;\n        g = 1e-3;\n        z = 1.8;\n        while (1) {\n            print(l + \"\\t\" + Math.floor(a) + \" + \" + Math.floor(5280 * (a - Math.floor(a))) + \" \\t\" + Math.floor(3600 * v * 100) / 100 + \"\\t\" + (m - n) + \"\\t\");\n            k = parseFloat(await input());\n            t = 10;\n            should_exit = false;\n            while (1) {\n                if (m - n < 1e-3)\n                    break;\n                if (t < 1e-3)\n                    break;\n                s = t;\n                if (m < n + s * k)\n                    s = (m - n) / k;\n                formula_set_2();\n                if (i <= 0) {\n                    formula_set_3();\n                    should_exit = true;\n                    break;\n                }\n                if (v > 0) {\n                    if (j < 0) {\n                        do {\n                            w = (1 - m * g / (z * k)) / 2;\n                            s = m * v / (z * k * (w + Math.sqrt(w * w + v / z))) + 0.05;\n                            formula_set_2();\n                            if (i <= 0) {\n                                formula_set_3();\n                                should_exit = true;\n                                break;\n                            }\n                            formula_set_1();\n                            if (j > 0)\n                                break;\n                        } while (v > 0) ;\n                        if (should_exit)\n                            break;\n                        continue;\n                    }\n                }\n                formula_set_1();\n            }\n            if (should_exit)\n                break;\n            if (m - n < 1e-3) {\n                print(\"FUEL OUT AT \" + l + \" SECOND\\n\");\n                s = (-v * Math.sqrt(v * v + 2 * a * g)) / g;\n                v = v + g * s;\n                l = l + s;\n                break;\n            }\n        }\n        w = 3600 * v;\n        print(\"ON MOON AT \" + l + \" SECONDS - IMPACT VELOCITY \" + w + \" MPH\\n\");\n        if (w <= 1.2) {\n            print(\"PERFECT LANDING!\\n\");\n        } else if (w <= 10) {\n            print(\"GOOD LANDING (COULD BE BETTER)\\n\");\n        } else if (w <= 60) {\n            print(\"CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE\\n\");\n            print(\"PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!\\n\");\n        } else {\n            print(\"SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!\\n\");\n            print(\"IN FACT, YOU BLASTED A NEW LUNAR CRATER \" + (w * 0.227) + \" FEET DEEP!\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"TRY AGAIN??\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/lem.bas",
    "content": "2 PRINT TAB(34);\"LEM\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n7 REM ROCKT2 IS AN INTERACTIVE GAME THAT SIMULATES A LUNAR\n8 REM LANDING IS SIMILAR TO THAT OF THE APOLLO PROGRAM.\n9 REM THERE IS ABSOLUTELY NO CHANCE INVOLVED\n10 Z$=\"GO\"\n15 B1=1\n20 M=17.95\n25 F1=5.25\n30 N=7.5\n35 R0=926\n40 V0=1.29\n45 T=0\n50 H0=60\n55 R=R0+H0\n60 A=-3.425\n65 R1=0\n70 A1=8.84361E-04\n75 R3=0\n80 A3=0\n85 M1=7.45\n90 M0=M1\n95 B=750\n100 T1=0\n105 F=0\n110 P=0\n115 N=1\n120 M2=0\n125 S=0\n130 C=0\n135 IF Z$=\"YES\" THEN 1150\n140 PRINT\n145 PRINT \"LUNAR LANDING SIMULATION\"\n150 PRINT\n155 PRINT \"HAVE YOU FLOWN AN APOLLO/LEM MISSION BEFORE\";\n160 PRINT \" (YES OR NO)\";\n165 INPUT Q$\n170 IF Q$=\"YES\" THEN 190\n175 IF Q$=\"NO\" THEN 205\n180 PRINT \"JUST ANSWER THE QUESTION, PLEASE, \";\n185 GOTO 160\n190 PRINT\n195 PRINT \"INPUT MEASUREMENT OPTION NUMBER\";\n200 GOTO 225\n205 PRINT\n210 PRINT \"WHICH SYSTEM OF MEASUREMENT DO YOU PREFER?\"\n215 PRINT \" 1=METRIC     0=ENGLISH\"\n220 PRINT \"ENTER THE APPROPRIATE NUMBER\";\n225 INPUT K\n230 PRINT\n235 IF K=0 THEN 280\n240 IF K=1 THEN 250\n245 GOTO 220\n250 Z=1852.8\n255 M$=\"METERS\"\n260 G3=3.6\n265 N$=\" KILOMETERS\"\n270 G5=1000\n275 GOTO 305\n280 Z=6080\n285 M$=\"FEET\"\n290 G3=.592\n295 N$=\"N.MILES\"\n300 G5=Z\n305 IF B1=3 THEN 670\n310 IF Q$=\"YES\" THEN 485\n315 PRINT\n320 PRINT \"  YOU ARE ON A LUNAR LANDING MISSION.  AS THE PILOT OF\"\n325 PRINT \"THE LUNAR EXCURSION MODULE, YOU WILL BE EXPECTED TO\"\n330 PRINT \"GIVE CERTAIN COMMANDS TO THE MODULE NAVIGATION SYSTEM.\"\n335 PRINT \"THE ON-BOARD COMPUTER WILL GIVE A RUNNING ACCOUNT\"\n340 PRINT \"OF INFORMATION NEEDED TO NAVIGATE THE SHIP.\"\n345 PRINT\n350 PRINT\n355 PRINT \"THE ATTITUDE ANGLE CALLED FOR IS DESCRIBED AS FOLLOWS.\"\n360 PRINT \"+ OR -180 DEGREES IS DIRECTLY AWAY FROM THE MOON\"\n365 PRINT \"-90 DEGREES IS ON A TANGENT IN THE DIRECTION OF ORBIT\"\n370 PRINT \"+90 DEGREES IS ON A TANGENT FROM THE DIRECTION OF ORBIT\"\n375 PRINT \"0 (ZERO) DEGREES IS DIRECTLY TOWARD THE MOON\"\n380 PRINT\n385 PRINT TAB(30);\"-180|+180\"\n390 PRINT TAB(34);\"^\"\n395 PRINT TAB(27);\"-90 < -+- > +90\"\n400 PRINT TAB(34);\"!\"\n405 PRINT TAB(34);\"0\"\n410 PRINT TAB(21);\"<<<< DIRECTION OF ORBIT <<<<\"\n415 PRINT\n420 PRINT TAB(20);\"------ SURFACE OF MOON ------\"\n425 PRINT\n430 PRINT\n435 PRINT \"ALL ANGLES BETWEEN -180 AND +180 DEGREES ARE ACCEPTED.\"\n440 PRINT\n445 PRINT \"1 FUEL UNIT = 1 SEC. AT MAX THRUST\"\n450 PRINT \"ANY DISCREPANCIES ARE ACCOUNTED FOR IN THE USE OF FUEL\"\n455 PRINT \"FOR AN ATTITUDE CHANGE.\"\n460 PRINT \"AVAILABLE ENGINE POWER: 0 (ZERO) AND ANY VALUE BETWEEN\"\n465 PRINT \"10 AND 100 PERCENT.\"\n470 PRINT\n475 PRINT\"NEGATIVE THRUST OR TIME IS PROHIBITED.\"\n480 PRINT\n485 PRINT\n490 PRINT \"INPUT: TIME INTERVAL IN SECONDS ------ (T)\"\n495 PRINT \"       PERCENTAGE OF THRUST ---------- (P)\"\n500 PRINT \"       ATTITUDE ANGLE IN DEGREES ----- (A)\"\n505 PRINT\n510 IF Q$=\"YES\" THEN 535\n515 PRINT \"FOR EXAMPLE:\"\n520 PRINT \"T,P,A? 10,65,-60\"\n525 PRINT \"TO ABORT THE MISSION AT ANY TIME, ENTER 0,0,0\"\n530 PRINT\n535 PRINT \"OUTPUT: TOTAL TIME IN ELAPSED SECONDS\"\n540 PRINT \"        HEIGHT IN \";M$\n545 PRINT \"        DISTANCE FROM LANDING SITE IN \";M$\n550 PRINT \"        VERTICAL VELOCITY IN \";M$;\"/SECOND\"\n555 PRINT \"        HORIZONTAL VELOCITY IN \";M$;\"/SECOND\"\n560 PRINT \"        FUEL UNITS REMAINING\"\n565 PRINT\n570 GOTO 670\n575 PRINT\n580 PRINT \"T,P,A\";\n585 INPUT T1,F,P\n590 F=F/100\n595 IF T1<0 THEN 905\n600 IF T1=0 THEN 1090\n605 IF ABS(F-.05)>1 THEN 945\n610 IF ABS(F-.05)<.05 THEN 945\n615 IF ABS(P)>180 THEN 925\n620 N=20\n625 IF T1<400 THEN 635\n630 N=T1/20\n635 T1=T1/N\n640 P=P*3.14159/180\n645 S=SIN(P)\n650 C=COS(P)\n655 M2=M0*T1*F/B\n660 R3=-.5*R0*((V0/R)^2)+R*A1*A1\n665 A3=-2*R1*A1/R\n670 FOR I=1 TO N\n675 IF M1=0 THEN 715\n680 M1=M1-M2\n685 IF M1>0 THEN 725\n690 F=F*(1+M1/M2)\n695 M2=M1+M2\n700 PRINT \"YOU ARE OUT OF FUEL.\"\n705 M1=0\n710 GOTO 725\n715 F=0\n720 M2=0\n725 M=M-.5*M2\n730 R4=R3\n735 R3=-.5*R0*((V0/R)^2)+R*A1*A1\n740 R2=(3*R3-R4)/2+.00526*F1*F*C/M\n745 A4=A3\n750 A3=-2*R1*A1/R\n755 A2=(3*A3-A4)/2+.0056*F1*F*S/(M*R)\n760 X=R1*T1+.5*R2*T1*T1\n765 R=R+X\n770 H0=H0+X\n775 R1=R1+R2*T1\n780 A=A+A1*T1+.5*A2*T1*T1\n785 A1=A1+A2*T1\n790 M=M-.5*M2\n795 T=T+T1\n800 IF H0<3.287828E-04 THEN 810\n805 NEXT I\n810 H=H0*Z\n815 H1=R1*Z\n820 D=R0*A*Z\n825 D1=R*A1*Z\n830 T2=M1*B/M0\n835 PRINT \" \";T;TAB(10);H;TAB(23);D;\n840 PRINT TAB(37);H1;TAB(49);D1;TAB(60);T2\n845 IF H0<3.287828E-04 THEN 880\n850 IF R0*A>164.474 THEN 1050\n855 IF M1>0 THEN 580\n860 T1=20\n865 F=0\n870 P=0\n875 GOTO 620\n880 IF R1<-8.21957E-04 THEN 1020\n885 IF ABS(R*A1)>4.93174E-04 THEN 1020\n890 IF H0<-3.287828E-04 THEN 1020\n895 IF ABS(D)>10*Z THEN 1065\n900 GOTO 995\n905 PRINT\n910 PRINT \"THIS SPACECRAFT IS NOT ABLE TO VIOLATE THE SPACE-\";\n915 PRINT \"TIME CONTINUUM.\"\n920 GOTO 575\n925 PRINT\n930 PRINT \"IF YOU WANT TO SPIN AROUND, GO OUTSIDE THE MODULE\"\n935 PRINT \"FOR AN E.V.A.\"\n940 GOTO 575\n945 PRINT\n950 PRINT \"IMPOSSIBLE THRUST VALUE \";\n955 IF F<0 THEN 985\n960 IF F-.05<.05 THEN 975\n965 PRINT \"TOO LARGE\"\n970 GOTO 575\n975 PRINT \"TOO SMALL\"\n980 GOTO 575\n985 PRINT \"NEGATIVE\"\n990 GOTO 575\n995 PRINT\n1000 PRINT \"TRANQUILITY BASE HERE -- THE EAGLE HAS LANDED.\"\n1005 PRINT \"CONGRATULATIONS -- THERE WAS NO SPACECRAFT DAMAGE.\"\n1010 PRINT \"YOU MAY NOW PROCEED WITH SURFACE EXPLORATION.\"\n1015 GOTO 1100\n1020 PRINT\n1025 PRINT \"CRASH !!!!!!!!!!!!!!!!\"\n1030 PRINT \"YOUR IMPACT CREATED A CRATER\";ABS(H);M$;\" DEEP.\"\n1035 X1=SQR(D1*D1+H1*H1)*G3\n1040 PRINT \"AT CONTACT YOU WERE TRAVELING\";X1;N$;\"/HR\"\n1045 GOTO 1100\n1050 PRINT\n1055 PRINT \"YOU HAVE BEEN LOST IN SPACE WITH NO HOPE OF RECOVERY.\"\n1060 GOTO 1100\n1065 PRINT \"YOU ARE DOWN SAFELY - \"\n1075 PRINT\n1080 PRINT \"BUT MISSED THE LANDING SITE BY\";ABS(D/G5);N$;\".\"\n1085 GOTO 1100\n1090 PRINT\n1095 PRINT \"MISSION ABENDED\"\n1100 PRINT\n1105 PRINT \"DO YOU WANT TO TRY IT AGAIN (YES/NO)?\"\n1110 INPUT Z$\n1115 IF Z$=\"YES\" THEN 20\n1120 IF Z$=\"NO\" THEN 1130\n1125 GOTO 1105\n1130 PRINT\n1135 PRINT \"TOO BAD, THE SPACE PROGRAM HATES TO LOSE EXPERIENCED\"\n1140 PRINT \"ASTRONAUTS.\"\n1145 STOP\n1150 PRINT\n1155 PRINT \"OK, DO YOU WANT THE COMPLETE INSTRUCTIONS OR THE INPUT -\"\n1160 PRINT \"OUTPUT STATEMENTS?\"\n1165 PRINT \"1=COMPLETE INSTRUCTIONS\"\n1170 PRINT \"2=INPUT-OUTPUT STATEMENTS\"\n1175 PRINT \"3=NEITHER\"\n1180 INPUT B1\n1185 Q$=\"NO\"\n1190 IF B1=1 THEN 205\n1195 Q$=\"YES\"\n1200 IF B1=2 THEN 190\n1205 IF B1=3 THEN 190\n1210 GOTO 1165\n1215 END\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/lunar.bas",
    "content": "10 PRINT TAB(33);\"LUNAR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\"\n25 PRINT:PRINT:PRINT\n30 PRINT \"THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR\"\n40 PRINT \"LANDING CAPSULE.\": PRINT: PRINT\n50 PRINT \"THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY\"\n60 PRINT \"XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.\"\n70 PRINT: PRINT \"SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN\"\n80 PRINT \"0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.\"\n90 PRINT \"SET NEW BURN RATE EVERY 10 SECONDS.\": PRINT\n100 PRINT \"CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,000 LBS.\"\n110 PRINT: PRINT: PRINT: PRINT \"GOOD LUCK\"\n120 L=0\n130 PRINT: PRINT \"SEC\",\"MI + FT\",\"MPH\",\"LB FUEL\",\"BURN RATE\":PRINT\n140 A=120:V=1:M=33000:N=16500:G=1E-03:Z=1.8\n150 PRINT L,INT(A);INT(5280*(A-INT(A))),3600*V,M-N,:INPUT K:T=10\n160 IF M-N<1E-03 THEN 240\n170 IF T<1E-03 THEN 150\n180 S=T: IF M>=N+S*K THEN 200\n190 S=(M-N)/K\n200 GOSUB 420: IF I<=0 THEN 340\n210 IF V<=0 THEN 230\n220 IF J<0 THEN 370\n230 GOSUB 330: GOTO 160\n240 PRINT \"FUEL OUT AT\";L;\"SECONDS\":S=(-V+SQR(V*V+2*A*G))/G\n250 V=V+G*S: L=L+S\n260 W=3600*V: PRINT \"ON MOON AT\";L;\"SECONDS - IMPACT VELOCITY\";W;\"MPH\"\n274 IF W<=1.2 THEN PRINT \"PERFECT LANDING!\": GOTO 440\n280 IF W<=10 THEN PRINT \"GOOD LANDING (COULD BE BETTER)\":GOTO 440\n282 IF W>60 THEN 300\n284 PRINT \"CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE\"\n286 PRINT \"PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!\"\n288 GOTO 440\n300 PRINT \"SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!\"\n310 PRINT \"IN FACT, YOU BLASTED A NEW LUNAR CRATER\";W*.227;\"FEET DEEP!\"\n320 GOTO 440\n330 L=L+S: T=T-S: M=M-S*K: A=I: V=J: RETURN\n340 IF S<5E-03 THEN 260\n350 D=V+SQR(V*V+2*A*(G-Z*K/M)):S=2*A/D\n360 GOSUB 420: GOSUB 330: GOTO 340\n370 W=(1-M*G/(Z*K))/2: S=M*V/(Z*K*(W+SQR(W*W+V/Z)))+.05:GOSUB 420\n380 IF I<=0 THEN 340\n390 GOSUB 330: IF J>0 THEN 160\n400 IF V>0 THEN 370\n410 GOTO 160\n420 Q=S*K/M: J=V+G*S+Z*(-Q-Q*Q/2-Q^3/3-Q^4/4-Q^5/5)\n430 I=A-G*S*S/2-V*S+Z*S*(Q/2+Q^2/6+Q^3/12+Q^4/20+Q^5/30):RETURN\n440 PRINT:PRINT:PRINT:PRINT \"TRY AGAIN??\": GOTO 70\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/python/lunar.py",
    "content": "\"\"\"\nLUNAR\n\nLunar landing simulation\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport math\nfrom dataclasses import dataclass\nfrom typing import Any, NamedTuple\n\nPAGE_WIDTH = 64\n\nCOLUMN_WIDTH = 2\nSECONDS_WIDTH = 4\nMPH_WIDTH = 6\nALT_MI_WIDTH = 6\nALT_FT_WIDTH = 4\nMPH_WIDTH = 6\nFUEL_WIDTH = 8\nBURN_WIDTH = 10\n\nSECONDS_LEFT = 0\nSECONDS_RIGHT = SECONDS_LEFT + SECONDS_WIDTH\nALT_LEFT = SECONDS_RIGHT + COLUMN_WIDTH\nALT_MI_RIGHT = ALT_LEFT + ALT_MI_WIDTH\nALT_FT_RIGHT = ALT_MI_RIGHT + COLUMN_WIDTH + ALT_FT_WIDTH\nMPH_LEFT = ALT_FT_RIGHT + COLUMN_WIDTH\nMPH_RIGHT = MPH_LEFT + MPH_WIDTH\nFUEL_LEFT = MPH_RIGHT + COLUMN_WIDTH\nFUEL_RIGHT = FUEL_LEFT + FUEL_WIDTH\nBURN_LEFT = FUEL_RIGHT + COLUMN_WIDTH\nBURN_RIGHT = BURN_LEFT + BURN_WIDTH\n\n\nclass PhysicalState(NamedTuple):\n    velocity: float\n    altitude: float\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n\ndef add_rjust(line: str, s: Any, pos: int) -> str:\n    \"\"\"Add a new field to a line right justified to end at pos\"\"\"\n    s_str = str(s)\n    slen = len(s_str)\n    if len(line) + slen > pos:\n        new_len = pos - slen\n        line = line[:new_len]\n    if len(line) + slen < pos:\n        spaces = \" \" * (pos - slen - len(line))\n        line = line + spaces\n    return line + s_str\n\n\ndef add_ljust(line: str, s: str, pos: int) -> str:\n    \"\"\"Add a new field to a line left justified starting at pos\"\"\"\n    s = s\n    if len(line) > pos:\n        line = line[:pos]\n    if len(line) < pos:\n        spaces = \" \" * (pos - len(line))\n        line = line + spaces\n    return line + s\n\n\ndef print_instructions() -> None:\n    \"\"\"Somebody had a bad experience with Xerox.\"\"\"\n    print(\"THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR\")\n    print(\"LANDING CAPSULE.\\n\\n\")\n    print(\"THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY\")\n    print(\"XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.\\n\")\n\n\ndef print_intro() -> None:\n    print(\"SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN\")\n    print(\"0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.\")\n    print(\"SET NEW BURN RATE EVERY 10 SECONDS.\\n\")\n    print(\"CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,000 LBS.\\n\\n\\n\")\n    print(\"GOOD LUCK\\n\")\n\n\ndef format_line_for_report(\n    t: Any,\n    miles: Any,\n    feet: Any,\n    velocity: Any,\n    fuel: Any,\n    burn_rate: str,\n    is_header: bool,\n) -> str:\n    line = add_rjust(\"\", t, SECONDS_RIGHT)\n    line = add_rjust(line, miles, ALT_MI_RIGHT)\n    line = add_rjust(line, feet, ALT_FT_RIGHT)\n    line = add_rjust(line, velocity, MPH_RIGHT)\n    line = add_rjust(line, fuel, FUEL_RIGHT)\n    if is_header:\n        line = add_rjust(line, burn_rate, BURN_RIGHT)\n    else:\n        line = add_ljust(line, burn_rate, BURN_LEFT)\n    return line\n\n\nclass SimulationClock:\n    def __init__(self, elapsed_time: float, time_until_next_prompt: float) -> None:\n        self.elapsed_time = elapsed_time\n        self.time_until_next_prompt = time_until_next_prompt\n\n    def time_for_prompt(self) -> bool:\n        return self.time_until_next_prompt < 1e-3\n\n    def advance(self, delta_t: float) -> None:\n        self.elapsed_time += delta_t\n        self.time_until_next_prompt -= delta_t\n\n\n@dataclass\nclass Capsule:\n    altitude: float = 120  # in miles above the surface\n    velocity: float = 1  # downward\n    m: float = 33000  # mass_with_fuel\n    n: float = 16500  # mass_without_fuel\n    g: float = 1e-3\n    z: float = 1.8\n    fuel_per_second: float = 0\n\n    def remaining_fuel(self) -> float:\n        return self.m - self.n\n\n    def is_out_of_fuel(self) -> bool:\n        return self.remaining_fuel() < 1e-3\n\n    def update_state(\n        self, sim_clock: SimulationClock, delta_t: float, new_state: PhysicalState\n    ) -> None:\n        sim_clock.advance(delta_t)\n        self.m = self.m - delta_t * self.fuel_per_second\n        self.altitude = new_state.altitude\n        self.velocity = new_state.velocity\n\n    def fuel_time_remaining(self) -> float:\n        # extrapolates out how many seconds we have at the current fuel burn rate\n        assert self.fuel_per_second > 0\n        return self.remaining_fuel() / self.fuel_per_second\n\n    def predict_motion(self, delta_t: float) -> PhysicalState:\n        # Perform an Euler's Method numerical integration of the equations of motion.\n\n        q = delta_t * self.fuel_per_second / self.m\n\n        # new velocity\n        new_velocity = (\n            self.velocity\n            + self.g * delta_t\n            + self.z * (-q - q**2 / 2 - q**3 / 3 - q**4 / 4 - q**5 / 5)\n        )\n\n        # new altitude\n        new_altitude = (\n            self.altitude\n            - self.g * delta_t**2 / 2\n            - self.velocity * delta_t\n            + self.z\n            * delta_t\n            * (q / 2 + q**2 / 6 + q**3 / 12 + q**4 / 20 + q**5 / 30)\n        )\n\n        return PhysicalState(altitude=new_altitude, velocity=new_velocity)\n\n    def make_state_display_string(self, sim_clock: SimulationClock) -> str:\n        seconds = sim_clock.elapsed_time\n        miles = int(self.altitude)\n        feet = int(5280 * (self.altitude - miles))\n        velocity = int(3600 * self.velocity)\n        fuel = int(self.remaining_fuel())\n        burn_rate = \" ? \"\n\n        return format_line_for_report(\n            seconds, miles, feet, velocity, fuel, burn_rate, False\n        )\n\n    def prompt_for_burn(self, sim_clock: SimulationClock) -> None:\n        msg = self.make_state_display_string(sim_clock)\n\n        self.fuel_per_second = float(input(msg))\n        sim_clock.time_until_next_prompt = 10\n\n\ndef show_landing(sim_clock: SimulationClock, capsule: Capsule) -> None:\n    w = 3600 * capsule.velocity\n    print(\n        f\"ON MOON AT {sim_clock.elapsed_time:.2f} SECONDS - IMPACT VELOCITY {w:.2f} MPH\"\n    )\n    if w < 1.2:\n        print(\"PERFECT LANDING!\")\n    elif w < 10:\n        print(\"GOOD LANDING (COULD BE BETTER)\")\n    elif w <= 60:\n        print(\"CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE\")\n        print(\"PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!\")\n    else:\n        print(\"SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!\")\n        print(f\"IN FACT, YOU BLASTED A NEW LUNAR CRATER {w*.227:.2f} FEET DEEP!\")\n    end_sim()\n\n\ndef show_out_of_fuel(sim_clock: SimulationClock, capsule: Capsule) -> None:\n    print(f\"FUEL OUT AT {sim_clock.elapsed_time} SECONDS\")\n    delta_t = (\n        -capsule.velocity\n        + math.sqrt(capsule.velocity**2 + 2 * capsule.altitude * capsule.g)\n    ) / capsule.g\n    capsule.velocity += capsule.g * delta_t\n    sim_clock.advance(delta_t)\n    show_landing(sim_clock, capsule)\n\n\ndef process_final_tick(\n    delta_t: float, sim_clock: SimulationClock, capsule: Capsule\n) -> None:\n    # When we extrapolated our position based on our velocity\n    # and delta_t, we overshot the surface. For better\n    # accuracy, we will back up and do shorter time advances.\n\n    while True:\n        if delta_t < 5e-3:\n            show_landing(sim_clock, capsule)\n            return\n        # line 35\n        average_vel = (\n            capsule.velocity\n            + math.sqrt(\n                capsule.velocity**2\n                + 2\n                * capsule.altitude\n                * (capsule.g - capsule.z * capsule.fuel_per_second / capsule.m)\n            )\n        ) / 2\n        delta_t = capsule.altitude / average_vel\n        new_state = capsule.predict_motion(delta_t)\n        capsule.update_state(sim_clock, delta_t, new_state)\n\n\ndef handle_flyaway(sim_clock: SimulationClock, capsule: Capsule) -> bool:\n    \"\"\"\n    The user has started flying away from the moon. Since this is a\n    lunar LANDING simulation, we wait until the capsule's velocity is\n    positive (downward) before prompting for more input.\n\n    Returns True if landed, False if simulation should continue.\n    \"\"\"\n\n    while True:\n        w = (1 - capsule.m * capsule.g / (capsule.z * capsule.fuel_per_second)) / 2\n        delta_t = (\n            capsule.m\n            * capsule.velocity\n            / (\n                capsule.z\n                * capsule.fuel_per_second\n                * math.sqrt(w**2 + capsule.velocity / capsule.z)\n            )\n        ) + 0.05\n\n        new_state = capsule.predict_motion(delta_t)\n\n        if new_state.altitude <= 0:\n            # have landed\n            return True\n\n        capsule.update_state(sim_clock, delta_t, new_state)\n\n        if (new_state.velocity > 0) or (capsule.velocity <= 0):\n            # return to normal sim\n            return False\n\n\ndef end_sim() -> None:\n    print(\"\\n\\n\\nTRY AGAIN??\\n\\n\\n\")\n\n\ndef run_simulation() -> None:\n    print()\n    print(\n        format_line_for_report(\"SEC\", \"MI\", \"FT\", \"MPH\", \"LB FUEL\", \"BURN RATE\", True)\n    )\n\n    sim_clock = SimulationClock(0, 10)\n    capsule = Capsule()\n\n    capsule.prompt_for_burn(sim_clock)\n\n    while True:\n        if capsule.is_out_of_fuel():\n            show_out_of_fuel(sim_clock, capsule)\n            return\n\n        if sim_clock.time_for_prompt():\n            capsule.prompt_for_burn(sim_clock)\n            continue\n\n        # clock advance is the shorter of the time to the next prompt,\n        # or when we run out of fuel.\n        if capsule.fuel_per_second > 0:\n            delta_t = min(\n                sim_clock.time_until_next_prompt, capsule.fuel_time_remaining()\n            )\n        else:\n            delta_t = sim_clock.time_until_next_prompt\n\n        new_state = capsule.predict_motion(delta_t)\n\n        if new_state.altitude <= 0:\n            process_final_tick(delta_t, sim_clock, capsule)\n            return\n\n        if capsule.velocity > 0 and new_state.velocity < 0:\n            if handle_flyaway(sim_clock, capsule):\n                process_final_tick(delta_t, sim_clock, capsule)\n                return\n\n        else:\n            capsule.update_state(sim_clock, delta_t, new_state)\n\n\ndef main() -> None:\n    print_header(\"LUNAR\")\n    print_instructions()\n    while True:\n        print_intro()\n        run_simulation()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/rocket.bas",
    "content": "10 PRINT TAB(30); \"ROCKET\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n70 PRINT \"LUNAR LANDING SIMULATION\"\n80 PRINT \"----- ------- ----------\": PRINT\n100 INPUT \"DO YOU WANT INSTRUCTIONS (YES OR NO)\";A$\n110 IF A$=\"NO\" THEN 390\n160 PRINT\n200 PRINT\"YOU ARE LANDING ON THE MOON AND AND HAVE TAKEN OVER MANUAL\"\n210 PRINT\"CONTROL 1000 FEET ABOVE A GOOD LANDING SPOT. YOU HAVE A DOWN-\"\n220 PRINT\"WARD VELOCITY OF 50 FEET/SEC. 150 UNITS OF FUEL REMAIN.\"\n225 PRINT\n230 PRINT\"HERE ARE THE RULES THAT GOVERN YOUR APOLLO SPACE-CRAFT:\": PRINT\n240 PRINT\"(1) AFTER EACH SECOND THE HEIGHT, VELOCITY, AND REMAINING FUEL\"\n250 PRINT\"    WILL BE REPORTED VIA DIGBY YOUR ON-BOARD COMPUTER.\"\n260 PRINT\"(2) AFTER THE REPORT A '?' WILL APPEAR. ENTER THE NUMBER\"\n270 PRINT\"    OF UNITS OF FUEL YOU WISH TO BURN DURING THE NEXT\"\n280 PRINT\"    SECOND. EACH UNIT OF FUEL WILL SLOW YOUR DESCENT BY\"\n290 PRINT\"    1 FOOT/SEC.\"\n310 PRINT\"(3) THE MAXIMUM THRUST OF YOUR ENGINE IS 30 FEET/SEC/SEC\"\n320 PRINT\"    OR 30 UNITS OF FUEL PER SECOND.\"\n330 PRINT\"(4) WHEN YOU CONTACT THE LUNAR SURFACE. YOUR DESCENT ENGINE\"\n340 PRINT\"    WILL AUTOMATICALLY SHUT DOWN AND YOU WILL BE GIVEN A\"\n350 PRINT\"    REPORT OF YOUR LANDING SPEED AND REMAINING FUEL.\"\n360 PRINT\"(5) IF YOU RUN OUT OF FUEL THE '?' WILL NO LONGER APPEAR\"\n370 PRINT\"    BUT YOUR SECOND BY SECOND REPORT WILL CONTINUE UNTIL\"\n380 PRINT\"    YOU CONTACT THE LUNAR SURFACE.\":PRINT\n390 PRINT\"BEGINNING LANDING PROCEDURE..........\":PRINT\n400 PRINT\"G O O D  L U C K ! ! !\"\n420 PRINT:PRINT\n430 PRINT\"SEC  FEET      SPEED     FUEL     PLOT OF DISTANCE\"\n450 PRINT\n455 T=0:H=1000:V=50:F=150\n490 PRINT T;TAB(6);H;TAB(16);V;TAB(26);F;TAB(35);\"I\";TAB(H/15);\"*\"\n500 INPUT B\n510 IF B<0 THEN 650\n520 IF B>30 THEN B=30\n530 IF B>F THEN B=F\n540 V1=V-B+5\n560 F=F-B\n570 H=H- .5*(V+V1)\n580 IF H<=0 THEN 670\n590 T=T+1\n600 V=V1\n610 IF F>0 THEN 490\n615 IF B=0 THEN 640\n620 PRINT\"**** OUT OF FUEL ****\"\n640 PRINT T;TAB(4);H;TAB(12);V;TAB(20);F;TAB(29);\"I\";TAB(H/12+29);\"*\"\n650 B=0\n660 GOTO 540\n670 PRINT\"***** CONTACT *****\"\n680 H=H+ .5*(V1+V)\n690 IF B=5 THEN 720\n700 D=(-V+SQR(V*V+H*(10-2*B)))/(5-B)\n710 GOTO 730\n720 D=H/V\n730 V1=V+(5-B)*D\n760 PRINT\"TOUCHDOWN AT\";T+D;\"SECONDS.\"\n770 PRINT\"LANDING VELOCITY=\";V1;\"FEET/SEC.\"\n780 PRINT F;\"UNITS OF FUEL REMAINING.\"\n790 IF V1<>0 THEN 810\n800 PRINT\"CONGRATULATIONS! A PERFECT LANDING!!\"\n805 PRINT\"YOUR LICENSE WILL BE RENEWED.......LATER.\"\n810 IF ABS(V1)<2 THEN 840\n820 PRINT\"***** SORRY, BUT YOU BLEW IT!!!!\"\n830 PRINT\"APPROPRIATE CONDOLENCES WILL BE SENT TO YOUR NEXT OF KIN.\"\n840 PRINT:PRINT:PRINT\n850 INPUT \"ANOTHER MISSION\";A$\n860 IF A$=\"YES\" THEN 390\n870 PRINT: PRINT \"CONTROL OUT.\": PRINT\n999 END\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/rust/README.md",
    "content": "README.md\n\nOriginal source downloaded from Vintage Basic\n\nThis folder for chapter #59 contains three different games.  Three folders here contain the three games:\n\n - Rocket\n - LEM\n - lunar\n\nConversion to [Rust](https://www.rust-lang.org)\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/rust/rocket/Cargo.toml",
    "content": "[package]\nname = \"rocket\"\nversion = \"1.0.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\ntext_io = \"0.1.10\"\nnum-integer = \"0.1\"\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/rust/rocket/src/main.rs",
    "content": "//Goal of this port is to keep Basic lang idioms where possible. Gotta have those single letter capital variables!\nuse num_integer::{sqrt};\nuse std::io::{self, Write};\nuse text_io::{read, try_read};\n#[allow(non_snake_case)]\nfn main() {\n    println!(\"{:>30}\", \"ROCKET\");\n    println!(\"{:>15}\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    println!();println!();println!();\n    println!(\"LUNAR LANDING SIMULATION\");\n    println!(\"----- ------- ----------\");println!();\n    let A= input(\"DO YOU WANT INSTRUCTIONS (YES OR NO) \");\n    if !(A==\"NO\") {\n        println!();\n        println!(\"YOU ARE LANDING ON THE MOON AND AND HAVE TAKEN OVER MANUAL\");\n        println!(\"CONTROL 1000 FEET ABOVE A GOOD LANDING SPOT. YOU HAVE A DOWN-\");\n        println!(\"WARD VELOCITY OF 50 FEET/SEC. 150 UNITS OF FUEL REMAIN.\");\n        println!();\n        println!(\"HERE ARE THE RULES THAT GOVERN YOUR APOLLO SPACE-CRAFT:\"); println!();\n        println!(\"(1) AFTER EACH SECOND THE HEIGHT, VELOCITY, AND REMAINING FUEL\");\n        println!(\"    WILL BE REPORTED VIA DIGBY YOUR ON-BOARD COMPUTER.\");\n        println!(\"(2) AFTER THE REPORT A '?' WILL APPEAR. ENTER THE NUMBER\");\n        println!(\"    OF UNITS OF FUEL YOU WISH TO BURN DURING THE NEXT\");\n        println!(\"    SECOND. EACH UNIT OF FUEL WILL SLOW YOUR DESCENT BY\");\n        println!(\"    1 FOOT/SEC.\");\n        println!(\"(3) THE MAXIMUM THRUST OF YOUR ENGINE IS 30 FEET/SEC/SEC\");\n        println!(\"    OR 30 UNITS OF FUEL PER SECOND.\");\n        println!(\"(4) WHEN YOU CONTACT THE LUNAR SURFACE. YOUR DESCENT ENGINE\");\n        println!(\"    WILL AUTOMATICALLY SHUT DOWN AND YOU WILL BE GIVEN A\");\n        println!(\"    REPORT OF YOUR LANDING SPEED AND REMAINING FUEL.\");\n        println!(\"(5) IF YOU RUN OUT OF FUEL THE '?' WILL NO LONGER APPEAR\");\n        println!(\"    BUT YOUR SECOND BY SECOND REPORT WILL CONTINUE UNTIL\");\n        println!(\"    YOU CONTACT THE LUNAR SURFACE.\");println!();\n    }\n    loop {\n        println!(\"BEGINNING LANDING PROCEDURE..........\");println!();\n        println!(\"G O O D  L U C K ! ! !\");\n        println!();println!();\n        println!(\"SEC  FEET      SPEED     FUEL     PLOT OF DISTANCE\");\n        println!();\n        let mut T=0;let mut H:i32=1000;let mut V=50;let mut F=150;\n        let D:i32; let mut V1:i32; let mut B:i32;\n        'falling: loop {\n            println!(\" {:<4}{:<11}{:<10}{:<8}I{capsule:>high$}\", T,H,V,F,high=(H/15) as usize,capsule=\"*\");\n            B = input_int(\"\");\n            if B<0 { B=0 }\n            else { if B>30 { B=30 } }\n            if B>F { B=F }\n            'nofuel: loop {\n                V1=V-B+5;\n                F=F-B;\n                H=H- (V+V1)/2;\n                if  H<=0 { break 'falling}\n                T=T+1;\n                V=V1;\n                if F>0 { break 'nofuel }\n                if B!=0 {\n                    println!(\"**** OUT OF FUEL ****\");\n                }\n                println!(\" {:<4}{:<11}{:<10}{:<8}I{capsule:>high$}\", T,H,V,F,high=(H/12+29) as usize,capsule=\"*\");\n                B=0;\n            }\n        }\n        H=H+ (V1+V)/2;\n        if B==5 {\n            D=H/V;\n        } else {\n            D=(-V+sqrt(V*V+H*(10-2*B)))/(5-B);\n            V1=V+(5-B)*D;\n        }\n        println!(\"***** CONTACT *****\");\n        println!(\"TOUCHDOWN AT {} SECONDS.\",T+D);\n        println!(\"LANDING VELOCITY={} FEET/SEC.\",V1);\n        println!(\"{} UNITS OF FUEL REMAINING.\", F);\n        if V1==0 {\n            println!(\"CONGRATULATIONS! A PERFECT LANDING!!\");\n            println!(\"YOUR LICENSE WILL BE RENEWED.......LATER.\");\n        }\n        if V1.abs()>=2 {\n            println!(\"***** SORRY, BUT YOU BLEW IT!!!!\");\n            println!(\"APPROPRIATE CONDOLENCES WILL BE SENT TO YOUR NEXT OF KIN.\");\n        }\n        println!();println!();println!();\n        let A = input(\"ANOTHER MISSION\");\n        if !(A==\"YES\") { break };\n    }\n    println!();println!( \"CONTROL OUT.\");println!();\n}\n\n\nfn input(prompt:&str) -> String {\n    loop {\n        print!(\"{} ? \",prompt);io::stdout().flush().unwrap();\n        let innn:String=read!(\"{}\\n\");\n        let out:String = innn.trim().to_string();\n        if out!=\"\" {return out}\n    }\n}\nfn input_int(prompt:&str) -> i32 {\n    loop {\n        print!(\"{} ? \",prompt);io::stdout().flush().unwrap();\n        match try_read!() {\n            Ok(n) => return n,\n            Err(_) => println!(\"Enter a number 0-30\"),\n        }\n    }\n}\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"LunarLEMRocket\", \"LunarLEMRocket.vbproj\", \"{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>LunarLEMRocket</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "59_Lunar_LEM_Rocket/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "60_Mastermind/README.md",
    "content": "### MasterMind\n\nIn that Match-April 1976 issue of _Creative_ we published a computerized version of Master Mind, a logic game. Master Mind is played by two people—one is called the code-maker; the other, the code-breaker. At the beginning of the game the code-maker forms a code, or combination of colored pegs. He hides these from the code-breaker. The code-breaker then attempts to deduce the code, by placing his own guesses, one at a time, on the board. After he makes a guess (by placing a combination of colored pegs on the board) the code-maker then gives the code-breaker clues to indicate how close the guess was to the code. For every peg in the guess that’s the right color but not in the right position, the code-breaker gets a white peg. Note that these black and white pegs do not indicate _which_ pegs in the guess are correct, but merely that they exist. For example, if the code was:\n```\nYellow Red Red Green\n```\n\nand my guess was\n```\nRed Red Yellow Black\n```\nI would receive two white pegs and one black peg for the guess. I wouldn’t know (except by comparing previous guesses) which one of the pegs in my guess was the right color in the right position.\n\nMany people have written computer programs to play Master Mind in the passive role, i.e., the computer is the code maker and the human is the code-breaker. This is relatively trivial; the challenge is writing a program that can also play actively as a code-breaker.\n\nActually, the task of getting the computer to deduce the correct combination is not at all difficult. Imagine, for instance, that you made a list of all possible codes. To begin, you select a guess from your list at random. Then, as you receive clues, you cross off from the list those combinations which you know are impossible. For example if your guess is Red Red Green Green and you receive no pegs, then you know that any combination containing either a red or a green peg is impossible and may be crossed of the list. The process is continued until the correct solution is reached or there are no more combinations left on the list (in which case you know that the code-maker made a mistake in giving you the clues somewhere).\n\nNote that in this particular implementation, we never actually create a list of the combinations, but merely keep track of which ones (in sequential order) may be correct. Using this system, we can easily say that the 523rd combination may be correct, but to actually produce the 523rd combination we have to count all the way from the first combination (or the previous one, if it was lower than 523). Actually, this problem could be simplified to a conversion from base 10 to base (number of colors) and then adjusting the values used in the MID$ function so as not to take a zeroth character from a string if you want to experiment. We did try a version that kept an actual list of all possible combinations (as a string array), which was significantly faster than this version, but which ate tremendous amounts of memory.\n\nAt the beginning of this game, you input the number of colors and number of positions you wish to use (which will directly affect the number of combinations) and the number of rounds you wish to play. While you are playing as the code-breaker, you may type BOARD at any time to get a list of your previous guesses and clues, and QUIT to end the game. Note that this version uses string arrays, but this is merely for convenience and can easily be converted for a BASIC that has no string arrays as long as it has a MID$ function. This is because the string arrays are one-dimensional, never exceed a length greater than the number of positions and the elements never contain more than one character.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=110)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=125)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n### How the computer deduces your guess.\n\nThe computer takes the number of black pegs and white pegs that the user reports\nand uses that information as a target. It then assumes its guess is the answer\nand proceeds to compare the black and white pegs against all remaining possible\nanswers. For each set of black and white pegs it gets in these comparisons, if \nthey don't match what the user reported, then they can not be part of the solution.\nThis can be a non-intuitive assumption, so we'll walk through it with a three color,\nthree position example (27 possible solutions.)\n\nLet's just suppose our secret code we're hiding from the computer is `BWB`\n\nFirst let's point out the commutative property of comparing two codes for their\nblack and white pegs. A black peg meaning correct color and correct position, and\na white peg meaning correct color and wrong position.  If the computer guesses\n`RBW` then the black/white peg report is 0 black, 2 white.  But if `RBW` is the \nsecret code and the computer guesses `BWB` the reporting for `BWB` is going to be\nthe same, 0 black, 2 white. \n\nNow lets look at a table with the reporting for every possible guess the computer \ncan make while our secret code is `BWB`.\n                                                         \n| Guess | Black | White |     | Guess | Black | White |     | Guess | Black | White |\n|-------|-------|-------|-----|-------|-------|-------|-----|-------|-------|-------|\n| BBB   | 2     | 0     |     | WBB   | 1     | 2     |     | RBB   | 1     | 1     |   \n| BBW   | 1     | 2     |     | WBW   | 0     | 2     |     | RBW   | 0     | 2     |   \n| BBR   | 1     | 1     |     | WBR   | 0     | 2     |     | RBR   | 0     | 1     |    \n| BWB   | 3     | 0     |     | WWB   | 2     | 0     |     | RWB   | 2     | 0     |    \n| BWW   | 2     | 0     |     | WWW   | 1     | 0     |     | RWW   | 1     | 0     |    \n| BWR   | 2     | 0     |     | WWR   | 1     | 0     |     | RWR   | 1     | 0     |    \n| BRB   | 2     | 0     |     | WRB   | 1     | 1     |     | RRB   | 1     | 0     |    \n| BRW   | 1     | 1     |     | WRW   | 0     | 1     |     | RRW   | 0     | 1     |    \n| BRR   | 1     | 0     |     | WRR   | 0     | 1     |     | RRR   | 0     | 0     | \n\nThe computer has guessed `RBW` and the report on it is 0 black, 2 white. The code\nused to eliminate other solutions looks like this:\n\n`1060 IF B1<>B OR W1<>W THEN I(X)=0`\n\nwhich says set `RBW` as the secret and compare it to all remaining solutions and \nget rid of any that don't match the same black and white report, 0 black and 2 white. \nSo let's do that.\n\nRemember, `RBW` is pretending to be the secret code here. These are the remaining\nsolutions reporting their black and white pegs against `RBW`.\n\n| Guess | Black | White |     | Guess | Black | White |     | Guess | Black | White |\n|-------|-------|-------|-----|-------|-------|-------|-----|-------|-------|-------|\n| BBB   | 1     | 0     |     | WBB   | 1     | 1     |     | RBB   | 2     | 0     |   \n| BBW   | 2     | 0     |     | WBW   | 2     | 0     |     | RBW   | 3     | 0     |   \n| BBR   | 1     | 1     |     | WBR   | 1     | 2     |     | RBR   | 2     | 0     |    \n| BWB   | 0     | 2     |     | WWB   | 0     | 2     |     | RWB   | 1     | 2     |    \n| BWW   | 1     | 1     |     | WWW   | 1     | 0     |     | RWW   | 2     | 0     |    \n| BWR   | 0     | 3     |     | WWR   | 1     | 1     |     | RWR   | 1     | 1     |    \n| BRB   | 0     | 2     |     | WRB   | 0     | 3     |     | RRB   | 1     | 1     |    \n| BRW   | 1     | 2     |     | WRW   | 1     | 1     |     | RRW   | 2     | 0     |    \n| BRR   | 0     | 2     |     | WRR   | 0     | 2     |     | RRR   | 1     | 0     | \n\nNow we are going to eliminate every solution that **DOESN'T** match 0 black and 2 white.\n\n| Guess    | Black | White |     | Guess    | Black | White |     | Guess    | Black | White |\n|----------|-------|-------|-----|----------|-------|-------|-----|----------|-------|-------|\n| ~~~BBB~~ | 1     | 0     |     | ~~~WBB~~ | 1     | 1     |     | ~~~RBB~~ | 2     | 0     |   \n| ~~~BBW~~ | 2     | 0     |     | ~~~WBW~~ | 2     | 0     |     | ~~~RBW~~ | 3     | 0     |   \n| ~~~BBR~~ | 1     | 1     |     | ~~~WBR~~ | 1     | 2     |     | ~~~RBR~~ | 2     | 0     |    \n| BWB      | 0     | 2     |     | WWB      | 0     | 2     |     | ~~~RWB~~ | 1     | 2     |    \n| ~~~BWW~~ | 1     | 1     |     | ~~~WWW~~ | 1     | 0     |     | ~~~RWW~~ | 2     | 0     |    \n| ~~~BWR~~ | 0     | 3     |     | ~~~WWR~~ | 1     | 1     |     | ~~~RWR~~ | 1     | 1     |    \n| BRB      | 0     | 2     |     | ~~~WRB~~ | 0     | 3     |     | ~~~RRB~~ | 1     | 1     |    \n| ~~~BRW~~ | 1     | 2     |     | ~~~WRW~~ | 1     | 1     |     | ~~~RRW~~ | 2     | 0     |    \n| BRR      | 0     | 2     |     | WRR      | 0     | 2     |     | ~~~RRR~~ | 1     | 0     |          \n                                   \n That wipes out all but five solutions. Notice how the entire right column of solutions \n is eliminated, including our original guess of `RBW`, therefore eliminating any \n special case to specifically eliminate this guess from the solution set when we first find out\n its not the answer.\n \n Continuing on, we have the following solutions left of which our secret code, `BWB` \n is one of them. Remember our commutative property explained previously. \n\n| Guess | Black | White |\n|-------|-------|-------|\n| BWB   | 0     | 2     |\n| BRB   | 0     | 2     |\n| BRR   | 0     | 2     |\n| WWB   | 0     | 2     |\n| WRR   | 0     | 2     |\n\nSo for its second pick, the computer will randomly pick one of these remaining solutions. Let's pick\nthe middle one, `BRR`, and perform the same ritual. Our user reports to the computer \nthat it now has 1 black, 0 whites when comparing to our secret code `BWB`. Let's \nnow compare `BRR` to the remaining five solutions and eliminate any that **DON'T**\nreport 1 black and 0 whites.\n\n| Guess    | Black | White |\n|----------|-------|-------|\n| BWB      | 1     | 0     |\n| ~~~BRB~~ | 2     | 0     |\n| ~~~BRR~~ | 3     | 0     |\n| ~~~WWB~~ | 0     | 1     |\n| ~~~WRR~~ | 2     | 0     | \n\nOnly one solution matches and it's our secret code! The computer will guess this\none next as it's the only choice left, for a total of three moves. \nCoincidentally, I believe the expected maximum number of moves the computer will \nmake is the number of positions plus one for the initial guess with no information.\nThis is because it is winnowing down the solutions \nlogarithmically on average. You noticed on the first pass, it wiped out 22 \nsolutions. If it was doing this logarithmically the worst case guess would \nstill eliminate 18 of the solutions leaving 9 (3<sup>2</sup>).  So we have as\na guideline:\n\n Log<sub>(# of Colors)</sub>TotalPossibilities\n \nbut TotalPossibilities = (# of Colors)<sup># of Positions</sup>\n\nso you end up with the number of positions as a guess limit. If you consider the\nsimplest non-trivial puzzle, two colors with two positions, and you guess BW or \nWB first, the most you can logically deduce if you get 1 black and 1 white is \nthat it is either WW, or BB which could bring your total guesses up to three \nwhich is the number of positions plus one.  So if your computer's turn is taking\nlonger than the number of positions plus one to find the answer then something \nis wrong with your code. \n\n#### Known Bugs\n\n- Line 622 is unreachable, as the previous line ends in a GOTO and that line number is not referenced anywhere.  It appears that the intent was to tell the user the correct combination after they fail to guess it in 10 tries, which would be a very nice feature, but does not actually work.  (In the MiniScript port, I have made this feature work.)\n"
  },
  {
    "path": "60_Mastermind/csharp/Code.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Represents a secret code in the game.\n    /// </summary>\n    public class Code\n    {\n        private readonly int[] m_colors;\n\n        /// <summary>\n        /// Initializes a new instance of the Code class from the given set\n        /// of positions.\n        /// </summary>\n        /// <param name=\"colors\">\n        /// Contains the color for each position.\n        /// </param>\n        public Code(IEnumerable<int> colors)\n        {\n            m_colors = colors.ToArray();\n            if (m_colors.Length == 0)\n                throw new ArgumentException(\"A code must contain at least one position\");\n        }\n\n        /// <summary>\n        /// Compares this code with the given code.\n        /// </summary>\n        /// <param name=\"other\">\n        /// The code to compare.\n        /// </param>\n        /// <returns>\n        /// A number of black pegs and a number of white pegs.  The number\n        /// of black pegs is the number of positions that contain the same\n        /// color in both codes.  The number of white pegs is the number of\n        /// colors that appear in both codes, but in the wrong positions.\n        /// </returns>\n        public (int blacks, int whites) Compare(Code other)\n        {\n            // What follows is the O(N^2) from the original BASIC program\n            // (where N is the number of positions in the code).  Note that\n            // there is an O(N) algorithm.  (Finding it is left as an\n            // exercise for the reader.)\n            if (other.m_colors.Length != m_colors.Length)\n                throw new ArgumentException(\"Only codes of the same length can be compared\");\n\n            // Keeps track of which positions in the other code have already\n            // been marked as exact or close matches.\n            var consumed = new bool[m_colors.Length];\n\n            var blacks = 0;\n            var whites = 0;\n\n            for (var i = 0; i < m_colors.Length; ++i)\n            {\n                if (m_colors[i] == other.m_colors[i])\n                {\n                    ++blacks;\n                    consumed[i] = true;\n                }\n                else\n                {\n                    // Check if the current color appears elsewhere in the\n                    // other code.  We must be careful not to consider\n                    // positions that are also exact matches.\n                    for (var j = 0; j < m_colors.Length; ++j)\n                    {\n                        if (!consumed[j] &&\n                            m_colors[i] == other.m_colors[j] &&\n                            m_colors[j] != other.m_colors[j])\n                        {\n                            ++whites;\n                            consumed[j] = true;\n                            break;\n                        }\n                    }\n                }\n            }\n\n            return (blacks, whites);\n        }\n\n        /// <summary>\n        /// Gets a string representation of the code.\n        /// </summary>\n        public override string ToString() =>\n            new (m_colors.Select(index => Colors.List[index].ShortName).ToArray());\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/CodeFactory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Provides methods for generating codes with a given number of positions\n    /// and colors.\n    /// </summary>\n    public class CodeFactory\n    {\n        /// <summary>\n        /// Gets the number of colors in codes generated by this factory.\n        /// </summary>\n        public int Colors { get; }\n\n        /// <summary>\n        /// Gets the number of positions in codes generated by this factory.\n        /// </summary>\n        public int Positions { get; }\n\n        /// <summary>\n        /// Gets the number of distinct codes that this factory can\n        /// generate.\n        /// </summary>\n        public int Possibilities { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the CodeFactory class.\n        /// </summary>\n        /// <param name=\"positions\">\n        /// The number of positions.\n        /// </param>\n        /// <param name=\"colors\">\n        /// The number of colors.\n        /// </param>\n        public CodeFactory(int positions, int colors)\n        {\n            if (positions < 1)\n                throw new ArgumentException(\"A code must contain at least one position\");\n\n            if (colors < 1)\n                throw new ArgumentException(\"A code must contain at least one color\");\n\n            if (colors > Game.Colors.List.Length)\n                throw new ArgumentException($\"A code can contain no more than {Game.Colors.List.Length} colors\");\n\n            Positions     = positions;\n            Colors        = colors;\n            Possibilities = (int)Math.Pow(colors, positions);\n        }\n\n        /// <summary>\n        /// Creates a specified code.\n        /// </summary>\n        /// <param name=\"number\">\n        /// The number of the code to create from 0 to Possibilities - 1.\n        /// </param>\n        public Code Create(int number) =>\n            EnumerateCodes().Skip(number).First();\n\n        /// <summary>\n        /// Creates a random code using the provided random number generator.\n        /// </summary>\n        /// <param name=\"random\">\n        /// The random number generator.\n        /// </param>\n        public Code Create(Random random) =>\n            Create(random.Next(Possibilities));\n\n        /// <summary>\n        /// Generates a collection of codes containing every code that this\n        /// factory can create exactly once.\n        /// </summary>\n        public IEnumerable<Code> EnumerateCodes()\n        {\n            var current = new int[Positions];\n            var position = default(int);\n\n            do\n            {\n                yield return new Code(current);\n\n                position = 0;\n                while (position < Positions && ++current[position] == Colors)\n                    current[position++] = 0;\n            }\n            while (position < Positions);\n        }\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/ColorInfo.cs",
    "content": "﻿using System;\n\nnamespace Game\n{\n    /// <summary>\n    /// Stores information about a color.\n    /// </summary>\n    public record ColorInfo\n    {\n        /// <summary>\n        /// Gets a single character that represents the color.\n        /// </summary>\n        public char ShortName { get; init; }\n\n        /// <summary>\n        /// Gets the color's full name.\n        /// </summary>\n        public string LongName { get; init; } = String.Empty;\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/Colors.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Provides information about the colors that can be used in codes.\n    /// </summary>\n    public static class Colors\n    {\n        public static readonly ColorInfo[] List = new[]\n        {\n            new ColorInfo { ShortName = 'B', LongName = \"BLACK\"  },\n            new ColorInfo { ShortName = 'W', LongName = \"WHITE\"  },\n            new ColorInfo { ShortName = 'R', LongName = \"RED\"    },\n            new ColorInfo { ShortName = 'G', LongName = \"GREEN\"  },\n            new ColorInfo { ShortName = 'O', LongName = \"ORANGE\" },\n            new ColorInfo { ShortName = 'Y', LongName = \"YELLOW\" },\n            new ColorInfo { ShortName = 'P', LongName = \"PURPLE\" },\n            new ColorInfo { ShortName = 'T', LongName = \"TAN\"    }\n        };\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/Command.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different commands that the user can issue during\n    /// the game.\n    /// </summary>\n    public enum Command\n    {\n        MakeGuess,\n        ShowBoard,\n        Quit\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/Controller.cs",
    "content": "﻿using System;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for getting input from the end user.\n    /// </summary>\n    public static class Controller\n    {\n        /// <summary>\n        /// Maps the letters for each color to the integer value representing\n        /// that color.\n        /// </summary>\n        /// <remarks>\n        /// We derive this map from the Colors list rather than defining the\n        /// entries directly in order to keep all color related information\n        /// in one place.  (This makes it easier to change the color options\n        /// later.)\n        /// </remarks>\n        private static ImmutableDictionary<char, int> ColorsByKey = Colors.List\n            .Select((info, index) => (key: info.ShortName, index))\n            .ToImmutableDictionary(entry => entry.key, entry => entry.index);\n\n        /// <summary>\n        /// Gets the number of colors to use in the secret code.\n        /// </summary>\n        public static int GetNumberOfColors()\n        {\n            var maximumColors = Colors.List.Length;\n            var colors = 0;\n\n            while (colors < 1 || colors > maximumColors)\n            {\n                colors = GetInteger(View.PromptNumberOfColors);\n                if (colors > maximumColors)\n                    View.NotifyTooManyColors(maximumColors);\n            }\n\n            return colors;\n        }\n\n        /// <summary>\n        /// Gets the number of positions in the secret code.\n        /// </summary>\n        /// <returns></returns>\n        public static int GetNumberOfPositions()\n        {\n            // Note: We should probably ensure that the user enters a sane\n            //  number of positions here.  (Things go south pretty quickly\n            //  with a large number of positions.)  But since the original\n            //  program did not, neither will we.\n            return GetInteger(View.PromptNumberOfPositions);\n        }\n\n        /// <summary>\n        /// Gets the number of rounds to play.\n        /// </summary>\n        public static int GetNumberOfRounds()\n        {\n            // Note: Silly numbers of rounds (like 0, or a negative number)\n            //  are harmless, but it would still make sense to validate.\n            return GetInteger(View.PromptNumberOfRounds);\n        }\n\n        /// <summary>\n        /// Gets a command from the user.\n        /// </summary>\n        /// <param name=\"moveNumber\">\n        /// The current move number.\n        /// </param>\n        /// <param name=\"positions\">\n        /// The number of code positions.\n        /// </param>\n        /// <param name=\"colors\">\n        /// The maximum number of code colors.\n        /// </param>\n        /// <returns>\n        /// The entered command and guess (if applicable).\n        /// </returns>\n        public static (Command command, Code? guess) GetCommand(int moveNumber, int positions, int colors)\n        {\n            while (true)\n            {\n                View.PromptGuess (moveNumber);\n\n                var input = Console.ReadLine();\n                if (input is null)\n                    Environment.Exit(0);\n\n                switch (input.ToUpperInvariant())\n                {\n                    case \"BOARD\":\n                        return (Command.ShowBoard, null);\n                    case \"QUIT\":\n                        return (Command.Quit, null);\n                    default:\n                        if (input.Length != positions)\n                            View.NotifyBadNumberOfPositions();\n                        else\n                        if (input.FindFirstIndex(c => !TranslateColor(c).HasValue) is int invalidPosition)\n                            View.NotifyInvalidColor(input[invalidPosition]);\n                        else\n                            return (Command.MakeGuess, new Code(input.Select(c => TranslateColor(c)!.Value)));\n\n                        break;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Waits until the user indicates that he or she is ready to continue.\n        /// </summary>\n        public static void WaitUntilReady()\n        {\n            View.PromptReady();\n            var input = Console.ReadLine();\n            if (input is null)\n                Environment.Exit(0);\n        }\n\n        /// <summary>\n        /// Gets the number of blacks and whites for the given code from the\n        /// user.\n        /// </summary>\n        public static (int blacks, int whites) GetBlacksWhites(Code code)\n        {\n            while (true)\n            {\n                View.PromptBlacksWhites(code);\n\n                var input = Console.ReadLine();\n                if (input is null)\n                    Environment.Exit(0);\n\n                var parts = input.Split(',');\n\n                if (parts.Length != 2)\n                    View.PromptTwoValues();\n                else\n                if (!Int32.TryParse(parts[0], out var blacks) || !Int32.TryParse(parts[1], out var whites))\n                    View.PromptValidInteger();\n                else\n                    return (blacks, whites);\n            }\n        }\n\n        /// <summary>\n        /// Gets an integer value from the user.\n        /// </summary>\n        private static int GetInteger(Action prompt)\n        {\n            while (true)\n            {\n                prompt();\n\n                var input = Console.ReadLine();\n                if (input is null)\n                    Environment.Exit(0);\n\n                if (Int32.TryParse(input, out var result))\n                    return result;\n                else\n                    View.PromptValidInteger();\n            }\n        }\n\n        /// <summary>\n        /// Translates the given character into the corresponding color.\n        /// </summary>\n        private static int? TranslateColor(char c) =>\n            ColorsByKey.TryGetValue(c, out var index) ? index : null;\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/EnumerableExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Provides additional methods for the <see cref=\"IEnumerable{T}\"/>\n    /// interface.\n    /// </summary>\n    public static class EnumerableExtensions\n    {\n        /// <summary>\n        /// Cycles through the integer values in the range [0, count).\n        /// </summary>\n        /// <param name=\"start\">\n        /// The first value to return.\n        /// </param>\n        /// <param name=\"count\">\n        /// The number of values to return.\n        /// </param>\n        public static IEnumerable<int> Cycle(int start, int count)\n        {\n            if (count < 1)\n                throw new ArgumentException(\"count must be at least 1\");\n\n            if (start < 0 || start >= count)\n                throw new ArgumentException(\"start must be in the range [0, count)\");\n\n            for (var i = start; i < count; ++i)\n                yield return i;\n\n            for (var i = 0; i < start; ++i)\n                yield return i;\n        }\n\n        /// <summary>\n        /// Finds the index of the first item in the given sequence that\n        /// satisfies the given predicate.\n        /// </summary>\n        /// <typeparam name=\"T\">\n        /// The type of elements in the sequence.\n        /// </typeparam>\n        /// <param name=\"source\">\n        /// The source sequence.\n        /// </param>\n        /// <param name=\"predicate\">\n        /// The predicate function.\n        /// </param>\n        /// <returns>\n        /// The index of the first element in the source sequence for which\n        /// predicate(element) is true.  If there is no such element, return\n        /// is null.\n        /// </returns>\n        public static int? FindFirstIndex<T>(this IEnumerable<T> source, Func<T, bool> predicate) =>\n            source.Select((element, index) => predicate(element) ? index : default(int?))\n                .FirstOrDefault(index => index.HasValue);\n\n        /// <summary>\n        /// Returns the first item in the given sequence that matches the\n        /// given predicate.\n        /// </summary>\n        /// <typeparam name=\"T\">\n        /// The type of elements in the sequence.\n        /// </typeparam>\n        /// <param name=\"source\">\n        /// The source sequence.\n        /// </param>\n        /// <param name=\"predicate\">\n        /// The predicate to check against each element.\n        /// </param>\n        /// <param name=\"defaultValue\">\n        /// The value to return if no elements match the predicate.\n        /// </param>\n        /// <returns>\n        /// The first item in the source sequence that matches the given\n        /// predicate, or the provided default value if none do.\n        /// </returns>\n        public static T FirstOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate, T defaultValue)\n        {\n            foreach (var element in source)\n                if (predicate(element))\n                    return element;\n\n            return defaultValue;\n        }\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/Mastermind.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "60_Mastermind/csharp/Mastermind.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Mastermind\", \"Mastermind.csproj\", \"{AEC839CD-C6D3-4476-AA85-79B160AF78BE}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1BDFBEE6-8345-438C-8FCE-B2C9394CC080}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "60_Mastermind/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game\n{\n    // MASTERMIND II\n    // STEVE NORTH\n    // CREATIVE COMPUTING\n    // PO BOX 789-M MORRISTOWN NEW JERSEY 07960\n    class Program\n    {\n        public const int MaximumGuesses = 10;\n\n        static void Main()\n        {\n            var (codeFactory, rounds) = StartGame();\n\n            var random        = new Random();\n            var humanScore    = 0;\n            var computerScore = 0;\n\n            for (var round = 1; round <= rounds; ++round)\n            {\n                View.ShowStartOfRound(round);\n\n                if (!HumanTakesTurn())\n                    return;\n\n                while (!ComputerTakesTurn())\n                    View.ShowInconsistentInformation();\n            }\n\n            View.ShowScores(humanScore, computerScore, isFinal: true);\n\n            /// <summary>\n            /// Gets the game start parameters from the user.\n            /// </summary>\n            (CodeFactory codeFactory, int rounds) StartGame()\n            {\n                View.ShowBanner();\n\n                var colors    = Controller.GetNumberOfColors();\n                var positions = Controller.GetNumberOfPositions();\n                var rounds    = Controller.GetNumberOfRounds();\n\n                var codeFactory = new CodeFactory(positions, colors);\n\n                View.ShowTotalPossibilities(codeFactory.Possibilities);\n                View.ShowColorTable(codeFactory.Colors);\n\n                return (codeFactory, rounds);\n            }\n\n            /// <summary>\n            /// Executes the human's turn.\n            /// </summary>\n            /// <returns>\n            /// True if thue human completed his or her turn and false if\n            /// he or she quit the game.\n            /// </returns>\n            bool HumanTakesTurn()\n            {\n                // Store a history of the human's guesses (used for the show\n                // board command below).\n                var history     = new List<TurnResult>();\n                var code        = codeFactory.Create(random);\n                var guessNumber = default(int);\n\n                for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)\n                {\n                    var guess = default(Code);\n\n                    while (guess is null)\n                    {\n                        switch (Controller.GetCommand(guessNumber, codeFactory.Positions, codeFactory.Colors))\n                        {\n                            case (Command.MakeGuess, Code input):\n                                guess = input;\n                                break;\n                            case (Command.ShowBoard, _):\n                                View.ShowBoard(history);\n                                break;\n                            case (Command.Quit, _):\n                                View.ShowQuitGame(code);\n                                return false;\n                        }\n                    }\n\n                    var (blacks, whites) = code.Compare(guess);\n                    if (blacks == codeFactory.Positions)\n                        break;\n\n                    View.ShowResults(blacks, whites);\n\n                    history.Add(new TurnResult(guess, blacks, whites));\n                }\n\n                if (guessNumber <= MaximumGuesses)\n                    View.ShowHumanGuessedCode(guessNumber);\n                else\n                    View.ShowHumanFailedToGuessCode(code);\n\n                humanScore += guessNumber;\n\n                View.ShowScores(humanScore, computerScore, isFinal: false);\n                return true;\n            }\n\n            /// <summary>\n            /// Executes the computers turn.\n            /// </summary>\n            /// <returns>\n            /// True if the computer completes its turn successfully and false\n            /// if it does not (due to human error).\n            /// </returns>\n            bool ComputerTakesTurn()\n            {\n                var isCandidate = new bool[codeFactory.Possibilities];\n                var guessNumber = default(int);\n\n                Array.Fill(isCandidate, true);\n\n                View.ShowComputerStartTurn();\n                Controller.WaitUntilReady();\n\n                for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)\n                {\n                    // Starting with a random code, cycle through codes until\n                    // we find one that is still a candidate solution.  If\n                    // there are no remaining candidates, then it implies that\n                    // the user made an error in one or more responses.\n                    var codeNumber = EnumerableExtensions.Cycle(random.Next(codeFactory.Possibilities), codeFactory.Possibilities)\n                        .FirstOrDefault(i => isCandidate[i], -1);\n\n                    if (codeNumber < 0)\n                        return false;\n\n                    var guess = codeFactory.Create(codeNumber);\n\n                    var (blacks, whites) = Controller.GetBlacksWhites(guess);\n                    if (blacks == codeFactory.Positions)\n                        break;\n\n                    // Mark codes which are no longer potential solutions.  We\n                    // know that the current guess yields the above number of\n                    // blacks and whites when compared to the solution, so any\n                    // code that yields a different number of blacks or whites\n                    // can't be the answer.\n                    foreach (var (candidate, index) in codeFactory.EnumerateCodes().Select((candidate, index) => (candidate, index)))\n                    {\n                        if (isCandidate[index])\n                        {\n                            var (candidateBlacks, candidateWhites) = guess.Compare(candidate);\n                            if (blacks != candidateBlacks || whites != candidateWhites)\n                                isCandidate[index] = false;\n                        }\n                    }\n                }\n\n                if (guessNumber <= MaximumGuesses)\n                    View.ShowComputerGuessedCode(guessNumber);\n                else\n                    View.ShowComputerFailedToGuessCode();\n\n                computerScore += guessNumber;\n                View.ShowScores(humanScore, computerScore, isFinal: false);\n\n                return true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "60_Mastermind/csharp/TurnResult.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Stores the result of a player's turn.\n    /// </summary>\n    public record TurnResult\n    {\n        /// <summary>\n        /// Gets the code guessed by the player.\n        /// </summary>\n        public Code Guess { get; }\n\n        /// <summary>\n        /// Gets the number of black pegs resulting from the guess.\n        /// </summary>\n        public int Blacks { get; }\n\n        /// <summary>\n        /// Gets the number of white pegs resulting from the guess.\n        /// </summary>\n        public int Whites { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the TurnResult record.\n        /// </summary>\n        /// <param name=\"guess\">\n        /// The player's guess.\n        /// </param>\n        /// <param name=\"blacks\">\n        /// The number of black pegs.\n        /// </param>\n        /// <param name=\"whites\">\n        /// The number of white pegs.\n        /// </param>\n        public TurnResult(Code guess, int blacks, int whites) =>\n            (Guess, Blacks, Whites) = (guess, blacks, whites);\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/csharp/View.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for displaying information to the end user.\n    /// </summary>\n    public static class View\n    {\n        public static void ShowBanner()\n        {\n            Console.WriteLine(\"                              MASTERMIND\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void ShowTotalPossibilities(int possibilities)\n        {\n            Console.WriteLine($\"TOTAL POSSIBILITIES = {possibilities}\");\n            Console.WriteLine();\n        }\n\n        public static void ShowColorTable(int numberOfColors)\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"COLOR     LETTER\");\n            Console.WriteLine(\"=====     ======\");\n\n            foreach (var color in Colors.List.Take(numberOfColors))\n                Console.WriteLine($\"{color.LongName,-13}{color.ShortName}\");\n\n            Console.WriteLine();\n        }\n\n        public static void ShowStartOfRound(int roundNumber)\n        {\n            Console.WriteLine();\n            Console.WriteLine($\"ROUND NUMBER {roundNumber} ----\");\n            Console.WriteLine();\n            Console.WriteLine(\"GUESS MY COMBINATION.\");\n            Console.WriteLine();\n        }\n\n        public static void ShowBoard(IEnumerable<TurnResult> history)\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"BOARD\");\n            Console.WriteLine(\"MOVE     GUESS          BLACK     WHITE\");\n\n            var moveNumber = 0;\n            foreach (var result in history)\n                Console.WriteLine($\"{++moveNumber,-9}{result.Guess,-16}{result.Blacks,-10}{result.Whites}\");\n\n            Console.WriteLine();\n        }\n\n        public static void ShowQuitGame(Code code)\n        {\n            Console.WriteLine($\"QUITTER!  MY COMBINATION WAS: {code}\");\n            Console.WriteLine(\"GOOD BYE\");\n        }\n\n        public static void ShowResults(int blacks, int whites)\n        {\n            Console.WriteLine($\"YOU HAVE  {blacks}  BLACKS AND  {whites}  WHITES.\");\n        }\n\n        public static void ShowHumanGuessedCode(int guessNumber)\n        {\n            Console.WriteLine($\"YOU GUESSED IT IN  {guessNumber}  MOVES!\");\n        }\n\n        public static void ShowHumanFailedToGuessCode(Code code)\n        {\n            // Note: The original code did not print out the combination, but\n            // this appears to be a bug.\n            Console.WriteLine(\"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\");\n            Console.WriteLine($\"THE ACTUAL COMBINATION WAS: {code}\");\n        }\n\n        public static void ShowScores(int humanScore, int computerScore, bool isFinal)\n        {\n            if (isFinal)\n            {\n                Console.WriteLine(\"GAME OVER\");\n                Console.WriteLine(\"FINAL SCORE:\");\n            }\n            else\n                Console.WriteLine(\"SCORE:\");\n\n            Console.WriteLine($\"     COMPUTER  {computerScore}\");\n            Console.WriteLine($\"     HUMAN     {humanScore}\");\n            Console.WriteLine();\n        }\n\n        public static void ShowComputerStartTurn()\n        {\n            Console.WriteLine(\"NOW I GUESS.  THINK OF A COMBINATION.\");\n        }\n\n        public static void ShowInconsistentInformation()\n        {\n            Console.WriteLine(\"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\");\n            Console.WriteLine(\"TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\");\n        }\n\n        public static void ShowComputerGuessedCode(int guessNumber)\n        {\n            Console.WriteLine($\"I GOT IT IN  {guessNumber}  MOVES!\");\n        }\n\n        public static void ShowComputerFailedToGuessCode()\n        {\n            Console.WriteLine(\"I USED UP ALL MY MOVES!\");\n            Console.WriteLine(\"I GUESS MY CPU IS JUST HAVING AN OFF DAY.\");\n        }\n\n        public static void PromptNumberOfColors()\n        {\n            Console.Write(\"NUMBER OF COLORS? \");\n        }\n\n        public static void PromptNumberOfPositions()\n        {\n            Console.Write(\"NUMBER OF POSITIONS? \");\n        }\n\n        public static void PromptNumberOfRounds()\n        {\n            Console.Write(\"NUMBER OF ROUNDS? \");\n        }\n\n        public static void PromptGuess(int moveNumber)\n        {\n            Console.Write($\"MOVE #  {moveNumber}  GUESS ? \");\n        }\n\n        public static void PromptReady()\n        {\n            Console.Write(\"HIT RETURN WHEN READY ? \");\n        }\n\n        public static void PromptBlacksWhites(Code code)\n        {\n            Console.Write($\"MY GUESS IS: {code}\");\n            Console.Write(\"  BLACKS, WHITES ? \");\n        }\n\n        public static void PromptTwoValues()\n        {\n            Console.WriteLine(\"PLEASE ENTER TWO VALUES, SEPARATED BY A COMMA\");\n        }\n\n        public static void PromptValidInteger()\n        {\n            Console.WriteLine(\"PLEASE ENTER AN INTEGER VALUE\");\n        }\n\n        public static void NotifyBadNumberOfPositions()\n        {\n            Console.WriteLine(\"BAD NUMBER OF POSITIONS\");\n        }\n\n        public static void NotifyInvalidColor(char colorKey)\n        {\n            Console.WriteLine($\"'{colorKey}' IS UNRECOGNIZED.\");\n        }\n\n        public static void NotifyTooManyColors(int maxColors)\n        {\n            Console.WriteLine($\"NO MORE THAN {maxColors}, PLEASE!\");\n        }\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/java/Mastermind.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.BitSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Random;\nimport java.util.Scanner;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\n/**\n * A port of the BASIC Mastermind game in java.\n *\n * Differences between this and the original BASIC:\n *    Uses a number base conversion approach to converting solution ids to\n *    color code strings. The original performs an inefficient add by 1\n *    with carry technique where every carry increments the next positions\n *    color id.\n *\n *    Implements a ceiling check on the number of positions in a secret code\n *    to not run out of memory. Because of the algorithm that the computer\n *    uses to deduce the players secret code, it searches through the entire\n *    possible spectrum of solutions. This can be a very large number because\n *    it's (number of colors) ^ (number of positions). The original will\n *    happily try to allocate all the memory on the system if this number is\n *    too large. If it did successfully allocate the memory on a large solution\n *    set then it would also take too long to compute code strings via its\n *    technique mentioned in the previous note.\n *\n *    An extra message is given at the start to alert the player to the\n *    BOARD and QUIT commands.\n */\npublic class Mastermind {\n  final Random random = new Random();\n  // some less verbose printing methods\n  static private void pf(String s, Object... o){ System.out.printf(s, o);}\n  static private void pl(String s){System.out.println(s);}\n  static private void pl(){System.out.println();}\n\n  public static void main(String[] args) {\n    title();\n    Mastermind game = setup();\n    game.play();\n  }\n\n  /**\n   * The eight possible color codes.\n   */\n  private enum Color {\n    B(\"BLACK\"), W(\"WHITE\"), R(\"RED\"), G(\"GREEN\"),\n    O(\"ORANGE\"), Y(\"YELLOW\"), P(\"PURPLE\"), T(\"TAN\");\n    public final String name;\n\n    Color(String name) {\n      this.name = name;\n    }\n  }\n\n  /**\n   * Represents a guess and the subsequent number of colors in the correct\n   * position (blacks), and the number of colors present but not in the correct\n   * position (whites.)\n   */\n  private record Guess(int guessNum, String guess, int blacks, int whites){}\n\n\n  private void play() {\n    IntStream.rangeClosed(1,rounds).forEach(this::playRound);\n    pl(\"GAME OVER\");\n    pl(\"FINAL SCORE: \");\n    pl(getScore());\n  }\n\n  /**\n   * Builder-ish pattern for creating Mastermind game\n   * @return Mastermind game object\n   */\n  private static Mastermind setup() {\n    int numOfColors;\n    pf(\"NUMBER OF COLORS? > \");\n    numOfColors = getPositiveNumberUpTo(Color.values().length);\n    int maxPositions = getMaxPositions(numOfColors);\n    pf(\"NUMBER OF POSITIONS (MAX %d)? > \", maxPositions);\n    int positions = getPositiveNumberUpTo(maxPositions);\n    pf(\"NUMBER OF ROUNDS? > \");\n    int rounds = getPositiveNumber();\n    pl(\"ON YOUR TURN YOU CAN ENTER 'BOARD' TO DISPLAY YOUR PREVIOUS GUESSES,\");\n    pl(\"OR 'QUIT' TO GIVE UP.\");\n    return new Mastermind(numOfColors, positions, rounds, 10);\n  }\n\n  /**\n   * Computes the number of allowable positions to prevent the total possible\n   * solution set that the computer has to check to a reasonable number, and\n   * to prevent out of memory errors.\n   *\n   * The computer guessing algorithm uses a BitSet which has a limit of 2^31\n   * bits (Integer.MAX_VALUE bits). Since the number of possible solutions to\n   * any mastermind game is (numColors) ^ (numPositions) we need find the\n   * maximum number of positions by finding the Log|base-NumOfColors|(2^31)\n   *\n   * @param numOfColors  number of different colors\n   * @return             max number of positions in the secret code.\n   */\n  private static int getMaxPositions(int numOfColors){\n    return (int)(Math.log(Integer.MAX_VALUE)/Math.log(numOfColors));\n  }\n\n  final int numOfColors, positions, rounds, possibilities;\n  int humanMoves, computerMoves;\n  final BitSet solutionSet;\n  final Color[] colors;\n  final int maxTries;\n\n  // A recording of human guesses made during the round for the BOARD command.\n  final List<Guess> guesses = new ArrayList<>();\n\n  // A regular expression to validate user guess strings\n  final String guessValidatorRegex;\n\n  public Mastermind(int numOfColors, int positions, int rounds, int maxTries) {\n    this.numOfColors = numOfColors;\n    this.positions = positions;\n    this.rounds = rounds;\n    this.maxTries = maxTries;\n    this.humanMoves = 0;\n    this.computerMoves = 0;\n    String colorCodes = Arrays.stream(Color.values())\n                              .limit(numOfColors)\n                              .map(Color::toString)\n                              .collect(Collectors.joining());\n    // regex that limits the number of color codes and quantity for a guess.\n    this.guessValidatorRegex = \"^[\" + colorCodes + \"]{\" + positions + \"}$\";\n    this.colors = Color.values();\n    this.possibilities = (int) Math.round(Math.pow(numOfColors, positions));\n    pf(\"TOTAL POSSIBILITIES =% d%n\", possibilities);\n    this.solutionSet = new BitSet(possibilities);\n    displayColorCodes(numOfColors);\n  }\n\n  private void playRound(int round) {\n    pf(\"ROUND NUMBER % d ----%n%n\",round);\n    humanTurn();\n    computerTurn();\n    pl(getScore());\n  }\n\n  private void humanTurn() {\n    guesses.clear();\n    String secretCode = generateColorCode();\n    pl(\"GUESS MY COMBINATION. \\n\");\n    int guessNumber = 1;\n    while (true) {   // User input loop\n      pf(\"MOVE #%d GUESS ?\", guessNumber);\n      final String guess = getWord();\n      if (guess.equals(secretCode)) {\n        guesses.add(new Guess(guessNumber, guess, positions, 0));\n        pf(\"YOU GUESSED IT IN %d MOVES!%n\", guessNumber);\n        humanMoves++;\n        pl(getScore());\n        return;\n      } else if (\"BOARD\".equals(guess)) {  displayBoard();\n      } else if (\"QUIT\".equals(guess))  {  quit(secretCode);\n      } else if (!validateGuess(guess)) {  pl(guess + \" IS UNRECOGNIZED.\");\n      } else {\n        Guess g = evaluateGuess(guessNumber, guess, secretCode);\n        pf(\"YOU HAVE %d BLACKS AND %d WHITES.%n\", g.blacks(), g.whites());\n        guesses.add(g);\n        humanMoves++;\n        guessNumber++;\n      }\n      if (guessNumber > maxTries) {\n        pl(\"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\");\n        pl(\"THE ACTUAL COMBINATION WAS: \" + secretCode);\n        return;\n      }\n    }\n  }\n\n  private void computerTurn(){\n    while (true) {\n      pl(\"NOW I GUESS.  THINK OF A COMBINATION.\");\n      pl(\"HIT RETURN WHEN READY:\");\n      solutionSet.set(0, possibilities);  // set all bits to true\n      getInput(\"RETURN KEY\", Scanner::nextLine, Objects::nonNull);\n      int guessNumber = 1;\n      while(true){\n        if (solutionSet.cardinality() == 0) {\n          // user has given wrong information, thus we have cancelled out\n          // any remaining possible valid solution.\n          pl(\"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\");\n          pl(\"TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\");\n          break;\n        }\n        // Randomly pick an untried solution.\n        int solution = solutionSet.nextSetBit(generateSolutionID());\n        if (solution == -1) {\n          solution = solutionSet.nextSetBit(0);\n        }\n        String guess = solutionIdToColorCode(solution);\n        pf(\"MY GUESS IS: %s  BLACKS, WHITES ? \",guess);\n        int[] bAndWPegs = getPegCount(positions);\n        if (bAndWPegs[0] == positions) {\n          pf(\"I GOT IT IN % d MOVES!%n\", guessNumber);\n          computerMoves+=guessNumber;\n          return;\n        }\n        // wrong guess, first remove this guess from solution set\n        solutionSet.clear(solution);\n        int index = 0;\n        // Cycle through remaining solution set, marking any solutions as invalid\n        // that don't exactly match what the user said about our guess.\n        while ((index = solutionSet.nextSetBit(index)) != -1) {\n          String solutionStr = solutionIdToColorCode(index);\n          Guess possibleSolution = evaluateGuess(0, solutionStr, guess);\n          if (possibleSolution.blacks() != bAndWPegs[0] ||\n              possibleSolution.whites() != bAndWPegs[1]) {\n            solutionSet.clear(index);\n          }\n          index++;\n        }\n        guessNumber++;\n      }\n    }\n  }\n\n  // tally black and white pegs\n  private Guess evaluateGuess(int guessNum, String guess, String secretCode) {\n    int blacks = 0, whites = 0;\n    char[] g = guess.toCharArray();\n    char[] sc = secretCode.toCharArray();\n    // An incremented number that marks this position as having been counted\n    // as a black or white peg already.\n    char visited = 0x8000;\n    // Cycle through guess letters and check for color and position match\n    // with the secretCode. If both match, mark it black.\n    // Else cycle through remaining secretCode letters and check if color\n    // matches. If this matches, a preventative check must be made against\n    // the guess letter matching the secretCode letter at this position in\n    // case it would be counted as a black in one of the next passes.\n    for (int j = 0; j < positions; j++) {\n      if (g[j] == sc[j]) {\n        blacks++;\n        g[j] = visited++;\n        sc[j] = visited++;\n      }\n      for (int k = 0; k < positions; k++) {\n        if (g[j] == sc[k] && g[k] != sc[k]) {\n          whites++;\n          g[j] = visited++;\n          sc[k] = visited++;\n        }\n      }\n    }\n    return new Guess(guessNum, guess, blacks, whites);\n  }\n\n  private boolean validateGuess(String guess) {\n    return guess.length() == positions && guess.matches(guessValidatorRegex);\n  }\n\n  private String getScore() {\n    return \"SCORE:%n\\tCOMPUTER \\t%d%n\\tHUMAN \\t%d%n\"\n        .formatted(computerMoves, humanMoves);\n  }\n\n  private void printGuess(Guess g){\n    pf(\"% 3d%9s% 15d% 10d%n\",g.guessNum(),g.guess(),g.blacks(),g.whites());\n  }\n  \n  private void displayBoard() {\n    pl();\n    pl(\"BOARD\");\n    pl(\"MOVE     GUESS          BLACK     WHITE\");\n    guesses.forEach(this::printGuess);\n    pl();\n  }\n\n  private void quit(String secretCode) {\n    pl(\"QUITTER!  MY COMBINATION WAS: \" + secretCode);\n    pl(\"GOOD BYE\");\n    System.exit(0);\n  }\n\n  /**\n   * Generates a set of color codes randomly.\n   */\n  private String generateColorCode() {\n    int solution = generateSolutionID();\n    return solutionIdToColorCode(solution);\n  }\n\n  /**\n   * From the total possible number of solutions created at construction, choose\n   * one randomly.\n   *\n   * @return one of many possible solutions\n   */\n  private int generateSolutionID() {\n    return random.nextInt(0, this.possibilities);\n  }\n\n  /**\n   * Given the number of colors and positions in a secret code, decode one of\n   * those permutations, a solution number, into a string of letters\n   * representing colored pegs.\n   *\n   * The pattern can be decoded easily as a number with base `numOfColors` and\n   * `positions` representing the digits. For example if numOfColors is 5 and\n   * positions is 3 then the pattern is converted to a number that is base 5\n   * with three digits. Each digit then maps to a particular color.\n   *\n   * @param solution one of many possible solutions\n   * @return String representing this solution's color combination.\n   */\n  private String solutionIdToColorCode(final int solution) {\n    StringBuilder secretCode = new StringBuilder();\n    int pos = possibilities;\n    int remainder = solution;\n    for (int i = positions - 1; i > 0; i--) {\n      pos = pos / numOfColors;\n      secretCode.append(colors[remainder / pos].toString());\n      remainder = remainder % pos;\n    }\n    secretCode.append(colors[remainder].toString());\n    return secretCode.toString();\n  }\n\n  private static void displayColorCodes(int numOfColors) {\n    pl(\"\\n\\nCOLOR     LETTER\\n=====     ======\");\n    Arrays.stream(Color.values())\n          .limit(numOfColors)\n          .map(c -> c.name + \" \".repeat(13 - c.name.length()) + c)\n          .forEach(Mastermind::pl);\n    pl();pl();\n  }\n\n  private static void title() {\n    pl(\"\"\"    \n                                  MASTERMIND\n                   CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY%n%n%n\n    \"\"\");\n  }\n\n  /////////////////////////////////////////////////////////\n  // User input functions from here on\n\n  /**\n   * Base input function to be called from a specific input function.\n   * Re-prompts upon unexpected or invalid user input.\n   * Discards any remaining input in the line of user entered input once\n   * it gets what it wants.\n   * @param descriptor  Describes explicit type of input expected\n   * @param extractor   The method performed against a Scanner object to parse\n   *                    the type of input.\n   * @param conditional A test that the input meets a minimum validation.\n   * @param <T>         Input type returned.\n   * @return            input type for this line of user input.\n   */\n  private static <T> T getInput(String descriptor,\n                                Function<Scanner, T> extractor,\n                                Predicate<T> conditional) {\n\n    Scanner scanner = new Scanner(System.in);\n    while (true) {\n      try {\n        T input = extractor.apply(scanner);\n        if (conditional.test(input)) {\n          return input;\n        }\n      } catch (Exception ex) {\n        try {\n          // If we are here then a call on the scanner was most likely unable to\n          // parse the input. We need to flush whatever is leftover from this\n          // line of interactive user input so that we can re-prompt for new input.\n          scanner.nextLine();\n        } catch (Exception ns_ex) {\n          // if we are here then the input has been closed, or we received an\n          // EOF (end of file) signal, usually in the form of a ctrl-d or\n          // in the case of Windows, a ctrl-z.\n          pl(\"END OF INPUT, STOPPING PROGRAM.\");\n          System.exit(1);\n        }\n      }\n      pf(\"!%s EXPECTED - RETRY INPUT LINE%n? \", descriptor);\n    }\n  }\n\n  private static int getPositiveNumber() {\n    return getInput(\"NUMBER\", Scanner::nextInt, num -> num > 0);\n  }\n\n  private static int getPositiveNumberUpTo(long to) {\n    return getInput(\n        \"NUMBER FROM 1 TO \" + to,\n        Scanner::nextInt,\n        num -> num > 0 && num <= to);\n  }\n\n  private static int[] getPegCount(int upperBound) {\n    int[] nums = {Integer.MAX_VALUE, Integer.MAX_VALUE};\n    while (true) {\n      String input = getInput(\n          \"NUMBER, NUMBER\",\n          Scanner::nextLine,\n          s -> s.matches(\"\\\\d+[\\\\s,]+\\\\d+$\"));\n      String[] numbers = input.split(\"[\\\\s,]+\");\n      nums[0] = Integer.parseInt(numbers[0].trim());\n      nums[1] = Integer.parseInt(numbers[1].trim());\n      if (nums[0] <= upperBound && nums[1] <= upperBound &&\n          nums[0] >= 0 && nums[1] >= 0) {\n        return nums;\n      }\n      pf(\"NUMBERS MUST BE FROM 0 TO %d.%n? \", upperBound);\n    }\n  }\n\n  private static String getWord() {\n    return getInput(\"WORD\", Scanner::next, word -> !\"\".equals(word));\n  }\n}\n"
  },
  {
    "path": "60_Mastermind/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "60_Mastermind/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "60_Mastermind/javascript/mastermind.html",
    "content": "<html>\n<head>\n<title>MASTERMIND</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"mastermind.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "60_Mastermind/javascript/mastermind.js",
    "content": "// MASTERMIND\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar p9;\nvar c9;\nvar b;\nvar w;\nvar f;\nvar m;\n\nvar qa;\nvar sa;\nvar ss;\nvar as;\nvar gs;\nvar hs;\n\nfunction initialize_qa()\n{\n    for (s = 1; s <= p9; s++)\n        qa[s] = 0;\n}\n\nfunction increment_qa()\n{\n    if (qa[1] <= 0) {\n        // If zero, this is our firt increment: make all ones\n        for (s = 1; s <= p9; s++)\n            qa[s] = 1;\n    } else {\n        q = 1;\n        while (1) {\n            qa[q] = qa[q] + 1;\n            if (qa[q] <= c9)\n                return;\n            qa[q] = 1;\n            q++;\n        }\n    }\n}\n\nfunction convert_qa()\n{\n    for (s = 1; s <= p9; s++) {\n        as[s] = ls.substr(qa[s] - 1, 1);\n    }\n}\n\nfunction get_number()\n{\n    b = 0;\n    w = 0;\n    f = 0;\n    for (s = 1; s <= p9; s++) {\n        if (gs[s] == as[s]) {\n            b++;\n            gs[s] = String.fromCharCode(f);\n            as[s] = String.fromCharCode(f + 1);\n            f += 2;\n        } else {\n            for (t = 1; t <= p9; t++) {\n                if (gs[s] == as[t] && gs[t] != as[t]) {\n                    w++;\n                    as[t] = String.fromCharCode(f);\n                    gs[s] = String.fromCharCode(f + 1);\n                    f += 2;\n                    break;\n                }\n            }\n        }\n    }\n}\n\nfunction convert_qa_hs()\n{\n    for (s = 1; s <= p9; s++) {\n        hs[s] = ls.substr(qa[s] - 1, 1);\n    }\n}\n\nfunction copy_hs()\n{\n    for (s = 1; s <= p9; s++) {\n        gs[s] = hs[s];\n    }\n}\n\nfunction board_printout()\n{\n    print(\"\\n\");\n    print(\"BOARD\\n\");\n    print(\"MOVE     GUESS          BLACK     WHITE\\n\");\n    for (z = 1; z <= m - 1; z++) {\n        str = \" \" + z + \" \";\n        while (str.length < 9)\n            str += \" \";\n        str += ss[z];\n        while (str.length < 25)\n            str += \" \";\n        str += sa[z][1];\n        while (str.length < 35)\n            str += \" \";\n        str += sa[z][2];\n        print(str + \"\\n\");\n    }\n    print(\"\\n\");\n}\n\nfunction quit()\n{\n    print(\"QUITTER!  MY COMBINATION WAS: \");\n    convert_qa();\n    for (x = 1; x <= p9; x++) {\n        print(as[x]);\n    }\n    print(\"\\n\");\n    print(\"GOOD BYE\\n\");\n}\n\nfunction show_score()\n{\n    print(\"SCORE:\\n\");\n    show_points();\n}\n\nfunction show_points()\n{\n    print(\"     COMPUTER \" + c + \"\\n\");\n    print(\"     HUMAN    \" + h + \"\\n\");\n    print(\"\\n\");\n}\n\nvar color = [\"BLACK\", \"WHITE\", \"RED\", \"GREEN\",\n             \"ORANGE\", \"YELLOW\", \"PURPLE\", \"TAN\"];\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"MASTERMIND\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    //\n    //  MASTERMIND II\n    //  STEVE NORTH\n    //  CREATIVE COMPUTING\n    //  PO BOX 789-M MORRISTOWN NEW JERSEY 07960\n    //\n    //\n    while (1) {\n        print(\"NUMBER OF COLORS\");\n        c9 = parseInt(await input());\n        if (c9 <= 8)\n            break;\n        print(\"NO MORE THAN 8, PLEASE!\\n\");\n    }\n    print(\"NUMBER OF POSITIONS\");\n    p9 = parseInt(await input());\n    print(\"NUMBER OF ROUNDS\");\n    r9 = parseInt(await input());\n    p = Math.pow(c9, p9);\n    print(\"TOTAL POSSIBILITIES = \" + p + \"\\n\");\n    h = 0;\n    c = 0;\n    qa = [];\n    sa = [];\n    ss = [];\n    as = [];\n    gs = [];\n    ia = [];\n    hs = [];\n    ls = \"BWRGOYPT\";\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"COLOR    LETTER\\n\");\n    print(\"=====    ======\\n\");\n    for (x = 1; x <= c9; x++) {\n        str = color[x - 1];\n        while (str.length < 13)\n            str += \" \";\n        str += ls.substr(x - 1, 1);\n        print(str + \"\\n\");\n    }\n    print(\"\\n\");\n    for (r = 1; r <= r9; r++) {\n        print(\"\\n\");\n        print(\"ROUND NUMBER \" + r + \" ----\\n\");\n        print(\"\\n\");\n        print(\"GUESS MY COMBINATION.\\n\");\n        print(\"\\n\");\n        // Get a combination\n        a = Math.floor(p * Math.random() + 1);\n        initialize_qa();\n        for (x = 1; x <= a; x++) {\n            increment_qa();\n        }\n        for (m = 1; m <= 10; m++) {\n            while (1) {\n                print(\"MOVE # \" + m + \" GUESS \");\n                str = await input();\n                if (str == \"BOARD\") {\n                    board_printout();\n                } else if (str == \"QUIT\") {\n                    quit();\n                    return;\n                } else if (str.length != p9) {\n                    print(\"BAD NUMBER OF POSITIONS.\\n\");\n                } else {\n                    // Unpack str into gs(1-p9)\n                    for (x = 1; x <= p9; x++) {\n                        y = ls.indexOf(str.substr(x - 1, 1));\n                        if (y < 0) {\n                            print(\"'\" + str.substr(x - 1, 1) + \"' IS UNRECOGNIZED.\\n\");\n                            break;\n                        }\n                        gs[x] = str.substr(x - 1, 1);\n                    }\n                    if (x > p9)\n                        break;\n                }\n            }\n            // Now we convert qa(1-p9) into as(1-p9) [ACTUAL GUESS]\n            convert_qa();\n            // And get number of blacks and white\n            get_number();\n            if (b == p9) {\n                print(\"YOU GUESSED IT IN \" + m + \" MOVES!\\n\");\n                break;\n            }\n            //tell human results\n            print(\"YOU HAVE \" + b + \" BLACKS AND \" + w + \" WHITES.\")\n            // Save all this stuff for board printout later\n            ss[m] = str;\n            sa[m] = [];\n            sa[m][1] = b;\n            sa[m][2] = w;\n        }\n        if (m > 10) {\n            print(\"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\\n\");\n        }\n        h += m;\n        show_score();\n\n        //\n        // Now computer guesses\n        //\n        for (x = 1; x <= p; x++)\n            ia[x] = 1;\n        print(\"NOW I GUESS.  THINK OF A COMBINATION.\\n\");\n        print(\"HIT RETURN WHEN READY:\");\n        str = await input();\n        for (m = 1; m <= 10; m++) {\n            initialize_qa();\n            // Find a guess\n            g = Math.floor(p * Math.random() + 1);\n            if (ia[g] != 1) {\n                for (x = g; x <= p; x++) {\n                    if (ia[x] == 1)\n                        break;\n                }\n                if (x > p) {\n                    for (x = 1; x <= g; x++) {\n                        if (ia[x] == 1)\n                            break;\n                    }\n                    if (x > g) {\n                        print(\"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\\n\");\n                        print(\"TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\\n\");\n                        for (x = 1; x <= p; x++)\n                            ia[x] = 1;\n                        print(\"NOW I GUESS.  THINK OF A COMBINATION.\\n\");\n                        print(\"HIT RETURN WHEN READY:\");\n                        str = await input();\n                        m = 0;\n                        continue;\n                    }\n                }\n                g = x;\n            }\n            // Now we convert guess #g into gs\n            for (x = 1; x <= g; x++) {\n                increment_qa();\n            }\n            convert_qa_hs();\n            print(\"MY GUESS IS: \");\n            for (x = 1; x <= p9; x++) {\n                print(hs[x]);\n            }\n            print(\"  BLACKS, WHITES \");\n            str = await input();\n            b1 = parseInt(str);\n            w1 = parseInt(str.substr(str.indexOf(\",\") + 1));\n            if (b1 == p9) {\n                print(\"I GOT IT IN \" + m + \" MOVES!\\n\");\n                break;\n            }\n            initialize_qa();\n            for (x = 1; x <= p; x++) {\n                increment_qa();\n                if (ia[x] != 0) {\n                    copy_hs();\n                    convert_qa();\n                    get_number();\n                    if (b1 != b || w1 != w)\n                        ia[x] = 0;\n                }\n            }\n        }\n        if (m > 10) {\n            print(\"I USED UP ALL MY MOVES!\\n\");\n            print(\"I GUESS MY CPU I JUST HAVING AN OFF DAY.\\n\");\n        }\n        c += m;\n        show_score();\n    }\n    print(\"GAME OVER\\n\");\n    print(\"FINAL SCORE:\\n\");\n    show_points();\n}\n\nmain();\n"
  },
  {
    "path": "60_Mastermind/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "60_Mastermind/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "60_Mastermind/mastermind.bas",
    "content": "2 PRINT TAB(30);\"MASTERMIND\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 REM\n20 REM     MASTERMIND II\n30 REM     STEVE NORTH\n40 REM     CREATIVE COMPUTING\n50 REM     PO BOX 789-M MORRISTOWN NEW JERSEY 07960\n60 REM\n70 REM\n80 INPUT \"NUMBER OF COLORS\";C9\n90 IF C9>8 THEN PRINT \"NO MORE THAN 8, PLEASE!\":GOTO 80\n100 INPUT \"NUMBER OF POSITIONS\";P9\n110 INPUT \"NUMBER OF ROUNDS\";R9\n120 P=C9^P9\n130 PRINT \"TOTAL POSSIBILITIES =\";P\n140 H=0:C=0\n150 DIM Q(P9),S(10,2),S$(10),A$(P9),G$(P9),I(P),H$(P9)\n160 L$=\"BWRGOYPT\"\n170 PRINT\n180 PRINT\n190 PRINT \"COLOR     LETTER\"\n200 PRINT \"=====     ======\"\n210 FOR X=1 TO C9\n220 READ X$\n230 PRINT X$;TAB(13);MID$(L$,X,1)\n240 NEXT X\n250 PRINT\n260 FOR R=1 TO R9\n270 PRINT\n280 PRINT \"ROUND NUMBER\";R;\"----\"\n290 PRINT\n300 PRINT \"GUESS MY COMBINATION.\":PRINT\n310 REM     GET A COMBINATION\n320 A=INT(P*RND(1)+1)\n330 GOSUB 3000\n340 FOR X=1 TO A\n350 GOSUB 3500\n360 NEXT X\n370 FOR M=1 TO 10\n380 PRINT \"MOVE # \";M;\" GUESS \";:INPUT X$\n390 IF X$=\"BOARD\" THEN 2000\n400 IF X$=\"QUIT\" THEN 2500\n410 IF LEN(X$)<>P9 THEN PRINT \"BAD NUMBER OF POSITIONS.\":GOTO 380\n420 REM     UNPACK X$ INTO G$(1-P9)\n430 FOR X=1 TO P9\n440 FOR Y=1 TO C9\n450 IF MID$(X$,X,1)=MID$(L$,Y,1) THEN 480\n460 NEXT Y\n470 PRINT \"'\"; MID$(X$,X,1); \"' IS UNRECOGNIZED.\":GOTO 380\n480 G$(X)=MID$(X$,X,1)\n490 NEXT X\n500 REM     NOW WE CONVERT Q(1-P9) INTO A$(1-P9) [ACTUAL GUESS]\n510 GOSUB 4000\n520 REM     AND GET NUMBER OF BLACKS AND WHITES\n530 GOSUB 4500\n540 IF B=P9 THEN 630\n550 REM     TELL HUMAN RESULTS\n560 PRINT \"YOU HAVE \";B;\" BLACKS AND \";W;\" WHITES.\"\n570 REM     SAVE ALL THIS STUFF FOR BOARD PRINTOUT LATER\n580 S$(M)=X$\n590 S(M,1)=B\n600 S(M,2)=W\n610 NEXT M\n620 PRINT \"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\":GOTO 640\n622 GOSUB 4000\n623 PRINT \"THE ACTUAL COMBINATION WAS: \";\n624 FOR X=1 TO P9\n625 PRINT A$(X);\n626 NEXT X\n627 PRINT\n630 PRINT \"YOU GUESSED IT IN \";M;\" MOVES!\"\n640 H=H+M\n650 GOSUB 5000\n660 REM\n670 REM     NOW COMPUTER GUESSES\n680 REM\n690 FOR X=1 TO P\n700 I(X)=1\n710 NEXT X\n720 PRINT \"NOW I GUESS.  THINK OF A COMBINATION.\"\n730 INPUT \"HIT RETURN WHEN READY:\";X$\n740 FOR M=1 TO 10\n750 GOSUB 3000\n760 REM     FIND A GUESS\n770 G=INT(P*RND(1)+1)\n780 IF I(G)=1 THEN 890\n790 FOR X=G TO P\n800 IF I(X)=1 THEN 880\n810 NEXT X\n820 FOR X=1 TO G\n830 IF I(X)=1 THEN 880\n840 NEXT X\n850 PRINT \"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\"\n860 PRINT \"TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\"\n870 GOTO 660\n880 G=X\n890 REM     NOW WE CONVERT GUESS #G INTO G$\n900 FOR X=1 TO G\n910 GOSUB 3500\n920 NEXT X\n930 GOSUB 6000\n940 PRINT \"MY GUESS IS: \";\n950 FOR X=1 TO P9\n960 PRINT H$(X);\n970 NEXT X\n980 INPUT \"  BLACKS, WHITES \";B1,W1\n990 IF B1=P9 THEN 1120\n1000 GOSUB 3000\n1010 FOR X=1 TO P\n1020 GOSUB 3500\n1030 IF I(X)=0 THEN 1070\n1035 GOSUB 6500\n1040 GOSUB 4000\n1050 GOSUB 4500\n1060 IF B1<>B OR W1<>W THEN I(X)=0\n1070 NEXT X\n1080 NEXT M\n1090 PRINT \"I USED UP ALL MY MOVES!\"\n1100 PRINT \"I GUESS MY CPU IS JUST HAVING AN OFF DAY.\"\n1110 GOTO 1130\n1120 PRINT \"I GOT IT IN \";M;\" MOVES!\"\n1130 C=C+M\n1140 GOSUB 5000\n1150 NEXT R\n1160 PRINT \"GAME OVER\"\n1170 PRINT \"FINAL SCORE:\"\n1180 GOSUB 5040\n1190 STOP\n2000 REM\n2010 REM     BOARD PRINTOUT ROUTINE\n2020 REM\n2025 PRINT\n2030 PRINT \"BOARD\"\n2040 PRINT \"MOVE     GUESS          BLACK     WHITE\"\n2050 FOR Z=1 TO M-1\n2060 PRINT Z;TAB(9);S$(Z);TAB(25);S(Z,1);TAB(35);S(Z,2)\n2070 NEXT Z\n2075 PRINT\n2080 GOTO 380\n2500 REM\n2510 REM     QUIT ROUTINE\n2520 REM\n2530 PRINT \"QUITTER!  MY COMBINATION WAS: \";\n2535 GOSUB 4000\n2540 FOR X=1 TO P9\n2550 PRINT A$(X);\n2560 NEXT X\n2565 PRINT\n2570 PRINT \"GOOD BYE\"\n2580 STOP\n3000 REM\n3010 REM     INITIALIZE Q(1-P9) TO ZEROS\n3020 REM\n3030 FOR S=1 TO P9\n3040 Q(S)=0\n3050 NEXT S\n3060 RETURN\n3500 REM\n3510 REM     INCREMENT Q(1-P9)\n3520 REM\n3522 IF Q(1)>0 THEN 3530\n3524 REM  IF ZERO, THIS IS OUR FIRST INCREMENT: MAKE ALL ONES\n3526 FOR S=1 TO P9\n3527 Q(S)=1\n3528 NEXT S\n3529 RETURN\n3530 Q=1\n3540 Q(Q)=Q(Q)+1\n3550 IF Q(Q)<=C9 THEN RETURN\n3560 Q(Q)=1\n3570 Q=Q+1\n3580 GOTO 3540\n4000 REM\n4010 REM     CONVERT Q(1-P9) TO A$(1-P9)\n4020 REM\n4030 FOR S=1 TO P9\n4040 A$(S)=MID$(L$,Q(S),1)\n4050 NEXT S\n4060 RETURN\n4500 REM\n4510 REM     GET NUMBER OF BLACKS (B) AND WHITES (W)\n4520 REM     MASHES G$ AND A$ IN THE PROCESS\n4530 REM\n4540 B=0:W=0:F=0\n4550 FOR S=1 TO P9\n4560 IF G$(S)<>A$(S) THEN 4620\n4570 B=B+1\n4580 G$(S)=CHR$(F)\n4590 A$(S)=CHR$(F+1)\n4600 F=F+2\n4610 GOTO 4660\n4620 FOR T=1 TO P9\n4630 IF G$(S)<>A$(T) THEN 4650\n4640 IF G$(T)=A$(T) THEN 4650\n4645 W=W+1:A$(T)=CHR$(F):G$(S)=CHR$(F+1):F=F+2:GOTO 4660\n4650 NEXT T\n4660 NEXT S\n4670 RETURN\n5000 REM\n5010 REM     PRINT SCORE\n5020 REM\n5030 PRINT \"SCORE:\"\n5040 PRINT \"     COMPUTER \";C\n5050 PRINT \"     HUMAN    \";H\n5060 PRINT\n5070 RETURN\n5500 REM\n5510 REM     CONVERT Q(1-P9) INTO G$(1-P9)\n5520 REM\n5530 FOR S=1 TO P9\n5540 G$(S)=MID$(L$,Q(S),1)\n5550 NEXT S\n5560 RETURN\n6000 REM\n6010 REM     CONVERT Q(1-P9) TO H$(1-P9)\n6020 REM\n6030 FOR S=1 TO P9\n6040 H$(S)=MID$(L$,Q(S),1)\n6050 NEXT S\n6060 RETURN\n6500 REM\n6510 REM     COPY H$ INTO G$\n6520 REM\n6530 FOR S=1 TO P9\n6540 G$(S)=H$(S)\n6550 NEXT S\n6560 RETURN\n8000 REM     PROGRAM DATA FOR COLOR NAMES\n8010 DATA BLACK,WHITE,RED,GREEN,ORANGE,YELLOW,PURPLE,TAN\n9998 REM   ...WE'RE SORRY BUT IT'S TIME TO GO...\n9999 END\n"
  },
  {
    "path": "60_Mastermind/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nThis is pretty much a re-implementation of the BASIC, taking advantage\nof Perl's array functionality and working directly with the alphabetic\ncolor codes.\n"
  },
  {
    "path": "60_Mastermind/perl/mastermind.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse List::Util qw{ min sum };   # Convenient list utilities\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nuse constant MAX_GUESSES    => 10;\n\nprint <<'EOD';\n                               MASTERMIND\n               Creative Computing  Morristown, New Jersey\n\n\nEOD\n\n=begin comment\n\n     MASTERMIND II\n     STEVE NORTH\n     CREATIVE COMPUTING\n     PO BOX 789-M MORRISTOWN NEW JERSEY 07960\n\n=end comment\n\n=cut\n\n# NOTE that mixed-case 'my' variables are 'global' in the sense that\n# they are used in subroutines, but not passed to them.\n\nsay '';\n\nmy $number_of_colors = get_input(\n    'Number of colors [1-8]: ',\n    sub { m/ \\A [1-8] \\z /smx },\n    \"No more than 8, please!\\n\",\n);\n\nsay '';\n\nmy $Number_of_Positions = get_input(\n    'Number of positions: ',\n    sub { m/ \\A [0-9]+ \\z /smx && $ARG },\n    \"A positive number, please\\n\",\n);\n\nsay '';\n\nmy $number_of_rounds = get_input(\n    'Number of rounds: ',\n    sub { m/ \\A [0-9]+ \\z /smx && $ARG },\n    \"A positive number, please\\n\",\n);\n\nmy $P = $number_of_colors ** $Number_of_Positions;\nsay 'Total possibilities = ', $P;\n\nmy @colors = ( qw{\n    Black White Red Green Orange Yellow Purple Tan\n})[ 0 .. $number_of_colors - 1 ];\nmy @Color_Codes = map { uc substr $ARG, 0, 1 } @colors;\n\nprint <<'EOD';\n\n\nColor        Letter\n=====        ======\nEOD\n\nforeach my $inx ( 0 .. $#colors ) {\n    printf \"%-13s%s\\n\", $colors[$inx], $Color_Codes[$inx];\n}\n\nsay '';\n\nmy $computer_score = 0;  # Computer score\nmy $human_score = 0;  # Human score\n\nforeach my $round_number ( 1 .. $number_of_rounds ) {\n\n    print <<\"EOD\";\n\nRound number $round_number ----\n\nGuess my combination.\n\nEOD\n\n    $human_score += human_guesses( $Number_of_Positions );\n\n    print_score( $computer_score, $human_score );\n\n    $computer_score += computer_guesses();\n\n    print_score( $computer_score, $human_score );\n\n}\n\n# Make a $pattern into a hash with one key for each possible color. The\n# value for each color is the number of times it appears in the pattern.\nsub hashify_pattern {\n    my $pattern = uc $ARG[0];\n    my %p = map { $ARG => 0 } @Color_Codes;\n    $p{$ARG}++ for split qr//, $pattern;\n    return \\%p;\n}\n\n# Given a $pattern, a $guess at that pattern, and $black and $white\n# scores, return a true value if the $black and $white scores of the\n# $guess are those supplied as arguments; otherwise return a false\n# value. This is used by computer_guesses() to eliminate possibilities.\nsub analyze_black_white {\n    my ( $pattern, $guess, $black, $white ) = @ARG;\n    my $info = analyze_guess( $pattern, $guess );\n    return $info->{black} == $black && $info->{white} == $white;\n}\n\n# Given a $pattern and a $guess at that pattern, return a reference to a\n# hash with the following keys:\n#  {guess} is the guess;\n#  {black} is the black score of the guess\n#  {white} is the white score of the guess\nsub analyze_guess {\n    my ( $pattern, $guess ) = @ARG;\n    my $pattern_hash = hashify_pattern( $pattern );\n    my $guess_hash = hashify_pattern( $guess );\n    my $white = sum(\n        map { min( $pattern_hash->{$ARG}, $guess_hash->{$ARG} ) } @Color_Codes,\n    );\n    my $black = 0;\n    foreach my $inx ( 0 .. length( $pattern ) - 1 ) {\n        if ( substr( $pattern, $inx, 1 ) eq substr( $guess, $inx, 1 ) )\n        {\n            $black++;\n            --$white;\n        }\n    }\n    return +{\n        guess   => $guess,\n        black   => $black,\n        white   => $white,\n    }\n}\n\n# Used by the computer to guess the human's choice. The return is the\n# number of guesses the computer took. The return is the maximum plus\n# one if the computer failed to guess.\nsub computer_guesses {\n\n    print <<'EOD';\n\nNow I guess. Think of a combination.\nEOD\n    get_input(\n        'Hit <return> when ready:',\n    );\n\n    # Generate all possible permutations.\n    my @possible;\n    foreach my $permutation ( 0 .. @Color_Codes ** $Number_of_Positions - 1 ) {\n        my $guess;\n        for ( 1 .. $Number_of_Positions ) {\n            my $inx = $permutation % @Color_Codes;\n            $guess .= $Color_Codes[ $inx ];\n            $permutation = int( $permutation / @Color_Codes );\n        }\n        push @possible, $guess;\n    }\n\n    # Guess ...\n    foreach my $guess_num ( 1 .. MAX_GUESSES ) {\n\n        # Guess a possible permutation at random, removing it from the\n        # list.\n        my $guess = splice @possible, int rand @possible, 1;\n        say 'My guess is: ', $guess;\n\n        # Find out its black/white score.\n        my ( $black, $white ) = split qr< , >smx, get_input(\n            'Blacks, Whites: ',\n            sub { m/ \\A [0-9]+ , [0-9]+ \\z /smx },\n            \"Please enter two unsigned integers\\n\",\n        );\n\n        # If it's all black, the computer wins.\n        if ( $black == $Number_of_Positions ) {\n            say \"I got it in $guess_num moves!\";\n            return $guess_num;\n        }\n\n        # Eliminate all possible permutations that give the black/white\n        # score that our guess got. If there are any left, take another\n        # guess.\n        next if @possible = grep { analyze_black_white( $ARG, $guess, $black,\n            $white ) } @possible;\n\n        # There were no permutations left. Complain.\n        print <<'EOD';\nYou have given me inconsistent information.\nTry again, and this time please be more careful.\nEOD\n\n        goto &computer_guesses; # Tail-call ourselves to try again.\n    }\n\n    print <<'EOD';\nI used up all my moves!\nI guess my CPU is just having an off day.\nEOD\n\n    return MAX_GUESSES + 1;\n}\n\n# Used to generate a pattern and process the human's guesses. The return\n# is the number of guesses the human took. The return is the maximum\n# plus one if the human failed to guess.\nsub human_guesses {\n\n    my @saved_moves;  # Saved moves\n    my $pattern = uc join '',\n        map { $Color_Codes[ rand @Color_Codes ] } 1 .. $Number_of_Positions;\n\n    foreach my $guess_num ( 1 .. MAX_GUESSES ) {\n\n        my $guess = uc get_input(\n            \"Move # $guess_num guess: \",\n            sub {\n\n                # If the user entered 'quit', bail out.\n                if ( m/ \\A quit \\z /smxi ) {\n                    die \"Quitter!  My combination was $pattern\\n\\nGood bye\\n\";\n                }\n\n                # If the user entered 'board', display the board so far.\n                # We return success to prevent the warning message, but\n                # we also clear $ARG. The caller's caller sees this and\n                # re-queries.\n                if ( m/ \\A board \\z /smxi ) {\n                    print <<'EOD';\n\nBoard\nMove     Guess          Black     White\nEOD\n                    my $number = 1;\n                    foreach my $item ( @saved_moves ) {\n                        printf \"%4d     %-13s  %3d       %3d\\n\", $number++,\n                        @{ $item }{ qw{ guess black white } };\n                    }\n                    return undef;   # Validation failure, but suppress warning.\n                }\n\n                # End of special-case code. Below here we are dealing\n                # with guess input.\n\n                # The length of the input must equal the number of\n                # positions.\n                if ( $Number_of_Positions != length ) {\n                    warn \"Bad number of positions\\n\";\n                    return 0;\n                }\n\n                # The input may contain only valid color codes.\n                state $invalid_color = do { # Evaluated only once\n                    local $LIST_SEPARATOR = '';\n                    qr< [^@Color_Codes] >smxi;\n                };\n                if ( m/ ( $invalid_color ) /smxi ) {\n                    warn \"'$1' is unrecognized.\\n\";\n                    return 0;\n                }\n\n                # We're good.\n                return 1;\n            },\n             \"Please enter 'board', 'quit', or any $Number_of_Positions of @{[\n                 join ', ', map { qq<'$ARG'> } @Color_Codes ]}.\\n\",\n        );\n\n        my $rslt = analyze_guess( $pattern, $guess );\n\n        push @saved_moves, $rslt;\n\n        if ( $rslt->{black} == $Number_of_Positions ) {\n            say \"You guessed it in $guess_num moves.\";\n            return $guess_num;\n        }\n\n        say \"You have $rslt->{black} blacks and $rslt->{white} whites.\";\n\n    }\n\n    print <<\"EOD\";\nYou ran out of moves.  That's all you get.\n\nThe actual combination was: $pattern\nEOD\n\n    return MAX_GUESSES + 1;\n}\n\n# Print the $computer and $human score\nsub print_score {\n    my ( $computer, $human ) = @ARG;\n    print <<\"EOD\";\nScore:\n     Computer: $computer\n        Human: $human\nEOD\n    return;\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return. It is suppressed if the validation code returned undef.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if my $rslt = $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning if defined $rslt;\n    }\n}\n\n# NOTE the following is unused, but left in place in case someone wants\n# to add a 'Do you want instructions?'\n#\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n__END__\n\n=head1 TITLE\n\nmastermind - Play the game 'Mastermind' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n mastermind.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of mastermind, which is the 60th\nentry in Basic Computer Games.\n\nThis is pretty much a re-implementation of the BASIC, taking advantage\nof Perl's array functionality and working directly with the alphabetic\ncolor codes.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "60_Mastermind/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "60_Mastermind/python/mastermind.py",
    "content": "import random\nimport sys\nfrom typing import List, Union, Tuple\n\n\n#  define some parameters for the game which should not be modified.\ndef setup_game() -> Tuple[int, int, int, int]:\n    print(\"\"\"\n                                  MASTERMIND\n                   CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n    \"\"\")\n    # get user inputs for game conditions\n    num_colors: int = len(COLOR_LETTERS) + 1\n    while num_colors > len(COLOR_LETTERS):\n        num_colors = int(input(\"Number of colors (max 8): \"))  # C9 in BASIC\n    num_positions = int(input(\"Number of positions: \"))  # P9 in BASIC\n    num_rounds = int(input(\"Number of rounds: \"))  # R9 in BASIC\n    possibilities = num_colors**num_positions\n\n    print(f\"Number of possibilities {possibilities}\")\n    print(\"Color\\tLetter\")\n    print(\"=====\\t======\")\n    for element in range(0, num_colors):\n        print(f\"{COLORS[element]}\\t{COLORS[element][0]}\")\n    return num_colors, num_positions, num_rounds, possibilities\n\n\n# Global variables\nCOLORS = [\"BLACK\", \"WHITE\", \"RED\", \"GREEN\", \"ORANGE\", \"YELLOW\", \"PURPLE\", \"TAN\"]\nCOLOR_LETTERS = \"BWRGOYPT\"\nNUM_COLORS, NUM_POSITIONS, NUM_ROUNDS, POSSIBILITIES = setup_game()\nhuman_score = 0\ncomputer_score = 0\n\n\ndef main() -> None:\n    current_round = 1\n    while current_round <= NUM_ROUNDS:\n        print(f\"Round number {current_round}\")\n        human_turn()\n        computer_turn()\n        current_round += 1\n    print_score(is_final_score=True)\n    sys.exit()\n\n\ndef human_turn() -> None:\n    global human_score\n    num_moves = 1\n    guesses: List[List[Union[str, int]]] = []\n    print(\"Guess my combination ...\")\n    secret_combination = int(POSSIBILITIES * random.random())\n    answer = possibility_to_color_code(secret_combination)\n    while True:\n        print(f\"Move # {num_moves} Guess : \")\n        user_command = input(\"Guess \")\n        if user_command == \"BOARD\":\n            print_board(guesses)  # 2000\n        elif user_command == \"QUIT\":  # 2500\n            print(f\"QUITTER! MY COMBINATION WAS: {answer}\")\n            print(\"GOOD BYE\")\n            quit()\n        elif len(user_command) != NUM_POSITIONS:  # 410\n            print(\"BAD NUMBER OF POSITIONS\")\n        else:\n            invalid_letters = get_invalid_letters(user_command)\n            if invalid_letters > \"\":\n                print(f\"INVALID GUESS: {invalid_letters}\")\n            else:\n                guess_results = compare_two_positions(user_command, answer)\n                if guess_results[1] == NUM_POSITIONS:  # correct guess\n                    print(f\"You guessed it in {num_moves} moves!\")\n                    human_score = human_score + num_moves\n                    print_score()\n                    return  # from human turn, triumphant\n                else:\n                    print(f\"You have {guess_results[1]} blacks and {guess_results[2]} whites\")\n                    guesses.append(guess_results)\n                    num_moves += 1\n\n        if num_moves > 10:  # RAN OUT OF MOVES\n            print(\"YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!\")\n            print(f\"THE ACTUAL COMBINATION WAS: {answer}\")\n            human_score = human_score + num_moves\n            print_score()\n            return  # from human turn, defeated\n\n\ndef computer_turn() -> None:\n    global computer_score\n    while True:\n        all_possibilities = [1] * POSSIBILITIES\n        num_moves = 1\n        print(\"NOW I GUESS. THINK OF A COMBINATION.\")\n        input(\"HIT RETURN WHEN READY: \")\n        while True:\n            possible_guess = find_first_solution_of(all_possibilities)\n            if possible_guess < 0:  # no solutions left :(\n                print(\"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\")\n                print(\"TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\")\n                break  # out of inner while loop, restart computer turn\n\n            computer_guess = possibility_to_color_code(possible_guess)\n            print(f\"My guess is: {computer_guess}\")\n            blacks_str, whites_str = input(\n                \"ENTER BLACKS, WHITES (e.g. 1,2): \"\n            ).split(\",\")\n            blacks = int(blacks_str)\n            whites = int(whites_str)\n            if blacks == NUM_POSITIONS:  # Correct guess\n                print(f\"I GOT IT IN {num_moves} MOVES\")\n                computer_score = computer_score + num_moves\n                print_score()\n                return  # from computer turn\n\n            # computer guessed wrong, deduce which solutions to eliminate.\n            for i in range(0, POSSIBILITIES):\n                if all_possibilities[i] == 0:  # already ruled out\n                    continue\n                possible_answer = possibility_to_color_code(i)\n                comparison = compare_two_positions(\n                    possible_answer, computer_guess\n                )\n                if (blacks != comparison[1]) or (whites != comparison[2]):\n                    all_possibilities[i] = 0\n\n            if num_moves == 10:\n                print(\"I USED UP ALL MY MOVES!\")\n                print(\"I GUESS MY CPU IS JUST HAVING AN OFF DAY.\")\n                computer_score = computer_score + num_moves\n                print_score()\n                return  # from computer turn, defeated.\n            num_moves += 1\n\n\ndef find_first_solution_of(all_possibilities: List[int]) -> int:\n    \"\"\"Scan through all_possibilities for first remaining non-zero marker,\n    starting from some random position and wrapping around if needed.\n    If not found return -1.\"\"\"\n    start = int(POSSIBILITIES * random.random())\n    for i in range(0, POSSIBILITIES):\n        solution = (i + start) % POSSIBILITIES\n        if all_possibilities[solution]:\n            return solution\n    return -1\n\n\n# 470\ndef get_invalid_letters(user_command) -> str:\n    \"\"\"Makes sure player input consists of valid colors for selected game configuration.\"\"\"\n    valid_colors = COLOR_LETTERS[:NUM_COLORS]\n    invalid_letters = \"\"\n    for letter in user_command:\n        if letter not in valid_colors:\n            invalid_letters = invalid_letters + letter\n    return invalid_letters\n\n\n# 2000\ndef print_board(guesses) -> None:\n    \"\"\"Print previous guesses within the round.\"\"\"\n    print(\"Board\")\n    print(\"Move\\tGuess\\tBlack White\")\n    for idx, guess in enumerate(guesses):\n        print(f\"{idx + 1}\\t{guess[0]}\\t{guess[1]}     {guess[2]}\")\n\n\ndef possibility_to_color_code(possibility: int) -> str:\n    \"\"\"Accepts a (decimal) number representing one permutation in the realm of\n    possible secret codes and returns the color code mapped to that permutation.\n    This algorithm is essentially converting a decimal  number to a number with\n    a base of #num_colors, where each color code letter represents a digit in\n    that #num_colors base.\"\"\"\n    color_code: str = \"\"\n    pos: int = NUM_COLORS ** NUM_POSITIONS  # start with total possibilities\n    remainder = possibility\n    for _ in range(NUM_POSITIONS - 1, 0, -1):  # process all but the last digit\n        pos = pos // NUM_COLORS\n        color_code += COLOR_LETTERS[remainder // pos]\n        remainder = remainder % pos\n    color_code += COLOR_LETTERS[remainder]  # last digit is what remains\n    return color_code\n\n\n# 4500\ndef compare_two_positions(guess: str, answer: str) -> List[Union[str, int]]:\n    \"\"\"Returns blacks (correct color and position) and whites (correct color\n    only) for candidate position (guess) versus reference position (answer).\"\"\"\n    blacks = 0\n    whites = 0\n    initial_guess = guess\n    increment = 0\n    for pos in range(0, NUM_POSITIONS):\n        if guess[pos] != answer[pos]:\n            for pos2 in range(0, NUM_POSITIONS):\n                if guess[pos] == answer[pos2] and guess[pos2] != answer[pos2]:  # correct color but not correct place\n                    whites = whites + 1\n                    answer = answer[:pos2] + chr(increment) + answer[pos2 + 1:]\n                    guess = guess[:pos] + chr(increment + 1) + guess[pos + 1:]\n                    increment = increment + 2\n        else:  # correct color and placement\n            blacks = blacks + 1\n            # THIS IS DEVIOUSLY CLEVER\n            guess = guess[:pos] + chr(increment + 1) + guess[pos + 1:]\n            answer = answer[:pos] + chr(increment) + answer[pos + 1:]\n            increment = increment + 2\n    return [initial_guess, blacks, whites]\n\n\n# 5000 + logic from 1160\ndef print_score(is_final_score: bool = False) -> None:\n    \"\"\"Print score after each turn ends, including final score at end of game.\"\"\"\n    if is_final_score:\n        print(\"GAME OVER\")\n        print(\"FINAL SCORE:\")\n    else:\n        print(\"SCORE:\")\n    print(f\"     COMPUTER {computer_score}\")\n    print(f\"     HUMAN    {human_score}\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "60_Mastermind/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "60_Mastermind/rust/Mastermind/Cargo.toml",
    "content": "[package]\nname = \"mastermind\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "60_Mastermind/rust/Mastermind/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "60_Mastermind/rust/Mastermind/src/main.rs",
    "content": "use rand::{Rng, prelude::{thread_rng, ThreadRng}};\nuse std::{io, fmt::Display, str::FromStr};\n\n//DATA\nconst COLORS: [&str;8] = [\"Black \", \"White \",\"Red \",\"Green \",\"Orange \",\"Yellow \", \"Purple \", \"Tan \"]; //all available colors\nconst LETTERS: &str = \"BWRGOYPT\"; //letters representing the above colors\n\nstruct CODE {\n    code: Vec<usize>, //maybe use a char array later, idk\n\n}\nimpl CODE {\n    /**\n     * create generic, empty code\n     */\n    fn new() -> CODE {\n        return CODE{code: Vec::new()};\n    }\n    /**\n     * generates and returns a random CODE with the given parameters\n     */\n    fn new_random(rng: &mut ThreadRng, num_colors: usize, num_positions: usize) -> CODE {\n        //data\n        let mut code = CODE{code: Vec::new()};\n        //generate random combination of colors\n        for _i in 0..num_positions {\n            code.code.push(rng.gen_range(0..num_colors));\n        }\n        return code;\n    }\n    /**\n     * converts input_int from base 10 to base num_colors to generate the code\n     * input_int must be between 0 and num_colors.pow(num_positions)\n     */\n    fn new_from_int(mut input_int: usize, num_colors: usize, num_positions: usize) -> CODE {\n        //DATA\n        let mut converted_number:Vec<_> = Vec::new();\n        assert!(2 <= num_colors && num_colors <= 36); //if num_colors is outside of this range, things break later on\n\n        //convert input_int into a code by effectively converting input_int from base 10 to base n where n is num_colors, uses some fancy stuff to do this\n        loop {\n            converted_number.push(std::char::from_digit((input_int % num_colors) as u32, num_colors as u32).unwrap()); //\n            input_int /= num_colors;\n            if input_int == 0 {break}\n        }\n\n        while converted_number.len() < num_positions {converted_number.push('0');} // fill remaining space with zero's\n        let converted_number: Vec<_> = converted_number.iter().rev().map(|e| e.to_digit(num_colors as u32).unwrap() as usize).collect(); //reverse the vector and convert it to integers\n        return CODE{code: converted_number};\n    }\n    /**\n     * returns a code parsed from the passed string\n     */\n    fn new_from_string(input_string: String, num_colors: usize) -> Option<CODE> {\n        let valid_chars = &LETTERS[0..num_colors];\n        //DATA\n        let new_code = CODE{\n            code:\n            input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase\n            .filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS\n            .map( |x| -> usize {valid_chars.find(x).expect(\"invalid character\")})//convert all the chars into usizes representing their index in LETTERS\n            .collect() //wrap this iterator up into a vector\n        };\n        //if code is empty, return None, otherwise return Some(code)\n        if new_code.code.is_empty() {return None;}\n        else {return Some(new_code);}\n    }\n\n    /**\n     * returns a string containing the code represented as characters\n     */\n    fn _as_human_readible_chars(&self) -> String {\n        return self.code.iter().map(|i|->char{LETTERS.chars().nth(*i).expect(\"index out of bounds\")}).collect();\n    }\n    /**\n     * returns a string containing the code represented as words\n     */\n    fn _as_human_readible_words(&self) -> String {\n        return self.code.iter().map(|i|->&str{COLORS.iter().nth(*i).expect(\"index out of bounds\")}).collect();\n    }\n}\nstruct GUESS {\n    code: CODE,\n    blacks: usize,\n    whites: usize,\n}\nimpl GUESS {\n    /**\n     * create a new guess, and evaluate it\n     */\n    fn new(code: CODE) -> GUESS {\n        return GUESS{code:code, blacks:0,whites:0 };\n    }\n\n    /**\n     * evaulates itself for the number of black and white pegs it should have for a given answer\n     */\n    fn evaluate(&mut self, answer:&CODE) {\n        //data\n        let mut consumed = vec![false;answer.code.len()];\n\n        if self.code.code.len() != answer.code.len() {\n            panic!(\"only codes of the same length can be compared\");\n        }\n\n        for i in 0..answer.code.len() {\n            if self.code.code[i] == answer.code[i] { //correct value correct place\n                self.blacks += 1;\n                consumed[i] = true;\n            }\n            else {\n                //check for correct value incorrect place, don't count positions that are already exact matches\n                for j in 0..answer.code.len() {\n                    if !consumed[j] && self.code.code[i] == answer.code[j] && self.code.code[j] != answer.code[j] {\n                        self.whites += 1;\n                        consumed[j] = true;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nfn main() {\n    //DATA\n    let mut rng = thread_rng();\n    let num_colors: usize;\n    let num_positions: usize;\n    let num_rounds: usize;\n    let num_guesses: usize;\n    let total_posibilities: usize;\n\n    let mut human_score: usize = 0;\n    let mut computer_score: usize = 0;\n\n    //print welcome message\n    welcome();\n\n    //ask user for a number of colors, positions, and rounds\n    num_colors = get_number_from_user_input(\"NUMBER OF COLORS\", \"\", 1, COLORS.len());\n    num_positions = get_number_from_user_input(\"NUMBER OF POSITIONS\", \"\", 2, 10);\n    num_rounds = get_number_from_user_input(\"NUMBER OF ROUNDS\", \"\", 1, 10);\n    num_guesses = get_number_from_user_input(\"NUMBER OF GUESSES\", \"\", 10, 0);\n\n\n    //print number of posibilities\n    total_posibilities = num_colors.pow(num_positions as u32);\n    println!(\"\\nTOTAL POSSIBILITIES = {}\\n\", total_posibilities);\n\n    //print color letter table\n    print_color_letter_table(num_colors);\n\n    //game loop\n    for round_num in 1..=num_rounds {\n        //data\n        let mut num_moves: usize = 1;\n        let mut answer: CODE;\n        let mut guess: GUESS;\n        let mut guesses: Vec<GUESS> = Vec::new();\n        let mut all_possibilities = vec![true; total_posibilities];\n\n\n        //print round number\n        println!(\"\\n\\nROUND NUMBER: {}\", round_num);\n\n        //human player is code-breaker, computer is code-maker\n        //generate a combination\n        answer = CODE::new_random(&mut rng, num_colors, num_positions);\n        //println!(\"CODE: {:?}\", answer._as_human_readible_chars()); //this is for troubleshooting, prints the code converted back into characters\n\n        //round loop\n        loop {\n            //loop condition\n            if num_moves > num_guesses {\n                println!(\"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\");\n                println!(\"THE ACTUAL COMBINATION WAS: {}\", answer._as_human_readible_chars());\n                human_score += num_moves;\n                print_scores(human_score,computer_score);\n                break;\n            }\n\n            //input loop\n            guess = GUESS::new(loop {\n                println!(\"\\nMOVE # {} GUESS: \", num_moves);\n\n                //get player move\n                let mut raw_input = String::new(); //temp variable to store user input\n                io::stdin().read_line(&mut raw_input).expect(\"CANNOT READ INPUT!\"); //read user input from standard input and store it to raw_input\n\n                //attempt to parse input\n                if raw_input.trim().eq_ignore_ascii_case(\"board\") {\n                    //print the board state\n                    print_board(&guesses);\n                    continue; //run loop again\n                }\n                else if raw_input.trim().eq_ignore_ascii_case(\"quit\") {\n                    //quit the game\n                    println!(\"QUITTER!  MY COMBINATION WAS: {}\\nGOOD BYE\", answer._as_human_readible_words());\n                    return; //exit the game\n                }\n                else {\n                    //parse input for a code\n                    match CODE::new_from_string(raw_input, num_colors) {\n                        Some(code) => {\n                            //ensure code is correct length\n                            if code.code.len() != num_positions { // if not\n                                println!(\"BAD NUMBER OF POSITIONS.\");\n                                continue; //run loop again\n                            }\n                            else {break code;}//break with the code\n                        },\n                        None => continue, //run loop again\n                    }\n                }\n            });\n\n            //evaluate guess\n            guess.evaluate(&answer);\n            let blacks = guess.blacks;\n            let whites = guess.whites;\n            //add guess to the list of guesses\n            guesses.push(guess);\n\n            //tell human the results\n            if blacks >= num_positions { //guessed it correctly\n                println!(\"YOU GUESSED IT IN {} MOVES!\", num_moves);\n                human_score += num_moves;\n                print_scores(human_score,computer_score);\n                break; //break from loop\n            } else { //didn't\n                println!(\"YOU HAVE {} BLACKS AND {} WHITES.\", blacks, whites);\n                //increment moves\n                num_moves += 1;\n            }\n        }\n\n        //computer is code-breaker, human player is code-maker\n        println!(\"\\nNOW I GUESS.  THINK OF A COMBINATION.\\nHIT RETURN WHEN READY: \");\n        //prompt user to give a valid combination #730\n        //input loop\n        answer = loop {\n            let mut raw_input = String::new(); //temp variable to store user input\n            io::stdin().read_line(&mut raw_input).expect(\"CANNOT READ INPUT!\"); //read user input from standard input and store it to raw_input\n\n            //attempt to create a code from the user input, if successful break the loop returning the code\n            if let Some(code) = CODE::new_from_string(raw_input, num_colors) {\n                if code.code.len() == num_positions {break code;} //exit loop with code\n                else {println!(\"CODE MUST HAVE {} POSITIONS\", num_positions);continue;} //tell them to try again\n            }\n\n            println!(\"INVALID CODE.  TRY AGAIN\"); //if unsuccessful, this is printed and the loop runs again\n        };\n\n        //reset some things in preparation for computer play\n        guesses.clear();\n        num_moves = 0;\n        //let num_colors = *answer.code.iter().max().unwrap(); //figure out the number of colors from the code | Commented bc we're enforcing that the computer cracks the same size code as the human\n        //let num_positions = answer.code.len(); //figure out the number of positions from the code | Commented bc we're enforcing that the computer cracks the same size code as the human\n\n        //round loop\n        loop {\n            //loop condition\n            if num_moves > num_guesses {\n                println!(\"I USED UP ALL MY MOVES!\");\n                println!(\"I GUESS MY CPU IS JUST HAVING AN OFF DAY.\");\n                computer_score += num_moves;\n                print_scores(human_score,computer_score);\n                break;\n            }\n\n            //randomly generate a guess //770\n            let mut guess_int = rng.gen_range(0..total_posibilities);\n            guess = GUESS::new(CODE::new());\n            //if it's possible, use it //780\n            if all_possibilities[guess_int] {\n                guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess\n            }\n            else {//if it's not possible:\n                //  search all possibilities after guess, use first valid one //790\n                for g in guess_int..total_posibilities {\n                    if all_possibilities[g] {\n                        guess_int=g;\n                        guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess\n                        break;\n                    }\n                }\n                //if none was found\n                //  search all possibilities before guess, use first valid one //820\n                if guess.code.code.is_empty() {\n                    for g in (0..guess_int).rev() {\n                        if all_possibilities[g] {\n                            guess_int=g;\n                            guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess\n                            break;\n                        }\n                    }\n                }\n                // if none where found, tell the user and start over #850\n                if guess.code.code.is_empty() {\n                    println!(\"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\");\n                    println!(\"PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\");\n                    return; //exit game\n                };\n            }\n\n            //convert guess into something readible #890\n            //print it #940\n            println!(\"MY GUESS IS: {}\", guess.code._as_human_readible_chars());\n            //ask user for feedback, #980\n            let blacks=get_number_from_user_input(\"BLACKS: \", \"\", 0, num_positions);\n            let whites=get_number_from_user_input(\"WHITES: \", \"\", 0, num_positions);\n\n            //if we got it, end #990\n            if blacks >= num_positions { //guessed it correctly\n                println!(\"I GOT IT IN {} MOVES!\", num_moves);\n                computer_score += num_moves;\n                print_scores(human_score,computer_score);\n                break; //break from loop\n            } else { //didn't\n                all_possibilities[guess_int] = false;\n                //if we didn't, eliminate the combinations that don't work\n                //we know the number of black and white pegs for a valid answer, so eleminate all that get different amounts\n                all_possibilities.iter_mut().enumerate().for_each(|b| {\n                    if *b.1 { //filter out ones we already know aren't possible\n                        let mut tmp_guess = GUESS::new(CODE::new_from_int(b.0, num_colors, num_positions));\n                        tmp_guess.evaluate(&guess.code); //compare with computer guess\n                        if blacks != tmp_guess.blacks || whites != tmp_guess.whites { //if number of blacks/whites is different, set it to false\n                            *b.1 = false;\n                        }\n                    }\n                });\n\n                //increment moves\n                num_moves += 1;\n            }\n\n\n        }\n\n    }\n}\n\n/**\n * print the welcome message\n */\nfn welcome() {\n    println!(\"\n                             MASTERMIND\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n    \");\n}\n\n/**\n * print scores\n */\nfn print_scores(human_score:usize, computer_score:usize) {\n    println!(\"SCORE\\n\\tCOMPUTER: {}\\n\\tHUMAN: {}\", computer_score, human_score);\n}\n\n/**\n * print the color - letter table\n * only prints the first num_colors pairs\n */\nfn print_color_letter_table(num_colors: usize) {\n    println!(\"COLOR\\tLETTER\");\n    println!(\"=====\\t======\");\n    for i in 0..num_colors {\n        println!(\"{}\\t{}\", COLORS[i], &LETTERS[i..i+1]);\n    }\n}\n\nfn print_board(guesses: &Vec<GUESS>) {\n    println!(\"BOARD\");\n    println!(\"MOVE\\tGUESS\\t\\tBLACK\\tWhite\");\n    for guess in guesses.iter().enumerate() {\n        println!(\"{}\\t{}\\t\\t{}\\t{}\", guess.0,guess.1.code._as_human_readible_chars(),guess.1.blacks,guess.1.whites);\n    }\n}\n\n/**\n * gets a number from user input\n * pass an empty &str for error_message if you don't want one printed\n * pass a min lower  than the max to have minimun and maximun bounds\n * pass a min higher than the max to only have a minumum bound\n * pass a min equal   to  the max to only have a maximun bound\n */\nfn get_number_from_user_input<T: Display + PartialOrd + FromStr>(prompt: &str, error_message: &str, min:T, max:T) -> T {\n    //DATA\n    let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n    //input loop\n    return loop {\n\n        //print prompt\n        println!(\"{}\", prompt);\n        //read user input from standard input, and store it to raw_input\n        raw_input.clear(); //clear input\n        io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n        //from input, try to read a number\n        if let Ok(i) = raw_input.trim().parse() {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    break i; //exit the loop with the value i, returning it\n                } else {println!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max);} //print error message specific to this case\n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {break i;} else {println!(\"NO LESS THAN {}, PLEASE!\", min);}\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {break i;} else {println!(\"NO MORE THAN {}, PLEASE!\", max);}\n            }\n            continue; //continue to the next loop iteration\n        };\n        //this is only reached if a number couldn't be parsed from the input\n        if !error_message.is_empty() {println!(\"{}\",error_message);} //if they gave an error message to use, print it\n    };\n}\n"
  },
  {
    "path": "60_Mastermind/rust/Mastermind_refactored_for_conventions/Cargo.toml",
    "content": "[package]\nname = \"mastermind_refactored_for_conventions\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\""
  },
  {
    "path": "60_Mastermind/rust/Mastermind_refactored_for_conventions/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "60_Mastermind/rust/Mastermind_refactored_for_conventions/src/lib.rs",
    "content": "/*\n lib.rs contains all the logic of the program\n*/\nuse rand::{Rng, prelude::thread_rng}; //rng\nuse std::error::Error; //better errors\nuse std::io::{self, Write}; //io interactions\nuse std::{str::FromStr, fmt::Display}; //traits\n\n//DATA\nconst COLORS: [&str;8] = [\"Black \", \"White \",\"Red \",\"Green \",\"Orange \",\"Yellow \", \"Purple \", \"Tan \"]; //all available colors\nconst LETTERS: &str = \"BWRGOYPT\"; //letters representing the above colors\n\n/// handles setup for the game\npub struct Config {\n    num_colors: usize,\n    num_positions: usize,\n    num_rounds: usize,\n    num_guesses: usize,\n    total_possibilities: usize,\n}\nimpl Config {\n    /// creates and returns a new Config from user input\n    pub fn new() -> Result<Config, Box<dyn Error>> {\n        //DATA\n        let mut config: Config = Config { \n            num_colors: 0,\n            num_positions: 0,\n            num_rounds: 0,\n            num_guesses: 0,\n            total_possibilities: 0,\n        };\n\n        //get data from user input\n        //input loop\n        loop {match get_number_from_input(\"NUMBER OF COLORS: \", 2, COLORS.len()) {\n            Ok(num) => {\n                config.num_colors = num;\n                break;\n            },\n            Err(e) => eprintln!(\"{}\",e),\n        }}\n        //input loop\n        loop {match get_number_from_input(\"NUMBER OF POSITIONS: \", 2, 10) {\n            Ok(num) => {\n                config.num_positions = num;\n                break;\n            },\n            Err(e) => eprintln!(\"{}\",e),\n        }}\n        //input loop\n        loop {match get_number_from_input(\"NUMBER OF ROUNDS: \", 1, 10) {\n            Ok(num) => {\n                config.num_rounds = num;\n                break;\n            },\n            Err(e) => eprintln!(\"{}\",e),\n        }}\n        //input loop\n        loop {match get_number_from_input(\"NUMBER OF GUESSES: \", 10, 0) {\n            Ok(num) => {\n                config.num_guesses = num;\n                break;\n            },\n            Err(e) => eprintln!(\"{}\",e),\n        }}\n        //calc total posibilities\n        config.total_possibilities = config.num_colors.pow(config.num_positions as u32);\n\n        //return new config\n        return Ok(config);\n    }\n}\n\n/// run the program\npub fn run(config: &Config) -> Result<(), Box<dyn Error>> {\n    //DATA\n    let mut human_score: usize = 0;\n    let mut computer_score: usize = 0;\n\n    //print number of possibilities\n    println!(\"\\nTOTAL POSSIBILITIES = {}\\n\", config.total_possibilities);\n\n    //print color letter table\n    print_color_letter_table(config.num_colors);\n\n    //for every round\n    for round in 1..=config.num_rounds {\n        //print round number\n        println!(\"\\n\\nROUND NUMBER: {}\", round);\n\n        //computer as code-maker\n        if let Some(score) = play_round_computer_codemaker(config) {\n            human_score += score;\n        } else {break;}\n\n        //human as code-maker\n        if let Some(score) = play_round_human_codemaker(config) {\n            computer_score += score;\n        } else {break;}\n\n        //print scores\n        print_scores(human_score,computer_score);\n    }\n\n    //return to main\n    Ok(())\n}\n\n/// run a round with computer as code-maker\n/// returns the number of turns it takes the human to guess the secret code\nfn play_round_computer_codemaker(config: &Config) -> Option<usize> {\n    //DATA\n    let mut rng = thread_rng();\n    let mut guesses: Vec<Code> = Vec::new();\n    let secret: Code;\n\n    //generate secret\n    secret = Code::new_from_int(rng.gen_range(0..config.num_colors.pow(config.num_positions.try_into().unwrap())), config);\n\n    //round loop\n    for human_moves in 1..=config.num_guesses {\n        //get guess from user input\n        //input loop\n        let mut guess = loop {\n            //get input\n            let user_input = get_string_from_user_input(format!(\"\\nMOVE # {} GUESS: \", human_moves).as_str()).expect(\"something went wrong getting user guess\");\n\n            //parse input\n            if user_input.trim().eq_ignore_ascii_case(\"board\") { //print the board state\n                print_board(&guesses);\n                continue; //run input loop again\n            } else if user_input.trim().eq_ignore_ascii_case(\"quit\") { //quit the game\n                println!(\"QUITTER!  MY COMBINATION WAS: {}\\nGOOD BYE\", secret.as_human_readible_chars());\n                return None; //exit the game\n            } else {\n                //parse input for a code\n                match Code::new_from_string(&user_input, &config) {\n                    Ok(code) => {\n                        //ensure code is correct length\n                        if code.code.len() != config.num_positions { // if not\n                            println!(\"BAD NUMBER OF POSITIONS.\");\n                            continue; //run loop again\n                        }\n                        else {break code;}//break with the code\n                    },\n                    Err(e) => {eprintln!(\"{}\",e); continue;}, //run loop again\n                }\n            }\n        };\n        \n        //evaluate guess\n        guess.evaluate(&secret).expect(\"something went wrong evaluating user guess\");\n\n        //tell user the results\n        if guess.black_pins >= config.num_positions { //guessed it correctly\n            println!(\"YOU GUESSED IT IN {} MOVES!\", human_moves);\n            return Some(human_moves); //exit function\n        } else { //didn't\n            println!(\"YOU HAVE {} BLACKS AND {} WHITES.\", guess.black_pins, guess.white_pins);\n        }\n\n        //add guess to the list of guesses\n        guesses.push(guess);\n    }\n\n    //only runs if user doesn't guess the code\n    println!(\"YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\");\n    println!(\"THE ACTUAL COMBINATION WAS: {}\", secret.as_human_readible_chars());\n    return Some(config.num_guesses); //max score gain per round\n}\n\n/// run a round with human as code-maker\n/// returns the number of turns it takes the computer to guess the secret code\nfn play_round_human_codemaker(config: &Config) -> Option<usize>{\n    //DATA\n    let mut rng = thread_rng();\n    let mut all_possibilities = vec![true; config.total_possibilities];\n    let _secret: Code;\n\n\n    //get a secret code from user input\n    println!(\"\\nNOW I GUESS.  THINK OF A COMBINATION.\\nHIT RETURN WHEN READY: \");\n    // input loop\n    _secret = loop {\n        //get input\n        let user_input = get_string_from_user_input(\"\").expect(\"something went wrong getting secret from user\");\n\n        //parse input\n        if let Ok(code) = Code::new_from_string(&user_input, config) {\n            if code.code.len() == config.num_positions {break code;} //exit loop with code\n            else {println!(\"CODE MUST HAVE {} POSITIONS\", config.num_positions);continue;} //tell them to try again\n        }\n        println!(\"INVALID CODE.  TRY AGAIN\"); //if unsuccessful, this is printed and the loop runs again\n    };\n\n    //round loop\n    for computer_moves in 1..=config.num_guesses {\n        let mut guess: Code = Code::new();\n\n        //randomly generate a guess //770\n        let mut guess_int = rng.gen_range(0..config.total_possibilities);\n        // if possible, use it //780\n        if all_possibilities[guess_int] {\n            guess = Code::new_from_int(guess_int, &config); //create guess\n        }\n        else {// if not possible:\n            // search all possibilities after guess, use first valid one //790\n            for g in guess_int..config.total_possibilities {\n                if all_possibilities[g] {\n                    guess_int=g;\n                    guess = Code::new_from_int(guess_int, &config); //create guess\n                    break;\n                }\n            }\n            // if none was found\n            //  search all possibilities before guess, use first valid one //820\n            if guess.code.is_empty() {\n                for g in (0..guess_int).rev() {\n                    if all_possibilities[g] {\n                        guess_int=g;\n                        guess = Code::new_from_int(guess_int, &config); //create guess\n                        break;\n                    }\n                }\n            }\n\n            // if none where found, tell the user and start over #850\n            if guess.code.is_empty() {\n                println!(\"YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\");\n                println!(\"PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\");\n                return None; //exit game\n            };\n        }\n\n        //convert guess into something readible #890\n        //print it #940\n        println!(\"MY GUESS IS: {}\", guess.as_human_readible_chars());\n\n        //ask user for feedback, #980\n        // input loop for black pegs\n        loop {match get_number_from_input(\"BLACKS: \", 0, config.num_positions) {\n            Ok(num) => {\n                guess.black_pins = num;\n                break;\n            },\n            Err(e) => eprintln!(\"{}\",e),\n        }}\n        // input loop for white pegs\n        loop {match get_number_from_input(\"WHITES: \", 0, config.num_positions) {\n            Ok(num) => {\n                guess.white_pins = num;\n                break;\n            },\n            Err(e) => eprintln!(\"{}\",e),\n        }}\n\n        //if computer guessed it, end #990\n        if guess.black_pins >= config.num_positions { //guessed it correctly\n            println!(\"I GOT IT IN {} MOVES!\", computer_moves);\n            return Some(computer_moves); //exit function\n        } else { //didn't\n            all_possibilities[guess_int] = false;\n            //if we didn't, eliminate the combinations that don't work\n            //we know the number of black and white pegs for a valid answer, so eleminate all that get different amounts\n            all_possibilities.iter_mut().enumerate().for_each(|b| {\n                if *b.1 { //filter out ones we already know aren't possible\n                    let mut tmp_guess = Code::new_from_int(b.0, &config);\n                    tmp_guess.evaluate(&guess).expect(\"something went wrong evaluation the computer's guess\"); //compare with computer guess\n                    if (guess.black_pins != tmp_guess.black_pins) || (guess.white_pins != tmp_guess.white_pins) { //if number of blacks/whites is different, set it to false\n                        *b.1 = false;\n                    }\n                }\n            });\n        }\n    }\n\n    //only runs if computer doesn't guess the code\n    println!(\"I USED UP ALL MY MOVES!\");\n    println!(\"I GUESS MY CPU IS JUST HAVING AN OFF DAY.\");\n    return Some(config.num_guesses); //max moves the computer could've taken\n}\n\nstruct Code {\n    code: Vec<usize>,\n    black_pins: usize,\n    white_pins: usize,\n}\nimpl Code {\n    /// create generic, empty code\n    fn new() -> Code {\n        return Code{code: Vec::new(), black_pins:0, white_pins:0};\n    }\n    /// converts input_int from base 10 to base num_colors to generate the code\n    /// input_int must be between 0 and num_colors.pow(num_positions)\n    fn new_from_int(mut input_int: usize, config: &Config) -> Code {\n        //DATA\n        let mut converted_number:Vec<_> = Vec::new();\n        assert!(2 <= config.num_colors && config.num_colors <= 36); //if num_colors is outside of this range, things break later on\n\n        //convert input_int into a code by effectively converting input_int from base 10 to base n where n is num_colors, uses some fancy stuff to do this\n        loop {\n            converted_number.push(std::char::from_digit((input_int % config.num_colors).try_into().unwrap(), config.num_colors.try_into().unwrap()).unwrap()); //\n            input_int /= config.num_colors;\n            if input_int == 0 {break}\n        }\n        \n        while converted_number.len() < config.num_positions {converted_number.push('0');} // fill remaining space with zero's\n        let converted_number: Vec<_> = converted_number.iter().rev().map(|e| e.to_digit(config.num_colors.try_into().unwrap()).unwrap() .try_into().unwrap()).collect(); //reverse the vector and convert it to integers\n        return Code{code: converted_number, black_pins:0, white_pins:0};\n    }\n    /// returns a code parsed from the passed string\n    fn new_from_string(input_string: &str, config: &Config) -> Result<Code,Box<dyn Error>> {\n        let valid_chars = &LETTERS[0..config.num_colors];\n        //DATA\n        let new_code = Code{\n            code: {\n                input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase\n                .filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS\n                .map( |x| -> usize {valid_chars.find(x).expect(\"invalid character\")})//convert all the chars into usizes representing their index in LETTERS\n                .collect() //wrap this iterator up into a vector\n            },\n            black_pins: 0,\n            white_pins: 0,\n        };\n        //if code is empty, return None, otherwise return Some(code)\n        if new_code.code.is_empty() {return Err(String::from(\"Input String did not contain enough valid characters\").into());}\n        else {return Ok(new_code);}\n    }\n\n    /// returns a string containing the code represented as characters\n    fn as_human_readible_chars(&self) -> String {\n        return self.code.iter().map(|i|->char{LETTERS.chars().nth(*i).expect(\"index out of bounds\")}).collect();\n    }\n\n    /**\n     * evaulates itself for the number of black and white pegs it should have when compared to a given secret\n     */\n    fn evaluate(&mut self, secret:&Code) -> Result<(),Box<dyn Error>> {\n        //data\n        let mut consumed = vec![false;secret.code.len()];\n\n        if self.code.len() != secret.code.len() {\n            return Err(String::from(\"only codes of the same length can be compared\").into());\n        }\n\n        for i in 0..secret.code.len() {\n            if self.code[i] == secret.code[i] { //correct value correct place\n                self.black_pins += 1;\n                consumed[i] = true;\n            }\n            else {\n                //check for correct value incorrect place, don't count positions that are already exact matches\n                for j in 0..secret.code.len() {\n                    if !consumed[j] && self.code[i] == secret.code[j] && self.code[j] != secret.code[j] {\n                        self.white_pins += 1;\n                        consumed[j] = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        return Ok(())\n    }\n}\n\n\n\n/// print scores\nfn print_scores(human_score:usize, computer_score:usize) {\n    println!(\"SCORE\\n\\tCOMPUTER: {}\\n\\tHUMAN: {}\", computer_score, human_score);\n}\n/// print the color - letter table\n/// only prints the first num_colors pairs\nfn print_color_letter_table(num_colors:usize) {\n    println!(\"COLOR\\tLETTER\");\n    println!(\"=====\\t======\");\n    for i in 0..num_colors {\n        println!(\"{}\\t{}\", COLORS[i], &LETTERS[i..i+1]);\n    }\n}\n/// prints the board state, previous guesses and the number of black/white pins for each\nfn print_board(guesses: &[Code]) {\n    println!(\"BOARD\");\n    println!(\"MOVE\\tGUESS\\t\\tBLACK\\tWhite\");\n    for guess in guesses.iter().enumerate() {\n        println!(\"{}\\t{}\\t\\t{}\\t{}\", guess.0,guess.1.as_human_readible_chars(),guess.1.black_pins,guess.1.white_pins);\n    }\n}\n\n\n\n/// gets a string from user input\nfn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\", prompt);\n    //make sure it's printed before getting input\n    io::stdout().flush().expect(\"couldn't flush stdout\");\n\n    //read user input from standard input, and store it to raw_input, then return it or an error as needed\n    raw_input.clear(); //clear input\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),\n        Err(err) => return Err(format!(\"ERROR: CANNOT READ INPUT!: {}\", err).into()),\n    }\n}\n/// generic function to get a number from the passed string (user input)\n/// pass a min lower  than the max to have minimun and maximun bounds\n/// pass a min higher than the max to only have a minumum bound\n/// pass a min equal   to  the max to only have a maximun bound\n/// \n/// Errors:\n/// no number on user input\nfn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {\n    //DATA\n    let raw_input: String;\n    let processed_input: String;\n\n    \n    //input looop\n    raw_input = loop {\n        match get_string_from_user_input(prompt) {\n            Ok(input) => break input,\n            Err(e) => {\n                eprintln!(\"{}\",e);\n                continue;\n            },\n        }\n    };\n\n    //filter out num-numeric characters from user input\n    processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();\n\n    //from input, try to read a number\n    match processed_input.trim().parse() {\n        Ok(i) => {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    return Ok(i); //exit the loop with the value i, returning it\n                } else { //print error message specific to this case\n                    return Err(format!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max).into());\n                } \n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO LESS THAN {}, PLEASE!\", min).into());\n                }\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO MORE THAN {}, PLEASE!\", max).into());\n                }\n            }\n        },\n        Err(_e) => return Err(format!(\"Error: couldn't find a valid number in {}\",raw_input).into()),\n    }\n}\n"
  },
  {
    "path": "60_Mastermind/rust/Mastermind_refactored_for_conventions/src/main.rs",
    "content": "use std::process;//allows for some better error handling\n\nmod lib; //allows access to lib.rs\nuse lib::Config;\n\n/// main function\n/// responsibilities:\n/// - Calling the command line logic with the argument values\n/// - Setting up any other configuration\n/// - Calling a run function in lib.rs\n/// - Handling the error if run returns an error\nfn main() {\n    //greet user\n    welcome();\n\n    // set up other configuration\n    let mut config = Config::new().unwrap_or_else(|err| {\n        eprintln!(\"Problem configuring program: {}\", err);\n        process::exit(1);\n    });\n\n    // run the program\n    if let Err(e) = lib::run(&mut config) {\n        eprintln!(\"Application Error: {}\", e); //use the eprintln! macro to output to standard error\n        process::exit(1); //exit the program with an error code\n    }\n\n    //end of program\n    println!(\"THANKS FOR PLAYING!\");\n}\n\n/// print the welcome message\nfn welcome() {\n    println!(\"\n                             MASTERMIND\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n    \");\n}\n"
  },
  {
    "path": "60_Mastermind/vbnet/Mastermind.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Mastermind\", \"Mastermind.vbproj\", \"{B32A8054-8790-4810-93A8-CD0C740CEBD5}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "60_Mastermind/vbnet/Mastermind.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Mastermind</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "60_Mastermind/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "61_Math_Dice/README.md",
    "content": "### Math Dice\n\nThe program presents pictorial drill on addition facts using printed dice with no reading involved. It is good for beginning addition, since the answer can be derived from counting spots on the dice as well as by memorizing math facts or awareness of number concepts. It is especially effective run on a CRT terminal.\n\nIt was originally written by Jim Gerrish, a teacher at the Bernice A. Ray School in Hanover, New Hampshire.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=113)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=128)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "61_Math_Dice/csharp/GameState.cs",
    "content": "﻿namespace MathDice\n{\n    public enum GameState\n    {\n        FirstAttempt = 0,\n        SecondAttempt = 1,\n    }\n}\n"
  },
  {
    "path": "61_Math_Dice/csharp/MathDice.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <RootNamespace>MathDice</RootNamespace>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "61_Math_Dice/csharp/MathDice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31025.194\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"MathDice\", \"MathDice.csproj\", \"{4F28D7EB-3CD6-434F-B643-0CEA5F09F96D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4F28D7EB-3CD6-434F-B643-0CEA5F09F96D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4F28D7EB-3CD6-434F-B643-0CEA5F09F96D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4F28D7EB-3CD6-434F-B643-0CEA5F09F96D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4F28D7EB-3CD6-434F-B643-0CEA5F09F96D}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {A1337DCA-4EFA-45EE-A1A9-22E37E74F362}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "61_Math_Dice/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace MathDice\n{\n    public static class Program\n    {\n        readonly static Random random = new Random();\n\n        static int DieOne = 0;\n        static int DieTwo = 0;\n\n        private const string NoPips = \"I     I\";\n        private const string LeftPip = \"I *   I\";\n        private const string CentrePip = \"I  *  I\";\n        private const string RightPip = \"I   * I\";\n        private const string TwoPips = \"I * * I\";\n        private const string Edge = \" ----- \";\n\n        static void Main(string[] args)\n        {\n            int answer;\n\n            GameState gameState = GameState.FirstAttempt;\n\n            Console.WriteLine(\"MATH DICE\".CentreAlign());\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".CentreAlign());\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\");\n            Console.WriteLine(\"WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\");\n            Console.WriteLine(\"MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\");\n            Console.WriteLine(\"TO CONCLUDE THE LESSON, TYPE CONTROL-C AS YOUR ANSWER.\");\n            Console.WriteLine();\n            Console.WriteLine();\n\n            while (true)\n            {\n                if (gameState == GameState.FirstAttempt)\n                {\n                    Roll(ref DieOne);\n                    Roll(ref DieTwo);\n\n                    DrawDie(DieOne);\n                    Console.WriteLine(\"   +\");\n                    DrawDie(DieTwo);\n                }\n\n                answer = GetAnswer();\n\n                if (answer == DieOne + DieTwo)\n                {\n                    Console.WriteLine(\"RIGHT!\");\n                    Console.WriteLine();\n                    Console.WriteLine(\"THE DICE ROLL AGAIN...\");\n\n                    gameState = GameState.FirstAttempt;\n                }\n                else\n                {\n                    if (gameState == GameState.FirstAttempt)\n                    {\n                        Console.WriteLine(\"NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.\");\n                        gameState = GameState.SecondAttempt;\n                    }\n                    else\n                    {\n                        Console.WriteLine($\"NO, THE ANSWER IS{DieOne + DieTwo}\");\n                        Console.WriteLine();\n                        Console.WriteLine(\"THE DICE ROLL AGAIN...\");\n                        gameState = GameState.FirstAttempt;\n                    }\n                }\n            }\n        }\n\n        private static int GetAnswer()\n        {\n            int answer;\n\n            Console.Write(\"      =?\");\n            var input = Console.ReadLine();\n\n            int.TryParse(input, out answer);\n\n            return answer;\n        }\n\n        private static void DrawDie(int pips)\n        {\n            Console.WriteLine(Edge);\n            Console.WriteLine(OuterRow(pips, true));\n            Console.WriteLine(CentreRow(pips));\n            Console.WriteLine(OuterRow(pips, false));\n            Console.WriteLine(Edge);\n            Console.WriteLine();\n        }\n\n        private static void Roll(ref int die) => die = random.Next(1, 7);\n\n        private static string OuterRow(int pips, bool top)\n        {\n            return pips switch\n            {\n                1 => NoPips,\n                var x when x == 2 || x == 3 => top ? LeftPip : RightPip,\n                _ => TwoPips\n            };\n        }\n\n        private static string CentreRow(int pips)\n        {\n            return pips switch\n            {\n                var x when x == 2 || x == 4 => NoPips,\n                6 => TwoPips,\n                _ => CentrePip\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "61_Math_Dice/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\nConversion Notes\n\n- There are minor spacing issues which have been preserved in this port.\n- This implementation uses switch expressions to concisely place the dice pips in the right place.\n- Random() is only pseudo-random but perfectly adequate for the purposes of simulating dice rolls.\n- Console width is assumed to be 120 chars for the purposes of centrally aligned the intro text.\n"
  },
  {
    "path": "61_Math_Dice/csharp/StringExtensions.cs",
    "content": "﻿namespace MathDice\n{\n    public static class StringExtensions\n    {\n        private const int ConsoleWidth = 120; // default console width\n\n        public static string CentreAlign(this string value)\n        {\n            int spaces = ConsoleWidth - value.Length;\n            int leftPadding = spaces / 2 + value.Length;\n\n            return value.PadLeft(leftPadding).PadRight(ConsoleWidth);\n        }\n    }\n}\n"
  },
  {
    "path": "61_Math_Dice/java/Die.java",
    "content": "import java.util.Random;\n\npublic class Die {\n    private static final int DEFAULT_SIDES = 6;\n    private int faceValue;\n    private int sides;\n    private Random generator = new Random();\n\n    /**\n     * Construct a new Die with default sides\n     */\n    public Die() {\n        this.sides = DEFAULT_SIDES;\n        this.faceValue = 1 + generator.nextInt(sides);\n    }\n\n    /**\n     * Generate a new random number between 1 and sides to be stored in faceValue\n     */\n    private void throwDie() {\n        this.faceValue = 1 + generator.nextInt(sides);\n    }\n\n\n    /**\n     * @return the faceValue\n     */\n    public int getFaceValue() {\n        return faceValue;\n    }\n\n\n    public void printDie() {\n        throwDie();\n        int x = this.getFaceValue();\n\n        System.out.println(\" ----- \");\n\n        if(x==4||x==5||x==6) {\n            printTwo();\n        } else if(x==2||x==3) {\n            System.out.println(\"| *   |\");\n        } else {\n            printZero();\n        }\n\n        if(x==1||x==3||x==5) {\n            System.out.println(\"|  *  |\");\n        } else if(x==2||x==4) {\n            printZero();\n        } else {\n            printTwo();\n        }\n\n        if(x==4||x==5||x==6) {\n            printTwo();\n        } else if(x==2||x==3) {\n            System.out.println(\"|   * |\");\n        } else {\n            printZero();\n        }\n\n        System.out.println(\" ----- \");\n    }\n\n    private void printZero() {\n        System.out.println(\"|     |\");\n    }\n\n    private void printTwo() {\n        System.out.println(\"| * * |\");\n    }\n}\n"
  },
  {
    "path": "61_Math_Dice/java/MathDice.java",
    "content": "import java.util.Scanner;\n\npublic class MathDice {\n\n    public static void main(String[] args) {\n        Scanner in = new Scanner(System.in);\n        Die dieOne = new Die();\n        Die dieTwo = new Die();\n        int guess = 1;\n        int answer;\n\n        System.out.println(\"Math Dice\");\n        System.out.println(\"https://github.com/coding-horror/basic-computer-games\");\n        System.out.println();\n        System.out.print(\"This program generates images of two dice.\\n\"\n                + \"When two dice and an equals sign followed by a question\\n\"\n                + \"mark have been printed, type your answer, and hit the ENTER\\n\" + \"key.\\n\"\n                + \"To conclude the program, type 0.\\n\");\n\n        while (true) {\n            dieOne.printDie();\n            System.out.println(\"   +\");\n            dieTwo.printDie();\n            System.out.println(\"   =\");\n            int tries = 0;\n            answer = dieOne.getFaceValue() + dieTwo.getFaceValue();\n\n            while (guess!=answer && tries < 2) {\n                if(tries == 1)\n                    System.out.println(\"No, count the spots and give another answer.\");\n                try{\n                    guess = in.nextInt();\n                } catch(Exception e) {\n                    System.out.println(\"Thats not a number!\");\n                    in.nextLine();\n                }\n\n                if(guess == 0)\n                    System.exit(0);\n\n                tries++;\n            }\n\n            if(guess != answer){\n                System.out.println(\"No, the answer is \" + answer + \"!\");\n            } else {\n                System.out.println(\"Correct\");\n            }\n            System.out.println(\"The dice roll again....\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "61_Math_Dice/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "61_Math_Dice/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "61_Math_Dice/javascript/mathdice.html",
    "content": "<html>\n<head>\n<title>MATH DICE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"mathdice.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "61_Math_Dice/javascript/mathdice.js",
    "content": "// MATH DICE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(31) + \"MATH DICE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\\n\");\n    print(\"WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\\n\");\n    print(\"MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\\n\"),\n    print(\"TO CONCLUDE THE LESSON, TYPE ZERO AS YOUR ANSWER.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    n = 0;\n    while (1) {\n        n++;\n        d = Math.floor(6 * Math.random() + 1);\n        print(\" ----- \\n\");\n        if (d == 1)\n            print(\"I     I\\n\");\n        else if (d == 2 || d == 3)\n            print(\"I *   I\\n\");\n        else\n            print(\"I * * I\\n\");\n        if (d == 2 || d == 4)\n            print(\"I     I\\n\");\n        else if (d == 6)\n            print(\"I * * I\\n\");\n        else\n            print(\"I  *  I\\n\");\n        if (d == 1)\n            print(\"I     I\\n\");\n        else if (d == 2 || d == 3)\n            print(\"I   * I\\n\");\n        else\n            print(\"I * * I\\n\");\n        print(\" ----- \\n\");\n        print(\"\\n\");\n        if (n != 2) {\n            print(\"   +\\n\");\n            print(\"\\n\");\n            a = d;\n            continue;\n        }\n        t = d + a;\n        print(\"      =\");\n        t1 = parseInt(await input());\n        if (t1 == 0)\n            break;\n        if (t1 != t) {\n            print(\"NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.\\n\");\n            print(\"      =\");\n            t1 = parseInt(await input());\n            if (t1 != t) {\n                print(\"NO, THE ANSWER IS \" + t + \"\\n\");\n            }\n        }\n        if (t1 == t) {\n            print(\"RIGHT!\\n\");\n        }\n        print(\"\\n\");\n        print(\"THE DICE ROLL AGAIN...\\n\");\n        print(\"\\n\");\n        n = 0;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "61_Math_Dice/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "61_Math_Dice/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "61_Math_Dice/mathdice.bas",
    "content": "10 PRINT TAB(31);\"MATH DICE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 PRINT \"THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\"\n50 PRINT \"WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\"\n60 PRINT \"MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\"\n70 PRINT \"TO CONCLUDE THE LESSON, TYPE CONTROL-C AS YOUR ANSWER.\"\n80 PRINT\n90 PRINT\n100 N=N+1\n110 D=INT(6*RND(1)+1)\n120 PRINT\" ----- \"\n130 IF D=1 THEN 200\n140 IF D=2 THEN 180\n150 IF D=3 THEN 180\n160 PRINT \"I * * I\"\n170 GOTO 210\n180 PRINT \"I *   I\"\n190 GOTO 210\n200 PRINT \"I     I\"\n210 IF D=2 THEN 260\n220 IF D=4 THEN 260\n230 IF D=6 THEN 270\n240 PRINT \"I  *  I\"\n250 GOTO 280\n260 PRINT \"I     I\"\n265 GOTO 280\n270 PRINT \"I * * I\"\n280 IF D=1 THEN 350\n290 IF D=2 THEN 330\n300 IF D=3 THEN 330\n310 PRINT \"I * * I\"\n320 GOTO 360\n330 PRINT \"I   * I\"\n340 GOTO 360\n350 PRINT \"I     I\"\n360 PRINT \" ----- \"\n370 PRINT\n375 IF N=2 THEN 500\n380 PRINT \"   +\"\n381 PRINT\n400 A=D\n410 GOTO 100\n500 T=D+A\n510 PRINT \"      =\";\n520 INPUT T1\n530 IF T1=T THEN 590\n540 PRINT \"NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.\"\n541 PRINT \"      =\";\n550 INPUT T2\n560 IF T2=T THEN 590\n570 PRINT \"NO, THE ANSWER IS\";T\n580 GOTO 600\n590 PRINT \"RIGHT!\"\n600 PRINT\n601 PRINT \"THE DICE ROLL AGAIN...\"\n610 PRINT\n615 N=0\n620 GOTO 100\n999 END\n"
  },
  {
    "path": "61_Math_Dice/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "61_Math_Dice/perl/mathdice.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\n&main;\n\n# Main subroutine\n\nsub main {\n\t&print_intro;\n\twhile (1==1) {\n\t\t&game_play; \t\t\t\t\t#function that actually plays the game\n\t}\n}\n\nsub game_play {\n\tmy $num = 0;\n\tmy $sum = 0;\n\tmy $tries = 0;\n\tuntil ($num == 2) {               \t# there are 2 dice rolls so we do it until the num equals 2\n\t\t$num++;\n\t\tmy $roll = 1+int rand(6);\t\t# getting a random number between 1 and 6\n\t\t&print_dice($roll);\t\t\t\t# function call to print out the dice\n\t\t$sum = $sum + $roll;\t\t\t# keeping track of the summary\n\t\t#print \"Sum: $sum Roll: $roll\\n\";\n\t\tif ($num == 1) {\n\t\t\tprint \"\\n   +\\n\\n\";\t\t\t# if its the first roll then print an addition sign\n\t\t}\n\t\tif ($num == 2) {\n\t\t\tprint \"     =? \";\t\t\t# if its the second roll print the equals sign and wait for an answer\n\t\t\tmy $answer = <STDIN>;\n\t\t\tchomp($answer);\n\t\t\tif ($answer == 0) {\n\t\t\t\tdie \"You input '0', Thanks for playing!\\n\";\n\t\t\t}\n\t\t\telsif ($answer == $sum) {\n\t\t\t\tprint \"RIGHT!\\n\\nTHE DICE ROLL AGAIN\\n\\n\";\n\t\t\t}\n\t\t\telse {\t\t\t\t\t\t# code execution if they don't get the right answer\n\t\t\t\tprint \"NO,COUNT THE SPOTS AND GIVE ANOTHER ANSWER\\n\";\n\t\t\t\tprint \"     =? \";\n\t\t\t\t$answer = <STDIN>;\n\t\t\t\tchomp($answer);\n\t\t\t\tif ($answer == $sum){\n\t\t\t\t\tprint \"RIGHT!\\n\\nTHE DICE ROLL AGAIN\\n\\n\";\n\t\t\t\t}\n\t\t\t    else {\n\t\t\t\t\tprint \"N0, THE ANSWER IS $sum\\n\";\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n}\n\nsub print_dice {\n\tmy $roll = shift;\n\tprint \" -----\\n\";\n\tif ($roll == 1) {\n\t\t&print_blank;\n\t\t&print_one_mid;\n\t\t&print_blank;\n\t}\n\tif ($roll == 2) {\n\t\t&print_one_left;\n\t\t&print_blank;\n\t\t&print_one_right;\n\t}\n\tif ($roll == 3) {\n\t\t&print_one_left;\n\t\t&print_one_mid;\n\t\t&print_one_right;\n\t}\n\tif ($roll == 4) {\n\t\t&print_two;\n\t\t&print_blank;\n\t\t&print_two;\n\t}\n\tif ($roll == 5) {\n\t\t&print_two;\n\t\t&print_one_mid;\n\t\t&print_two;\n\t}\n\tif ($roll == 6) {\n\t\t&print_two;\n\t\t&print_two;\n\t\t&print_two;\n\t}\n\tprint \" -----\\n\";\n}\n\nsub print_one_left {\n\tprint \"I *   I\\n\";\n}\n\nsub print_one_mid {\n\tprint \"I  *  I\\n\";\n}\n\nsub print_one_right {\n\tprint \"I   * I\\n\";\n}\n\nsub print_two {\n\tprint \"I * * I\\n\";\n}\n\nsub print_blank {\n\tprint \"I     I\\n\";\n}\n\nsub print_intro {\n\tmy $spaces = \" \"x31;\n\tprint \"$spaces MATH DICE\\n\";\n\t$spaces = \" \"x15;\n\tprint \"$spaces CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\n\tprint \"THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\\n\";\n\tprint \"WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\\n\";\n\tprint \"MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\\n\";\n\tprint \"TO CONCLUDE THE LESSON, TYPE '0' AS YOUR ANSWER.\\n\\n\\n\";\n}\n"
  },
  {
    "path": "61_Math_Dice/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "61_Math_Dice/python/mathdice.py",
    "content": "from random import randint\n\nprint(\"Math Dice\")\nprint(\"https://github.com/coding-horror/basic-computer-games\")\nprint()\nprint(\n    \"\"\"This program generates images of two dice.\nWhen two dice and an equals sign followed by a question\nmark have been printed, type your answer, and hit the ENTER\nkey.\nTo conclude the program, type 0.\n\"\"\"\n)\n\n\ndef print_dice(n: int) -> None:\n    def print_0() -> None:\n        print(\"|     |\")\n\n    def print_2() -> None:\n        print(\"| * * |\")\n\n    print(\" ----- \")\n\n    if n in {4, 5, 6}:\n        print_2()\n    elif n in {2, 3}:\n        print(\"| *   |\")\n    else:\n        print_0()\n\n    if n in {1, 3, 5}:\n        print(\"|  *  |\")\n    elif n in {2, 4}:\n        print_0()\n    else:\n        print_2()\n\n    if n in {4, 5, 6}:\n        print_2()\n    elif n in {2, 3}:\n        print(\"|   * |\")\n    else:\n        print_0()\n\n    print(\" ----- \")\n\n\ndef main() -> None:\n\n    while True:\n        d1 = randint(1, 6)\n        d2 = randint(1, 6)\n        guess = 13\n\n        print_dice(d1)\n        print(\"   +\")\n        print_dice(d2)\n        print(\"   =\")\n\n        tries = 0\n        while guess != (d1 + d2) and tries < 2:\n            if tries == 1:\n                print(\"No, count the spots and give another answer.\")\n            try:\n                guess = int(input())\n            except ValueError:\n                print(\"That's not a number!\")\n            if guess == 0:\n                exit()\n            tries += 1\n\n        if guess != (d1 + d2):\n            print(f\"No, the answer is {d1 + d2}!\")\n        else:\n            print(\"Correct!\")\n\n        print(\"The dice roll again....\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "61_Math_Dice/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "61_Math_Dice/ruby/mathdice.rb",
    "content": "def intro\n  puts \"                               MATH DICE\n                 CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\nTHIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\nWHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\nMARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\nTO CONCLUDE THE LESSON, TYPE '0' AS YOUR ANSWER.\n\"\nend\n\ndef game_play\n  num = 0\n  sum = 0\n  tries = 0\n  until num == 2 do\n    num+=1\n    roll = rand(6) + 1\n    print_dice(roll)\n    sum = sum + roll\n    if num == 1\n      print \"\\n   +\\n\\n\"\n    end\n    if num == 2\n      print \"\\n   =? \"\n      ans = gets.chomp\n      if ans.to_i == 0\n        #END GAME\n        exit(0)\n      elsif ans.to_i == sum\n        puts \"RIGHT!\"\n        puts \"THE DICE ROLL AGAIN\"\n      else\n        puts \"NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER\"\n        print \"\\n   =? \"\n        ans = gets.chomp\n        if ans.to_i == sum\n          puts \"RIGHT!\"\n          puts \"THE DICE ROLL AGAIN\"\n        elsif ans.to_i == 0\n          exit(0)\n        else\n          puts \"NO, THE ANSWER IS #{sum}\"\n        end\n      end\n    end\n  end\nend\n\n\n\ndef print_dice(roll)\n  puts \" -----\"\n  if roll == 1\n    print_blank\n    print_one_mid\n    print_blank\n  elsif roll == 2\n    print_one_left\n    print_blank\n    print_one_right\n  elsif roll == 3\n    print_one_left\n    print_one_mid\n    print_one_right\n  elsif roll == 4\n    print_two\n    print_blank\n    print_two\n  elsif roll == 5\n    print_two\n    print_one_mid\n    print_two\n  elsif roll == 6\n    print_two\n    print_two\n    print_two\n  else\n    puts \"not a legit dice roll\"\n  end\n  puts \" -----\"\nend\n\n\ndef print_one_left\n  puts \"I *   I\"\nend\n\ndef print_one_mid\n  puts \"I  *  I\"\nend\n\ndef print_one_right\n  puts \"I   * I\"\nend\n\ndef print_two\n  puts \"I * * I\"\nend\n\ndef print_blank\n  puts \"I     I\"\nend\n\n\n\ndef main\n  intro\n  #Continue playing forever until it terminates with exit in game_play\n  while 1 == 1 do\n    game_play\n  end\nend\n\nmain\n"
  },
  {
    "path": "61_Math_Dice/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "61_Math_Dice/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n\nIf you wish to give the user more than 2 attempts to get the number, change value assigned to the num_tries variable at the start of the main function\n"
  },
  {
    "path": "61_Math_Dice/rust/src/main.rs",
    "content": "use rand::{Rng, prelude::{thread_rng}};\nuse std::io;\n\nfn main() {\n    //DATA\n    let num_tries:u8 = 2; //number of tries the player gets each round, must be at least 1\n    let mut rng = thread_rng();\n    let mut user_guess: u8;\n    let mut dice_1:u8;\n    let mut dice_2:u8;\n\n    //print welcome message\n    welcome();\n\n    //game loop\n    loop {\n        //roll dice\n        dice_1 = rng.gen_range(1..=6);\n        dice_2 = rng.gen_range(1..=6);\n\n        //print dice\n        print_dice(dice_1);\n        println!(\"   +\");\n        print_dice(dice_2);\n        println!(\"   =\");\n\n        //get user guess, they have 2 tries\n        for t in 0..num_tries {\n            //get guess\n            user_guess = get_number_from_user_input(\"\", \"That's not a valid number!\", 1, 12);\n\n            //if they get it wrong\n            if user_guess != (dice_1+dice_2) {\n                //print different message depending on what try they're on\n                if t < num_tries-1 { // user has tries left\n                    println!(\"NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.\");\n                    println!(\"   =\");\n                }\n                else { //this is their last try\n                    println!(\"NO, THE ANSWER IS {}\", dice_1+dice_2);\n                }\n            }\n            else {\n                println!(\"RIGHT!\");\n                break;\n            }\n        }\n\n        //play again\n        println!(\"\\nThe dice roll again....\");\n    }\n\n}\n\n/**\n * prints the welcome message to the console\n */\nfn welcome() {\n    println!(\"\n                              MATH DICE\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n    \\n\\n\n    THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\n    WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\n    MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\n    TO CONCLUDE THE LESSON, PRESS Ctrl+C AS YOUR ANSWER.\\n\n    \");\n}\n\n/**\n * print the dice,\n */\nfn print_dice(dice_value:u8) {\n    //data\n\n    //top\n    println!(\" ----- \");\n    //first layer\n    match dice_value {\n        4|5|6 => println!(\"| * * |\"),\n        2|3 => println!(\"| *   |\"),\n        _=>println!(\"|     |\"),\n    }\n\n    //second layer\n    match dice_value {\n        1|3|5 => println!(\"|  *  |\"),\n        2|4 => println!(\"|     |\"),\n        _=>println!(\"| * * |\"),\n    }\n\n    //third layer\n    match dice_value {\n        4|5|6 => println!(\"| * * |\"),\n        2|3 => println!(\"|   * |\"),\n        _=>println!(\"|     |\"),\n    }\n\n    //bottom\n    println!(\" ----- \");\n}\n\n/**\n * gets a integer from user input\n */\nfn get_number_from_user_input(prompt: &str, error_message: &str, min:u8, max:u8) -> u8 {\n    //input loop\n    return loop {\n        let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n        //print prompt\n        println!(\"{}\", prompt);\n        //read user input from standard input, and store it to raw_input\n        //raw_input.clear(); //clear input\n        io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n        //from input, try to read a number\n        match raw_input.trim().parse::<u8>() {\n            Ok(i) => {\n                if i < min || i > max { //input out of desired range\n                    println!(\"{}  ({}-{})\", error_message, min,max);\n                    continue; // run the loop again\n                }\n                else {\n                    break i;// this escapes the loop, returning i\n                }\n            },\n            Err(e) => {\n                println!(\"{}  {}\", error_message, e.to_string().to_uppercase());\n                continue; // run the loop again\n            }\n        };\n    };\n}\n"
  },
  {
    "path": "61_Math_Dice/vbnet/MathDice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"MathDice\", \"MathDice.vbproj\", \"{1341C416-E919-4262-B378-113A6B6317DD}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{1341C416-E919-4262-B378-113A6B6317DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{1341C416-E919-4262-B378-113A6B6317DD}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{1341C416-E919-4262-B378-113A6B6317DD}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{1341C416-E919-4262-B378-113A6B6317DD}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "61_Math_Dice/vbnet/MathDice.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>MathDice</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "61_Math_Dice/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "62_Mugwump/README.md",
    "content": "### Mugwump\n\nYour objective in this game is to find the four Mugwumps hiding on various squares of a 10 by 10 grid. Homebase (lower left) is position (0,0) and a guess is a pair of whole numbers (0 to 9), separated by commas. The first number is the number of units to the right of homebase and the second number is the distance above homebase.\n\nYou get ten guesses to locate the four Mugwumps; after each guess, the computer tells you how close you are to each Mugwump. Playing the game with the aid of graph paper and a compass should allow you to find all the Mugwumps in six or seven moves using triangulation similar to Loran radio navigation.\n\nIf you want to make the game somewhat more difficult, you can print the distance to each Mugwump either rounded or truncated to the nearest integer.\n\nThis program was modified slightly by Bob Albrecht of People’s Computer Company. It was originally written by students of Bud Valenti of Project SOLO in Pittsburg, Pennsylvania.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=114)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=129)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "62_Mugwump/csharp/Distance.cs",
    "content": "namespace Mugwump;\n\ninternal struct Distance\n{\n    private readonly float _value;\n\n    public Distance(float deltaX, float deltaY)\n    {\n        _value = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);\n    }\n\n    public override string ToString() => _value.ToString(\"0.0\");\n}\n"
  },
  {
    "path": "62_Mugwump/csharp/Game.cs",
    "content": "using System.Reflection;\n\nnamespace Mugwump;\n\ninternal class Game\n{\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n\n    internal Game(TextIO io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    internal void Play(Func<bool> playAgain = null)\n    {\n        DisplayIntro();\n\n        while (playAgain?.Invoke() ?? true)\n        {\n            Play(new Grid(_io, _random));\n\n            _io.WriteLine();\n            _io.WriteLine(\"That was fun! Let's play again.......\");\n            _io.WriteLine(\"Four more mugwumps are now in hiding.\");\n        }\n    }\n\n    private void DisplayIntro()\n    {\n        using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(\"Mugwump.Strings.Intro.txt\");\n\n        _io.Write(stream);\n    }\n\n    private void Play(Grid grid)\n    {\n        for (int turn = 1; turn <= 10; turn++)\n        {\n            var guess = _io.ReadGuess($\"Turn no. {turn} -- what is your guess\");\n\n            if (grid.Check(guess))\n            {\n                _io.WriteLine();\n                _io.WriteLine($\"You got them all in {turn} turns!\");\n                return;\n            }\n        }\n\n        _io.WriteLine();\n        _io.WriteLine(\"Sorry, that's 10 tries.  Here is where they're hiding:\");\n        grid.Reveal();\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/csharp/Grid.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Mugwump;\n\ninternal class Grid\n{\n    private readonly TextIO _io;\n    private readonly List<Mugwump> _mugwumps;\n\n    public Grid(TextIO io, IRandom random)\n    {\n        _io = io;\n        _mugwumps = Enumerable.Range(1, 4).Select(id => new Mugwump(id, random.NextPosition(10, 10))).ToList();\n    }\n\n    public bool Check(Position guess)\n    {\n        foreach (var mugwump in _mugwumps.ToList())\n        {\n            var (found, distance) = mugwump.FindFrom(guess);\n\n            _io.WriteLine(found ? $\"You have found {mugwump}\" : $\"You are {distance} units from {mugwump}\");\n            if (found)\n            {\n                _mugwumps.Remove(mugwump);\n            }\n        }\n\n        return _mugwumps.Count == 0;\n    }\n\n    public void Reveal()\n    {\n        foreach (var mugwump in _mugwumps)\n        {\n            _io.WriteLine(mugwump.Reveal());\n        }\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/csharp/IRandomExtensions.cs",
    "content": "namespace Mugwump;\n\ninternal static class IRandomExtensions\n{\n    internal static Position NextPosition(this IRandom random, int maxX, int maxY) =>\n        new(random.Next(maxX), random.Next(maxY));\n}\n"
  },
  {
    "path": "62_Mugwump/csharp/Mugwump.cs",
    "content": "namespace Mugwump;\n\ninternal class Mugwump\n{\n    private readonly int _id;\n    private readonly Position _position;\n\n    public Mugwump(int id, Position position)\n    {\n        _id = id;\n        _position = position;\n    }\n\n    public (bool, Distance) FindFrom(Position guess) => (guess == _position, guess - _position);\n\n    public string Reveal() => $\"{this} is at {_position}\";\n\n    public override string ToString() => $\"Mugwump {_id}\";\n}\n"
  },
  {
    "path": "62_Mugwump/csharp/Mugwump.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Strings\\Intro.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "62_Mugwump/csharp/Mugwump.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Mugwump\", \"Mugwump.csproj\", \"{DB23BDB0-10A4-4771-B942-E646A1A5C416}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1FE34948-9066-4F57-A4C1-423293A430C5}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "62_Mugwump/csharp/Position.cs",
    "content": "namespace Mugwump;\n\ninternal record struct Position(float X, float Y)\n{\n    public override string ToString() => $\"( {X} , {Y} )\";\n\n    public static Distance operator -(Position p1, Position p2) => new(p1.X - p2.X, p1.Y - p2.Y);\n}\n"
  },
  {
    "path": "62_Mugwump/csharp/Program.cs",
    "content": "﻿global using System;\nglobal using Games.Common.IO;\nglobal using Games.Common.Randomness;\n\nusing Mugwump;\n\nvar random = new RandomNumberGenerator();\nvar io = new ConsoleIO();\n\nvar game = new Game(io, random);\n\ngame.Play();\n"
  },
  {
    "path": "62_Mugwump/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "62_Mugwump/csharp/Strings/Intro.txt",
    "content": "                                 Mugwump\n               Creative Computing  Morristown, New Jersey\n\n\n\nThe object of this game is to find four mugwumps\nhidden on a 10 by 10 grid.  Homebase is position 0,0.\nAny guess you make must be two numbers with each\nnumber between 0 and 9, inclusive.  First number\nis distance to right of homebase and second number\nis distance above homebase.\n\nYou get 10 tries.  After each try, I will tell\nyou how far you are from each wugwump.\n"
  },
  {
    "path": "62_Mugwump/csharp/TextIOExtensions.cs",
    "content": "namespace Mugwump;\n\n// Provides input methods which emulate the BASIC interpreter's keyboard input routines\ninternal static class TextIOExtensions\n{\n    internal static Position ReadGuess(this TextIO io, string prompt)\n    {\n        io.WriteLine();\n        io.WriteLine();\n        var (x, y) = io.Read2Numbers(prompt);\n        return new Position(x, y);\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "62_Mugwump/java/src/Mugwump.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Mugwump\n * <p>\n * Based on the Basic game of Mugwump here\n * https://github.com/coding-horror/basic-computer-games/blob/main/62%20Mugwump/mugwump.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\npublic class Mugwump {\n\n    public static final int NUMBER_OF_MUGWUMPS = 4;\n\n    public static final int MAX_TURNS = 10;\n\n    public static final int FOUND = -1;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        INIT,\n        GAME_START,\n        PLAY_TURN\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    int[][] mugwumpLocations;\n\n    int turn;\n\n    public Mugwump() {\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.INIT;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case INIT:\n                    intro();\n                    gameState = GAME_STATE.GAME_START;\n\n                    break;\n\n                case GAME_START:\n\n                    turn = 0;\n\n                    // initialise all array elements with 0\n                    mugwumpLocations = new int[NUMBER_OF_MUGWUMPS][2];\n\n                    // Place 4 mugwumps\n                    for (int i = 0; i < NUMBER_OF_MUGWUMPS; i++) {\n                        for (int j = 0; j < 2; j++) {\n                            mugwumpLocations[i][j] = (int) (Math.random() * 10);\n                        }\n                    }\n                    gameState = GAME_STATE.PLAY_TURN;\n                    break;\n\n                case PLAY_TURN:\n                    turn++;\n                    String locations = displayTextAndGetInput(\"TURN NO.\" + turn + \" -- WHAT IS YOUR GUESS? \");\n                    int distanceRightGuess = getDelimitedValue(locations, 0);\n                    int distanceUpGuess = getDelimitedValue(locations, 1);\n\n                    int numberFound = 0;\n                    for (int i = 0; i < NUMBER_OF_MUGWUMPS; i++) {\n\n                        if (mugwumpLocations[i][0] == FOUND) {\n                            numberFound++;\n                        }\n\n                        int right = mugwumpLocations[i][0];\n                        int up = mugwumpLocations[i][1];\n\n                        if (right == distanceRightGuess && up == distanceUpGuess) {\n                            if (right != FOUND) {\n                                System.out.println(\"YOU HAVE FOUND MUGWUMP \" + (i + 1));\n                                mugwumpLocations[i][0] = FOUND;\n                            }\n                            numberFound++;\n                        } else {\n                            // Not found so show distance\n                            if (mugwumpLocations[i][0] != FOUND) {\n                                double distance = Math.sqrt((Math.pow(right - distanceRightGuess, 2.0d))\n                                        + (Math.pow(up - distanceUpGuess, 2.0d)));\n\n                                System.out.println(\"YOU ARE \" + (int) ((distance * 10) / 10) + \" UNITS FROM MUGWUMP\");\n                            }\n                        }\n                    }\n\n                    if (numberFound == NUMBER_OF_MUGWUMPS) {\n                        System.out.println(\"YOU GOT THEM ALL IN \" + turn + \" TURNS!\");\n                        gameState = GAME_STATE.GAME_START;\n                    } else if (turn >= MAX_TURNS) {\n                        System.out.println(\"SORRY, THAT'S \" + MAX_TURNS + \" TRIES.  HERE IS WHERE THEY'RE HIDING\");\n                        for (int i = 0; i < NUMBER_OF_MUGWUMPS; i++) {\n                            if (mugwumpLocations[i][0] != FOUND) {\n                                System.out.println(\"MUGWUMP \" + (i + 1) + \" IS AT (\"\n                                        + mugwumpLocations[i][0] + \",\" + mugwumpLocations[i][1] + \")\");\n                            }\n                        }\n                        gameState = GAME_STATE.GAME_START;\n                    }\n\n                    // Game ended?\n                    if (gameState != GAME_STATE.PLAY_TURN) {\n                        System.out.println(\"THAT WAS FUN! LET'S PLAY AGAIN.......\");\n                        System.out.println(\"FOUR MORE MUGWUMPS ARE NOW IN HIDING.\");\n                    }\n            }\n            // Infinite loop - based on original basic version\n        } while (true);\n    }\n\n    private void intro() {\n        System.out.println(addSpaces(33) + \"MUGWUMP\");\n        System.out.println(addSpaces(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS\");\n        System.out.println(\"HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0.\");\n        System.out.println(\"ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH\");\n        System.out.println(\"NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER\");\n        System.out.println(\"IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER\");\n        System.out.println(\"IS DISTANCE ABOVE HOMEBASE.\");\n        System.out.println();\n        System.out.println(\"YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL\");\n        System.out.println(\"YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\");\n    }\n\n    /**\n     * Accepts a string delimited by comma's and returns the pos'th delimited\n     * value (starting at count 0).\n     *\n     * @param text - text with values separated by comma's\n     * @param pos  - which position to return a value for\n     * @return the int representation of the value\n     */\n    private int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        return Integer.parseInt(tokens[pos]);\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.nextLine();\n    }\n\n    /**\n     * Return a string of x spaces\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String addSpaces(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    public static void main(String[] args) {\n\n        Mugwump mugwump = new Mugwump();\n        mugwump.play();\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "62_Mugwump/javascript/mugwump.html",
    "content": "<html>\n<head>\n<title>MUGWUMP</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"mugwump.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "62_Mugwump/javascript/mugwump.js",
    "content": "// MUGWUMP\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar p = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"MUGWUMP\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // Courtesy People's Computer Company\n    print(\"THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS\\n\");\n    print(\"HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0.\\n\");\n    print(\"ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH\\n\");\n    print(\"NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER\\n\");\n    print(\"IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER\\n\");\n    print(\"IS DISTANCE ABOVE HOMEBASE.\\n\");\n    print(\"\\n\");\n    print(\"YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL\\n\");\n    print(\"YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\\n\");\n    print(\"\\n\");\n    while (1) {\n        for (i = 1; i <= 4; i++) {\n            p[i] = [];\n            for (j = 1; j <= 2; j++) {\n                p[i][j] = Math.floor(10 * Math.random());\n            }\n        }\n        t = 0;\n        do {\n            t++;\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"TURN NO. \" + t + \" -- WHAT IS YOUR GUESS\");\n            str = await input();\n            m = parseInt(str);\n            n = parseInt(str.substr(str.indexOf(\",\") + 1));\n            for (i = 1; i <= 4; i++) {\n                if (p[i][1] == -1)\n                    continue;\n                if (p[i][1] == m && p[i][2] == n) {\n                    p[i][1] = -1;\n                    print(\"YOU HAVE FOUND MUGWUMP \" + i + \"\\n\");\n                } else {\n                    d = Math.sqrt(Math.pow(p[i][1] - m, 2) + Math.pow(p[i][2] - n, 2));\n                    print(\"YOU ARE \" + Math.floor(d * 10) / 10 + \" UNITS FROM MUGWUMP \" + i + \"\\n\");\n                }\n            }\n            for (j = 1; j <= 4; j++) {\n                if (p[j][1] != -1)\n                    break;\n            }\n            if (j > 4) {\n                print(\"\\n\");\n                print(\"YOU GOT THEM ALL IN \" + t + \" TURNS!\\n\");\n                break;\n            }\n        } while (t < 10) ;\n        if (t == 10) {\n            print(\"\\n\");\n            print(\"SORRY, THAT'S 10 TRIES.  HERE IS WHERE THEY'RE HIDING:\\n\");\n            for (i = 1; i <= 4; i++) {\n                if (p[i][1] != -1)\n                    print(\"MUGWUMP \" + i + \" IS AT (\" + p[i][1] + \",\" + p[i][2] + \")\\n\");\n            }\n        }\n        print(\"\\n\");\n        print(\"THAT WAS FUN! LET'S PLAY AGAIN.......\\n\");\n        print(\"FOUR MORE MUGWUMPS ARE NOW IN HIDING.\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "62_Mugwump/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "62_Mugwump/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "62_Mugwump/mugwump.bas",
    "content": "1 PRINT TAB(33);\"MUGWUMP\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 REM     COURTESY PEOPLE'S COMPUTER COMPANY\n10 DIM P(4,2)\n20 PRINT \"THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS\"\n30 PRINT \"HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0.\"\n40 PRINT \"ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH\"\n50 PRINT \"NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER\"\n60 PRINT \"IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER\"\n70 PRINT \"IS DISTANCE ABOVE HOMEBASE.\"\n80 PRINT\n90 PRINT \"YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL\"\n100 PRINT \"YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\"\n110 PRINT\n240 GOSUB 1000\n250 T=0\n260 T=T+1\n270 PRINT\n275 PRINT\n290 PRINT \"TURN NO.\";T;\"-- WHAT IS YOUR GUESS\";\n300 INPUT M,N\n310 FOR I=1 TO 4\n320 IF P(I,1)=-1 THEN 400\n330 IF P(I,1)<>M THEN 380\n340 IF P(I,2)<>N THEN 380\n350 P(I,1)=-1\n360 PRINT \"YOU HAVE FOUND MUGWUMP\";I\n370 GOTO 400\n380 D=SQR((P(I,1)-M)^2+(P(I,2)-N)^2)\n390 PRINT \"YOU ARE\";(INT(D*10))/10;\"UNITS FROM MUGWUMP\";I\n400 NEXT I\n410 FOR J=1 TO 4\n420 IF P(J,1)<>-1 THEN 470\n430 NEXT J\n440 PRINT\n450 PRINT \"YOU GOT THEM ALL IN\";T;\"TURNS!\"\n460 GOTO 580\n470 IF T<10 THEN 260\n480 PRINT\n490 PRINT \"SORRY, THAT'S 10 TRIES.  HERE IS WHERE THEY'RE HIDING:\"\n540 FOR I=1 TO 4\n550 IF P(I,1)=-1 THEN 570\n560 PRINT \"MUGWUMP\";I;\"IS AT (\";P(I,1);\",\";P(I,2);\")\"\n570 NEXT I\n580 PRINT\n600 PRINT \"THAT WAS FUN! LET'S PLAY AGAIN.......\"\n610 PRINT \"FOUR MORE MUGWUMPS ARE NOW IN HIDING.\"\n630 GOTO 240\n1000 FOR J=1 TO 2\n1010 FOR I=1 TO 4\n1020 P(I,J)=INT(10*RND(1))\n1030 NEXT I\n1040 NEXT J\n1050 RETURN\n1099 END\n"
  },
  {
    "path": "62_Mugwump/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "62_Mugwump/perl/mugwump.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\n# global variables defined here\nmy(@MUGWUMP) = ();\n\n# subroutines defined here\n\n# init_mugwump: pick the random places for the Mugwumps\nsub init_mugwump() {\n    @MUGWUMP = ();\n    for (1 .. 4) {\n        push @MUGWUMP, [ int(rand 10), int(rand 10) ];\n    }\n}\n\n\n# main code starts here\n\n# print introductory text\nprint <<HERE;\n                  Mugwump\nCreative Computing  Morristown, New Jersey\n\n\n\nThe object of this game is to find four Mugwumps\nhidden on a 10 by 10 grid.  Homebase is position 0,0.\nAny guess you make must be two numbers with each\nnumber between 0 and 9, inclusive.  First number\nis distance to right of homebase and second number\nis distance above homebase.\n\nYou get 10 tries.  After each try, I will tell\nyou how far you are from each Mugwump.\n\nHERE\n\n\n# PLAY block implements a complete game, and the\n# continue block prints the \"let's play again\" msg\nPLAY: while (1) {\n\n    init_mugwump();\n    TURN: for my $turn (1 .. 10) {\n\n        printf(\"\\nTurn no %d -- what is your guess ? \", $turn);\n\n        # Note that parsing of input is rudimentary, in keeping with the\n        # spirit of the original BASIC program. Increased input checks\n        # would be a good place to start working on this program!\n        chomp(my $in = <STDIN>);\n        my($M,$N) = split(/,/,$in);\n        $M = int($M);\n        $N = int($N);\n\n        for my $i (0 .. $#MUGWUMP) {\n            # -1 indicates a Mugwump that was already found\n            next if $MUGWUMP[$i]->[0] == -1;\n\n            if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) {\n                $MUGWUMP[$i]->[0] = -1;\n                printf(\"You have found Mugwump %d\\n\", $i+1);\n            } else {\n                my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2);\n                printf(\"You are %.1f units away from Mugwump %d\\n\", $d, $i+1);\n            }\n        }\n\n        # If a Mugwump still has not been found,\n        # go to the next turn\n        for my $j (0 .. $#MUGWUMP) {\n            if ($MUGWUMP[$j]->[0] != -1) {\n                next TURN;\n            }\n        }\n        # You win!\n        printf(\"You got all of them in %d %s!\\n\\n\", $turn, ($turn == 1 ? 'turn' : 'turns'));\n        # Pass execution down to the continue block\n        next PLAY;\n\n    } # end of TURN loop\n\n    print \"\\nSorry, that's 10 tries.  Here's where they're hiding:\\n\";\n    for my $i (0 .. $#MUGWUMP) {\n        printf(\"Mugwump %d is at (%d, %d)\\n\", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1])\n            if $MUGWUMP[$i]->[0] != -1;\n    }\n}\ncontinue {\n    print \"\\nThat was fun! Let's play again.......\\n\";\n    print \"Four more Mugwumps are now in hiding.\\n\\n\";\n}\n"
  },
  {
    "path": "62_Mugwump/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "62_Mugwump/python/mugwump.py",
    "content": "from math import sqrt\nfrom random import randint\nfrom typing import List, Tuple\n\n\ndef introduction() -> None:\n    print(\n        \"\"\"The object of this game is to find 4 mugwumps\nhidden on a 10*10 grid.  Homebase is position 0,0.\nAny guess you make must be two numbers with each\nnumber between 0 and 9 inclusive.  First number\nis distance to right of homebase, and second number\nis the distance above homebase.\"\"\"\n    )\n\n    print(\n        \"\"\"You get 10 tries.  After each try, I will tell\nyou how far you are from each mugwump.\"\"\"\n    )\n\n\ndef generate_mugwumps(n: int = 4) -> List[List[int]]:\n    mugwumps = []\n    for _ in range(n):\n        current = [randint(0, 9), randint(0, 9)]\n        mugwumps.append(current)\n    return mugwumps\n\n\ndef reveal_mugwumps(mugwumps: List[List[int]]) -> None:\n    print(\"Sorry, that's 10 tries.  Here's where they're hiding.\")\n    for idx, mugwump in enumerate(mugwumps, 1):\n        if mugwump[0] != -1:\n            print(f\"Mugwump {idx} is at {mugwump[0]},{mugwump[1]}\")\n\n\ndef calculate_distance(guess: Tuple[int, int], mugwump: List[int]) -> float:\n    return sqrt(((mugwump[0] - guess[0]) ** 2) + ((mugwump[1] - guess[1]) ** 2))\n\n\ndef play_again() -> None:\n    print(\"THAT WAS FUN! LET'S PLAY AGAIN.......\")\n    choice = input(\"Press Enter to play again, any other key then Enter to quit.\")\n    if choice == \"\":\n        print(\"Four more mugwumps are now in hiding.\")\n    else:\n        exit()\n\n\ndef play_round() -> None:\n    mugwumps = generate_mugwumps()\n    turns = 1\n    score = 0\n    while turns <= 10 and score != 4:\n        m = -1\n        while m == -1:\n            try:\n                m, n = map(int, input(f\"Turn {turns} - what is your guess? \").split())\n            except ValueError:\n                m = -1\n        for idx, mugwump in enumerate(mugwumps):\n            if m == mugwump[0] and n == mugwump[1]:\n                print(f\"You found mugwump {idx + 1}\")\n                mugwumps[idx][0] = -1\n                score += 1\n            if mugwump[0] == -1:\n                continue\n            print(\n                f\"You are {calculate_distance((m, n), mugwump):.1f} units from mugwump {idx + 1}\"\n            )\n        turns += 1\n    if score == 4:\n        print(f\"Well done! You got them all in {turns} turns.\")\n    else:\n        reveal_mugwumps(mugwumps)\n\n\nif __name__ == \"__main__\":\n    introduction()\n    while True:\n        play_round()\n        play_again()\n"
  },
  {
    "path": "62_Mugwump/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "62_Mugwump/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "62_Mugwump/rust/src/coordinate.rs",
    "content": "#![allow(dead_code)]\n\n#[derive(Debug)]\npub struct Coordinate {\n    x: u8,\n    y: u8,\n    pub state: CoordState,\n    pub mugwump_number: u8,\n}\n\nimpl Coordinate {\n    pub fn new(pos: (u8, u8), has_mugwump: bool, mugwump_number: i32) -> Self {\n        let mut mug_no = 0;\n\n        let state = if has_mugwump {\n            mug_no = mugwump_number;\n            CoordState::HasMugwump\n        } else {\n            CoordState::Normal\n        };\n\n        Coordinate {\n            x: pos.0,\n            y: pos.1,\n            state,\n            mugwump_number: mug_no as u8,\n        }\n    }\n\n    pub fn get_pos(&self) -> (u8, u8) {\n        (self.x, self.y)\n    }\n}\n\n#[derive(Debug, PartialEq)]\npub enum CoordState {\n    Normal,\n    HasMugwump,\n    Checked,\n    FoundMugwump,\n}\n"
  },
  {
    "path": "62_Mugwump/rust/src/draw.rs",
    "content": "use crate::coordinate::{CoordState, Coordinate};\n\npub fn draw_board(coords: &Vec<Coordinate>, show_mugwumps: bool) {\n    let draw_top_bottom = |is_top: bool| {\n        let (mut left, mut right) = (\"╔\", \"╗\");\n\n        if !is_top {\n            (left, right) = (\"╚\", \"╝\");\n        }\n\n        for i in 0..11 {\n            if i == 0 {\n                print!(\"{}══\", left);\n            } else if i == 10 {\n                print!(\"═══{}\", right)\n            } else {\n                print!(\"══\");\n            }\n        }\n        println!(\"\");\n    };\n\n    draw_top_bottom(true);\n\n    let mut y: i8 = 9;\n\n    print!(\"║ {} \", y);\n    for (i, c) in coords.iter().enumerate() {\n        {\n            use CoordState::*;\n\n            let mut _char = ' ';\n\n            match c.state {\n                Normal => _char = '-',\n                HasMugwump => _char = if show_mugwumps { 'M' } else { '-' },\n                Checked => _char = '*',\n                FoundMugwump => _char = '𑗌',\n            }\n\n            print!(\"{} \", _char);\n        }\n\n        if ((i + 1) % 10) == 0 {\n            y -= 1;\n\n            print!(\"║\");\n            println!(\"\");\n\n            if i != 99 {\n                print!(\"║ {} \", y);\n            }\n        }\n    }\n\n    print!(\"║ ♥︎ \");\n    for i in 0..10 {\n        print!(\"{} \", i);\n\n        if i == 9 {\n            print!(\"║\");\n        }\n    }\n    println!(\"\");\n\n    draw_top_bottom(false);\n}\n"
  },
  {
    "path": "62_Mugwump/rust/src/game.rs",
    "content": "use rand::Rng;\n\nuse crate::{\n    coordinate::{CoordState, Coordinate},\n    draw::draw_board,\n    util,\n};\n\npub struct Game {\n    pub coords: Vec<Coordinate>,\n    tries: u8,\n    show_board: bool,\n}\n\nimpl Game {\n    pub fn new(show_board: bool) -> Self {\n        let mut coords = Vec::new();\n        let mut random_indexes = Vec::new();\n        let get_random_index = || -> i32 { rand::thread_rng().gen_range(0..100) };\n\n        for _ in 0..4 {\n            let mut i = get_random_index();\n            while random_indexes.contains(&i) {\n                i = get_random_index();\n            }\n            random_indexes.push(i);\n        }\n\n        let mut x = 0;\n        let mut y: i8 = 9;\n\n        let mut mugwump_number = 0;\n\n        for i in 0..100 {\n            let mut has_mugwump = false;\n\n            if random_indexes.contains(&i) {\n                has_mugwump = true;\n                mugwump_number += 1;\n            }\n\n            coords.push(Coordinate::new((x, y as u8), has_mugwump, mugwump_number));\n\n            x += 1;\n\n            if ((i + 1) % 10) == 0 {\n                x = 0;\n                y -= 1;\n            }\n        }\n\n        Game {\n            coords,\n            tries: 0,\n            show_board,\n        }\n    }\n\n    pub fn tick(&mut self) -> Option<bool> {\n        let mut game_over = false;\n\n        if self.tries >= 10 {\n            println!(\"SORRY THAT'S 10 TRIES. HERE IS WHERE THEY ARE HIDING\");\n\n            for m in self.get_mugwumps() {\n                println!(\"MUGWUMP {} IS AT {:?}\", m.mugwump_number, m.get_pos());\n            }\n\n            if self.show_board {\n                draw_board(&self.coords, true);\n            }\n\n            game_over = true;\n        }\n\n        if self.get_mugwumps().len() == 0 {\n            println!(\"YOU HAVE FOUND ALL MUGWUMPS!\");\n\n            game_over = true;\n        }\n\n        if game_over {\n            return util::prompt_bool(\"THAT WAS FUN! PLAY AGAIN (Y/n)?\");\n        }\n\n        self.tries += 1;\n\n        if self.show_board {\n            draw_board(&self.coords, true);\n        }\n\n        let entered_position = self.input_coordinate();\n        self.check_position(entered_position);\n\n        None\n    }\n\n    fn check_position(&mut self, pos: (u8, u8)) {\n        if let Some(coord) = self.coords.iter_mut().find(|c| c.get_pos() == pos) {\n            use CoordState::*;\n\n            match coord.state {\n                Normal => {\n                    coord.state = Checked;\n                    self.print_distances(pos);\n                }\n                HasMugwump => {\n                    coord.state = FoundMugwump;\n                    println!(\"YOU FOUND MUGWUMP {}\", coord.mugwump_number);\n                    self.print_distances(pos);\n                }\n                Checked | FoundMugwump => println!(\"YOU ALREADY LOOKED HERE!\"),\n            }\n        }\n    }\n\n    fn print_distances(&self, (x, y): (u8, u8)) {\n        let print = |m: &Coordinate| {\n            let (mx, my) = m.get_pos();\n            let (x, y, mx, my) = (x as i32, y as i32, mx as i32, my as i32);\n            let distance = (((x - mx).pow(2) + (y - my).pow(2)) as f32).sqrt();\n\n            println!(\n                \"YOU ARE {} UNITS FROM MUGWUMP {}\",\n                distance, m.mugwump_number\n            );\n        };\n\n        for m in self.get_mugwumps() {\n            print(m);\n        }\n    }\n\n    fn input_coordinate(&self) -> (u8, u8) {\n        let msg = format!(\"TURN NO. {} WHAT IS YOUR GUESS?\", self.tries);\n        let input = util::prompt(msg.as_str());\n\n        if !input.contains(\",\") {\n            println!(\"YOU MUST ENTER A COORDINATE: #,#\");\n            return (0, 0);\n        }\n\n        let axes: Vec<&str> = input.split(\",\").collect();\n        let mut pos = [0; 2];\n\n        for (i, a) in axes.iter().enumerate() {\n            match a.parse::<usize>() {\n                Ok(p) => pos[i] = p as u8,\n                Err(_) => println!(\"YOU MUST ENTER A COORDINATE: #,#\"),\n            }\n        }\n\n        (pos[0], pos[1])\n    }\n\n    fn get_mugwumps(&self) -> Vec<&Coordinate> {\n        self.coords\n            .iter()\n            .filter(|c| c.state == CoordState::HasMugwump)\n            .collect()\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/rust/src/main.rs",
    "content": "mod coordinate;\nmod draw;\nmod game;\npub mod util;\n\nuse crate::game::Game;\n\nfn main() {\n    println!(\"\\n\\nMUGWUMP\");\n    println!(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n\n    println!(\"THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS\");\n    println!(\"HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0.\");\n    println!(\"ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH\");\n    println!(\"NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER\");\n    println!(\"IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER\");\n    println!(\"IS DISTANCE ABOVE HOMEBASE!\\n\");\n\n    println!(\"YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL\");\n    println!(\"YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\\n\");\n\n    let mut _quit = false;\n\n    while !_quit {\n        let mut show_board = true;\n\n        if let Some(r) = util::prompt_bool(\"WOULD YOU LIKE TO SEE THE BOARD?\") {\n            show_board = r;\n        }\n\n        let mut game = Game::new(show_board);\n\n        loop {\n            if let Some(again) = game.tick() {\n                if !again {\n                    _quit = true;\n                } else {\n                    println!(\"FOUR MORE MUGWUMPS ARE NOW IN HIDING\")\n                }\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/rust/src/util.rs",
    "content": "use std::io;\n\npub fn prompt(msg: &str) -> String {\n    println!(\"\\n{}\", msg);\n\n    let mut input = String::new();\n\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line.\");\n\n    input.trim().to_string()\n}\n\npub fn prompt_bool(msg: &str) -> Option<bool> {\n    loop {\n        let response = prompt(msg);\n\n        match response.to_uppercase().as_str() {\n            \"Y\" | \"YES\" => return Some(true),\n            \"N\" | \"NO\" => return Some(false),\n            _ => println!(\"PLEASE ENTER (Y)ES or (N)O.\"),\n        }\n    }\n}\n"
  },
  {
    "path": "62_Mugwump/vbnet/Mugwump.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Mugwump\", \"Mugwump.vbproj\", \"{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "62_Mugwump/vbnet/Mugwump.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Mugwump</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "62_Mugwump/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "63_Name/README.md",
    "content": "### Name\n\nNAME is a silly little ice-breaker to get a relationship going between a computer and a shy human. The sorting algorithm used is highly inefficient — as any reader of _Creative Computing_ will recognize, this is the worst possible sort for speed. But the program is good fun and that’s what counts here.\n\nNAME was originally written by Geoffrey Chase of the Abbey, Portsmouth, Rhode Island.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=116)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=131)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "63_Name/csharp/Name.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "63_Name/csharp/Name.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31005.135\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Name\", \"Name.csproj\", \"{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {FCD5BEAE-D35E-49A7-B8F3-B8B3F4A8C624}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "63_Name/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Name\n{\n    public class Program\n    {\n        static void Main(string[] args)\n        {\n            Console.WriteLine(\"NAME\".CentreAlign());\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".CentreAlign());\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"HELLO.\");\n            Console.WriteLine(\"MY NAME IS CREATIVE COMPUTER.\");\n            Console.Write(\"WHAT'S YOUR NAME (FIRST AND LAST? \");\n            var name = Console.ReadLine();\n            Console.WriteLine();\n            Console.WriteLine($\"THANK YOU, {name.Reverse()}.\");\n            Console.WriteLine(\"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\");\n            Console.WriteLine(\"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\");\n            Console.WriteLine();\n            Console.WriteLine(\"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\");\n            Console.WriteLine($\"LET'S PUT THEM IN ORDER LIKE THIS: {name.Sort()}\");\n            Console.WriteLine();\n            Console.Write(\"DON'T YOU LIKE THAT BETTER? \");\n            var like = Console.ReadLine();\n            Console.WriteLine();\n\n            if (like.ToUpperInvariant() == \"YES\")\n            {\n                Console.WriteLine(\"I KNEW YOU'D AGREE!!\");\n            }\n            else\n            {\n                Console.WriteLine(\"I'M SORRY YOU DON'T LIKE IT THAT WAY.\");\n            }\n\n            Console.WriteLine();\n            Console.WriteLine($\"I REALLY ENJOYED MEETING YOU {name}.\");\n            Console.WriteLine(\"HAVE A NICE DAY!\");\n        }\n    }\n}\n"
  },
  {
    "path": "63_Name/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "63_Name/csharp/StringExtensions.cs",
    "content": "﻿using System;\n\nnamespace Name\n{\n    public static class StringExtensions\n    {\n        private const int ConsoleWidth = 120; // default console width\n\n        public static string CentreAlign(this string value)\n        {\n            int spaces = ConsoleWidth - value.Length;\n            int leftPadding = spaces / 2 + value.Length;\n\n            return value.PadLeft(leftPadding).PadRight(ConsoleWidth);\n        }\n\n        public static string Reverse(this string value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            char[] characterArray = value.ToCharArray();\n            Array.Reverse(characterArray);\n            return new String(characterArray);\n        }\n\n        public static string Sort(this string value)\n        {\n            if (value is null)\n            {\n                return null;\n            }\n\n            char[] characters = value.ToCharArray();\n            Array.Sort(characters);\n            return new string(characters);\n        }\n    }\n}\n"
  },
  {
    "path": "63_Name/java/Name.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\npublic class Name {\n\n    public static void printempty() { System.out.println(\" \"); }\n\n    public static void print(String toprint) { System.out.println(toprint); }\n\n    public static void main(String[] args) {\n        print(\"                                          NAME\");\n        print(\"                         CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        printempty();\n        printempty();\n        print(\"HELLO.\");\n        print(\"MY NAME iS CREATIVE COMPUTER.\");\n        print(\"WHATS YOUR NAME? (FIRST AND LAST)\");\n\n        Scanner namesc = new Scanner(System.in);\n        String name = namesc.nextLine();\n\n        String namereversed = new StringBuilder(name).reverse().toString();\n\n        char namesorted[] = name.toCharArray();\n        Arrays.sort(namesorted);\n\n        printempty();\n        print(\"THANK YOU, \" + namereversed);\n        printempty();\n        print(\"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\");\n        print(\"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\");\n        printempty();\n        printempty();\n        print(\"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\");\n\n        print(\"LET'S PUT THEM IN ORDER LIKE THIS: \" + new String(namesorted));\n        printempty();\n        printempty();\n\n        print(\"DON'T YOU LIKE THAT BETTER?\");\n        printempty();\n\n        Scanner agreementsc = new Scanner(System.in);\n        String agreement = agreementsc.nextLine();\n\n        if (agreement.equalsIgnoreCase(\"yes\")) {\n            print(\"I KNEW YOU'D AGREE!!\");\n        } else {\n            print(\"I'M SORRY YOU DON'T LIKE IT THAT WAY.\");\n            printempty();\n            print(\"I REALLY ENJOYED MEETING YOU, \" + name);\n            print(\"HAVE A NICE DAY!\");\n        }\n    }\n}\n"
  },
  {
    "path": "63_Name/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "63_Name/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "63_Name/javascript/name.html",
    "content": "<html>\n<head>\n<title>NAME</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"name.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "63_Name/javascript/name.js",
    "content": "// NAME\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar str;\nvar b;\n\n// Main program\nasync function main()\n{\n    print(tab(34) + \"NAME\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"HELLO.\\n\");\n    print(\"MY NAME IS CREATIVE COMPUTER.\\n\");\n    print(\"WHAT'S YOUR NAME (FIRST AND LAST)\");\n    str = await input();\n    l = str.length;\n    print(\"\\n\");\n    print(\"THANK YOU, \");\n    for (i = l; i >= 1; i--)\n        print(str[i - 1]);\n    print(\".\\n\");\n    print(\"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\\n\");\n    print(\"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\\n\");\n    print(\"\\n\");\n    print(\"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\\n\");\n    print(\"LET'S PUT THEM IN ORDER LIKE THIS: \");\n    b = [];\n    for (i = 1; i <= l; i++)\n        b[i - 1] = str.charCodeAt(i - 1);\n    b.sort();\n    for (i = 1; i <= l; i++)\n        print(String.fromCharCode(b[i - 1]));\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"DON'T YOU LIKE THAT BETTER\");\n    ds = await input();\n    if (ds == \"YES\") {\n        print(\"\\n\");\n        print(\"I KNEW YOU'D AGREE!!\\n\");\n    } else {\n        print(\"\\n\");\n        print(\"I'M SORRY YOU DON'T LIKE IT THAT WAY.\\n\");\n    }\n    print(\"\\n\");\n    print(\"I REALLY ENJOYED MEETING YOU \" + str + \".\\n\");\n    print(\"HAVE A NICE DAY!\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "63_Name/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "63_Name/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "63_Name/lua/name.lua",
    "content": "-- HELLO\n--\n-- Converted from BASIC to Lua by Recanman\n\nlocal function tab(space)\n    local str = \"\"\n\n    for _ = space, 1, -1 do\n        str = str .. \" \"\n    end\n\n    return str\nend\n\n-- reused from Bagels.lua\nfunction getInput(prompt)\n    io.write(prompt)\n    io.flush()\n    local input = io.read(\"l\")\n    if not input then  --- test for EOF\n        print(\"GOODBYE\")\n        os.exit(0)\n    end\n    return input\nend\n\nprint(tab(33) .. \"HELLO\\n\")\nprint(tab(15) .. \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\nprint(\"\\n\")\nprint(\"\\n\")\nprint(\"\\n\")\n\nprint(\"HELLO.  MY NAME IS CREATIVE COMPUTER.\\n\")\nprint(\"\\n\")\nprint(\"\\n\")\n\nprint(\"WHAT'S YOUR NAME (FIRST AND LAST)\")\n\nlocal ns = getInput(\"? \")\nlocal l = string.len(ns)\nprint(\"\\n\")\n\nlocal function main()\n    print(\"THANK YOU, \" .. string.reverse(ns) .. \".\\n\")\n\n    print(\"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\")\n    print(\"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\\n\")\n    print(\"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\\n\")\n    print(\"LET'S PUT THEM IN ORDER LIKE THIS: \")\n    \n    local b = {}\n    \n    for i = 1, l, 1 do\n        local letter = string.sub(ns, i, i)\n        b[i] = string.byte(letter)\n    end\n    \n    table.sort(b, function(v1, v2)\n        return v1 < v2\n    end)\n    \n    local str = \"\"\n    for _, letter in ipairs(b) do\n        str = str .. string.char(letter)\n    end\n    \n    str = string.reverse(str)\n    print(str)\n    \n    print(\"\\n\\n\")\n    print(\"DON'T YOU LIKE THAT BETTER\")\n    \n    local ds = getInput(\"? \")\n        \n    if ds == \"YES\" then\n        print(\"I KNEW YOU'D AGREE!!\\n\")\n    else\n        print(\"I'M SORRY YOU DON'T LIKE IT THAT WAY.\\n\")\n    end\n    \n    print(\"I REALLY ENJOYED MEETING YOU \" ..  ns .. \".\\n\")\n    print(\"HAVE A NICE DAY!\\n\")\nend\n\nmain()\n"
  },
  {
    "path": "63_Name/name.bas",
    "content": "1 PRINT TAB(34);\"NAME\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT: PRINT: PRINT\n5 DIM B$(40)\n10 PRINT \"HELLO.\": PRINT \"MY NAME IS CREATIVE COMPUTER.\"\n20 PRINT \"WHAT'S YOUR NAME (FIRST AND LAST\";: INPUT A$: L=LEN(A$)\n30 PRINT: PRINT \"THANK YOU, \";\n40 FOR I=1 TO L: B$(I)=MID$(A$,I,1): NEXT I\n50 FOR I=L TO 1 STEP -1: PRINT B$(I);: NEXT I\n60 PRINT \".\": PRINT \"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\"\n70 PRINT \"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\": PRINT\n80 PRINT \"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\"\n90 PRINT \"LET'S PUT THEM IN ORDER LIKE THIS: \";\n100 FOR J=2 TO L: I=J-1: T$=B$(J)\n110 IF T$>B$(I) THEN 130\n120 B$(I+1)=B$(I): I=I-1: IF I>0 THEN 110\n130 B$(I+1)=T$: NEXT J\n140 FOR I=1 TO L: PRINT B$(I);: NEXT I: PRINT: PRINT\n150 PRINT \"DON'T YOU LIKE THAT BETTER\";: INPUT D$\n160 IF D$=\"YES\" THEN 180\n170 PRINT: PRINT \"I'M SORRY YOU DON'T LIKE IT THAT WAY.\": GOTO 200\n180 PRINT: PRINT \"I KNEW YOU'D AGREE!!\"\n200 PRINT: PRINT \"I REALLY ENJOYED MEETING YOU \";A$;\".\"\n210 PRINT \"HAVE A NICE DAY!\"\n999 END\n"
  },
  {
    "path": "63_Name/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "63_Name/perl/name.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x34 . \"NAME\\n\";\nprint ' 'x15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \"HELLO.\\n\"; print \"MY NAME IS CREATIVE COMPUTER.\\n\";\nprint \"WHAT'S YOUR NAME (FIRST AND LAST): \";\nchomp (my $A = <STDIN>);\n\nmy @B= split(\"\", $A); #Convert string to array of characters.\n\nprint \"\\n\"; print \"THANK YOU, \";\nprint reverse @B;\n\nprint \".\\n\"; print \"OOPS! I GUESS I GOT IT BACKWARDS. A SMART\\n\";\nprint \"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\\n\\n\";\nprint \"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\\n\";\nprint \"LET'S PUT THEM IN ORDER LIKE THIS: \";\nprint sort @B;\n\nprint \"\\n\\n\";\nprint \"DON'T YOU LIKE THAT BETTER? \";\nchomp (my $D = <STDIN>);\nif (uc($D) eq \"YES\") {\n\tprint \"\\n\"; print \"I KNEW YOU'D AGREE!!\\n\";\n\t} else {\n\tprint \"\\n\"; print \"I'M SORRY YOU DON'T LIKE IT THAT WAY.\\n\";\n\t}\nprint \"\\n\"; print \"I REALLY ENJOYED MEETING YOU $A.\\n\";\nprint \"HAVE A NICE DAY!\\n\";\nexit;\n"
  },
  {
    "path": "63_Name/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "63_Name/python/name.py",
    "content": "\"\"\"\nNAME\n\nsimple string manipulations on the user's name\n\nPorted by Dave LeCompte\n\"\"\"\n\n\ndef is_yes_ish(answer: str) -> bool:\n    cleaned = answer.strip().upper()\n    return cleaned in {\"Y\", \"YES\"}\n\n\ndef main() -> None:\n    print(\" \" * 34 + \"NAME\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"HELLO.\")\n    print(\"MY NAME iS CREATIVE COMPUTER.\")\n    name = input(\"WHAT'S YOUR NAME (FIRST AND LAST)?\")\n    print()\n    name_as_list = list(name)\n    reversed_name = \"\".join(name_as_list[::-1])\n    print(f\"THANK YOU, {reversed_name}.\\n\")\n    print(\"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\")\n    print(\"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\\n\\n\")\n    print(\"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\")\n\n    sorted_name = \"\".join(sorted(name_as_list))\n    print(f\"LET'S PUT THEM IN ORDER LIKE THIS: {sorted_name}\\n\\n\")\n\n    print(\"DON'T YOU LIKE THAT BETTER?\")\n    like_answer = input()\n    print()\n    if is_yes_ish(like_answer):\n        print(\"I KNEW YOU'D AGREE!!\")\n    else:\n        print(\"I'M SORRY YOU DON'T LIKE IT THAT WAY.\")\n    print()\n    print(f\"I REALLY ENJOYED MEETING YOU, {name}.\")\n    print(\"HAVE A NICE DAY!\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "63_Name/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "63_Name/ruby/name.rb",
    "content": "def is_yes_ish answer\n    cleaned = answer.upcase\n    return true if [\"Y\", \"YES\"].include? cleaned\n    return false\nend\n\ndef main\n    puts \" \" * 34 + \"NAME\"\n\n    puts \"HELLO.\"\n    puts \"MY NAME iS COMPUTER.\"\n    print \"WHAT'S YOUR NAME (FIRST AND LAST)? \"\n    name = gets.chomp!\n    puts \"\"\n    name_as_list = name.split(\"\")\n    reversed_name = name_as_list.reverse.join(\"\")\n\n    puts \"THANK YOU, #{reversed_name}.\\n\"\n    puts \"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\"\n    puts \"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\\n\\n\"\n    puts \"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\"\n\n    sorted_name = name_as_list.sort.join(\"\")\n    puts \"LET'S PUT THEM IN ORDER LIKE THIS: #{sorted_name}\\n\\n\"\n    print \"DON'T YOU LIKE THAT BETTER? \"\n    like_answer = gets.chomp!\n    puts\n    if is_yes_ish(like_answer)\n        puts \"I KNEW YOU'D AGREE!!\"\n    else\n        puts \"I'M SORRY YOU DON'T LIKE IT THAT WAY.\"\n    end\n\n    puts \"\"\n    puts \"I REALLY ENJOYED MEETING YOU, #{name}.\"\n    puts \"HAVE A NICE DAY!\"\nend\n\n\nif __FILE__ == $0\n    main\nend"
  },
  {
    "path": "63_Name/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n"
  },
  {
    "path": "63_Name/rust/src/main.rs",
    "content": "/** NAME GAME BY GEOFFREY CHASE\n * https://github.com/coding-horror/basic-computer-games/blob/main/63_Name/name.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 17/02/25\n*/\n\nuse std::io::Write;\n\nfn main() {\n    let mut input = String::new();\n    \n    //1 PRINT TAB(34);\"NAME\"\n    //2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    //3 PRINT: PRINT: PRINT\n    print!(\"{}{}\\n{}{}\\n\\n\\n\\n\",\n        \" \".repeat(34),\n        \"NAME\",\n        \" \".repeat(15),\n        \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    \n    //5 DIM B$(40)\n    let mut b = [0; 40];\n    \n    //10 PRINT \"HELLO.\": PRINT \"MY NAME IS CREATIVE COMPUTER.\"\n    //20 PRINT \"WHAT'S YOUR NAME (FIRST AND LAST\";: INPUT A$: L=LEN(A$)\n    print!(\"{}\\n{}\\n{}\",\n        \"HELLO.\",\n        \"MY NAME IS CREATIVE COMPUTER.\",\n        \"WHAT'S YOUR NAME (FIRST AND LAST)? \"\n    );\n    \n    let _ = std::io::stdout().flush().unwrap();\n    std::io::stdin().read_line(&mut input).unwrap();\n    let a = input.trim().to_uppercase();\n    let l = a.len();\n    \n    //30 PRINT: PRINT \"THANK YOU, \";\n    print!(\"\\nTHANK YOU, \");\n    \n    //40 FOR I=1 TO L: B$(I)=MID$(A$,I,1): NEXT I\n    for i in 1..=l {\n        b[i-1] = a.chars().nth(i-1).unwrap() as u8;\n    }\n    \n    //50 FOR I=L TO 1 STEP -1: PRINT B$(I);: NEXT I\n    for i in (1..=l).rev() {\n        print!(\"{}\", b[i-1] as char);\n    }\n    \n    //60 PRINT \".\": PRINT \"OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\"\n    //70 PRINT \"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\": PRINT\n    //80 PRINT \"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\"\n    //90 PRINT \"LET'S PUT THEM IN ORDER LIKE THIS: \";\n    print!(\"{}\\n{}\\n{}\\n\\n{}\\n{}\",\n        \".\",\n        \"OOPS! I GUESS I GOT IT BACKWARDS. A SMART\",\n        \"COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\",\n        \"BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\",\n        \"LET'S PUT THEM IN ORDER LIKE THIS: \"\n    );\n\n    //100 FOR J=2 TO L: I=J-1: T$=B$(J)\n    let mut i;\n    let mut t;\n    for j in 2..=l { \n        i = j - 1;\n        t = b[j-1];\n        loop {\n            //110 IF T$>B$(I) THEN 130\n            if i == 0 || t > b[i-1] {\n                //130 B$(I+1)=T$: NEXT J\n                b[i] = t;\n                break;\n            } else {\n                //120 B$(I+1)=B$(I): I=I-1: IF I>0 THEN 110\n                b[i] = b[i-1];\n                i = i - 1;\n            }\n        } \n    }\n    \n    //140 FOR I=1 TO L: PRINT B$(I);: NEXT I: PRINT: PRINT\n    for i in 1..=l {\n        print!(\"{}\", b[i-1] as char);\n    }\n    print!(\"\\n\\n\");\n    \n    //150 PRINT \"DON'T YOU LIKE THAT BETTER\";: INPUT D$\n    print!(\"DON'T YOU LIKE THAT BETTER? \");\n    \n    let _ = std::io::stdout().flush().unwrap();\n    input.clear();\n    std::io::stdin().read_line(&mut input).unwrap();\n    let d = input.trim().to_uppercase();\n    \n    //160 IF D$=\"YES\" THEN 180\n    if d == \"YES\" || d == \"Y\" {\n        //180 PRINT: PRINT \"I KNEW YOU'D AGREE!!\"\n        print!(\"\\nI KNEW YOU'D AGREE!!\");\n    }\n    else {\n        //170 PRINT: PRINT \"I'M SORRY YOU DON'T LIKE IT THAT WAY.\": GOTO 200\n        print!(\"\\nI'M SORRY YOU DON'T LIKE IT THAT WAY.\");\n    }\n    \n    print!(\"\\n\\n{}{}.\\n{}\\n\",\n        \"I REALLY ENJOYED MEETING YOU \",\n        a,\n        \"HAVE A NICE DAY!\"\n    );\n    \n    //999 END\n}\n"
  },
  {
    "path": "63_Name/vbnet/Name.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Name\", \"Name.vbproj\", \"{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "63_Name/vbnet/Name.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Name</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "63_Name/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "64_Nicomachus/README.md",
    "content": "### Nicomachus\n\nOne of the most ancient forms of arithmetic puzzle is sometimes referred to as a “boomerang.” At some time, everyone has been asked to “think of a number,” and, after going through some process of private calculation, to state the result, after which the questioner promptly tells you the number you originally thought of. There are hundreds of varieties of this puzzle.\n\nThe oldest recorded example appears to be that given in _Arithmetica_ of Nicomachus, who died about the year 120. He tells you to think of any whole number between 1 and 100 and divide it successfully by 3, 5, and 7, telling him the remainder in each case. On receiving this information, he promptly discloses the number you thought of.\n\nCan you discover a simple method of mentally performing this feat? If not, you can see how the ancient mathematician did it by looking at this program.\n\nNicomachus was written by David Ahl.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=117)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=132)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "64_Nicomachus/csharp/Nicomachus.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "64_Nicomachus/csharp/Nicomachus.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Nicomachus\", \"Nicomachus.csproj\", \"{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "64_Nicomachus/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "64_Nicomachus/csharp/program.cs",
    "content": "using System.Text;\nusing System.Threading;\n\nnamespace Nicomachus\n{\n    class Nicomachus\n    {\n        private void DisplayIntro()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"NICOMA\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"Boomerang puzzle from Arithmetica of Nicomachus -- A.D. 90!\");\n       }\n\n        private bool PromptYesNo(string Prompt)\n        {\n            bool Success = false;\n\n            while (!Success)\n            {\n                Console.Write(Prompt);\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (LineInput.Equals(\"yes\"))\n                    return true;\n                else if (LineInput.Equals(\"no\"))\n                    return false;\n                else\n                    Console.WriteLine(\"Eh?  I don't understand '{0}'  Try 'Yes' or 'No'.\", LineInput);\n            }\n\n            return false;\n        }\n\n        private int PromptForNumber(string Prompt)\n        {\n            bool InputSuccess = false;\n            int ReturnResult = 0;\n\n            while (!InputSuccess)\n            {\n                Console.Write(Prompt);\n                string Input = Console.ReadLine().Trim();\n                InputSuccess = int.TryParse(Input, out ReturnResult);\n                if (!InputSuccess)\n                    Console.WriteLine(\"*** Please enter a valid number ***\");\n            }   \n\n            return ReturnResult;\n        }\n\n        private void PlayOneRound()\n        {\n            Random rand = new Random();\n            int A_Number = 0;\n            int B_Number = 0;\n            int C_Number = 0;\n            int D_Number = 0;\n\n            Console.WriteLine();\n            Console.WriteLine(\"Please think of a number between 1 and 100.\");\n\n            A_Number = PromptForNumber(\"Your number divided by 3 has a remainder of? \");\n            B_Number = PromptForNumber(\"Your number divided by 5 has a remainder of? \");\n            C_Number = PromptForNumber(\"Your number divided by 7 has a remainder of? \");\n\n            Console.WriteLine();\n            Console.WriteLine(\"Let me think a moment...\");\n\n            Thread.Sleep(2000);\n\n            D_Number = 70 * A_Number + 21 * B_Number + 15 * C_Number;\n\n            while (D_Number > 105)\n            {\n                D_Number -= 105;\n            }\n\n            if (PromptYesNo(\"Your number was \" + D_Number.ToString() + \", right? \"))\n            {\n                Console.WriteLine();\n                Console.WriteLine(\"How about that!!\");\n            }\n            else\n            {\n                Console.WriteLine();\n                Console.WriteLine(\"I feel your arithmetic is in error.\");\n            }\n\n            Console.WriteLine();\n\n       }\n\n        public void Play()\n        {\n            bool ContinuePlay = true;\n\n            DisplayIntro();\n\n            do \n            {\n                PlayOneRound();\n\n                ContinuePlay = PromptYesNo(\"Let's try another? \");\n            }\n            while (ContinuePlay);\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Nicomachus().Play();\n\n        }\n    }\n}"
  },
  {
    "path": "64_Nicomachus/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "64_Nicomachus/java/src/Nicomachus.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Nichomachus\n * <p>\n * Based on the Basic game of Nichomachus here\n * https://github.com/coding-horror/basic-computer-games/blob/main/64%20Nicomachus/nicomachus.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\npublic class Nicomachus {\n\n    public static final long TWO_SECONDS = 2000;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        START_GAME,\n        GET_INPUTS,\n        RESULTS,\n        PLAY_AGAIN\n    }\n\n    int remainderNumberDividedBy3;\n    int remainderNumberDividedBy5;\n    int remainderNumberDividedBy7;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    public Nicomachus() {\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.START_GAME;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() throws Exception {\n\n        do {\n            switch (gameState) {\n\n                case START_GAME:\n                    intro();\n                    gameState = GAME_STATE.GET_INPUTS;\n                    break;\n\n                case GET_INPUTS:\n\n                    System.out.println(\"PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\");\n                    remainderNumberDividedBy3 = displayTextAndGetNumber(\"YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF? \");\n                    remainderNumberDividedBy5 = displayTextAndGetNumber(\"YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF? \");\n                    remainderNumberDividedBy7 = displayTextAndGetNumber(\"YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF? \");\n\n                    gameState = GAME_STATE.RESULTS;\n\n                case RESULTS:\n                    System.out.println(\"LET ME THINK A MOMENT...\");\n                    // Simulate the basic programs for/next loop to delay things.\n                    // Here we are sleeping for one second.\n                    Thread.sleep(TWO_SECONDS);\n\n                    // Calculate the number the player was thinking of.\n                    int answer = (70 * remainderNumberDividedBy3) + (21 * remainderNumberDividedBy5)\n                            + (15 * remainderNumberDividedBy7);\n\n                    // Something similar was in the original basic program\n                    // (to test if the answer was 105 and deducting 105 until it was <= 105\n                    while (answer > 105) {\n                        answer -= 105;\n                    }\n\n                    do {\n                        String input = displayTextAndGetInput(\"YOUR NUMBER WAS \" + answer + \", RIGHT? \");\n                        if (yesEntered(input)) {\n                            System.out.println(\"HOW ABOUT THAT!!\");\n                            break;\n                        } else if (noEntered(input)) {\n                            System.out.println(\"I FEEL YOUR ARITHMETIC IS IN ERROR.\");\n                            break;\n                        } else {\n                            System.out.println(\"EH?  I DON'T UNDERSTAND '\" + input + \"'  TRY 'YES' OR 'NO'.\");\n                        }\n                    } while (true);\n\n                    gameState = GAME_STATE.PLAY_AGAIN;\n                    break;\n\n                case PLAY_AGAIN:\n                    System.out.println(\"LET'S TRY ANOTHER\");\n                    gameState = GAME_STATE.GET_INPUTS;\n                    break;\n            }\n\n            // Original basic program looped until CTRL-C\n        } while (true);\n    }\n\n    private void intro() {\n        System.out.println(addSpaces(33) + \"NICOMA\");\n        System.out.println(addSpaces(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\");\n        System.out.println();\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.nextLine();\n    }\n\n    /**\n     * Return a string of x spaces\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String addSpaces(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Checks whether player entered N or NO to a question.\n     *\n     * @param text player string from kb\n     * @return true of N or NO was entered, otherwise false\n     */\n    private boolean noEntered(String text) {\n        return stringIsAnyValue(text, \"N\", \"NO\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text));\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        Nicomachus nicomachus = new Nicomachus();\n        nicomachus.play();\n    }\n}\n"
  },
  {
    "path": "64_Nicomachus/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "64_Nicomachus/javascript/nicomachus.html",
    "content": "<html>\n<head>\n<title>NICOMACHUS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"nicomachus.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "64_Nicomachus/javascript/nicomachus.js",
    "content": "// NICOMACHUS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar str;\nvar b;\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"NICOMA\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\\n\");\n    while (1) {\n        print(\"\\n\");\n        print(\"PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\\n\");\n        print(\"YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF\");\n        a = parseInt(await input());\n        print(\"YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF\");\n        b = parseInt(await input());\n        print(\"YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF\");\n        c = parseInt(await input());\n        print(\"\\n\");\n        print(\"LET ME THINK A MOMENT...\\n\");\n        print(\"\\n\");\n        d = 70 * a + 21 * b + 15 * c;\n        while (d > 105)\n            d -= 105;\n        print(\"YOUR NUMBER WAS \" + d + \", RIGHT\");\n        while (1) {\n            str = await input();\n            print(\"\\n\");\n            if (str == \"YES\") {\n                print(\"HOW ABOUT THAT!!\\n\");\n                break;\n            } else if (str == \"NO\") {\n                print(\"I FEEL YOUR ARITHMETIC IS IN ERROR.\\n\");\n                break;\n            } else {\n                print(\"EH?  I DON'T UNDERSTAND '\" + str + \"'  TRY 'YES' OR 'NO'.\\n\");\n            }\n        }\n        print(\"\\n\");\n        print(\"LET'S TRY ANOTHER.\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "64_Nicomachus/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "64_Nicomachus/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "64_Nicomachus/nicomachus.bas",
    "content": "2 PRINT TAB(33);\"NICOMA\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 PRINT \"BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\"\n20 PRINT\n30 PRINT \"PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\"\n40 PRINT \"YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF\";\n45 INPUT A\n50 PRINT \"YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF\";\n55 INPUT B\n60 PRINT \"YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF\";\n65 INPUT C\n70 PRINT\n80 PRINT \"LET ME THINK A MOMENT...\"\n85 PRINT\n90 FOR I=1 TO 1500: NEXT I\n100 D=70*A+21*B+15*C\n110 IF D<=105 THEN 140\n120 D=D-105\n130 GOTO 110\n140 PRINT \"YOUR NUMBER WAS\";D;\", RIGHT\";\n160 INPUT A$\n165 PRINT\n170 IF A$=\"YES\" THEN 220\n180 IF A$=\"NO\" THEN 240\n190 PRINT \"EH?  I DON'T UNDERSTAND '\";A$;\"'  TRY 'YES' OR 'NO'.\"\n200 GOTO 160\n220 PRINT \"HOW ABOUT THAT!!\"\n230 GOTO 250\n240 PRINT \"I FEEL YOUR ARITHMETIC IS IN ERROR.\"\n250 PRINT\n260 PRINT \"LET'S TRY ANOTHER.\"\n270 GOTO 20\n999 END\n"
  },
  {
    "path": "64_Nicomachus/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "64_Nicomachus/perl/nicomachus.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 33 . \"NICOMA\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\nprint \"BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\\n\";\n\n\nwhile (1) {\n\tprint \"\\n\";\n\tprint \"PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\\n\";\n\tprint \"YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF\";\n\tprint \"? \"; chomp(my $A = <STDIN>);\n\tprint \"YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF\";\n\tprint \"? \"; chomp(my $B = <STDIN>);\n\tprint \"YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF\";\n\tprint \"? \"; chomp(my $C = <STDIN>);\n\tprint \"\\n\";\n\tprint \"LET ME THINK A MOMENT...\\n\";\n\tprint \"\\n\";\n\tfor (my $I=1; $I<=1500; $I++) { }\n\tmy $D= 70*$A+21*$B+15*$C;\n\n\twhile ($D>105) {\n\t\t$D= $D-105;\n\t\t}\n\n\tprint \"YOUR NUMBER WAS $D, RIGHT\";\n\n\tmy $Flag=0;\n\tdo {\n\t\tprint \"? \"; chomp($A = uc(<STDIN>));\n\t\tprint \"\\n\";\n\t\tif ($A eq \"YES\") { print \"HOW ABOUT THAT!!\\n\"; $Flag=1; }\n\t\tif ($A eq \"NO\") { print \"I FEEL YOUR ARITHMETIC IS IN ERROR.\\n\"; $Flag=1; }\n\t\tif ($Flag==0) { print \"EH? I DON'T UNDERSTAND '$A' TRY 'YES' OR 'NO'.\\n\"; }\n\t\t} until ($Flag==1);\n\n\tprint \"\\n\";\n\tprint \"LET'S TRY ANOTHER.\\n\";\n\t} #goto Line20;\nexit;\n"
  },
  {
    "path": "64_Nicomachus/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "64_Nicomachus/python/nicomachus.py",
    "content": "\"\"\"\nNICOMACHUS\n\nMath exercise/demonstration\n\nPorted by Dave LeCompte\n\"\"\"\n\n# PORTING NOTE\n#\n# The title, as printed ingame, is \"NICOMA\", hinting at a time when\n# filesystems weren't even 8.3, but could only support 6 character\n# filenames.\n\nimport time\n\n\ndef get_yes_or_no() -> bool:\n    while True:\n        response = input().upper()\n        if response == \"YES\":\n            return True\n        elif response == \"NO\":\n            return False\n        print(f\"EH?  I DON'T UNDERSTAND '{response}'  TRY 'YES' OR 'NO'.\")\n\n\ndef play_game() -> None:\n    print(\"PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\")\n    print(\"YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF\")\n    a = int(input())\n    print(\"YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF\")\n    b = int(input())\n    print(\"YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF\")\n    c = int(input())\n    print()\n    print(\"LET ME THINK A MOMENT...\")\n    print()\n\n    time.sleep(2.5)\n\n    d = (70 * a + 21 * b + 15 * c) % 105\n\n    print(f\"YOUR NUMBER WAS {d}, RIGHT?\")\n\n    if get_yes_or_no():\n        print(\"HOW ABOUT THAT!!\")\n    else:\n        print(\"I FEEL YOUR ARITHMETIC IS IN ERROR.\")\n    print()\n    print(\"LET'S TRY ANOTHER\")\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"NICOMA\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    print(\"BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\")\n    print()\n    while True:\n        play_game()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "64_Nicomachus/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "64_Nicomachus/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "64_Nicomachus/rust/src/main.rs",
    "content": "use std::io;\n\nfn main() {\n    println!(\"\\n\\n~~Nicomachus~~\");\n    println!(\"Creative Computing Morristown, New Jersey\\n\");\n\n    println!(\"Boomerang Puzzle from Arithmetica of Nicomachus -- A.D. 90!\\n\");\n\n    loop {\n        println!(\"Please think of a number between 1 and 100.\\n\");\n\n        let a = question(\"3\");\n        let b = question(\"5\");\n        let c = question(\"7\");\n\n        println!(\"\\nLet me think a moment...\");\n        std::thread::sleep(std::time::Duration::from_secs(2));\n\n        let d: i32 = (70 * a + 21 * b + 15 * c) % 105;\n\n        if prompt(format!(\"Your number was {}, right?\", d)) {\n            println!(\"\\nHow about that!!\");\n        } else {\n            println!(\"\\nI feel your arithmetic is in error.\");\n        }\n\n        if !prompt(\"\\nTry another?\".to_string()) {\n            break;\n        }\n    }\n}\n\nfn question(n: &str) -> i32 {\n    loop {\n        println!(\"Your number divided by {} has a remainder of?\", n);\n\n        let input = read_line().trim().parse::<i32>();\n\n        match input {\n            Ok(r) => return r,\n            Err(_) => println!(\"Input must be a number.\"),\n        }\n    }\n}\n\nfn prompt(msg: String) -> bool {\n    println!(\"{}\", msg);\n\n    loop {\n        let input = read_line().trim().to_uppercase();\n        let input = input.as_str();\n\n        if input == \"Y\" || input == \"YES\" {\n            return true;\n        } else if input == \"N\" || input == \"NO\" {\n            return false;\n        } else {\n            println!(\"Please input either (Y)es or (N)o.\")\n        }\n    }\n}\n\nfn read_line() -> String {\n    let mut input = String::new();\n\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line.\");\n\n    input\n}\n"
  },
  {
    "path": "64_Nicomachus/vbnet/Nicomachus.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Nicomachus\", \"Nicomachus.vbproj\", \"{B4987617-A235-4CBA-A158-A668B6C36FE1}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B4987617-A235-4CBA-A158-A668B6C36FE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B4987617-A235-4CBA-A158-A668B6C36FE1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B4987617-A235-4CBA-A158-A668B6C36FE1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B4987617-A235-4CBA-A158-A668B6C36FE1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "64_Nicomachus/vbnet/Nicomachus.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Nicomachus</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "64_Nicomachus/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "65_Nim/README.md",
    "content": "### Nim\n\nNIM is one of the oldest two-person games known to man; it is believed to have originated in ancient China. The name, which was coined by the first mathematician to analyze it, comes from an archaic English verb which means to steal or to take away. Objects are arranged in rows between the two opponents as in the following example:\n|         |       |           |\n|---------|-------|-----------|\n| XXXXXXX | Row 1 | 7 Objects |\n| XXXXX   | Row 2 | 5 Objects |\n| XXX     | Row 3 | 3 Objects |\n| X       | Row 4 | 1 Object  |\n\nOpponents take turns removing objects until there are none left. The one who picks up the last object wins. The moves are made according to the following rules:\n1. On any given turn only objects from one row may be removed. There is no restriction on which row or on how many objects you remove. Of course, you cannot remove more than are in the row.\n2. You cannot skip a move or remove zero objects.\n\nThe winning strategy can be mathematically defined, however, rather than presenting it here, we’d rather let you find it on your own. HINT: Play a few games with the computer and mark down on a piece of paper the number of objects in each stack (in binary!) after each move. Do you see a pattern emerging?\n\nThis game of NIM is from Dartmouth College and allows you to specify any starting size for the four piles and also a win option. To play traditional NIM, you would simply specify 7,5,3 and 1, and win option 1.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=118)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=133)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\nThis can be a real challenge to port because of all the `GOTO`s going out of loops down to code. You may need breaks and continues, or other techniques.\n\n#### Known Bugs\n\n- If, after the player moves, all piles are gone, the code prints \"MACHINE LOSES\" regardless of the win condition (when line 1550 jumps to line 800).  This should instead jump to line 800 (\"machine loses\") if W=1, but jump to 820 (\"machine wins\") if W=2.\n"
  },
  {
    "path": "65_Nim/csharp/Nim.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "65_Nim/csharp/Nim.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Nim\", \"Nim.csproj\", \"{00B15B50-9CB1-46B1-8066-5877F972EE88}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{00B15B50-9CB1-46B1-8066-5877F972EE88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{00B15B50-9CB1-46B1-8066-5877F972EE88}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{00B15B50-9CB1-46B1-8066-5877F972EE88}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{00B15B50-9CB1-46B1-8066-5877F972EE88}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "65_Nim/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "65_Nim/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "65_Nim/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "65_Nim/javascript/nim.html",
    "content": "<html>\n<head>\n<title>NIM</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"nim.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "65_Nim/javascript/nim.js",
    "content": "// NIM\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a = [];\nvar b = [];\nvar d = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"NIM\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 1; i <= 100; i++) {\n        a[i] = 0;\n        b[i] = [];\n        for (j = 0; j <= 10; j++)\n            b[i][j] = 0;\n    }\n    d[0] = 0;\n    d[1] = 0;\n    d[2] = 0;\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    while (1) {\n        str = await input();\n        str = str.toUpperCase();\n        if (str == \"YES\" || str == \"NO\")\n            break;\n        print(\"PLEASE ANSWER YES OR NO\\n\");\n    }\n    if (str == \"YES\") {\n        print(\"THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.\\n\");\n        print(\"ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND\\n\");\n        print(\"THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE\\n\");\n        print(\"ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST\\n\");\n        print(\"TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM\\n\");\n        print(\"ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER\\n\");\n        print(\"WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,\\n\");\n        print(\"THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE\\n\");\n        print(\"ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A\\n\");\n        print(\"DIFFERENT NUMBER OF OBJECTS.\\n\");\n        print(\"THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE\\n\");\n        print(\"NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS\\n\");\n        print(\"MOVES.\\n\");\n    }\n    while (1) {\n        print(\"\\n\");\n        while (1) {\n            print(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST\");\n            w = parseInt(await input());\n            if (w == 1 || w == 2)\n                break;\n        }\n        while (1) {\n            print(\"ENTER NUMBER OF PILES\");\n            n = parseInt(await input());\n            if (n >= 1 && n <= 100)\n                break;\n        }\n        print(\"ENTER PILE SIZES\\n\");\n        for (i = 1; i <= n; i++) {\n            while (1) {\n                print(i + \" \");\n                a[i] = parseInt(await input());\n                if (a[i] >= 1 && a[i] <= 2000)\n                    break;\n            }\n        }\n        print(\"DO YOU WANT TO MOVE FIRST\");\n        while (1) {\n            str = await input();\n            str = str.toUpperCase();\n            if (str == \"YES\" || str == \"NO\")\n                break;\n            print(\"PLEASE ANSWER YES OR NO.\\n\");\n        }\n        if (str == \"YES\")\n            player_first = true;\n        else\n            player_first = false;\n        while (1) {\n            if (!player_first) {\n                if (w != 1) {\n                    c = 0;\n                    for (i = 1; i <= n; i++) {\n                        if (a[i] == 0)\n                            continue;\n                        c++;\n                        if (c == 3)\n                            break;\n                        d[c] = i;\n                    }\n                    if (i > n) {\n                        if (c == 2) {\n                            if (a[d[1]] == 1 || a[d[2]] == 1) {\n                                print(\"MACHINE WINS\\n\");\n                                break;\n                            }\n                        } else {\n                            if (a[d[1]] > 1)\n                                print(\"MACHINE WINS\\n\");\n                            else\n                                print(\"MACHINE LOSES\\n\");\n                            break;\n                        }\n\n                    } else {\n                        c = 0;\n                        for (i = 1; i <= n; i++) {\n                            if (a[i] > 1)\n                                break;\n                            if (a[i] == 0)\n                                continue;\n                            c++;\n                        }\n                        if (i > n && c % 2) {\n                            print(\"MACHINE LOSES\\n\");\n                            break;\n                        }\n                    }\n                }\n                for (i = 1; i <= n; i++) {\n                    e = a[i];\n                    for (j = 0; j <= 10; j++) {\n                        f = e / 2;\n                        b[i][j] = 2 * (f - Math.floor(f));\n                        e = Math.floor(f);\n                    }\n                }\n                for (j = 10; j >= 0; j--) {\n                    c = 0;\n                    h = 0;\n                    for (i = 1; i <= n; i++) {\n                        if (b[i][j] == 0)\n                            continue;\n                        c++;\n                        if (a[i] <= h)\n                            continue;\n                        h = a[i];\n                        g = i;\n                    }\n                    if (c % 2)\n                        break;\n                }\n                if (j < 0) {\n                    do {\n                        e = Math.floor(n * Math.random() + 1);\n                    } while (a[e] == 0) ;\n                    f = Math.floor(a[e] * Math.random() + 1);\n                    a[e] -= f;\n                } else {\n                    a[g] = 0;\n                    for (j = 0; j <= 10; j++) {\n                        b[g][j] = 0;\n                        c = 0;\n                        for (i = 1; i <= n; i++) {\n                            if (b[i][j] == 0)\n                                continue;\n                            c++;\n                        }\n                        a[g] = a[g] + (c % 2) * Math.pow(2, j);\n                    }\n                    if (w != 1) {\n                        c = 0;\n                        for (i = 1; i <= n; i++) {\n                            if (a[i] > 1)\n                                break;\n                            if (a[i] == 0)\n                                continue;\n                            c++;\n                        }\n                        if (i > n && c % 2 == 0)\n                            a[g] = 1 - a[g];\n                    }\n                }\n                print(\"PILE  SIZE\\n\");\n                for (i = 1; i <= n; i++)\n                    print(\" \" + i + \"  \" + a[i] + \"\\n\");\n                if (w != 2) {\n                    if (game_completed()) {\n                        print(\"MACHINE WINS\");\n                        break;\n                    }\n                }\n            } else {\n                player_first = false;\n            }\n            while (1) {\n                print(\"YOUR MOVE - PILE , NUMBER TO BE REMOVED\");\n                str = await input();\n                x = parseInt(str);\n                y = parseInt(str.substr(str.indexOf(\",\") + 1));\n                if (x < 1 || x > n)\n                    continue;\n                if (y < 1 || y > a[x])\n                    continue;\n                break;\n            }\n            a[x] -= y;\n            if (game_completed()) {\n                print(\"MACHINE LOSES\");\n                break;\n            }\n        }\n        print(\"DO YOU WANT TO PLAY ANOTHER GAME\");\n        while (1) {\n            str = await input();\n            str = str.toUpperCase();\n            if (str == \"YES\" || str == \"NO\")\n                break;\n            print(\"PLEASE ANSWER YES OR NO.\\n\");\n        }\n        if (str == \"NO\")\n            break;\n    }\n}\n\nfunction game_completed()\n{\n    for (var i = 1; i <= n; i++) {\n        if (a[i] != 0)\n            return false;\n    }\n    return true;\n}\n\nmain();\n"
  },
  {
    "path": "65_Nim/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "65_Nim/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "65_Nim/nim.bas",
    "content": "100 PRINT TAB(33);\"NIM\"\n110 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n120 PRINT:PRINT:PRINT\n210 DIM A(100),B(100,10),D(2)\n220 PRINT \"THIS IS THE GAME OF NIM.\"\n230 PRINT \"DO YOU WANT INSTRUCTIONS\";\n240 INPUT Z$\n250 IF Z$=\"NO\" THEN 440\n260 IF Z$=\"no\" THEN 440\n270 IF Z$=\"YES\" THEN 310\n280 IF Z$=\"yes\" THEN 310\n290 PRINT \"PLEASE ANSWER YES OR NO\"\n300 GOTO 240\n310 PRINT \"THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.\"\n320 PRINT \"ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND\"\n330 PRINT \"THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE\"\n340 PRINT \"ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST\"\n350 PRINT \"TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM\"\n360 PRINT \"ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER\"\n370 PRINT \"WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,\"\n380 PRINT \"THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE\"\n390 PRINT \"ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A\"\n400 PRINT \"DIFFERENT NUMBER OF OBJECTS.\"\n410 PRINT \"THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE\"\n420 PRINT \"NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS\"\n430 PRINT \"MOVES.\"\n440 PRINT\n450 PRINT \"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST\";\n460 INPUT W\n470 IF W=1 THEN 490\n480 IF W<>2 THEN 450\n490 PRINT \"ENTER NUMBER OF PILES\";\n500 INPUT N\n510 IF N>100 THEN 490\n520 IF N<1 THEN 490\n530 IF N<>INT(N) THEN 490\n540 PRINT \"ENTER PILE SIZES\"\n550 FOR I=1 TO N\n560 PRINT I;\n570 INPUT A(I)\n580 IF A(I)>2000 THEN 560\n590 IF A(I)<1 THEN 560\n600 IF A(I)<>INT(A(I)) THEN 560\n610 NEXT I\n620 PRINT \"DO YOU WANT TO MOVE FIRST\";\n630 INPUT Q9$\n640 IF Q9$=\"YES\" THEN 1450\n650 IF Q9$=\"yes\" THEN 1450\n660 IF Q9$=\"NO\" THEN 700\n670 IF Q9$=\"no\" THEN 700\n680 PRINT \"PLEASE ANSWER YES OR NO.\"\n690 GOTO 630\n700 IF W=1 THEN 940\n710 LET C=0\n720 FOR I=1 TO N\n730 IF A(I)=0 THEN 770\n740 LET C=C+1\n750 IF C=3 THEN 840\n760 LET D(C)=I\n770 NEXT I\n780 IF C=2 THEN 920\n790 IF A(D(1))>1 THEN 820\n800 PRINT \"MACHINE LOSES\"\n810 GOTO 1640\n820 PRINT \"MACHINE WINS\"\n830 GOTO 1640\n840 LET C=0\n850 FOR I=1 TO N\n860 IF A(I)>1 THEN 940\n870 IF A(I)=0 THEN 890\n880 LET C=C+1\n890 NEXT I\n900 IF C/2<>INT(C/2) THEN 800\n910 GOTO 940\n920 IF A(D(1))=1 THEN 820\n930 IF A(D(2))=1 THEN 820\n940 FOR I=1 TO N\n950 LET E=A(I)\n960 FOR J=0 TO 10\n970 LET F=E/2\n980 LET B(I,J)=2*(F-INT(F))\n990 LET E=INT(F)\n1000 NEXT J\n1010 NEXT I\n1020 FOR J=10 TO 0 STEP -1\n1030 LET C=0\n1040 LET H=0\n1050 FOR I=1 TO N\n1060 IF B(I,J)=0 THEN 1110\n1070 LET C=C+1\n1080 IF A(I)<=H THEN 1110\n1090 LET H=A(I)\n1100 LET G=I\n1110 NEXT I\n1120 IF C/2<>INT(C/2) THEN 1190\n1130 NEXT J\n1140 LET E=INT(N*RND(1)+1)\n1150 IF A(E)=0 THEN 1140\n1160 LET F=INT(A(E)*RND(1)+1)\n1170 LET A(E)=A(E)-F\n1180 GOTO 1380\n1190 LET A(G)=0\n1200 FOR J=0 TO 10\n1210 LET B(G,J)=0\n1220 LET C=0\n1230 FOR I=1 TO N\n1240 IF B(I,J)=0 THEN 1260\n1250 LET C=C+1\n1260 NEXT I\n1270 LET A(G)=A(G)+2*(C/2-INT(C/2))*2^J\n1280 NEXT J\n1290 IF W=1 THEN 1380\n1300 LET C=0\n1310 FOR I=1 TO N\n1320 IF A(I)>1 THEN 1380\n1330 IF A(I)=0 THEN 1350\n1340 LET C=C+1\n1350 NEXT I\n1360 IF C/2<>INT(C/2) THEN 1380\n1370 LET A(G)=1-A(G)\n1380 PRINT \"PILE  SIZE\"\n1390 FOR I=1 TO N\n1400 PRINT I;A(I)\n1410 NEXT I\n1420 IF W=2 THEN 1450\n1430 GOSUB 1570\n1440 IF Z=1 THEN 820\n1450 PRINT \"YOUR MOVE - PILE, NUMBER TO BE REMOVED\";\n1460 INPUT X,Y\n1470 IF X>N THEN 1450\n1480 IF X<1 THEN 1450\n1490 IF X<>INT(X) THEN 1450\n1500 IF Y>A(X) THEN 1450\n1510 IF Y<1 THEN 1450\n1520 IF Y<>INT(Y) THEN 1450\n1530 LET A(X)=A(X)-Y\n1540 GOSUB 1570\n1550 IF Z=1 THEN 800\n1560 GOTO 700\n1570 LET Z=0\n1580 FOR I=1 TO N\n1590 IF A(I)=0 THEN 1610\n1600 RETURN\n1610 NEXT I\n1620 LET Z=1\n1630 RETURN\n1640 PRINT \"do you want to play another game\";\n1650 INPUT Q9$\n1660 IF Q9$=\"YES\" THEN 1720\n1670 IF Q9$=\"yes\" THEN 1720\n1680 IF Q9$=\"NO\" THEN 1730\n1690 IF Q9$=\"no\" THEN 1730\n1700 PRINT \"PLEASE.  YES OR NO.\"\n1710 GOTO 1650\n1720 GOTO 440\n1730 END\n"
  },
  {
    "path": "65_Nim/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "65_Nim/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "65_Nim/python/Traditional_NIM.py",
    "content": "import random\nfrom typing import Tuple\n\n\nclass NIM:\n    def __init__(self) -> None:\n        self.piles = {1: 7, 2: 5, 3: 3, 4: 1}\n\n    def remove_pegs(self, command) -> None:\n        try:\n\n            pile, num = command.split(\",\")\n            num = int(num)\n            pile = int(pile)\n\n        except Exception as e:\n\n            if \"not enough values\" in str(e):\n                print(\n                    '\\nNot a valid command. Your command should be in the form of \"1,3\", Try Again\\n'\n                )\n\n            else:\n                print(\"\\nError, Try again\\n\")\n            return None\n\n        if self._command_integrity(num, pile):\n            self.piles[pile] -= num\n        else:\n            print(\"\\nInvalid value of either Peg or Pile\\n\")\n\n    def get_ai_move(self) -> Tuple[int, int]:\n        possible_pile = [k for k, v in self.piles.items() if v != 0]\n        pile = random.choice(possible_pile)\n\n        num = random.randint(1, self.piles[pile])\n\n        return pile, num\n\n    def _command_integrity(self, num, pile) -> bool:\n        return pile <= 4 and pile >= 1 and num <= self.piles[pile]\n\n    def print_pegs(self) -> None:\n        for pile, peg in self.piles.items():\n            print(f'Pile {pile} : {\"O \" * peg}')\n\n    def help(self) -> None:\n        print(\"-\" * 10)\n        print('\\nThe Game is player with a number of Piles of Objects(\"O\" == one peg)')\n        print(\"\\nThe Piles are arranged as given below(Tradional NIM)\\n\")\n        self.print_pegs()\n        print(\n            '\\nAny Number of of Objects are removed one pile by \"YOU\" and the machine alternatively'\n        )\n        print(\"\\nOn your turn, you may take all the objects that remain in any pile\")\n        print(\"but you must take ATLEAST one object\")\n        print(\"\\nAnd you may take objects from only one pile on a single turn.\")\n        print(\"\\nThe winner is defined as the one that picks the last remaning object\")\n        print(\"-\" * 10)\n\n    def check_for_win(self) -> bool:\n        sum = 0\n        for v in self.piles.values():\n            sum += v\n\n        return sum == 0\n\n\ndef main() -> None:\n    # Game initialization\n    game = NIM()\n\n    print(\"Hello, This is a game of NIM\")\n    help = input(\"Do You Need Instruction (YES or NO): \")\n\n    if help.lower() == \"yes\":\n        game.help()\n\n    # Start game loop\n    input(\"\\nPress Enter to start the Game:\\n\")\n\n    while True:\n        game.print_pegs()\n\n        # Players Move\n        command = input(\"\\nYOUR MOVE - Number of PILE, Number of Object? \")\n        game.remove_pegs(command)\n        if game.check_for_win():\n            print(\"\\nPlayer Wins the Game, Congratulations!!\")\n            input(\"\\nPress any key to exit\")\n            break\n\n        # Computers Move\n        ai_command = game.get_ai_move()\n        print(\n            f\"\\nA.I MOVE - A.I Removed {ai_command[1]} pegs from Pile {ai_command[0]}\"\n        )\n        game.remove_pegs(f\"{str(ai_command[0])},{str(ai_command[1])}\")\n        if game.check_for_win():\n            print(\"\\nComputer Wins the Game, Better Luck Next Time\\n\")\n            input(\"Press any key to exit\")\n            break\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "65_Nim/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "65_Nim/ruby/nim.rb",
    "content": "puts \"NIM\".center(80)\nputs\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".center(80)\nputs \"\\n\\n\\n\"\n\n#210 DIM A(100),B(100,10),D(2)\n$pileArray = Array.new[100]\n$bArray = Array.new\n$dArray = Array.new[2]\n$winOption = 0 # take-last option\n$numberOfPiles = 1\n$c = 0\n$e = 0\n$f = 0\n$g = 0\n$h = 0\n\ndef displayTheRules\nputs \"THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.\"\nputs \"ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND\"\nputs \"THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE\"\nputs \"ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST\"\nputs \"TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM\"\nputs \"ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER\"\nputs \"WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,\"\nputs \"THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE\"\nputs \"ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A\"\nputs \"DIFFERENT NUMBER OF OBJECTS.\"\nputs \"THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE\"\nputs \"NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS\"\nputs \"MOVES.\"\nend\n\ndef sub1570\n    $z=0\n    for i in 1..$numberOfPiles do\n        if $pileArray[i] != 0 then\n            return\n        end\n        $z=1\n        return\n    end\nend\n\ndef playAnother\n    put \"do you want to play another game\";\n    return gets.strip.ucase == \"YES\"\nend\nputs \"THIS IS THE GAME OF NIM.\"\nprint \"DO YOU WANT INSTRUCTIONS?\"\n240\nwantInstructions = gets.strip.upcase\nif wantInstructions == \"YES\" then\n    displayTheRules\nend\n#250 IF Z$=\"NO\" THEN 440\n#260 IF Z$=\"no\" THEN 440\n#270 IF Z$=\"YES\" THEN displayTheRules\n#280 IF Z$=\"yes\" THEN displayTheRules\n#290 PRINT \"PLEASE ANSWER YES OR NO\"\n#300 GOTO 240\n\ndef sub490 # get number of piles\n    print \"ENTER NUMBER OF PILES:\"\n    while $numberOfPiles < 0 && $numberOfPiles <= 100 do\n        $numberOfPiles = gets.strip.to_i\n    end\nend\n\ndef getPileSizes\n    puts \"ENTER PILE SIZES:\"\n    for i in 1..$numberOfPiles do\n        print i\n        while true do\n            $pileArray[i] = gets.strip.to_i\n            if $pileArray[i] < 2000 && $pileArray[i] > 0 then\n                break\n            end\n        end\n    end\nend\n\ndef sub440 # get win option\n    puts \"\"\n    $winOption = 0\n    while $winOption != 1 && q != 2 do\n        puts \"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST\"\n        $winOption = gets.strip.to_i\n    end\nend\n\nputs \"DO YOU WANT TO MOVE FIRST?\";\n#630 INPUT Q9$\nmoveFirst = \"\"\nwhile moveFirst != \"YES\" && moveFirst != \"NO\" do\n    moveFirst = gets.strip.upcase\n    case moveFirst\n        when \"YES\"\n            yourMove\n        when \"NO\"\n            machineMove\n    end\nend\n\n#640 IF Q9$=\"YES\" THEN 1450\n#650 IF Q9$=\"yes\" THEN 1450\n#660 IF Q9$=\"NO\" THEN 700\n#670 IF Q9$=\"no\" THEN 700\n#680 PRINT \"PLEASE ANSWER YES OR NO.\"\n#690 GOTO 630\n\ndef machineMove\n    if $winOption == 1 then\n        sub940 # take last\n    end\n    $c=0\n    for i in 1..$numberOfPiles do\n    if $pileArray[i] != 0 then 770\n    $c=$c+1\n    if $c == 3 then\n        sub840\n    end\n        $dArray[$c-1]=i\n    end\n    end\n\n    if $c == 2 then\n        sub920\n    end\n    if $pileArray[$dArray[0]] > 1 then\n        machineWins\n    end\n    machineLoses\nend\n\ndef machineLoses\n    puts \"MACHINE LOSES\"\n# 810 GOTO playAnother\n    if playAnother then\n        sub440 # loop for another\n    end\nend\n\ndef machineWins\n    puts \"MACHINE WINS\"\n#    830 GOTO playAnother\n    if playAnother then\n        sub440 # loop for another\n    end\nend\n\ndef sub840\n    $c=0\n    for i in 1..$numberOfPiles do\n    if $pileArray[i] > 1 then\n        sub940\n    end\n    if $pileArray[i] == 0 then 890\n        $c=$c+1\n    end\n    if $c/2 != ($c/2).to_i then\n        machineLoses\n    end\n    sub940 # goto\n    end\nend\n\ndef sub920\n    if $pileArray[$dArray[0]] == 1 then\n        machineWins\n    end\n    if $pileArray[$dArray[1]] == 1 then\n        machineWins\n    end\nend\n\ndef sub940\n    for i in 1..$numberOfPiles do\n        e=$pileArray[i]\n        for j in 0..10 do\n        $f = $e/2\n        $bArray[i][j] = 2*($f-($f.to_i))\n        $e = $f.to_i\n        end\n    end\nend\n\n#for j in 10..0 STEP -1 do\n10..0.step(-1).each do|index|\n    $c=0\n    $h=0\n    for i in 1..$numberOfPiles do\n        if $bArray[i][index] != 0 then\n            $c=$c+1\n            if $pileArray[i] > $h then\n                $h = $pileArray[i]\n                $g = i\n            end\n        end\n    end\nend\n\nif $c/2 != ($c/2).to_i then 1190\nend\n$e = rand($numberOfPiles).to_i\n#if $pileArray[$e] == 0 then 1140\n\n$f = rand($pileArray[$e]).to_i\n$pileArray[$e] = $pileArray[$e]-$f\nsub1380\n$pileArray[$g]=0\nfor j in 0..10 do\n$bArray[$g][index]=0\n$c=0\nfor i in 1..$numberOfPiles do\n    if $bArray[i][index] != 0 then\n            $c=$c+1\n        end\n    end\n$pileArray[$g]=$pileArray[$g]+2*($c/2-($c/2)).to_i*2^j\nend\nif $winOption == 1 then\n    sub1380\nend\n$c=0\nfor i in 1..$numberOfPiles do\nif $pileArray[i]>1 then\n    sub1380\nend\nif $pileArray[i] != 0 then\n    $c=$c+1\nend\nif $c/2 == ($c/2).to_i then\n    sub1380\nend\n$pileArray[$g] == 1 -$pileArray[$g]\n\ndef sub1380\n    puts \"PILE  SIZE\"\n    for i in 1..$numberOfPiles do\n        put i\n        put $pileArray[i]\n    end\n    if $winOption == 2 then # avoid take-last option\n        yourMove\n    end\n    sub1570\n    if $z == 1 then\n        machineWins\n    end\nend\n\ndef yourMove\n    put \"YOUR MOVE - PILE, NUMBER TO BE REMOVED\"\n#    1460 INPUT x,y\nx = gets.strip.to_i\ny = gets.strip.to_i\n    if x > $numberOfPiles then yourMove\n    if x < 1 then yourMove\n    if x != INT(x) then yourMove\n    if y > $pileArray[x] then yourMove\n    if y < 1 then\n        yourMove\n    end\n    if y != INT(y) then\n        yourMove\n    end\n\n    $pileArray[x] = $pileArray[x]-y\n    sub1570 # gosub\n    if $z == 1 then\n        machineLoses\n    end\n#    1560 GOTO 700\nend\n\nend\nend\nend\nend\nend\n"
  },
  {
    "path": "65_Nim/rust/Cargo.toml",
    "content": "[package]\nname = \"nim\"\nversion = \"1.0.0\"\nedition = \"2021\"\n\n[dependencies]\ntext_io = \"0.1.10\"\nnanorand = \"0.6.1\""
  },
  {
    "path": "65_Nim/rust/src/main.rs",
    "content": "/*\n * Nim\n * Originally from the wonderful book: _Basic Computer Games_\n * Port to Rust By David Lotts\n*/\nuse nanorand::{tls::TlsWyRand, Rng};\nuse std::io::{self, Write};\nuse text_io::{read, try_read};\n\n/// Play Nim\n// line numbers from the orginal Basic program are in the end of line comments. \n// If you see two number comments: the first one is a \n// GOTO or THEN destination, second is the current line. Example: // 800 //210\nfn main() {\n    let mut rng = nanorand::tls_rng();\n    println!(\"{:>37}\", \"NIM\"); //100\n    println!(\"{:>15}{}\", \"\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"); //110\n    println!();\n    println!();\n    println!(); //120\n    let mut piles = [0.0; 100];\n    let mut b_piles = [[0.0; 100]; 11];\n    let mut ix_do = [0usize; 3]; //210\n    println!(\"THIS IS THE GAME OF NIM.\"); //220\n                                          //230\n    loop {\n        let instuct_me = input(\"DO YOU WANT INSTRUCTIONS\"); //240\n        if instuct_me == \"NO\" || instuct_me == \"no\" {\n            break;\n        } //440   //260\n        if instuct_me == \"YES\" || instuct_me == \"yes\" {\n            instructions();\n            break;\n        } //310   //280\n        println!(\"PLEASE ANSWER YES OR NO\"); //290\n    } //300\n    'play_again: loop {\n        println!(); //440\n        let winner_take_last: bool = loop {\n            let choice = input_int(\"ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST\"); //460\n            if (1..=2).contains(&choice) {\n                break choice == 1;\n            } //490  //470\n        };\n        let np = loop {\n            //490\n            let choice = input_int(\"ENTER NUMBER OF PILES\"); //500\n            if choice <= 100 && choice >= 1 {\n                break choice;\n            } //490   //510\n              //490   //520\n              //490   //530\n        };\n        println!(\"ENTER PILE SIZES\"); //540\n        for ix in 0..np as usize {\n            //550\n            piles[ix] = loop {\n                let choice = input_int(&(ix + 1).to_string()); //570\n                if choice <= 2000 && choice >= 1 && choice >= 1 {\n                    break choice as f64;\n                } //560   //580\n                  //560   //600\n            }\n        } //610\n        let human_first = loop {\n            //620\n            let choice = input(\"DO YOU WANT TO MOVE FIRST\"); //630\n            let choice = choice.to_lowercase();\n            if choice == \"yes\" {\n                break true;\n            } //1450   //650\n            if choice == \"no\" {\n                break false;\n            } //700   //670\n            println!(\"PLEASE ANSWER YES OR NO.\"); //680\n        }; //690\n\n        let mut winner = WinState::GameOn;\n        if human_first {\n            winner = human_turn(winner_take_last, np, &mut piles);\n        };\n        //### main game loop\n        if winner.is_game_on() {\n            winner = loop {\n                // break on winner returning from here:\n                let win = machines_turn(\n                    &mut rng,\n                    winner_take_last,\n                    np,\n                    &mut piles,\n                    &mut ix_do,\n                    &mut b_piles,\n                );\n                if !win.is_game_on() {\n                    break win;\n                }; //starts at 700\n\n                println!(\"PILE  SIZE\"); //1380\n                for ix in 0..np as usize {\n                    //1390\n                    println!(\"{} {}\", ix + 1, piles[ix]); //1400\n                } //  NEXT ix   //1410\n\n                // break on winner returning from here:\n                let win = human_turn(winner_take_last, np, &mut piles);\n                if !win.is_game_on() {\n                    break win;\n                };\n                //  GOTO 700   //1560\n            };\n        }\n        println!(\n            \"MACHINE {}\",\n            if winner == WinState::ComputerWins {\n                \"WINS\"\n            } else {\n                \"LOSES\"\n            }\n        );\n        loop {\n            // Game over //1640\n            let choice = input(\"do you want to play another game\"); //1650\n            match choice.to_ascii_lowercase().as_str() {\n                \"yes\" => break,                       //1720   //1660\n                \"no\" => break 'play_again,            //1730   //1680\n                _ => println!(\"PLEASE.  YES OR NO.\"), //1700\n            } //  GOTO 1650    //1710\n        } //  GOTO 440   //1720\n    } //  END   //1730\n}\n\n#[derive(PartialEq)]\nenum WinState {\n    GameOn,\n    ComputerWins,\n    HumanWins,\n}\n\nimpl WinState {\n    /// Returns `true` if the win state is [`GameOn`].\n    ///\n    /// [`GameOn`]: WinState::GameOn\n    fn is_game_on(&self) -> bool {\n        matches!(self, Self::GameOn)\n    }\n}\n\n/// Computer's turn\nfn machines_turn(\n    rng: &mut TlsWyRand,\n    winner_take_last: bool,\n    np: i32,\n    piles: &mut [f64; 100],\n    ix_do: &mut [usize; 3],\n    b_piles: &mut [[f64; 100]; 11],\n) -> WinState {\n    if !winner_take_last {\n        //940   //700\n        //### Loser takes last, check for winner\n        let mut count = 0; //710\n        'wayout: loop {\n            'outer: loop {\n                for ix in 0..np as usize {\n                    //720\n                    if piles[ix] == 0.0 {\n                        continue;\n                    } //730\n                    count += 1; //740\n                    if count == 3 {\n                        break 'outer;\n                    } //840   //750\n                    ix_do[count] = ix; //760\n                } //770\n                  // exactly two piles remain\n                if count == 2 {\n                    // println!(\"Only two piles remain : unused0={} pile1={} pile2={}\",ix_do[0]+1,ix_do[1]+1,ix_do[2]+1); //diagnostic\n                    if piles[ix_do[1]] == 1.0 || piles[ix_do[2]] == 1.0 {\n                        //920\n                        return WinState::ComputerWins;\n                    } //820   //930\n                    break 'wayout;\n                } //920   //780\n                  // exactly one pile remains, loser takes last, and before machine's turn\n                  // println!(\"Only one pile remains : pile={}\",ix_do[1]); //diagnostic\n                assert!(piles[ix_do[1]] > 0.0);\n                if piles[ix_do[1]] == 1.0 {\n                    //820    //790\n                    return WinState::HumanWins; //800\n                                                // GOTO 1640   //810\n                } else {\n                    return WinState::ComputerWins; //820\n                                                   // GOTO 1640   //830\n                }\n            }\n            count = 0; //840\n            let mut is_all_ones = true;\n            for ix in 0..np as usize {\n                // FOR ix=1 TO N   //850\n                if piles[ix] > 1.0 {\n                    is_all_ones = false;\n                    break;\n                } //940   //860\n                if piles[ix] != 0.0 {\n                    //890   //870\n                    count = count + 1; //880\n                }\n            } // NEXT ix   //890\n            if is_all_ones && count % 2 != 0 {\n                //800   //900\n                return WinState::HumanWins;\n            }\n            break; // GOTO 940   //910\n        }\n    }\n    //### winner take last (or first?) -- check for winner\n    for ix in 0..np as usize {\n        //940\n        let mut sticks = piles[ix]; //950\n        for jx in 0..=10 {\n            //960\n            let half = sticks / 2.0; //970\n            b_piles[ix][jx] = 2.0 * (half - half.trunc()); //980\n            sticks = half.trunc(); //990\n        } //  NEXT J   //1000\n    } //  NEXT I   //1010\n\n    let mut is_odd = false;\n    let mut ix_max_pile = usize::MAX; // make sure this fails if ever used.\n    for jx in (0..=10).rev() {\n        //1020\n        let mut count = 0; //1030\n        let mut highest = 0.0; //1040\n        for ix in 0..np as usize {\n            //1050\n            if b_piles[ix][jx] == 0.0 {\n                continue;\n            }; //1110   //1060\n            count = count + 1; //1070\n            if piles[ix] <= highest as f64 {\n                continue;\n            }; //1110   //1080\n            highest = piles[ix]; //1090\n            ix_max_pile = ix; //1100\n        } //NEXT I   //1110\n          // println!(\"if none are odd, use random: count={} odd={}\", count,count%2!=0); //diagnostic\n        if count % 2 != 0 {\n            is_odd = true;\n            break;\n        } // C/2<>INT(C/2) //1190   //1120\n    } //  NEXT J   //1130\n    if !is_odd {\n        let mut ix_random;\n        loop {\n            ix_random = rng.generate_range(0..np as usize); //(N*RND(1)+1).trunc();   //1140\n            if piles[ix_random] != 0.0 {\n                break;\n            } //1140   //1150\n        }\n        let remove_random = rng.generate_range(1..=piles[ix_random] as i32); // INT(A[E]*RND(1)+1)   //1160\n        piles[ix_random] = piles[ix_random] - remove_random as f64; //1170\n        // println!(\"I choose random: pile={} removed={}\",ix_random+1,remove_random) //diagnostic\n        // GOTO 1380   //1180\n    } else {\n        // println!(\"max pile: pile={}, was={} setting to 0. Expect add back.\",ix_max_pile+1,piles[ix_max_pile]); //diagnostic\n        piles[ix_max_pile] = 0.0; //1190\n        for jx in 0..=10 {\n            //1200\n            b_piles[ix_max_pile][jx] = 0.0; //1210\n            let mut countum = 0; //1220\n            for ix in 0..np as usize {\n                //1230\n                if b_piles[ix][jx] == 0.0 {\n                    continue;\n                } //1260   //1240\n                countum += 1; // count non-empty  //1250\n            } //  NEXT ix   //1260\n            piles[ix_max_pile] =\n                piles[ix_max_pile] + ((countum % 2) * 2usize.pow(jx as u32)) as f64;\n            //1270\n            // println!(\"I choose max pile : pile={}, add back=odd?2^{}:0={}\",ix_max_pile+1,jx,((countum%2)*2usize.pow(jx as u32))); //diagnostic\n        } //  NEXT J   //1280\n\n        'done: loop {\n            if !winner_take_last {\n                //1380   //1290\n                let mut counter = 0; //1300\n                for ix in 0..np as usize {\n                    //1310\n                    if piles[ix] > 1.0 {\n                        break 'done;\n                    } //1380   //1320\n                    if piles[ix] != 0.0 {\n                        //1350  //1330\n                        counter += 1; //1340\n                    }\n                } //  NEXT ix   //1350\n                  // done if C is odd\n                if counter % 2 != 0 {\n                    break;\n                } //1380   //1360\n                  // println!(\"max pile if even: 1 - pile : pile={}, before 1-p = {}\",ix_max_pile+1,piles[ix_max_pile]); //diagnostic\n                piles[ix_max_pile] = 1.0 - piles[ix_max_pile]; //1370\n            }\n            break;\n        }\n    }\n    return WinState::GameOn; //1380 is after this\n}\n\n/// Human decide what you want to do and see if there is a winner\nfn human_turn(winner_take_last: bool, np: i32, piles: &mut [f64; 100]) -> WinState {\n    if winner_take_last {\n        //1450   //1420\n        let is_all_empty = one_if_all_zero(np, &piles); //  GOSUB 1570   //1430\n        if is_all_empty == 1 {\n            return WinState::ComputerWins;\n        } //820   //1440  //### machine wins\n    }\n    //### many things go here\n    loop {\n        //1450\n        let (pile_choice, remove_choice) = input_2int(\"YOUR MOVE - PILE, NUMBER TO BE REMOVED\"); //1460\n        if pile_choice > np || pile_choice < 1 {\n            continue;\n        } //1450   //1480\n        let ix_choice = (pile_choice - 1) as usize;\n        if remove_choice < 1 || remove_choice as f64 > piles[ix_choice] {\n            continue;\n        }; //1450   //1500\n           // remove the humans choice:\n        piles[ix_choice] = piles[ix_choice] - remove_choice as f64; //1530\n        break;\n    }\n    if one_if_all_zero(np, &piles) == 1\n    //  GOSUB 1570   //1540\n    {\n        return WinState::HumanWins;\n    } //800   //1550  //### machine loses!\n    return WinState::GameOn;\n}\n\n/// returns 0 if all A are 0, otherwise 1\nfn one_if_all_zero(np: i32, piles: &[f64; 100]) -> i32 {\n    // sets Z to the return value\n    //1570\n    for ix in 0..np as usize {\n        //1580\n        if piles[ix] != 0.0 {\n            return 0;\n        } //1610   //1590\n          //1600\n    } //1610\n    return 1; //1620\n} //1630\n\nfn instructions() {\n    println!(\"THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.\");\n    println!(\"ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND\");\n    println!(\"THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE\");\n    println!(\"ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST\");\n    println!(\"TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM\");\n    println!(\"ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER\");\n    println!(\"WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,\");\n    println!(\"THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE\");\n    println!(\"ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A\");\n    println!(\"DIFFERENT NUMBER OF OBJECTS.\");\n    println!(\"THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE\");\n    println!(\"NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS\");\n    println!(\"MOVES.\");\n}\n\n/// print the prompt, wait for a number and newline.  Loop if invalid.\nfn input(prompt: &str) -> String {\n    loop {\n        print!(\"{} ? \", prompt);\n        io::stdout().flush().unwrap();\n        // TODO:  asks twice on win10, not linux.  \\r vs \\n?\n        let innn: String = read!(\"{}\\n\");\n        let out: String = innn.trim().to_string();\n        if out != \"\" {\n            return out;\n        }\n    }\n}\nfn input_int(prompt: &str) -> i32 {\n    loop {\n        print!(\"{} ? \", prompt);\n        io::stdout().flush().unwrap();\n        match try_read!() {\n            Ok(n) => return n,\n            Err(_) => {}\n        }\n    }\n}\n\nfn input_2int(prompt: &str) -> (i32, i32) {\n    loop {\n        let inp = input(prompt);\n        let nums: Vec<i32> = inp\n            .split(\",\")\n            .filter_map(|c| c.parse::<i32>().ok())\n            .collect();\n        if nums.len() != 2 {\n            println!(\"Enter two numbers like: 9,9\",);\n            continue;\n        }\n        return (nums[0], nums[1]);\n    }\n}\n"
  },
  {
    "path": "65_Nim/vbnet/Nim.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Nim\", \"Nim.vbproj\", \"{224F08AA-BE60-4B49-877F-36F239C56F6F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{224F08AA-BE60-4B49-877F-36F239C56F6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{224F08AA-BE60-4B49-877F-36F239C56F6F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{224F08AA-BE60-4B49-877F-36F239C56F6F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{224F08AA-BE60-4B49-877F-36F239C56F6F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "65_Nim/vbnet/Nim.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Nim</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "65_Nim/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "66_Number/README.md",
    "content": "### Number\n\nIn contrast to other number guessing games where you keep guessing until you get the random number selected by the computer (GUESS, TRAP, STARS, etc.), in this game you only get one guess per play and you gain or lose points depending upon how close your guess is to the random number selected by the computer. You occasionally get a jackpot which will double your point count. You win when you get 500 points.\n\nTom Adametx wrote this program while a student at Curtis Junior High School in Sudbury, Massachusetts.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=121)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=136)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\nContrary to the description, the computer picks *five* random numbers per turn, not one.  You are not rewarded based on how close your guess is to one number, but rather to which of these five random numbers (if any) it happens to match exactly.\n"
  },
  {
    "path": "66_Number/csharp/Number.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "66_Number/csharp/Number.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Number\", \"Number.csproj\", \"{F39E3DE8-3564-424C-AD89-D47478FD6E47}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "66_Number/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "66_Number/csharp/program.cs",
    "content": "using System.Text;\n\nnamespace Number\n{\n    class Number\n    {\n        private void DisplayIntro()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"NUMBER\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"You have 100 points.  By guessing numbers from 1 to 5, you\");\n            Console.WriteLine(\"can gain or lose points depending upon how close you get to\");\n            Console.WriteLine(\"a random number selected by the computer.\");\n            Console.WriteLine();\n            Console.WriteLine(\"You occaisionally will get a jackpot which will double(!)\");\n            Console.WriteLine(\"your point count.  You win when you get 500 points.\");\n            Console.WriteLine();\n\n        }\n        private int PromptForGuess()\n        {\n            bool Success = false;\n            int Guess = 0;\n\n            while (!Success)\n            {\n                Console.Write(\"Guess a number from 1 to 5? \");\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (int.TryParse(LineInput, out Guess))\n                {\n                    if (Guess >= 0 && Guess <= 5)\n                        Success = true;\n                }\n                else\n                    Console.WriteLine(\"Please enter a number between 1 and 5.\");\n            }\n\n            return Guess;\n        }\n\n        private void GetRandomNumbers(out int Random1, out int Random2, out int Random3, out int Random4, out int Random5)\n        {\n            Random rand = new Random();\n\n            // Get a unique set of random numbers between 1 and 5\n            // I assume this is what the original BASIC  FNR(X)=INT(5*RND(1)+1) is doing\n            Random1 = (int)(5 * rand.NextDouble() + 1);\n            do\n            {\n                Random2 = (int)(5 * rand.NextDouble() + 1);\n            } while (Random2 == Random1);\n            do\n            {\n                Random3 = (int)(5 * rand.NextDouble() + 1);\n            } while (Random3 == Random1 || Random3 == Random2);\n            do\n            {\n                Random4 = (int)(5 * rand.NextDouble() + 1);\n            } while (Random4 == Random1 || Random4 == Random2 || Random4 == Random3);\n            do\n            {\n                Random5 = (int)(5 * rand.NextDouble() + 1);\n            } while (Random5 == Random1 || Random5 == Random2 || Random5 == Random3 || Random5 == Random4);\n\n        }\n        private void Play()\n        {\n\n            int Points = 100;\n            bool Win = false;\n            int Random1, Random2, Random3, Random4, Random5;\n            int Guess = 0;\n\n            GetRandomNumbers(out Random1, out Random2, out Random3, out Random4, out Random5);\n\n            while (!Win)\n            {\n\n                Guess = PromptForGuess();\n\n                if (Guess == Random1)\n                    Points -= 5;\n                else if (Guess == Random2)\n                    Points += 5;\n                else if (Guess == Random3)\n                {\n                    Points += Points;\n                    Console.WriteLine(\"You hit the jackpot!!!\");\n                }\n                else if (Guess == Random4)\n                    Points += 1;\n                else if (Guess == Random5)\n                    Points -= (int)(Points * 0.5);\n\n                if (Points > 500)\n                {\n                    Console.WriteLine(\"!!!!You Win!!!! with {0} points.\", Points);\n                    Win = true;\n                }\n                else\n                    Console.WriteLine(\"You have {0} points.\", Points);\n            }\n        }\n\n        public void PlayTheGame()\n        {\n            DisplayIntro();\n\n            Play();\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Number().PlayTheGame();\n\n        }\n    }\n}\n"
  },
  {
    "path": "66_Number/java/1/Number.java",
    "content": "\nimport java.time.temporal.ValueRange;\nimport java.util.Arrays;\nimport java.util.Random;\nimport java.util.Scanner;\n\npublic class Number {\n\n    public static int points = 0;\n\n    public static void printempty() { System.out.println(\" \"); }\n\n    public static void print(String toprint) { System.out.println(toprint); }\n\n    public static void main(String[] args) {\n        print(\"YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\");\n        print(\"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\");\n        print(\"A RANDOM NUMBER SELECTED BY THE COMPUTER.\");\n        printempty();\n        print(\"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\");\n        print(\"YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\");\n        printempty();\n\n        try {\n            while (true) {\n                print(\"GUESS A NUMBER FROM 1 TO 5\");\n\n\n                Scanner numbersc = new Scanner(System.in);\n                String numberstring = numbersc.nextLine();\n\n                int number = Integer.parseInt(numberstring);\n\n                if (!(number < 1| number > 5)) {\n\n                    Random rand = new Random();\n\n                    int randomNum = rand.nextInt((5 - 1) + 1) + 1;\n\n                    if (randomNum == number) {\n                        print(\"YOU HIT THE JACKPOT!!!\");\n                        points = points * 2;\n                    } else if(ValueRange.of(randomNum, randomNum + 1).isValidIntValue(number)) {\n                        print(\"+5\");\n                        points = points + 5;\n                    } else if(ValueRange.of(randomNum - 1, randomNum + 2).isValidIntValue(number)) {\n                        print(\"+1\");\n                        points = points + 1;\n                    } else if(ValueRange.of(randomNum - 3, randomNum + 1).isValidIntValue(number)) {\n                        print(\"-1\");\n                        points = points - 1;\n                    } else {\n                        print(\"-half\");\n                        points = (int) (points * 0.5);\n                    }\n\n                    print(\"YOU HAVE \" + points + \" POINTS.\");\n                }\n\n                if (points >= 500) {\n                    print(\"!!!!YOU WIN!!!! WITH \" + points + \" POINTS.\");\n                    return;\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "66_Number/java/2/Number.java",
    "content": "import java.util.Scanner;\n\npublic class Number {\n\n\tpublic static void main(String[] args) {\n\t\tprintIntro();\n\t\tint points = 100; //start with 100 points for the user\n\n\t\tScanner scan = new Scanner(System.in);\n\t\tboolean done = false;\n\t\twhile (!done) {\n\t\t\tSystem.out.print(\"GUESS A NUMBER FROM 1 TO 5? \");\n\t\t\tint g = scan.nextInt();\n\n\t\t\t//Initialize 5 random numbers between 1-5\n\t\t\tvar r = randomNumber(1);\n\t\t\tvar s = randomNumber(1);\n\t\t\tvar t = randomNumber(1);\n\t\t\tvar u = randomNumber(1);\n\t\t\tvar v = randomNumber(1);\n\n\t\t\tif (r == g) {\n\t\t\t\tpoints -= 5;\n\t\t\t} else if (s == g) {\n\t\t\t\tpoints += 5;\n\t\t\t} else if (t == g) {\n\t\t\t\tpoints += points;\n\t\t\t} else if (u == g) {\n\t\t\t\tpoints += 1;\n\t\t\t} else if (v == g) {\n\t\t\t\tpoints -= points * 0.5;\n\t\t\t} else {\n\t\t\t\tcontinue; //Doesn't match any of our random numbers, so just ask for another guess\n\t\t\t}\n\n\t\t\tif (points > 500) {\n\t\t\t\tdone = true;\n\t\t\t} else {\n\t\t\t\tSystem.out.println(\"YOU HAVE \" + points + \" POINTS.\");\n\t\t\t}\n\t\t}\n\n\t\tSystem.out.println(\"!!!!YOU WIN!!!! WITH \" + points + \" POINTS.\\n\");\n\t}\n\n\tprivate static int randomNumber(int x) {\n\t\t//Note: 'x' is totally ignored as was in the original basic listing\n\t\treturn (int) (5 * Math.random() + 1);\n\t}\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                NUMBER\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\\n\");\n\t\tSystem.out.println(\"YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\");\n\t\tSystem.out.println(\"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\");\n\t\tSystem.out.println(\"A RANDOM NUMBER SELECTED BY THE COMPUTER.\");\n\t\tSystem.out.println(\"\\n\");\n\t\tSystem.out.println(\"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\");\n\t\tSystem.out.println(\"YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\");\n\t}\n}\n"
  },
  {
    "path": "66_Number/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "66_Number/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "66_Number/javascript/number.html",
    "content": "<html>\n<head>\n<title>NUMBER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"number.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "66_Number/javascript/number.js",
    "content": "// NUMBER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"NUMBER\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\\n\");\n    print(\"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\\n\");\n    print(\"A RANDOM NUMBER SELECTED BY THE COMPUTER.\\n\");\n    print(\"\\n\");\n    print(\"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\\n\");\n    print(\"YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\\n\");\n    print(\"\\n\");\n    p = 0;\n    while (1) {\n        do {\n            print(\"GUESS A NUMBER FROM 1 TO 5\");\n            g = parseInt(await input());\n        } while (g < 1 || g > 5) ;\n        r = Math.floor(5 * Math.random() + 1);\n        s = Math.floor(5 * Math.random() + 1);\n        t = Math.floor(5 * Math.random() + 1);\n        u = Math.floor(5 * Math.random() + 1);\n        v = Math.floor(5 * Math.random() + 1);\n        if (g == r) {\n            p -= 5;\n        } else if (g == s) {\n            p += 5;\n        } else if (g == t) {\n            p += p;\n            print(\"YOU HIT THE JACKPOT!!!\\n\");\n        } else if (g == u) {\n            p += 1;\n        } else if (g == v) {\n            p -= p * 0.5;\n        }\n        if (p <= 500) {\n            print(\"YOU HAVE \" + p + \" POINTS.\\n\");\n            print(\"\\n\");\n        } else {\n            print(\"!!!!YOU WIN!!!! WITH \" + p + \" POINTS.\\n\");\n            break;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "66_Number/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "66_Number/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "66_Number/number.bas",
    "content": "1 PRINT TAB(33);\"NUMBER\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n4 PRINT \"YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\"\n5 PRINT \"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\"\n6 PRINT \"A RANDOM NUMBER SELECTED BY THE COMPUTER.\": PRINT\n7 PRINT \"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\"\n8 PRINT \"YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\"\n9 PRINT: P=100\n10 DEF FNR(X)=INT(5*RND(1)+1)\n12 INPUT \"GUESS A NUMBER FROM 1 TO 5\";G\n15 R=FNR(1)\n16 S=FNR(1)\n17 T=FNR(1)\n18 U=FNR(1)\n19 V=FNR(1)\n20 IF G=R THEN 30\n21 IF G=S THEN 40\n22 IF G=T THEN 50\n23 IF G=U THEN 60\n24 IF G=V THEN 70\n25 IF G>5 THEN 12\n30 P=P-5\n35 GOTO 80\n40 P=P+5\n45 GOTO 80\n50 P=P+P\n53 PRINT \"YOU HIT THE JACKPOT!!!\"\n55 GOTO 80\n60 P=P+1\n65 GOTO 80\n70 P=P-(P*.5)\n80 IF P>500 THEN 90\n82 PRINT \"YOU HAVE\";P;\"POINTS.\":PRINT\n85 GOTO 12\n90 PRINT \"!!!!YOU WIN!!!! WITH \";P;\"POINTS.\"\n99 END\n"
  },
  {
    "path": "66_Number/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "66_Number/perl/number.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x 33 . \"NUMBER\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\nprint \"YOU HAVE 100 POINTS. BY GUESSING NUMBERS FROM 1 TO 5, YOU\\n\";\nprint \"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\\n\";\nprint \"A RANDOM NUMBER SELECTED BY THE COMPUTER.\\n\"; print \"\\n\";\nprint \"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\\n\";\nprint \"YOUR POINT COUNT. YOU WIN WHEN YOU GET 500 POINTS.\\n\";\nprint \"\\n\"; my $P=100;\n\nLine12:\nwhile ($P<500) {\n\tprint \"GUESS A NUMBER FROM 1 TO 5? \"; chomp(my $G = <STDIN>);\n\tmy $R= &FNR(1);\n\tmy $S= &FNR(1);\n\tmy $T= &FNR(1);\n\tmy $U= &FNR(1);\n\tmy $V= &FNR(1);\n\tif ($G eq $R) { $P=$P-5; }\n\tif ($G eq $S) { $P=$P+5; }\n\tif ($G eq $T) { $P=$P+$P; print \"YOU HIT THE JACKPOT!!!\\n\"; }\n\tif ($G eq $U) { $P=$P+1; }\n\tif ($G eq $V) { $P=$P-($P*.5); }\n\tif ($G<1 || $G>5) { redo; }\n\tprint \"YOU HAVE $P POINTS.\\n\"; print \"\\n\";\n\t}\nprint \"!!!!YOU WIN!!!! WITH $P POINTS.\\n\";\nexit;\n\n\nsub FNR {\n\tmy ($X)= @_; #Useless...\n\treturn int(5*rand(1)+1);\n\t}\n"
  },
  {
    "path": "66_Number/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "66_Number/python/number.py",
    "content": "\"\"\"\nNUMBER\n\nA number guessing (gambling) game.\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\n\n\ndef print_instructions() -> None:\n    print(\"YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\")\n    print(\"CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\")\n    print(\"A RANDOM NUMBER SELECTED BY THE COMPUTER.\")\n    print()\n    print(\"YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\")\n    print(\"YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\")\n    print()\n\n\ndef fnr() -> int:\n    return random.randint(1, 5)\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"NUMBER\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n\n    print_instructions()\n\n    points: float = 100\n\n    while points <= 500:\n        print(\"GUESS A NUMBER FROM 1 TO 5\")\n        guess = int(input())\n\n        if (guess < 1) or (guess > 5):\n            continue\n\n        r = fnr()\n        s = fnr()\n        t = fnr()\n        u = fnr()\n        v = fnr()\n\n        if guess == r:\n            # lose 5\n            points -= 5\n        elif guess == s:\n            # gain 5\n            points += 5\n        elif guess == t:\n            # double!\n            points += points\n            print(\"YOU HIT THE JACKPOT!!!\")\n        elif guess == u:\n            # gain 1\n            points += 1\n        elif guess == v:\n            # lose half\n            points = points - (points * 0.5)\n\n        print(f\"YOU HAVE {points} POINTS.\")\n        print()\n    print(f\"!!!!YOU WIN!!!! WITH {points} POINTS.\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "66_Number/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "66_Number/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nauthors = [\"AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com>\"]\nedition = \"2018\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "66_Number/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "66_Number/rust/src/main.rs",
    "content": "use rand::{Rng, prelude::thread_rng};\nuse std::io;\n\nfn main() {\n    //DATA\n    let mut points: usize = 100;\n    let mut rng = thread_rng();\n    let mut number:u8;\n\n    //print welcome message\n    welcome();\n\n    //game loop\n    while points <= 500 {\n        //generate number\n        number = rng.gen_range(1..=5);\n        //NOTE: while looking at the original basic, I realized that the outcome of your guess is effectively random\n        //so instead of generating 5 variables with random values between 1-5 and doing something depedning which one has the value they guess...\n        //why not just let them \"guess\" and do a random action without using uneeded variables? .. so that's what I did.\n\n        //let them \"guess\"\n        println!(\"GUESS A NUMBER FROM 1 TO 5\");//print prompt\n        if let Ok(_i) = io::stdin().read_line(&mut String::new()) {} // get input from standard in, and do nothing with it even if an error is thrown\n\n        //do something depending on the previously generated random number\n        match number {\n            1 => if points>=5{points -= 5},//the if statement here prevents overflow, points is stored as an unsigned integer, so we can't let it be negative\n            2 => points += 5,\n            3 => {//jackpot\n                points *= 2;\n                println!(\"YOU HIT THE JACKPOT!!!\");\n            },\n            4 => points += 1,\n            5 => points /= 2,\n            _ => {},\n        };\n\n        //tell then how many points they have\n        println!(\"YOU HAVE {} POINTS.\", points);\n    }\n\n    //print\n}\n\n/**\n * print the welcome message\n */\nfn welcome() {\n    println!(\"\n              CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n    YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\n    CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\n    A RANDOM NUMBER SELECTED BY THE COMPUTER.\n\n    YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\n    YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS\n\n    \");\n}\n"
  },
  {
    "path": "66_Number/vbnet/Number.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Number\", \"Number.vbproj\", \"{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "66_Number/vbnet/Number.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Number</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "66_Number/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "67_One_Check/README.md",
    "content": "### One Check\n\nIn this game or puzzle, 48 checkers are placed on the two outside spaces of a standard 64-square checkerboard as shown:\n\n|   |   |   |   |   |   |   |   |\n|---|---|---|---|---|---|---|---|\n| ● | ● | ● | ● | ● | ● | ● | ● |\n| ● | ● | ● | ● | ● | ● | ● | ● |\n| ● | ● |   |   |   |   | ● | ● |\n| ● | ● |   |   |   |   | ● | ● |\n| ● | ● |   |   |   |   | ● | ● |\n| ● | ● |   |   |   |   | ● | ● |\n| ● | ● | ● | ● | ● | ● | ● | ● |\n| ● | ● | ● | ● | ● | ● | ● | ● |\n\nThe object is to remove as many checkers as possible by diagonal jumps (as in standard checkers).\n\nIt is easy to remove 30 to 39 checkers, a challenge to remove 40 to 44, and a substantial feat to remove 45 to 47.\n\nThe program was created and written by David Ahl.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=122)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=137)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "67_One_Check/csharp/Board.cs",
    "content": "namespace OneCheck;\n\ninternal class Board\n{\n    private readonly bool[][] _checkers;\n    private int _pieceCount;\n    private int _moveCount;\n\n    public Board()\n    {\n        _checkers = \n            Enumerable.Range(0, 8)\n                .Select(r => Enumerable.Range(0, 8)\n                    .Select(c => r <= 1 || r >= 6 || c <= 1 || c >= 6).ToArray())\n                .ToArray();\n        _pieceCount = 48;\n    }\n\n    private bool this[int index]\n    {\n        get => _checkers[index / 8][index % 8];\n        set => _checkers[index / 8][index % 8] = value;\n    }\n\n    public bool PlayMove(IReadWrite io)\n    {\n        while (true)\n        {\n            var from = (int)io.ReadNumber(Prompts.From);\n            if (from == 0) { return false; }\n\n            var move = new Move { From = from - 1, To = (int)io.ReadNumber(Prompts.To) - 1 };\n\n            if (TryMove(move)) \n            { \n                _moveCount++;\n                return true; \n            }\n\n            io.Write(Streams.IllegalMove);\n        }\n    }\n\n    public bool TryMove(Move move)\n    {\n        if (move.IsInRange && move.IsTwoSpacesDiagonally && IsPieceJumpingPieceToEmptySpace(move))\n        {\n            this[move.From] = false;\n            this[move.Jumped] = false;\n            this[move.To] = true;\n            _pieceCount--;\n            return true;\n        }\n\n        return false;\n    }\n\n    private bool IsPieceJumpingPieceToEmptySpace(Move move) => this[move.From] && this[move.Jumped] && !this[move.To];\n\n    public string GetReport() => string.Format(Formats.Results, _moveCount, _pieceCount);\n\n    public override string ToString() => \n        string.Join(Environment.NewLine, _checkers.Select(r => string.Join(\" \", r.Select(c => c ? \" 1\" : \" 0\"))));\n}\n"
  },
  {
    "path": "67_One_Check/csharp/Game.cs",
    "content": "namespace OneCheck;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n\n    public Game(IReadWrite io)\n    {\n        _io = io;\n    }\n\n    public void Play()\n    {\n        _io.Write(Streams.Introduction);\n        \n        do\n        {\n            var board = new Board();\n            do\n            {\n                _io.WriteLine(board);\n                _io.WriteLine();\n            } while (board.PlayMove(_io));\n\n            _io.WriteLine(board.GetReport());\n        } while (_io.ReadYesNo(Prompts.TryAgain) == \"yes\");\n\n        _io.Write(Streams.Bye);\n    }\n}\n\ninternal static class IOExtensions\n{\n    internal static string ReadYesNo(this IReadWrite io, string prompt)\n    {\n        while (true)\n        {\n            var response = io.ReadString(prompt).ToLower();\n\n            if (response == \"yes\" || response == \"no\") { return response; }\n\n            io.Write(Streams.YesOrNo);\n        }\n    }\n}\n"
  },
  {
    "path": "67_One_Check/csharp/Move.cs",
    "content": "namespace OneCheck;\n\ninternal class Move\n{\n    public int From { get; init; }\n    public int To { get; init; }\n    public int Jumped => (From + To) / 2;\n\n    public bool IsInRange => From >= 0 && From <= 63 && To >= 0 && To <= 63;\n    public bool IsTwoSpacesDiagonally => RowDelta == 2 && ColumnDelta == 2;\n    private int RowDelta => Math.Abs(From / 8 - To / 8);\n    private int ColumnDelta => Math.Abs(From % 8 - To % 8);\n}"
  },
  {
    "path": "67_One_Check/csharp/OneCheck.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "67_One_Check/csharp/OneCheck.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"OneCheck\", \"OneCheck.csproj\", \"{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "67_One_Check/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using static OneCheck.Resources.Resource;\nusing OneCheck;\n\nnew Game(new ConsoleIO()).Play();\n"
  },
  {
    "path": "67_One_Check/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "67_One_Check/csharp/Resources/Bye.txt",
    "content": "\nO.K.  Hope you had fun!!"
  },
  {
    "path": "67_One_Check/csharp/Resources/From.txt",
    "content": "Jump from"
  },
  {
    "path": "67_One_Check/csharp/Resources/IllegalMove.txt",
    "content": "Illegal move.  Try again..."
  },
  {
    "path": "67_One_Check/csharp/Resources/Introduction.txt",
    "content": "                              One Check\n               Creative Computing  Morristown, New Jersey\n\n\n\nSolitaire checker puzzle by David Ahl\n\n48 checkers and placed on the 2 outside spaces of a\nstandard 64-square checkerboard.  The object is to\nremove as many checkers as possible by diagonal jumps\n(as in standard checkers).  Use the numbered board to\nindicate the square you wish to jump from and to.  On\nthe board printed out on each turn '1' indicates a\nchecker and '0' an empty square.  When you have no\npossible jumps remaining, input a '0' in response to\nquestion 'Jump from ?'\n\nHere is the numerical board:\n\n 1   2   3   4   5   6   7   8\n 9   10  11  12  13  14  15  16\n 17  18  19  20  21  22  23  24\n 25  26  27  28  29  30  31  32\n 33  34  35  36  37  38  39  40\n 41  42  43  44  45  46  47  48\n 49  50  51  52  53  54  55  56\n 57  58  59  60  61  62  63  64\n\nAnd here is the opening position of the checkers.\n\n"
  },
  {
    "path": "67_One_Check/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace OneCheck.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Introduction => GetStream();\n        public static Stream IllegalMove => GetStream();\n        public static Stream YesOrNo => GetStream();\n        public static Stream Bye => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string Results => GetString();\n    }\n\n    internal static class Prompts\n    {\n        public static string From => GetString();\n        public static string To => GetString();\n        public static string TryAgain => GetString();\n    }\n\n    internal static class Strings\n    {\n        public static string TooManyColumns => GetString();\n        public static string TooManyRows => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "67_One_Check/csharp/Resources/Results.txt",
    "content": "\nYou made {0} jumps and had {1} pieces\nremaining on the board.\n"
  },
  {
    "path": "67_One_Check/csharp/Resources/To.txt",
    "content": "to"
  },
  {
    "path": "67_One_Check/csharp/Resources/TryAgain.txt",
    "content": "Try again"
  },
  {
    "path": "67_One_Check/csharp/Resources/YesOrNo.txt",
    "content": "Please answer 'Yes' or 'No'."
  },
  {
    "path": "67_One_Check/java/OneCheck.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of One Check\n * <p>\n * Based on the BASIC game of One Check here\n * https://github.com/coding-horror/basic-computer-games/blob/main/67%20One%20Check/onecheck.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class OneCheck {\n\n  private final Scanner scan;  // For user input\n\n  private enum Step {\n    SHOW_INSTRUCTIONS, SHOW_BOARD, GET_MOVE, GET_SUMMARY, QUERY_RETRY\n  }\n\n  public OneCheck() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor OneCheck\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(29) + \"ONE CHECK\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    int fromSquare = 0;\n    int numJumps = 0;\n    int numPieces = 0;\n    int square = 0;\n    int startPosition = 0;\n    int toSquare = 0;\n\n    // Move legality test variables\n    int fromTest1 = 0;\n    int fromTest2 = 0;\n    int toTest1 = 0;\n    int toTest2 = 0;\n\n    int[] positions = new int[65];\n\n    Step nextStep = Step.SHOW_INSTRUCTIONS;\n\n    String lineContent = \"\";\n    String userResponse = \"\";\n\n    // Begin outer while loop\n    while (true) {\n\n      // Begin switch\n      switch (nextStep) {\n\n        case SHOW_INSTRUCTIONS:\n\n          System.out.println(\"SOLITAIRE CHECKER PUZZLE BY DAVID AHL\\n\");\n          System.out.println(\"48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A\");\n          System.out.println(\"STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO\");\n          System.out.println(\"REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS\");\n          System.out.println(\"(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO\");\n          System.out.println(\"INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON\");\n          System.out.println(\"THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A\");\n          System.out.println(\"CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO\");\n          System.out.println(\"POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO\");\n          System.out.println(\"QUESTION 'JUMP FROM ?'\\n\");\n          System.out.println(\"HERE IS THE NUMERICAL BOARD:\\n\");\n\n          nextStep = Step.SHOW_BOARD;\n          break;\n\n        case SHOW_BOARD:\n\n          // Begin loop through all squares\n          for (square = 1; square <= 57; square += 8) {\n\n            lineContent = String.format(\"% -4d%-4d%-4d%-4d%-4d%-4d%-4d%-4d\", square, square + 1, square + 2,\n                                        square + 3, square + 4, square + 5, square + 6, square + 7);\n            System.out.println(lineContent);\n\n          }  // End loop through all squares\n\n          System.out.println(\"\");\n          System.out.println(\"AND HERE IS THE OPENING POSITION OF THE CHECKERS.\");\n          System.out.println(\"\");\n\n          Arrays.fill(positions, 1);\n\n          // Begin generating start positions\n          for (square = 19; square <= 43; square += 8) {\n\n            for (startPosition = square; startPosition <= square + 3; startPosition++) {\n\n              positions[startPosition] = 0;\n\n            }\n          }  // End generating start positions\n\n          numJumps = 0;\n\n          printBoard(positions);\n\n          nextStep = Step.GET_MOVE;\n          break;\n\n        case GET_MOVE:\n\n          System.out.print(\"JUMP FROM? \");\n          fromSquare = scan.nextInt();\n          scan.nextLine();  // Discard newline\n\n          // User requested summary\n          if (fromSquare == 0) {\n            nextStep = Step.GET_SUMMARY;\n            break;\n          }\n\n          System.out.print(\"TO? \");\n          toSquare = scan.nextInt();\n          scan.nextLine();  // Discard newline\n          System.out.println(\"\");\n\n          // Check legality of move\n          fromTest1 = (int) Math.floor((fromSquare - 1.0) / 8.0);\n          fromTest2 = fromSquare - 8 * fromTest1;\n          toTest1 = (int) Math.floor((toSquare - 1.0) / 8.0);\n          toTest2 = toSquare - 8 * toTest1;\n\n          if ((fromTest1 > 7) ||\n              (toTest1 > 7) ||\n              (fromTest2 > 8) ||\n              (toTest2 > 8) ||\n              (Math.abs(fromTest1 - toTest1) != 2) ||\n              (Math.abs(fromTest2 - toTest2) != 2) ||\n              (positions[(toSquare + fromSquare) / 2] == 0) ||\n              (positions[fromSquare] == 0) ||\n              (positions[toSquare] == 1)) {\n\n            System.out.println(\"ILLEGAL MOVE.  TRY AGAIN...\");\n            nextStep = Step.GET_MOVE;\n            break;\n          }\n\n          positions[toSquare] = 1;\n          positions[fromSquare] = 0;\n          positions[(toSquare + fromSquare) / 2] = 0;\n          numJumps++;\n\n          printBoard(positions);\n\n          nextStep = Step.GET_MOVE;\n          break;\n\n        case GET_SUMMARY:\n\n          numPieces = 0;\n\n          // Count remaining pieces\n          for (square = 1; square <= 64; square++) {\n            numPieces += positions[square];\n          }\n\n          System.out.println(\"\");\n          System.out.println(\"YOU MADE \" + numJumps + \" JUMPS AND HAD \" + numPieces + \" PIECES\");\n          System.out.println(\"REMAINING ON THE BOARD.\\n\");\n\n          nextStep = Step.QUERY_RETRY;\n          break;\n\n        case QUERY_RETRY:\n\n          while (true) {\n            System.out.print(\"TRY AGAIN? \");\n            userResponse = scan.nextLine();\n            System.out.println(\"\");\n\n            if (userResponse.toUpperCase().equals(\"YES\")) {\n              nextStep = Step.SHOW_BOARD;\n              break;\n            }\n            else if (userResponse.toUpperCase().equals(\"NO\")) {\n              System.out.println(\"O.K.  HOPE YOU HAD FUN!!\");\n              return;\n            }\n            else {\n              System.out.println(\"PLEASE ANSWER 'YES' OR 'NO'.\");\n            }\n          }\n          break;\n\n        default:\n          System.out.println(\"INVALID STEP\");\n          nextStep = Step.QUERY_RETRY;\n          break;\n\n      }  // End of switch\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public void printBoard(int[] positions) {\n\n    int column = 0;\n    int row = 0;\n    String lineContent = \"\";\n\n    // Begin loop through all rows\n    for (row = 1; row <= 57; row += 8) {\n\n      // Begin loop through all columns\n      for (column = row; column <= row + 7; column++) {\n\n        lineContent += \" \" + positions[column];\n\n      }  // End loop through all columns\n\n      System.out.println(lineContent);\n      lineContent = \"\";\n\n    }  // End loop through all rows\n\n    System.out.println(\"\");\n\n  }  // End of method printBoard\n\n  public static void main(String[] args) {\n\n    OneCheck game = new OneCheck();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class OneCheck\n"
  },
  {
    "path": "67_One_Check/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "67_One_Check/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "67_One_Check/javascript/onecheck.html",
    "content": "<html>\n<head>\n<title>ONE CHECK</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"onecheck.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "67_One_Check/javascript/onecheck.js",
    "content": "// ONE CHECK\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a = [];\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"ONE CHECK\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 0; i <= 64; i++)\n        a[i] = 0;\n    print(\"SOLITAIRE CHECKER PUZZLE BY DAVID AHL\\n\");\n    print(\"\\n\");\n    print(\"48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A\\n\");\n    print(\"STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO\\n\");\n    print(\"REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS\\n\");\n    print(\"(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO\\n\");\n    print(\"INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON\\n\");\n    print(\"THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A\\n\");\n    print(\"CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO\\n\");\n    print(\"POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO\\n\");\n    print(\"QUESTION 'JUMP FROM ?'\\n\");\n    print(\"\\n\");\n    print(\"HERE IS THE NUMERICAL BOARD:\\n\");\n    print(\"\\n\");\n    while (1) {\n        for (j = 1; j <= 57; j += 8) {\n            str = \"\";\n            for (i = 0; i <= 7; i++) {\n                while (str.length < 4 * i)\n                    str += \" \";\n                str += \" \" + (j + i);\n            }\n            print(str + \"\\n\");\n        }\n        print(\"\\n\");\n        print(\"AND HERE IS THE OPENING POSITION OF THE CHECKERS.\\n\");\n        print(\"\\n\");\n        for (j = 1; j <= 64; j++)\n            a[j] = 1;\n        for (j = 19; j <= 43; j += 8)\n            for (i = j; i <= j + 3; i++)\n                a[i] = 0;\n        m = 0;\n        while (1) {\n            // Print board\n            for (j = 1; j <= 57; j += 8) {\n                str = \"\";\n                for (i = j; i <= j + 7; i++) {\n                    str += \" \" + a[i] + \" \";\n                }\n                print(str + \"\\n\");\n            }\n            print(\"\\n\");\n            while (1) {\n                print(\"JUMP FROM\");\n                f = parseInt(await input());\n                if (f == 0)\n                    break;\n                print(\"TO\");\n                t = parseInt(await input());\n                print(\"\\n\");\n                // Check legality of move\n                f1 = Math.floor((f - 1) / 8);\n                f2 = f - 8 * f1;\n                t1 = Math.floor((t - 1) / 8);\n                t2 = t - 8 * t1;\n                if (f1 > 7 || t1 > 7 || f2 > 8 || t2 > 8 || Math.abs(f1 - t1) != 2 || Math.abs(f2 - t2) != 2 || a[(t + f) / 2] == 0 || a[f] == 0 || a[t] == 1) {\n                    print(\"ILLEGAL MOVE.  TRY AGAIN...\\n\");\n                    continue;\n                }\n                break;\n            }\n            if (f == 0)\n                break;\n            // Update board\n            a[t] = 1;\n            a[f] = 0;\n            a[(t + f) / 2] = 0;\n            m++;\n        }\n        // End game summary\n        s = 0;\n        for (i = 1; i <= 64; i++)\n            s += a[i];\n        print(\"\\n\");\n        print(\"YOU MADE \" + m + \" JUMPS AND HAD \" + s + \" PIECES\\n\");\n        print(\"REMAINING ON THE BOARD.\\n\");\n        print(\"\\n\");\n        while (1) {\n            print(\"TRY AGAIN\");\n            str = await input();\n            if (str == \"YES\")\n                break;\n            if (str == \"NO\")\n                break;\n            print(\"PLEASE ANSWER 'YES' OR 'NO'.\\n\");\n        }\n        if (str == \"NO\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"O.K.  HOPE YOU HAD FUN!!\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "67_One_Check/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "67_One_Check/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "67_One_Check/onecheck.bas",
    "content": "2 PRINT TAB(30);\"ONE CHECK\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n8 DIM A(64)\n10 PRINT \"SOLITAIRE CHECKER PUZZLE BY DAVID AHL\"\n15 PRINT\n20 PRINT \"48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A\"\n25 PRINT \"STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO\"\n30 PRINT \"REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS\"\n35 PRINT \"(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO\"\n40 PRINT \"INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON\"\n45 PRINT \"THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A\"\n50 PRINT \"CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO\"\n55 PRINT \"POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO\"\n60 PRINT \"QUESTION 'JUMP FROM ?'\"\n62 PRINT\n63 PRINT \"HERE IS THE NUMERICAL BOARD:\"\n66 PRINT\n70 FOR J=1 TO 57 STEP 8\n74 PRINT J;TAB(4);J+1;TAB(8);J+2;TAB(12);J+3;TAB(16);J+4;TAB(20);J+5;\n75 PRINT TAB(24);J+6;TAB(28);J+7\n76 NEXT J\n77 PRINT\n78 PRINT \"AND HERE IS THE OPENING POSITION OF THE CHECKERS.\"\n79 PRINT\n80 FOR J=1 TO 64\n82 A(J)=1\n84 NEXT J\n86 FOR J=19 TO 43 STEP 8\n88 FOR I=J TO J+3\n90 A(I)=0\n92 NEXT I\n94 NEXT J\n96 M=0\n98 GOTO 340\n100 INPUT \"JUMP FROM\";F\n105 IF F=0 THEN 500\n110 INPUT \"TO\";T\n112 PRINT\n118 REM *** CHECK LEGALITY OF MOVE\n120 F1=INT((F-1)/8)\n130 F2=F-8*F1\n140 T1=INT((T-1)/8)\n150 T2=T-8*T1\n160 IF F1>7 THEN 230\n170 IF T1>7 THEN 230\n180 IF F2>8 THEN 230\n190 IF T2>8 THEN 230\n200 IF ABS(F1-T1)<>2 THEN 230\n210 IF ABS(F2-T2)<>2 THEN 230\n212 IF A((T+F)/2)=0 THEN 230\n215 IF A(F)=0 THEN 230\n220 IF A(T)=1 THEN 230\n225 GOTO 250\n230 PRINT \"ILLEGAL MOVE.  TRY AGAIN...\"\n240 GOTO 100\n245 REM *** UPDATE BOARD\n250 A(T)=1\n260 A(F)=0\n270 A((T+F)/2)=0\n290 M=M+1\n310 REM *** PRINT BOARD\n340 FOR J=1 TO 57 STEP 8\n350 FOR I=J TO J+7\n360 PRINT A(I);\n370 NEXT I\n380 PRINT\n390 NEXT J\n400 PRINT\n410 GOTO 100\n490 REM *** END GAME SUMMARY\n500 S=0\n510 FOR I=1 TO 64\n520 S=S+A(I)\n530 NEXT I\n540 PRINT:PRINT \"YOU MADE\";M;\"JUMPS AND HAD\";S;\"PIECES\"\n550 PRINT \"REMAINING ON THE BOARD.\"\n560 PRINT\n562 INPUT \"TRY AGAIN\";A$\n570 IF A$=\"YES\" THEN 70\n575 IF A$=\"NO\" THEN 600\n580 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.\"\n590 GOTO 562\n600 PRINT\n610 PRINT \"O.K.  HOPE YOU HAD FUN!!\"\n999 END\n"
  },
  {
    "path": "67_One_Check/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "67_One_Check/perl/onecheck.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse List::Util qw{ sum };   # Add all its arguments\nuse Term::ReadLine;         # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nprint <<'EOD';\n                              ONE CHECK\n               Creative Computing  Morristown, New Jersey\n\n\n\nSolitaire checker puzzle by David Ahl\n\n48 checkers are placed on the 2 outside spaces of a\nstandard 64-square checkerboard.  The object is to\nremove as many checkers as possible by diagonal jumps\n(as in standard checkers).  Use the numbered board to\nindicate the square you wish to jump from and to.  On\nthe board printed out on each turn '1' indicates a\nchecker and '0' an empty square.  When you have no\npossible jumps remaining, input a '0' in response to\nquestion 'Jump from?'\nEOD\n\nwhile ( 1 ) {   # Iterate indefinitely\n\n    board_num();    # Display the numerical board.\n\n    # Initialize the board, which is a two-dimensional array.\n    my @board = map { [ ( 1 ) x 8 ] } 0 .. 7;   # Initialize to all 1.\n    for my $row ( 2 .. 5 ) {        # Set the center section to 0\n        for my $col ( 2 .. 5 ) {\n            $board[$row][$col] = 0;\n        }\n    }\n\n    print <<'EOD';\nAnd here is the opening position of the checkers.\n\nEOD\n    board_pos( \\@board );\n\n    my $moves = 0;  # Number of moves made.\n\n    # A game proceeds while 'Jump from' is a true value. We make use of\n    # the fact that of the possible returns, only 0 evaluates false.\n    while ( my $jump_from = get_input(\n            'Jump from? ',\n            sub {\n                $ARG = lc;  # The caller sees this.\n                return 1 if $ARG eq 'b';\n                return unless m/ \\A [0-9]+ \\z /smx;\n                $ARG += 0;  # Numify, because string '00' is true.\n                return $ARG < 65;\n            },\n            \"Please enter a number from 0 to 64, or 'b' to re-display the numeric board\\n\"\n        )\n    ) {\n        if ( $jump_from eq 'b' ) {\n            board_num();\n            board_pos( \\@board );\n            next;\n        }\n\n        my $jump_to = get_input(\n            '       to? ',\n            sub { m/ \\A [0-9]+ \\z /smx },\n            \"Please enter a number from 1 to 64\\n\",\n        );\n\n        if ( make_move( \\@board, $jump_from, $jump_to ) ) {\n            $moves++;\n            board_pos( \\@board );\n        } else {\n            say 'Illegal move.  Try again.';\n        }\n    }\n\n    my $checkers_left = sum( map { sum( @{ $board[$_] } ) } 0 .. 7 );\n    print <<\"EOD\";\n\nYou made $moves jumps and had $checkers_left pieces\nremaining on the board.\n\nEOD\n\n    last unless get_yes_no( 'Try again' );\n\n}\n\nprint <<'EOD';\n\nO.K.  Hope you had fun!!\nEOD\n\n# Print the numerical board\nsub board_num {\n    print <<'EOD';\n\nHere is the numerical board:\n\nEOD\n    foreach my $row ( 0 .. 7 ) {\n        state $tplt = ( '%3d' x 8 ) . \"\\n\";\n        my $inx = $row * 8;\n        printf $tplt, map { $inx + $_ } 1 .. 8;\n    }\n    say '';\n    return;\n}\n\n# Print the board position\nsub board_pos {\n    my ( $board ) = @_;\n    for my $row ( 0 .. 7 ) {\n        state $tplt = ( '%2d' x 8 ) . \"\\n\";\n        printf $tplt, @{ $board->[$row] };\n    }\n    say '';\n    return;\n}\n\n# Make the move. This is a subroutine for convenience in control flow.\n# We return a true value for success, and false for failure.\nsub make_move {\n    my ( $board, $jump_from, $jump_to ) = @_;\n    $jump_from -= 1;\n    $jump_to   -= 1;\n    my $from_row = int( $jump_from / 8 );   # Truncates toward 0\n    my $from_col = $jump_from % 8;\n    my $to_row   = int( $jump_to / 8 );     # Truncates toward 0\n    my $to_col   = $jump_to % 8;\n    return unless $board->[$from_row][$from_col];   # From must be occupied\n    return if $board->[$to_row][$to_col];           # To must be vacant\n    return unless abs( $from_row - $to_row ) == 2;  # Must cross two rows\n    return unless abs( $from_col - $to_col ) == 2;  # Must cross two cols\n    my $over_row = ( $from_row + $to_row ) / 2;     # The row jumped over\n    my $over_col = ( $from_col + $to_col ) / 2;     # The col jumped over\n    $board->[$from_row][$from_col] =                # Clear the from cell\n        $board->[$over_row][$over_col] = 0;         # and the jumped cell\n    $board->[$to_row][$to_col] = 1;                 # Occupy the to cell\n    return 1;\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n__END__\n\n=head1 TITLE\n\none check - Play the game 'One Check' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n one check.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of onecheck.\n\nThis is a solitaire game played on a checker board, where the object is\nto eliminate as many checkers as possible by making diagonal jumps and\nremoving the jumped checkers.\n\nIt is pretty much a straight port of the BASIC original.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "67_One_Check/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "67_One_Check/python/onecheck.py",
    "content": "\"\"\"\nONE CHECK\n\nPort to Python by imiro\n\"\"\"\n\nfrom typing import Tuple\n\n\ndef main() -> None:\n    # Initial instructions\n    print(\" \" * 30 + \"ONE CHECK\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"SOLITAIRE CHECKER PUZZLE BY DAVID AHL\\n\")\n    print(\"48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A\")\n    print(\"STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO\")\n    print(\"REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS\")\n    print(\"(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO\")\n    print(\"INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON\")\n    print(\"THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A\")\n    print(\"CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO\")\n    print(\"POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO\")\n    print(\"QUESTION 'JUMP FROM ?'\\n\")\n    print(\"HERE IS THE NUMERICAL BOARD:\\n\")\n\n    while True:\n        for j in range(1, 64, 8):\n            for i in range(j, j + 7):\n                print(i, end=(\" \" * (3 if i < 10 else 2)))\n            print(j + 7)\n        print(\"\\nAND HERE IS THE OPENING POSITION OF THE CHECKERS.\\n\")\n\n        (jumps, left) = play_game()\n\n        print()\n        print(f\"YOU MADE {jumps} JUMPS AND HAD {left} PIECES\")\n        print(\"REMAINING ON THE BOARD.\\n\")\n\n        if not (try_again()):\n            break\n\n    print(\"\\nO.K.  HOPE YOU HAD FUN!!\")\n\n\ndef play_game() -> Tuple[str, str]:\n    # Initialize board\n    # Give more than 64 elements to accomodate 1-based indexing\n    board = [1] * 70\n    for j in range(19, 44, 8):\n        for i in range(j, j + 4):\n            board[i] = 0\n    jumps = 0\n    while True:\n        # print board\n        for j in range(1, 64, 8):\n            for i in range(j, j + 7):\n                print(board[i], end=\" \")\n            print(board[j + 7])\n        print()\n\n        while True:\n            print(\"JUMP FROM\", end=\" \")\n            f_str = input()\n            f = int(f_str)\n            if f == 0:\n                break\n            print(\"TO\", end=\" \")\n            t_str = input()\n            t = int(t_str)\n            print()\n\n            # Check legality of move\n            f1 = (f - 1) // 8\n            f2 = f - 8 * f1\n            t1 = (t - 1) // 8\n            t2 = t - 8 * t1\n            if (\n                f1 > 7\n                or t1 > 7\n                or f2 > 8\n                or t2 > 8\n                or abs(f1 - t1) != 2\n                or abs(f2 - t2) != 2\n                or board[(t + f) // 2] == 0\n                or board[f] == 0\n                or board[t] == 1\n            ):\n                print(\"ILLEGAL MOVE.  TRY AGAIN...\")\n                continue\n            break\n\n        if f == 0:\n            break\n        board[t] = 1\n        board[f] = 0\n        board[(t + f) // 2] = 0\n        jumps = jumps + 1\n\n    left = 0\n    for i in range(1, 64 + 1):\n        left = left + board[i]\n    return (str(jumps), str(left))\n\n\ndef try_again() -> bool:\n    print(\"TRY AGAIN\", end=\" \")\n    answer = input().upper()\n    if answer == \"YES\":\n        return True\n    elif answer == \"NO\":\n        return False\n    print(\"PLEASE ANSWER 'YES' OR 'NO'.\")\n    return try_again()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "67_One_Check/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "67_One_Check/vbnet/OneCheck.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"OneCheck\", \"OneCheck.vbproj\", \"{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "67_One_Check/vbnet/OneCheck.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>OneCheck</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "67_One_Check/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "68_Orbit/README.md",
    "content": "### Orbit\n\nORBIT challenges you to visualize spacial positions in polar coordinates. The object is to detonate a Photon explosive within a certain distance of a germ laden Romulan spaceship. This ship is orbiting a planet at a constant altitude and orbital rate (degrees/hour). The location of the ship is hidden by a device that renders the ship invisible, but after each bomb you are told how close to the enemy ship your bomb exploded. The challenge is to hit an invisible moving target with a limited number of shots.\n\nThe planet can be replaced by a point at its center (called the origin); then the ship’s position can be given as a distance form the origin and an angle between its position and the eastern edge of the planet.\n\n```\ndirection\nof orbit    <       ^ ship\n              \\     ╱\n                \\  ╱ <\n                 |╱   \\\n                 ╱      \\\n                ╱         \\\n               ╱           | angle\n              ╱           /\n             ╱          /\n            ╱         /\n           ╱——————————————————— E\n\n```\n\nThe distance of the bomb from the ship is computed using the law of cosines. The law of cosines states:\n\n```\nD = SQUAREROOT( R**2 + D1**2 - 2*R*D1*COS(A-A1) )\n```\n\nWhere D is the distance between the ship and the bomb, R is the altitude of the ship, D1 is the altitude of the bomb, and A-A1 is the angle between the ship and the bomb.\n\n\n```\n                 bomb  <\n                        ╲                   ^ ship\n                         ╲                  ╱\n                          ╲                ╱ <\n                           ╲              ╱   \\\n                        D1  ╲            ╱      \\\n                             ╲        R ╱         \\\n                              ╲   A1   ╱           | A\n                               ╲⌄——— ◝╱           /\n                                ╲    ╱ \\        /\n                                 ╲  ╱   \\      /\n                                  ╲╱───────────────────── E\n\n```\n\nORBIT was originally called SPACE WAR and was written by Jeff Lederer of Project SOLO Pittsburgh, Pennsylvania.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=124)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=139)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "68_Orbit/csharp/Orbit.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "68_Orbit/csharp/Orbit.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Orbit\", \"Orbit.csproj\", \"{2912E79E-D9A2-488F-B77E-7C348E3347E7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "68_Orbit/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "68_Orbit/csharp/program.cs",
    "content": "using System.Text;\n\nnamespace Orbit\n{\n    class Orbit\n    {\n        private void DisplayIntro()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"ORBIT\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\");\n            Console.WriteLine();\n            Console.WriteLine(\"THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\");\n            Console.WriteLine(\"DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\");\n            Console.WriteLine(\"10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\");\n            Console.WriteLine(\"CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\");\n            Console.WriteLine();\n            Console.WriteLine(\"UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\");\n            Console.WriteLine(\"YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\");\n            Console.WriteLine(\"INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\");\n            Console.WriteLine(\"PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\");\n            Console.WriteLine(\"HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\");\n            Console.WriteLine(\"YOUR PLANET'S GRAVITY.\");\n            Console.WriteLine();\n            Console.WriteLine(\"YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\");\n            Console.WriteLine();\n            Console.WriteLine(\"AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\");\n            Console.WriteLine(\"ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\");\n            Console.WriteLine(\"100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\");\n            Console.WriteLine(\"DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\");\n            Console.WriteLine();\n            Console.WriteLine(\"AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\");\n            Console.WriteLine(\"WILL DESTROY IT.\");\n            Console.WriteLine();\n            Console.WriteLine(\"BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"                          90\");\n            Console.WriteLine(\"                    0000000000000\");\n            Console.WriteLine(\"                 0000000000000000000\");\n            Console.WriteLine(\"               000000           000000\");\n            Console.WriteLine(\"             00000                 00000\");\n            Console.WriteLine(\"            00000    XXXXXXXXXXX    00000\");\n            Console.WriteLine(\"           00000    XXXXXXXXXXXXX    00000\");\n            Console.WriteLine(\"          0000     XXXXXXXXXXXXXXX     0000\");\n            Console.WriteLine(\"         0000     XXXXXXXXXXXXXXXXX     0000\");\n            Console.WriteLine(\"        0000     XXXXXXXXXXXXXXXXXXX     0000\");\n            Console.WriteLine(\"180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\");\n            Console.WriteLine(\"        0000     XXXXXXXXXXXXXXXXXXX     0000\");\n            Console.WriteLine(\"         0000     XXXXXXXXXXXXXXXXX     0000\");\n            Console.WriteLine(\"          0000     XXXXXXXXXXXXXXX     0000\");\n            Console.WriteLine(\"           00000    XXXXXXXXXXXXX    00000\");\n            Console.WriteLine(\"            00000    XXXXXXXXXXX    00000\");\n            Console.WriteLine(\"             00000                 00000\");\n            Console.WriteLine(\"               000000           000000\");\n            Console.WriteLine(\"                 0000000000000000000\");\n            Console.WriteLine(\"                    0000000000000\");\n            Console.WriteLine(\"                         270\");\n            Console.WriteLine();\n            Console.WriteLine(\"X - YOUR PLANET\");\n            Console.WriteLine(\"O - THE ORBIT OF THE ROMULAN SHIP\");\n            Console.WriteLine();\n            Console.WriteLine(\"ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\");\n            Console.WriteLine(\"COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\");\n            Console.WriteLine(\"WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\");\n            Console.WriteLine(\"AND ORBITAL RATE WILL REMAIN CONSTANT.\");\n            Console.WriteLine();\n            Console.WriteLine(\"GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\");\n       }\n\n        private bool PromptYesNo(string Prompt)\n        {\n            bool Success = false;\n\n            while (!Success)\n            {\n                Console.Write(Prompt);\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (LineInput.Equals(\"yes\"))\n                    return true;\n                else if (LineInput.Equals(\"no\"))\n                    return false;\n                else\n                    Console.WriteLine(\"Yes or No\");\n            }\n\n            return false;\n        }\n\n        private int PromptForNumber(string Prompt)\n        {\n            bool InputSuccess = false;\n            int ReturnResult = 0;\n\n            while (!InputSuccess)\n            {\n                Console.Write(Prompt);\n                string Input = Console.ReadLine().Trim();\n                InputSuccess = int.TryParse(Input, out ReturnResult);\n                if (!InputSuccess)\n                    Console.WriteLine(\"*** Please enter a valid number ***\");\n            }   \n\n            return ReturnResult;\n        }\n\n        private void PlayOneRound()\n        {\n            Random rand = new Random();\n            string Prompt = \"\";\n\n            int A_AngleToShip = 0;\n            int D_DistanceFromBombToShip = 0;\n            int R_DistanceToShip = 0;\n            int H_Hour = 0;\n            int A1_Angle = 0;\n            int D1_DistanceForDetonation = 0;\n            int T = 0;\n            double C_ExplosionDistance = 0;\n\n            A_AngleToShip = Convert.ToInt32(360 * rand.NextDouble());\n            D_DistanceFromBombToShip = Convert.ToInt32(200 * rand.NextDouble()) + 200;\n            R_DistanceToShip = Convert.ToInt32(20 * rand.NextDouble()) + 10;\n\n            while (H_Hour < 7)\n            {\n                H_Hour++;\n\n                Console.WriteLine();\n                Console.WriteLine();\n                Prompt = \"This is hour \" + H_Hour.ToString() + \", at what angle do you wish to send\\nyour photon bomb? \";\n                A1_Angle = PromptForNumber(Prompt);\n\n                D1_DistanceForDetonation = PromptForNumber(\"How far out do you wish to detonate it? \");\n\n                Console.WriteLine();\n                Console.WriteLine();\n\n                A_AngleToShip += R_DistanceToShip;\n                if (A_AngleToShip >= 360)\n                    A_AngleToShip -= 360;\n\n                T = Math.Abs(A_AngleToShip = A1_Angle);\n                if (T >= 180)\n                    T = 360 - T;\n\n                C_ExplosionDistance = Math.Sqrt(D_DistanceFromBombToShip * D_DistanceFromBombToShip + D1_DistanceForDetonation * \n                                                D1_DistanceForDetonation - 2 * D_DistanceFromBombToShip * D1_DistanceForDetonation * \n                                                Math.Cos(T * 3.14159 / 180));\n                \n                Console.WriteLine(\"Your photon bomb exploded {0:N3}*10^2 miles from the\", C_ExplosionDistance);\n                Console.WriteLine(\"Romulan ship.\");\n\n                if (C_ExplosionDistance <= 50)\n                {\n                    Console.WriteLine(\"You have successfully completed your mission.\");\n                    return;\n                }\n            }\n\n            Console.WriteLine(\"You allowed the Romulans to escape.\");\n            return;\n \n        }\n\n        public void Play()\n        {\n            bool ContinuePlay = true;\n\n            DisplayIntro();\n\n            do \n            {\n                PlayOneRound();\n\n                Console.WriteLine(\"Another Romulan ship has gone in to orbit.\");\n                ContinuePlay = PromptYesNo(\"Do you wish to try to destroy it? \");\n            }\n            while (ContinuePlay);\n            \n            Console.WriteLine(\"Good bye.\");\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Orbit().Play();\n\n        }\n    }\n}"
  },
  {
    "path": "68_Orbit/java/Orbit.java",
    "content": "import java.lang.Integer;\nimport java.lang.Math;\nimport java.util.Scanner;\n\n/**\n * Game of Orbit\n * <p>\n * Based on the BASIC game of Orbit here\n * https://github.com/coding-horror/basic-computer-games/blob/main/68%20Orbit/orbit.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Orbit {\n\n  private final Scanner scan;  // For user input\n\n  public Orbit() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Orbit\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"ORBIT\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n    System.out.println(\"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\");\n    System.out.println(\"\");\n    System.out.println(\"THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\");\n    System.out.println(\"DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\");\n    System.out.println(\"10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\");\n    System.out.println(\"CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\");\n    System.out.println(\"\");\n    System.out.println(\"UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\");\n    System.out.println(\"YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\");\n    System.out.println(\"INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\");\n    System.out.println(\"PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\");\n    System.out.println(\"HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\");\n    System.out.println(\"YOUR PLANET'S GRAVITY.\");\n    System.out.println(\"\");\n    System.out.println(\"YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\");\n    System.out.println(\"\");\n    System.out.println(\"AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\");\n    System.out.println(\"ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\");\n    System.out.println(\"100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\");\n    System.out.println(\"DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\");\n    System.out.println(\"\");\n    System.out.println(\"AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\");\n    System.out.println(\"WILL DESTROY IT.\");\n    System.out.println(\"\");\n    System.out.println(\"BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\");\n    System.out.println(\"\");\n    System.out.println(\"\");\n    System.out.println(\"                          90\");\n    System.out.println(\"                    0000000000000\");\n    System.out.println(\"                 0000000000000000000\");\n    System.out.println(\"               000000           000000\");\n    System.out.println(\"             00000                 00000\");\n    System.out.println(\"            00000    XXXXXXXXXXX    00000\");\n    System.out.println(\"           00000    XXXXXXXXXXXXX    00000\");\n    System.out.println(\"          0000     XXXXXXXXXXXXXXX     0000\");\n    System.out.println(\"         0000     XXXXXXXXXXXXXXXXX     0000\");\n    System.out.println(\"        0000     XXXXXXXXXXXXXXXXXXX     0000\");\n    System.out.println(\"180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\");\n    System.out.println(\"        0000     XXXXXXXXXXXXXXXXXXX     0000\");\n    System.out.println(\"         0000     XXXXXXXXXXXXXXXXX     0000\");\n    System.out.println(\"          0000     XXXXXXXXXXXXXXX     0000\");\n    System.out.println(\"           00000    XXXXXXXXXXXXX    00000\");\n    System.out.println(\"            00000    XXXXXXXXXXX    00000\");\n    System.out.println(\"             00000                 00000\");\n    System.out.println(\"               000000           000000\");\n    System.out.println(\"                 0000000000000000000\");\n    System.out.println(\"                    0000000000000\");\n    System.out.println(\"                         270\");\n    System.out.println(\"\");\n    System.out.println(\"X - YOUR PLANET\");\n    System.out.println(\"O - THE ORBIT OF THE ROMULAN SHIP\");\n    System.out.println(\"\");\n    System.out.println(\"ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\");\n    System.out.println(\"COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\");\n    System.out.println(\"WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\");\n    System.out.println(\"AND ORBITAL RATE WILL REMAIN CONSTANT.\");\n    System.out.println(\"\");\n    System.out.println(\"GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    double bombDistance = 0;\n    int bombAltitude = 0;\n    int bombAngle = 0;\n    int deltaAngle = 0;\n    int hour = 0;\n    int shipAltitude = 0;\n    int shipAngle = 0;\n    int shipRate = 0;\n    String userResponse = \"\";\n\n    // Begin outer while loop\n    while (true) {\n      shipAngle = (int) (361 * Math.random());\n      shipAltitude = (int) (201 * Math.random() + 200);\n      shipRate = (int) (21 * Math.random() + 10);\n\n      hour = 0;\n\n      // Begin time limit loop\n      while (hour < 7) {\n\n        System.out.println(\"\");\n        System.out.println(\"\");\n        System.out.println(\"THIS IS HOUR \" + (hour + 1) + \", AT WHAT ANGLE DO YOU WISH TO SEND\");\n        System.out.print(\"YOUR PHOTON BOMB? \");\n        bombAngle = Integer.parseInt(scan.nextLine());\n\n        System.out.print(\"HOW FAR OUT DO YOU WISH TO DETONATE IT? \");\n        bombAltitude = Integer.parseInt(scan.nextLine());\n\n        System.out.println(\"\");\n        System.out.println(\"\");\n\n        // Update ship position\n        shipAngle += shipRate;\n\n        // Handle full revolutions\n        if (shipAngle >= 360) {\n          shipAngle -= 360;\n        }\n\n        deltaAngle = Math.abs(shipAngle - bombAngle);\n\n        // Keep angle in upper quadrants\n        if (deltaAngle >= 180) {\n          deltaAngle = 360 - deltaAngle;\n        }\n\n        bombDistance = Math.sqrt(shipAltitude * shipAltitude + bombAltitude * bombAltitude - 2 * shipAltitude\n                       * bombAltitude * Math.cos(deltaAngle * Math.PI / 180));\n\n        System.out.format(\"YOUR PHOTON BOMB EXPLODED \" + \"%.5f\" + \"*10^2 MILES FROM THE\\n\", bombDistance);\n        System.out.println(\"ROMULAN SHIP.\");\n\n        // Win condition\n        if (bombDistance <= 50) {\n          System.out.println(\"YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.\");\n          break;\n        }\n\n        hour++;\n\n      }  // End time limit loop\n\n      // Lose condition\n      if (hour == 7) {\n        System.out.println(\"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\");\n      }\n\n      System.out.println(\"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\");\n      System.out.print(\"DO YOU WISH TO TRY TO DESTROY IT? \");\n      userResponse = scan.nextLine();\n\n      if (!userResponse.toUpperCase().equals(\"YES\")) {\n        System.out.println(\"GOOD BYE.\");\n        break;\n      }\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    Orbit game = new Orbit();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class Orbit\n"
  },
  {
    "path": "68_Orbit/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "68_Orbit/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "68_Orbit/javascript/orbit.html",
    "content": "<html>\n<head>\n<title>ORBIT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"orbit.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "68_Orbit/javascript/orbit.js",
    "content": "// ORBIT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"ORBIT\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\\n\");\n    print(\"\\n\");\n    print(\"THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\\n\");\n    print(\"DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\\n\");\n    print(\"10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\\n\");\n    print(\"CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\\n\");\n    print(\"\\n\");\n    print(\"UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\\n\");\n    print(\"YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\\n\");\n    print(\"INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\\n\");\n    print(\"PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\\n\");\n    print(\"HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\\n\");\n    print(\"YOUR PLANET'S GRAVITY.\\n\");\n    print(\"\\n\");\n    print(\"YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\\n\");\n    print(\"\\n\");\n    print(\"AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\\n\");\n    print(\"ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\\n\");\n    print(\"100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\\n\");\n    print(\"DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\\n\");\n    print(\"\\n\");\n    print(\"AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\\n\");\n    print(\"WILL DESTROY IT.\\n\");\n    print(\"\\n\");\n    print(\"BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"                          90\\n\");\n    print(\"                    0000000000000\\n\");\n    print(\"                 0000000000000000000\\n\");\n    print(\"               000000           000000\\n\");\n    print(\"             00000                 00000\\n\");\n    print(\"            00000    XXXXXXXXXXX    00000\\n\");\n    print(\"           00000    XXXXXXXXXXXXX    00000\\n\");\n    print(\"          0000     XXXXXXXXXXXXXXX     0000\\n\");\n    print(\"         0000     XXXXXXXXXXXXXXXXX     0000\\n\");\n    print(\"        0000     XXXXXXXXXXXXXXXXXXX     0000\\n\");\n    print(\"180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\\n\");\n    print(\"        0000     XXXXXXXXXXXXXXXXXXX     0000\\n\");\n    print(\"         0000     XXXXXXXXXXXXXXXXX     0000\\n\");\n    print(\"          0000     XXXXXXXXXXXXXXX     0000\\n\");\n    print(\"           00000    XXXXXXXXXXXXX    00000\\n\");\n    print(\"            00000    XXXXXXXXXXX    00000\\n\");\n    print(\"             00000                 00000\\n\");\n    print(\"               000000           000000\\n\");\n    print(\"                 0000000000000000000\\n\");\n    print(\"                    0000000000000\\n\");\n    print(\"                         270\\n\");\n    print(\"\\n\");\n    print(\"X - YOUR PLANET\\n\");\n    print(\"O - THE ORBIT OF THE ROMULAN SHIP\\n\");\n    print(\"\\n\");\n    print(\"ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\\n\");\n    print(\"COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\\n\");\n    print(\"WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\\n\");\n    print(\"AND ORBITAL RATE WILL REMAIN CONSTANT.\\n\");\n    print(\"\\n\");\n    print(\"GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\\n\");\n    while (1) {\n        a = Math.floor(360 * Math.random());\n        d = Math.floor(200 * Math.random() + 200);\n        r = Math.floor(20 * Math.random() + 10);\n        h = 0;\n        while (h < 7) {\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"THIS IS HOUR \" + (h + 1) + \", AT WHAT ANGLE DO YOU WISH TO SEND\\n\");\n            print(\"YOUR PHOTON BOMB\");\n            a1 = parseFloat(await input());\n            print(\"HOW FAR OUT DO YOU WISH TO DETONATE IT\");\n            d1 = parseFloat(await input());\n            print(\"\\n\");\n            print(\"\\n\");\n            a += r;\n            if (a >= 360)\n                a -= 360;\n            t = Math.abs(a - a1);\n            if (t >= 180)\n                t = 360 - t;\n            c = Math.sqrt(d * d + d1 * d1 - 2 * d * d1 * Math.cos(t * Math.PI / 180));\n            print(\"YOUR PHOTON BOMB EXPLODED \" + c + \"*10^2 MILES FROM THE\\n\");\n            print(\"ROMULAN SHIP.\\n\");\n            if (c <= 50)\n                break;\n            h++;\n        }\n        if (h == 7) {\n            print(\"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\\n\");\n        } else {\n            print(\"YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.\\n\");\n        }\n        print(\"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\\n\");\n        print(\"DO YOU WISH TO TRY TO DESTROY IT\");\n        str = await input();\n        if (str != \"YES\")\n            break;\n    }\n    print(\"GOOD BYE.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "68_Orbit/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "68_Orbit/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "68_Orbit/orbit.bas",
    "content": "2 PRINT TAB(33);\"ORBIT\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n10 PRINT \"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\"\n15 PRINT\n20 PRINT \"THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\"\n25 PRINT \"DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\"\n30 PRINT \"10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\"\n31 PRINT \"CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\"\n35 PRINT\n40 PRINT \"UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\"\n45 PRINT \"YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\"\n50 PRINT \"INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\"\n55 PRINT \"PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\"\n60 PRINT \"HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\"\n65 PRINT \"YOUR PLANET'S GRAVITY.\"\n70 PRINT\n75 PRINT \"YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\"\n80 PRINT\n85 PRINT \"AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\"\n90 PRINT \"ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\"\n95 PRINT \"100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\"\n100 PRINT \"DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\"\n105 PRINT\n110 PRINT \"AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\"\n111 PRINT \"WILL DESTROY IT.\"\n114 PRINT\n115 PRINT \"BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\"\n116 PRINT\n117 PRINT\n168 PRINT \"                          90\"\n170 PRINT \"                    0000000000000\"\n171 PRINT \"                 0000000000000000000\"\n172 PRINT \"               000000           000000\"\n173 PRINT \"             00000                 00000\"\n174 PRINT \"            00000    XXXXXXXXXXX    00000\"\n175 PRINT \"           00000    XXXXXXXXXXXXX    00000\"\n176 PRINT \"          0000     XXXXXXXXXXXXXXX     0000\"\n177 PRINT \"         0000     XXXXXXXXXXXXXXXXX     0000\"\n178 PRINT \"        0000     XXXXXXXXXXXXXXXXXXX     0000\"\n179 PRINT \"180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\"\n180 PRINT \"        0000     XXXXXXXXXXXXXXXXXXX     0000\"\n181 PRINT \"         0000     XXXXXXXXXXXXXXXXX     0000\"\n182 PRINT \"          0000     XXXXXXXXXXXXXXX     0000\"\n183 PRINT \"           00000    XXXXXXXXXXXXX    00000\"\n184 PRINT \"            00000    XXXXXXXXXXX    00000\"\n185 PRINT \"             00000                 00000\"\n186 PRINT \"               000000           000000\"\n187 PRINT \"                 0000000000000000000\"\n188 PRINT \"                    0000000000000\"\n190 PRINT \"                         270\"\n192 PRINT\n195 PRINT \"X - YOUR PLANET\"\n196 PRINT \"O - THE ORBIT OF THE ROMULAN SHIP\"\n197 PRINT\n198 PRINT \"ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\"\n199 PRINT \"COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\"\n200 PRINT \"WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\"\n210 PRINT \"AND ORBITAL RATE WILL REMAIN CONSTANT.\"\n220 PRINT\n230 PRINT \"GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\"\n270 A=INT(360*RND(1))\n280 D=INT(200*RND(1)+200)\n290 R=INT(20*RND(1)+10)\n300 H=0\n310 IF H=7 THEN 490\n320 H=H+1\n325 PRINT\n326 PRINT\n330 PRINT \"THIS IS HOUR\";H;\", AT WHAT ANGLE DO YOU WISH TO SEND\"\n335 PRINT \"YOUR PHOTON BOMB\";\n340 INPUT A1\n350 PRINT \"HOW FAR OUT DO YOU WISH TO DETONATE IT\";\n360 INPUT D1\n365 PRINT\n366 PRINT\n370 A=A+R\n380 IF A<360 THEN 400\n390 A=A-360\n400 T=ABS(A-A1)\n410 IF T<180 THEN 430\n420 T=360-T\n430 C=SQR(D*D+D1*D1-2*D*D1*COS(T*3.14159/180))\n440 PRINT \"YOUR PHOTON BOMB EXPLODED\";C;\"*10^2 MILES FROM THE\"\n445 PRINT \"ROMULAN SHIP.\"\n450 IF C<=50 THEN 470\n460 GOTO 310\n470 PRINT \"YOU HAVE SUCCESFULLY COMPLETED YOUR MISSION.\"\n480 GOTO 500\n490 PRINT \"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\"\n500 PRINT \"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\"\n510 PRINT \"DO YOU WISH TO TRY TO DESTROY IT\";\n520 INPUT C$\n530 IF C$=\"YES\" THEN 270\n540 PRINT \"GOOD BYE.\"\n999 END\n"
  },
  {
    "path": "68_Orbit/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nThis Perl script is a port of orbit, which is the 68th entry in Basic\nComputer Games.\n\nIn this game you are a planetary defense gunner trying to shoot down a\ncloaked Romulan ship before it can escape.\n\nThis is pretty much a straight port of the BASIC into idiomatic Perl.\n"
  },
  {
    "path": "68_Orbit/perl/orbit.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nuse constant PI => atan2( 0, -1 );\nuse constant DEG_TO_RAD => atan2( 0, -1 ) / 180;\n\nprint <<'EOD';\n                                 ORBIT\n               Creative Computing  Morristown, New Jersey\n\n\n\nSomewhere above your planet is a Romulan ship.\n\nThe ship is in a constant polar orbit.  Its\ndistance from the center of your planet is from\n10,000 to 30,000 miles and at its present velocity can\ncircle your planet once every 12 to 36 hours.\n\nUnfortunately, they are using a cloaking device so\nyou are unable to see them, but with a special\ninstrument you can tell how near their ship your\nphoton bomb exploded.  You have seven hours until they\nhave built up sufficient power in order to escape\nyour planet's gravity.\n\nYour planet has enough power to fire one bomb an hour.\n\nAt the beginning of each hour you will be asked to give an\nangle (between 0 and 360) and a distance in units of\n100 miles (between 100 and 300), after which your bomb's\ndistance from the enemy ship will be given.\n\nAn explosion within 5,000 miles of the Romulan ship\nwill destroy it.\n\nBelow is a diagram to help you visualize your plight.\n\n\n                          90\n                    0000000000000\n                 0000000000000000000\n               000000           000000\n             00000                 00000\n            00000    XXXXXXXXXXX    00000\n           00000    XXXXXXXXXXXXX    00000\n          0000     XXXXXXXXXXXXXXX     0000\n         0000     XXXXXXXXXXXXXXXXX     0000\n        0000     XXXXXXXXXXXXXXXXXXX     0000\n180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\n        0000     XXXXXXXXXXXXXXXXXXX     0000\n         0000     XXXXXXXXXXXXXXXXX     0000\n          0000     XXXXXXXXXXXXXXX     0000\n           00000    XXXXXXXXXXXXX    00000\n            00000    XXXXXXXXXXX    00000\n             00000                 00000\n               000000           000000\n                 0000000000000000000\n                    0000000000000\n                         270\n\nX - Your planet\nO - The orbit of the Romulan ship\n\nOn the above diagram, the Romulan ship is circling\ncounterclockwise around your planet.  Don't forget that\nwithout sufficient power the Romulan ship's altitude\nand orbital rate will remain constant.\n\nGood luck.  The Federation is counting on you.\nEOD\n\nwhile ( 1 ) {   # Iterate indefinitely\n\n    my $romulan_angle = int( 360 * rand() );\n    my $romulan_distance = int( 200 * rand() + 200 );\n    my $romulan_velocity = int( 20 * rand() + 10 );\n\n    my $hour = 0;\n    while ( 1 ) {   # Iterate indefinitely\n        $hour++;\n\n        print <<\"EOD\";\n\n\nThis is hour $hour, at what angle do you wish to send\nEOD\n        my $bomb_angle = get_input(\n            'do you wish to send your photon bomb? ',\n            sub { m/ \\A [0-9]+ \\z /smx },\n            \"Please enter an integer angle in degrees\\n\",\n        );\n        say '';\n        my $bomb_distance = get_input(\n            'How far out do you wish to detonate it? ',\n            sub { m/ \\A [0-9]+ \\z /smx },\n            \"Please enter an integer distance in hundreds of miles\\n\",\n        );\n\n        $romulan_angle = ( $romulan_angle + $romulan_velocity ) % 360;\n        my $miss_angle = abs( $romulan_angle - $bomb_angle );\n        $miss_angle = 360 - $miss_angle if $miss_angle >= 180;\n        my $miss_distance = int sqrt(\n            $romulan_distance * $romulan_distance +\n            $bomb_distance * $bomb_distance -\n            2 * $romulan_distance * $bomb_distance *\n                cos( $miss_angle * DEG_TO_RAD ) );\n        print <<\"EOD\";\n\nYour photon bomb exploded $miss_distance*10^2 miles from the\nRomulan ship.\nEOD\n        if ( $miss_distance <= 50 ) {\n            say \"\\nYou have successfully completed your mission.\";\n            last;\n        } elsif ( $hour > 6 ) {\n            say \"\\nYou have allowed the Romulans to escape.\";\n            last;\n        }\n    }\n\n    say \"\\nAnother Romulan ship has gone into orbit.\";\n    last unless get_yes_no( 'Do you wish to try to destroy it' );\n}\n\nprint <<'EOD';\n\nGood bye.\nEOD\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n__END__\n\n=head1 TITLE\n\norbit - Play the game 'Orbit' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n orbit.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of orbit, which is the 68th entry in Basic\nComputer Games.\n\nIn this game you are a planetary defense gunner trying to shoot down a\ncloaked Romulan ship before it can escape.\n\nThis is pretty much a straight port of the BASIC into idiomatic Perl.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "68_Orbit/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "68_Orbit/python/orbit.py",
    "content": "\"\"\"\nORBIT\n\nOrbital mechanics simulation\n\nPort by Dave LeCompte\n\"\"\"\n\nimport math\nimport random\n\nPAGE_WIDTH = 64\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_instructions() -> None:\n    print(\n        \"\"\"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\n\nTHE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\nDISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\n10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\nCIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\n\nUNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\nYOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\nINSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\nPHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\nHAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\nYOUR PLANET'S GRAVITY.\n\nYOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\n\nAT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\nANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\n100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\nDISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\n\nAN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\nWILL DESTROY IT.\n\nBELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\n\n\n                          90\n                    0000000000000\n                 0000000000000000000\n               000000           000000\n             00000                 00000\n            00000    XXXXXXXXXXX    00000\n           00000    XXXXXXXXXXXXX    00000\n          0000     XXXXXXXXXXXXXXX     0000\n         0000     XXXXXXXXXXXXXXXXX     0000\n        0000     XXXXXXXXXXXXXXXXXXX     0000\n180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\n        0000     XXXXXXXXXXXXXXXXXXX     0000\n         0000     XXXXXXXXXXXXXXXXX     0000\n          0000     XXXXXXXXXXXXXXX     0000\n           00000    XXXXXXXXXXXXX    00000\n            00000    XXXXXXXXXXX    00000\n             00000                 00000\n               000000           000000\n                 0000000000000000000\n                    0000000000000\n                         270\n\nX - YOUR PLANET\nO - THE ORBIT OF THE ROMULAN SHIP\n\nON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\nCOUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\nWITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\nAND ORBITAL RATE WILL REMAIN CONSTANT.\n\nGOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\n\"\"\"\n    )\n\n\ndef get_yes_or_no() -> bool:\n    while True:\n        response = input().upper()\n        if response == \"YES\":\n            return True\n        elif response == \"NO\":\n            return False\n        else:\n            print(\"PLEASE TYPE 'YES' OR 'NO'\")\n\n\ndef game_over(is_success: bool) -> bool:\n    if is_success:\n        print(\"YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.\")\n    else:\n        print(\"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\")\n    print(\"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\")\n    print(\"DO YOU WISH TO TRY TO DESTROY IT?\")\n\n    return get_yes_or_no()\n\n\ndef play_game() -> bool:\n    rom_angle = random.randint(0, 359)\n    rom_distance = random.randint(100, 300)\n    rom_angular_velocity = random.randint(10, 30)\n    for hour in range(1, 8):\n        print()\n        print()\n        print(f\"THIS IS HOUR {hour}, AT WHAT ANGLE DO YOU WISH TO SEND\")\n        print(\"YOUR PHOTON BOMB?\")\n\n        bomb_angle = float(input())\n        print(\"HOW FAR OUT DO YOU WISH TO DETONATE IT?\")\n        bomb_distance = float(input())\n        print()\n        print()\n\n        rom_angle = (rom_angle + rom_angular_velocity) % 360\n        angular_difference = rom_angle - bomb_angle\n        c = math.sqrt(\n            rom_distance**2\n            + bomb_distance**2\n            - 2\n            * rom_distance\n            * bomb_distance\n            * math.cos(math.radians(angular_difference))\n        )\n\n        print(f\"YOUR PHOTON BOMB EXPLODED {c:.4f}*10^2 MILES FROM THE\")\n        print(\"ROMULAN SHIP.\")\n\n        if c <= 50:\n            # Destroyed the Romulan\n            return True\n\n    # Ran out of time\n    return False\n\n\ndef main() -> None:\n    print_centered(\"ORBIT\")\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    print_instructions()\n\n    while True:\n        success = play_game()\n        again = game_over(success)\n        if not again:\n            return\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "68_Orbit/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "68_Orbit/ruby/orbit.rb",
    "content": "PAGE_WIDTH = 64\n\ndef print_centered(msg)\n\tspaces = \" \" * ((PAGE_WIDTH / msg.length).fdiv(2))\n\tputs \"#{spaces}#{msg}\"\nend\n\ndef print_instructions\n\tputs \"SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\nTHE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\nDISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\n10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\nCIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\nUNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\nYOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\nINSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\nPHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\nHAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\nYOUR PLANET'S GRAVITY.\nYOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\nAT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\nANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\n100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\nDISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\nAN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\nWILL DESTROY IT.\nBELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\n                          90\n                    0000000000000\n                 0000000000000000000\n               000000           000000\n             00000                 00000\n            00000    XXXXXXXXXXX    00000\n           00000    XXXXXXXXXXXXX    00000\n          0000     XXXXXXXXXXXXXXX     0000\n         0000     XXXXXXXXXXXXXXXXX     0000\n        0000     XXXXXXXXXXXXXXXXXXX     0000\n180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\n        0000     XXXXXXXXXXXXXXXXXXX     0000\n         0000     XXXXXXXXXXXXXXXXX     0000\n          0000     XXXXXXXXXXXXXXX     0000\n           00000    XXXXXXXXXXXXX    00000\n            00000    XXXXXXXXXXX    00000\n             00000                 00000\n               000000           000000\n                 0000000000000000000\n                    0000000000000\n                         270\nX - YOUR PLANET\nO - THE ORBIT OF THE ROMULAN SHIP\nON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\nCOUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\nWITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\nAND ORBITAL RATE WILL REMAIN CONSTANT.\nGOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\n\"\nend\n\n\ndef get_yes_or_no()\n\twhile true\n\t\tresponse = gets.chomp!.upcase\n\t\tif response == \"YES\"\n\t\t\treturn true\n\t\telsif response == \"NO\"\n\t\t\treturn false\n\t\telse\n\t\t\tprint(\"PLEASE TYPE 'YES' OR 'NO'\")\n\t\tend\n\tend\nend\n\ndef game_over(is_success)\n\tif is_success\n\t\tputs \"YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.\"\n\telse\n\t\tputs \"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\"\n\t\tputs \"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\"\n\t\tputs \"DO YOU WISH TO TRY TO DESTROY IT?\"\n\t\treturn get_yes_or_no()\n\tend\nend\n\ndef play_game\n\trom_angle = rand(1...360)\n\trom_distance = rand(100...301)\n\trom_angular_velocity = rand(10...31)\n\thour = 0\n\twhile hour < 7\n\t\thour += 1\n\t\tputs \"\\n\\n\"\n\t\tputs \"THIS IS HOUR #{hour}, AT WHAT ANGLE DO YOU WISH TO SEND\"\n\t\tputs \"YOUR PHOTON BOMB?\"\n\n\t\tbomb_angle = gets.chomp!.to_f\n\t\tputs \"HOW FAR OUT DO YOU WISH TO DETONATE IT?\"\n\t\tbomb_distance = gets.chomp!.to_f\n\t\tputs \"\\n\\n\"\n\n\t\trom_angle = (rom_angle + rom_angular_velocity) % 360\n\t\tangular_difference = rom_angle - bomb_angle\n\t\tc = Math.sqrt(rom_distance**2 + bomb_distance**2 - 2 * rom_distance * bomb_distance * Math.cos(angular_difference * Math::PI / 180))\n\n\t\tputs \"YOUR PHOTON BOMB EXPLODED #{sprintf('%.4f', 5)}*10^2 MILES FROM THE\"\n\t\tputs \"ROMULAN SHIP.\"\n\n\t\tif c <= 50\n\t\t\t# Destroyed the Romulan\n\t\t\treturn true\n\t\tend\n\tend\n\treturn false\nend\n\ndef main\n    print_centered \"ORBIT\"\n\n    print_instructions()\n\n    while true\n        success = play_game()\n        again = game_over(success)\n        if !again\n            return\n        end\n    end\nend\n\nif __FILE__ == $0\n  main\nend\n    "
  },
  {
    "path": "68_Orbit/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\""
  },
  {
    "path": "68_Orbit/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "68_Orbit/rust/src/lib.rs",
    "content": "/*\n lib.rs contains all the logic of the program\n*/\n\nuse std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}, f64::consts::PI};\n\nuse rand::{thread_rng, Rng};\n\n/// handles setup for the game\npub struct Config {\n}\nimpl Config {\n    /// creates and returns a new Config from user input\n    pub fn new() -> Result<Config, Box<dyn Error>> {\n        //DATA\n        let config: Config = Config {};\n\n        //this game doesn't actually need a config\n\n        //return new config\n        return Ok(config);\n    }\n}\n\n/// run the program\npub fn run(_config: &Config) -> Result<(), Box<dyn Error>> {\n    \n    //play game as long as user wants to play it\n    while play_game() {}\n    \n    //return to main\n    Ok(())\n}\n\n/// handles playing the game one time\n/// after playing, asks the user if they want to play again and ...\n/// returns true if user wants to play again, false otherwise\nfn play_game() -> bool {\n    //DATA\n    let mut rng = thread_rng();\n    let mut ship_destroyed:bool = false;\n    //generate position of the ship\n    let mut ship:Polar =  Polar::new(rng.gen_range(0.0..2.0*PI), rng.gen_range(100.0_f64..300.0_f64).floor());\n    let ship_speed:f64 = rng.gen_range((PI/36.0)..(PI/12.0)); //10deg - 30deg, but radians\n\n    //game\n    // round loop\n    for hour in 0..7 {\n        //DATA\n        let photon_bomb:Polar;\n        let two_pi = 2.0*PI;\n        let distance;\n        \n        //tell user the hour\n        println!(\"THIS IS HOUR {},\", hour);\n\n        //get input for angle and distance to send the bomb\n        photon_bomb = get_bomb_from_user_input();\n\n        //move ship\n        ship.angle += ship_speed;\n        if ship.angle > two_pi { ship.angle -= two_pi}\n\n        //calculate distance of bomb from ship\n        distance = photon_bomb.distance_from(&ship);\n        //tell user how far away they were from the target\n        println!(\"YOUR PHOTON BOMB EXPLODED {}*10^2 MILES FROM THE ROMULAN SHIP\\n\\n\", distance);\n\n        //did the bomb destroy the ship?\n        ship_destroyed = distance <= 50.0;\n        if ship_destroyed {break;}\n        //otherwise user didn't destroy the ship, run loop again\n    }\n    \n    //print results message depending on whether or not the user destroyed the ship in time\n    if ship_destroyed {\n        println!(\"YOU HAVE SUCCESFULLY COMPLETED YOUR MISSION.\");\n    } else {\n        println!(\"YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\")\n    }\n\n    //prompt user to play again\n    //do they want to play yes? if they do return true, otherwise false\n    return match get_string_from_user_input(\"ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\\nDO YOU WISH TO TRY TO DESTROY IT?\\n(y/n) \") {\n        Ok(string) => string.chars().any(|c| c.eq_ignore_ascii_case(&'y')),\n        Err(_e) => false,\n    };\n}\n\n/// structure to handle polar coordinates\nstruct Polar {\n    angle: f64,\n    radius: f64,\n}\nimpl Polar {\n    /// create new polar cordinate with the given angle (in degrees) and radiurd from the origin\n    fn new(angle:f64, radius:f64) -> Polar {\n        //if radius is negative, correct it\n        if radius < 0.0 {\n            return Polar{ angle: angle + PI/2.0, radius: -radius };\n        }\n        Polar { angle, radius}\n    }\n    ///create new polar cordinate with the given angle (in degrees, converted to radians) and radius from the origin\n    fn new_from_degrees(angle:usize, radius:f64) -> Polar {\n        let angle_to_rads: f64 = f64::from( (angle % 360) as u16) * PI/180.0;\n        \n        Polar::new(angle_to_rads, radius)\n    }\n    ///calculates the distance between 2 coordinates using the law of cosines\n    fn distance_from(&self,other:&Polar) -> f64 {\n        (other.radius*other.radius + self.radius*self.radius - 2.0*other.radius*self.radius*((other.angle-self.angle).abs().cos())).sqrt().floor()\n    }\n}\n\n/// gets a Polar with bomb angle and detonation range from user\nfn get_bomb_from_user_input() -> Polar {\n    return loop {//input loop\n        //DATA\n        let bomb_angle:usize;\n        let bomb_altitude:f64;\n        //get angle\n        match get_number_from_input(\"AT WHAT ANGLE DO YOU WISH TO SEND YOUR PHOTON BOMB (0-360): \", 0_usize, 360_usize) {\n            Ok(angle) => bomb_angle = angle,\n            Err(err) => {\n                println!(\"{}\",err);\n                continue;\n            },\n        }\n        //get radius\n        match get_number_from_input(\"HOW FAR OUT DO YOU WISH TO DETONATE IT (100.0-300.0): \", 100.0, 300.0) {\n            Ok(radius) => bomb_altitude = radius,\n            Err(err) => {\n                println!(\"{}\",err);\n                continue;\n            },\n        }\n        println!(\"\");\n        //create coordinates from input\n        break Polar::new_from_degrees( bomb_angle, bomb_altitude);\n    };\n}\n\n/// gets a string from user input\nfn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\", prompt);\n    //make sure it's printed before getting input\n    io::stdout().flush().unwrap();\n\n    //read user input from standard input, and store it to raw_input, then return it or an error as needed\n    raw_input.clear(); //clear input\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),\n        Err(err) => return Err(format!(\"ERROR: CANNOT READ INPUT!: {}\", err).into()),\n    }\n}\n\n/// generic function to get a number from the passed string (user input)\n/// pass a min lower  than the max to have minimun and maximun bounds\n/// pass a min higher than the max to only have a minumum bound\n/// pass a min equal   to  the max to only have a maximun bound\n/// \n/// Errors:\n/// no number on user input\nfn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {\n    //DATA\n    let raw_input: String;\n    let processed_input: String;\n\n    \n    //input looop\n    raw_input = loop {\n        match get_string_from_user_input(prompt) {\n            Ok(input) => break input,\n            Err(e) => {\n                eprintln!(\"{}\",e);\n                continue;\n            },\n        }\n    };\n\n    //filter out num-numeric characters from user input\n    processed_input = raw_input.chars().filter(|c| c.is_numeric() || c.eq_ignore_ascii_case(&'.')).collect();\n\n    //from input, try to read a number\n    match processed_input.trim().parse() {\n        Ok(i) => {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    return Ok(i); //exit the loop with the value i, returning it\n                } else { //print error message specific to this case\n                    return Err(format!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max).into());\n                } \n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO LESS THAN {}, PLEASE!\", min).into());\n                }\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO MORE THAN {}, PLEASE!\", max).into());\n                }\n            }\n        },\n        Err(_e) => return Err(format!(\"Error: couldn't find a valid number in {}\",raw_input).into()),\n    }\n}"
  },
  {
    "path": "68_Orbit/rust/src/main.rs",
    "content": "/*\n    The responsibilities that remain in the main function after separating concerns\n    should be limited to the following:\n - Setting up any configuration\n - Calling a run function in lib.rs\n - Handling the error if run returns an error\n*/\n\nuse std::process;       //allows for some better error handling\n\nmod lib;\nuse lib::Config;\n\n/// main function\nfn main() {\n    //greet user\n    welcome();\n\n    // set up other configuration\n    let mut config = Config::new().unwrap_or_else(|err| {\n        eprintln!(\"Problem configuring program: {}\", err);\n        process::exit(1);\n    });\n\n    // run the program\n    if let Err(e) = lib::run(&mut config) {\n        eprintln!(\"Application Error: {}\", e); //use the eprintln! macro to output to standard error\n        process::exit(1); //exit the program with an error code\n    }\n\n    //end of program\n    println!(\"THANKS FOR PLAYING!\");\n}\n\n/// prints the welcome/start message\nfn welcome() {\n    println!(\"\n                                Orbit\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n    SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\n\n    THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\n    DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\n    10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\n    CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\n\n    UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\n    YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\n    INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\n    PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\n    HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\n    YOUR PLANET'S GRAVITY.\n\n    YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\n\n    AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\n    ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\n    100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\n    DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\n\n    AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\n    WILL DESTROY IT.\n\n    BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\n\n\n                              90\n                        0000000000000\n                     0000000000000000000\n                   000000           000000\n                 00000                 00000\n                00000    XXXXXXXXXXX    00000\n               00000    XXXXXXXXXXXXX    00000\n              0000     XXXXXXXXXXXXXXX     0000\n             0000     XXXXXXXXXXXXXXXXX     0000\n            0000     XXXXXXXXXXXXXXXXXXX     0000\n    180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\n            0000     XXXXXXXXXXXXXXXXXXX     0000\n             0000     XXXXXXXXXXXXXXXXX     0000\n              0000     XXXXXXXXXXXXXXX     0000\n               00000    XXXXXXXXXXXXX    00000\n                00000    XXXXXXXXXXX    00000\n                 00000                 00000\n                   000000           000000\n                     0000000000000000000\n                        0000000000000\n                             270\n\n    X - YOUR PLANET\n    O - THE ORBIT OF THE ROMULAN SHIP\n\n    ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\n    COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\n    WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\n    AND ORBITAL RATE WILL REMAIN CONSTANT.\n\n    GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\n    \");\n}\n\n"
  },
  {
    "path": "68_Orbit/vbnet/Orbit.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Orbit\", \"Orbit.vbproj\", \"{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "68_Orbit/vbnet/Orbit.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Orbit</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "68_Orbit/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "69_Pizza/README.md",
    "content": "### Pizza\n\nIn this game, you take orders for pizzas from people living in Hyattsville. Armed with a map of the city, you must then tell your delivery boy the address where the pizza is to be delivered. If the pizza is delivered to the correct address, the customer phones you and thanks you; if not, you must give the driver the correct address until the pizza gets delivered.\n\nSome interesting modifications suggest themselves for this program such as pizzas getting cold after two incorrect delivery attempts or taking three or more orders at a time and figuring out the shortest delivery route. Send us your modifications!\n\nThis program seems to have surfaced originally at the University of Georgia in Athens, Georgia. The author is unknown.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=126)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=141)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The program does no validation of its input, and crashes if you enter coordinates outside the valid range.  (Ports may choose to improve on this, for example by repeating the prompt until valid coordinates are given.)\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "69_Pizza/csharp/CustomerMap.cs",
    "content": "﻿using System.Text;\n\nnamespace Pizza\n{\n    internal class CustomerMap\n    {\n        private readonly int _mapSize;\n        private readonly string[,] _customerMap;\n\n        public CustomerMap(int mapSize)\n        {\n            _mapSize = mapSize;\n            _customerMap = GenerateCustomerMap();\n        }\n\n        /// <summary>\n        /// Gets customer on position X, Y.\n        /// </summary>\n        /// <param name=\"x\">Represents X position.</param>\n        /// <param name=\"y\">Represents Y position.</param>\n        /// <returns>If positions is valid then returns customer name otherwise returns empty string.</returns>\n        public string GetCustomerOnPosition(int x, int y)\n        {\n            if(IsPositionOutOfRange(x, y))\n            {\n                return string.Empty;\n            }\n\n            return _customerMap[y, x];\n        }\n\n        /// <summary>\n        /// Overridden ToString for getting text representation of customers map.\n        /// </summary>\n        /// <returns>Text representation of customers map.</returns>\n        public override string ToString()\n        {\n            int verticalSpace = 4;\n            int horizontalSpace = 5;\n\n            var mapToDisplay = new StringBuilder();\n\n            AppendXLine(mapToDisplay, horizontalSpace);\n\n            for (int i = _customerMap.GetLength(0) - 1; i >= 0; i--)\n            {\n                mapToDisplay.AppendLine(\"-\", verticalSpace);\n                mapToDisplay.Append($\"{i + 1}\");\n                mapToDisplay.Append(' ', horizontalSpace);\n\n                for (var j = 0; j < _customerMap.GetLength(1); j++)\n                {\n                    mapToDisplay.Append($\"{_customerMap[i, j]}\");\n                    mapToDisplay.Append(' ', horizontalSpace);\n                }\n\n                mapToDisplay.Append($\"{i + 1}\");\n                mapToDisplay.Append(' ', horizontalSpace);\n                mapToDisplay.Append(Environment.NewLine);\n            }\n\n            mapToDisplay.AppendLine(\"-\", verticalSpace);\n\n            AppendXLine(mapToDisplay, horizontalSpace);\n\n            return mapToDisplay.ToString();\n        }\n\n        /// <summary>\n        /// Checks if position is out of range or not.\n        /// </summary>\n        /// <param name=\"x\">Represents X position.</param>\n        /// <param name=\"y\">Represents Y position.</param>\n        /// <returns>True if position is out of range otherwise false.</returns>\n        private bool IsPositionOutOfRange(int x, int y)\n        {\n            return\n                x < 0 || x > _mapSize - 1 ||\n                y < 0 || y > _mapSize - 1;\n        }\n\n        /// <summary>\n        /// Generates array which represents customers map.\n        /// </summary>\n        /// <returns>Returns customers map.</returns>\n        private string[,] GenerateCustomerMap()\n        {\n            string[,] customerMap = new string[_mapSize, _mapSize];\n            string[] customerNames = GetCustomerNames(_mapSize * _mapSize);\n            int currentCustomerNameIndex = 0;\n\n            for (int i = 0; i < customerMap.GetLength(0); i++)\n            {\n                for (int j = 0; j < customerMap.GetLength(1); j++)\n                {\n                    customerMap[i, j] = customerNames[currentCustomerNameIndex++].ToString();\n                }\n            }\n\n            return customerMap;\n        }\n\n        /// <summary>\n        /// Generates customer names. Names are represented by alphanumerics from 'A'. Name of last customer depends on passed parameter.\n        /// </summary>\n        /// <param name=\"numberOfCustomers\">How many customers need to be generated.</param>\n        /// <returns>List of customer names.</returns>\n        private static string[] GetCustomerNames(int numberOfCustomers)\n        {\n            // returns [\"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\",\"P\"];\n            return Enumerable.Range(65, numberOfCustomers).Select(c => ((Char)c).ToString()).ToArray();\n        }\n\n        /// <summary>\n        /// Appends line with X coordinates.\n        /// </summary>\n        /// <param name=\"mapToDisplay\">Current map where a new line will be appended.</param>\n        /// <param name=\"horizontalSpace\">Number of horizontal delimiters which will be added between each coordination.</param>\n        private void AppendXLine(StringBuilder mapToDisplay, int horizontalSpace)\n        {\n            mapToDisplay.Append(' ');\n            mapToDisplay.Append('-', horizontalSpace);\n            for (var i = 0; i < _customerMap.GetLength(0); i++)\n            {\n                mapToDisplay.Append($\"{i + 1}\");\n                mapToDisplay.Append('-', horizontalSpace);\n            }\n            mapToDisplay.Append(Environment.NewLine);\n        }\n    }\n}\n"
  },
  {
    "path": "69_Pizza/csharp/Pizza.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "69_Pizza/csharp/Pizza.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31912.275\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Pizza\", \"Pizza.csproj\", \"{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {8F7E9FAD-38C5-47A2-B5CA-2B6E5947B982}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "69_Pizza/csharp/PizzaGame.cs",
    "content": "﻿namespace Pizza\n{\n    internal class PizzaGame\n    {\n        private const int CustomerMapSize = 4;\n        private readonly CustomerMap _customerMap = new CustomerMap(CustomerMapSize);\n\n        /// <summary>\n        /// Starts game. Main coordinator for pizza game.\n        /// It is responsible for showing information, getting data from user and starting to delivery pizza.\n        /// </summary>\n        public void Play()\n        {\n            ShowHeader();\n\n            string playerName = GetPlayerName();\n\n            ShowIntroduction(playerName);\n            ShowMap();\n\n            if (AskForMoreDirections())\n            {\n                ShowMoreDirections(playerName);\n\n                var playerUnderstands = AskIfPlayerUnderstand();\n                if (!playerUnderstands)\n                {\n                    return;\n                }\n            }\n\n            StartDelivery(playerName);\n            EndDelivery(playerName);\n        }\n\n        /// <summary>\n        /// Starts with pizza delivering to customers.\n        /// Every 5 deliveries it is asking user whether want to continue in delivering.\n        /// </summary>\n        /// <param name=\"playerName\">Player name which was filled by user.</param>\n        private void StartDelivery(string playerName)\n        {\n            var numberOfDeliveredPizzas = 0;\n            while (true)\n            {\n                numberOfDeliveredPizzas++;\n                string deliverPizzaToCustomer = GetRandomCustomer();\n\n                WriteEmptyLine();\n                Console.WriteLine($\"HELLO {playerName}'S PIZZA.  THIS IS {deliverPizzaToCustomer}.\");\n                Console.WriteLine(\"\\tPLEASE SEND A PIZZA.\");\n\n                DeliverPizzaByPlayer(playerName, deliverPizzaToCustomer);\n\n                if (numberOfDeliveredPizzas % 5 == 0)\n                {\n                    bool playerWantToDeliveryMorePizzas = AskQuestionWithYesNoResponse(\"DO YOU WANT TO DELIVER MORE PIZZAS?\");\n                    if (!playerWantToDeliveryMorePizzas)\n                    {\n                        WriteEmptyLine();\n                        break;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets random customer for which pizza should be delivered.\n        /// </summary>\n        /// <returns>Customer name.</returns>\n        private string GetRandomCustomer()\n        {\n            int randomPositionOnX = Random.Shared.Next(0, CustomerMapSize);\n            int randomPositionOnY = Random.Shared.Next(0, CustomerMapSize);\n\n            return _customerMap.GetCustomerOnPosition(randomPositionOnX, randomPositionOnY);\n        }\n\n        /// <summary>\n        /// Delivers pizza to customer by player. It verifies whether player was delivering pizza to correct customer.\n        /// </summary>\n        /// <param name=\"playerName\">Player name which was filled by user.</param>\n        /// <param name=\"deliverPizzaToCustomer\">Customer name which order pizza.</param>\n        private void DeliverPizzaByPlayer(string playerName, string deliverPizzaToCustomer)\n        {\n            while (true)\n            {\n                string userInput = GetPlayerInput($\"\\tDRIVER TO {playerName}:  WHERE DOES {deliverPizzaToCustomer} LIVE?\");\n                var deliveredToCustomer = GetCustomerFromPlayerInput(userInput);\n                if (string.IsNullOrEmpty(deliveredToCustomer))\n                {\n                    deliveredToCustomer = \"UNKNOWN CUSTOMER\";\n                }\n\n                if (deliveredToCustomer.Equals(deliverPizzaToCustomer))\n                {\n                    Console.WriteLine($\"HELLO {playerName}.  THIS IS {deliverPizzaToCustomer}, THANKS FOR THE PIZZA.\");\n                    break;\n                }\n\n                Console.WriteLine($\"THIS IS {deliveredToCustomer}.  I DID NOT ORDER A PIZZA.\");\n                Console.WriteLine($\"I LIVE AT {userInput}\");\n            }\n        }\n\n        /// <summary>\n        /// Gets customer name by user input with customer coordinations.\n        /// </summary>\n        /// <param name=\"userInput\">Input from users - it should represent customer coordination separated by ','.</param>\n        /// <returns>If coordinations are correct and customer exists then returns true otherwise false.</returns>\n        private string GetCustomerFromPlayerInput(string userInput)\n        {\n            var pizzaIsDeliveredToPosition = userInput?\n                .Split(',')\n                .Select(i => int.TryParse(i, out var customerPosition) ? (customerPosition - 1) : -1)\n                .Where(i => i != -1)\n                .ToArray() ?? Array.Empty<int>();\n            if (pizzaIsDeliveredToPosition.Length != 2)\n            {\n                return string.Empty;\n            }\n\n            return _customerMap.GetCustomerOnPosition(pizzaIsDeliveredToPosition[0], pizzaIsDeliveredToPosition[1]);\n        }\n\n        /// <summary>\n        /// Shows game header in console.\n        /// </summary>\n        private void ShowHeader()\n        {\n            Console.WriteLine(\"PIZZA\".PadLeft(22));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            WriteEmptyLine(3);\n            Console.WriteLine(\"PIZZA DELIVERY GAME\");\n            WriteEmptyLine();\n        }\n\n        /// <summary>\n        /// Asks user for name which will be used in game.\n        /// </summary>\n        /// <returns>Player name.</returns>\n        private string GetPlayerName()\n        {\n            return GetPlayerInput(\"WHAT IS YOUR FIRST NAME:\");\n        }\n\n        /// <summary>\n        /// Shows game introduction in console\n        /// </summary>\n        /// <param name=\"playerName\">Player name which was filled by user.</param>\n        private void ShowIntroduction(string playerName)\n        {\n            Console.WriteLine($\"HI, {playerName}.  IN THIS GAME YOU ARE TO TAKE ORDERS\");\n            Console.WriteLine(\"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\");\n            Console.WriteLine(\"WHERE TO DELIVER THE ORDERED PIZZAS.\");\n            WriteEmptyLine(2);\n        }\n\n        /// <summary>\n        /// Shows customers map in console. In this method is used overridden method 'ToString' for getting text representation of customers map.\n        /// </summary>\n        private void ShowMap()\n        {\n            Console.WriteLine(\"MAP OF THE CITY OF HYATTSVILLE\");\n            WriteEmptyLine();\n\n            Console.WriteLine(_customerMap.ToString());\n\n            Console.WriteLine(\"THE OUTPUT IS A MAP OF THE HOMES WHERE\");\n            Console.WriteLine(\"YOU ARE TO SEND PIZZAS.\");\n            WriteEmptyLine();\n            Console.WriteLine(\"YOUR JOB IS TO GIVE A TRUCK DRIVER\");\n            Console.WriteLine(\"THE LOCATION OR COORDINATES OF THE\");\n            Console.WriteLine(\"HOME ORDERING THE PIZZA.\");\n            WriteEmptyLine();\n        }\n\n        /// <summary>\n        /// Asks user if needs more directions.\n        /// </summary>\n        /// <returns>True if user need more directions otherwise false.</returns>\n        private bool AskForMoreDirections()\n        {\n            var playerNeedsMoreDirections = AskQuestionWithYesNoResponse(\"DO YOU NEED MORE DIRECTIONS?\");\n            WriteEmptyLine();\n\n            return playerNeedsMoreDirections;\n        }\n\n        /// <summary>\n        /// Shows more directions.\n        /// </summary>\n        /// <param name=\"playerName\">Player name which was filled by user.</param>\n        private void ShowMoreDirections(string playerName)\n        {\n            Console.WriteLine(\"SOMEBODY WILL ASK FOR A PIZZA TO BE\");\n            Console.WriteLine(\"DELIVERED.  THEN A DELIVERY BOY WILL\");\n            Console.WriteLine(\"ASK YOU FOR THE LOCATION.\");\n            Console.WriteLine(\"\\tEXAMPLE:\");\n            Console.WriteLine(\"THIS IS J.  PLEASE SEND A PIZZA.\");\n            Console.WriteLine($\"DRIVER TO {playerName}.  WHERE DOES J LIVE?\");\n            Console.WriteLine(\"YOUR ANSWER WOULD BE 2,3\");\n        }\n\n        /// <summary>\n        /// Asks user if understands to instructions.\n        /// </summary>\n        /// <returns>True if user understand otherwise false.</returns>\n        private bool AskIfPlayerUnderstand()\n        {\n            var playerUnderstands = AskQuestionWithYesNoResponse(\"UNDERSTAND?\");\n            if (!playerUnderstands)\n            {\n                Console.WriteLine(\"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\");\n                return false;\n            }\n\n            WriteEmptyLine();\n            Console.WriteLine(\"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\");\n            WriteEmptyLine();\n            Console.WriteLine(\"GOOD LUCK!!\");\n            WriteEmptyLine();\n\n            return true;\n        }\n\n        /// <summary>\n        /// Shows message about ending delivery in console.\n        /// </summary>\n        /// <param name=\"playerName\">Player name which was filled by user.</param>\n        private void EndDelivery(string playerName)\n        {\n            Console.WriteLine($\"O.K. {playerName}, SEE YOU LATER!\");\n            WriteEmptyLine();\n        }\n\n        /// <summary>\n        /// Gets input from user.\n        /// </summary>\n        /// <param name=\"question\">Question which is displayed in console.</param>\n        /// <returns>User input.</returns>\n        private string GetPlayerInput(string question)\n        {\n            Console.Write($\"{question} \");\n\n            while (true)\n            {\n                var userInput = Console.ReadLine();\n                if (!string.IsNullOrWhiteSpace(userInput))\n                {\n                    return userInput;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Asks user with required resposne 'YES', 'Y, 'NO', 'N'.\n        /// </summary>\n        /// <param name=\"question\">Question which is displayed in console.</param>\n        /// <returns>True if user write 'YES', 'Y'. False if user write 'NO', 'N'.</returns>\n        private static bool AskQuestionWithYesNoResponse(string question)\n        {\n            var possitiveResponse = new string[] { \"Y\", \"YES\" };\n            var negativeResponse = new string[] { \"N\", \"NO\" };\n            var validUserInputs = possitiveResponse.Concat(negativeResponse);\n\n            Console.Write($\"{question} \");\n\n            string? userInput;\n            while (true)\n            {\n                userInput = Console.ReadLine();\n                if (!string.IsNullOrWhiteSpace(userInput) && validUserInputs.Contains(userInput.ToUpper()))\n                {\n                    break;\n                }\n\n                Console.Write($\"'YES' OR 'NO' PLEASE, NOW THEN, {question} \");\n            }\n\n            return possitiveResponse.Contains(userInput.ToUpper());\n        }\n\n        /// <summary>\n        /// Writes empty line in console.\n        /// </summary>\n        /// <param name=\"numberOfEmptyLines\">Number of empty lines which will be written in console. Parameter is optional and default value is 1.</param>\n        private void WriteEmptyLine(int numberOfEmptyLines = 1)\n        {\n            for (int i = 0; i < numberOfEmptyLines; i++)\n            {\n                Console.WriteLine();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "69_Pizza/csharp/Program.cs",
    "content": "﻿namespace Pizza\n{\n    internal class Program\n    {\n        static void Main(string[] args)\n        {\n            var pizzaGame = new PizzaGame();\n            pizzaGame.Play();\n        }\n    }\n}\n"
  },
  {
    "path": "69_Pizza/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "69_Pizza/csharp/StringBuilderExtensions.cs",
    "content": "﻿using System.Text;\n\nnamespace Pizza\n{\n    internal static class StringBuilderExtensions\n    {\n        /// <summary>\n        /// Extensions for adding new lines of specific value.\n        /// </summary>\n        /// <param name=\"stringBuilder\">Extended class.</param>\n        /// <param name=\"value\">Value which will be repeated.</param>\n        /// <param name=\"numberOfLines\">Number of lines that will be appended.</param>\n        public static void AppendLine(this StringBuilder stringBuilder, string value, int numberOfLines)\n        {\n            for (int i = 0; i < numberOfLines; i++)\n            {\n                stringBuilder.AppendLine(value);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "69_Pizza/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "69_Pizza/java/src/Pizza.java",
    "content": "import java.util.Scanner;\n\n/**\n * Game of Pizza\n * <p>\n * Based on the Basic game of Hurkle here\n * https://github.com/coding-horror/basic-computer-games/blob/main/69%20Pizza/pizza.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Pizza {\n\n    private final int MAX_DELIVERIES = 5;\n\n    private enum GAME_STATE {\n        STARTING,\n        ENTER_NAME,\n        DRAW_MAP,\n        MORE_DIRECTIONS,\n        START_DELIVER,\n        DELIVER_PIZZA,\n        TOO_DIFFICULT,\n        END_GAME,\n        GAME_OVER\n    }\n\n    // houses that can order pizza\n    private final char[] houses = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',\n            'J', 'K', 'L', 'M', 'N', 'O', 'P'};\n\n    // size of grid\n    private final int[] gridPos = new int[]{1, 2, 3, 4};\n\n    private GAME_STATE gameState;\n\n    private String playerName;\n\n    // How many pizzas have been successfully delivered\n    private int pizzaDeliveryCount;\n\n    // current house that ordered a pizza\n    private int currentHouseDelivery;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    public Pizza() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    init();\n                    intro();\n                    gameState = GAME_STATE.ENTER_NAME;\n                    break;\n\n                // Enter the players name\n                case ENTER_NAME:\n                    playerName = displayTextAndGetInput(\"WHAT IS YOUR FIRST NAME? \");\n                    System.out.println(\"HI \" + playerName + \". IN GAME YOU ARE TO TAKE ORDERS\");\n                    System.out.println(\"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\");\n                    System.out.println(\"WHERE TO DELIVER THE ORDERED PIZZAS.\");\n                    System.out.println();\n                    gameState = GAME_STATE.DRAW_MAP;\n                    break;\n\n                // Draw the map\n                case DRAW_MAP:\n                    drawMap();\n                    gameState = GAME_STATE.MORE_DIRECTIONS;\n                    break;\n\n                // need more directions (how to play) ?\n                case MORE_DIRECTIONS:\n                    extendedIntro();\n                    String moreInfo = displayTextAndGetInput(\"DO YOU NEED MORE DIRECTIONS? \");\n                    if (!yesOrNoEntered(moreInfo)) {\n                        System.out.println(\"'YES' OR 'NO' PLEASE, NOW THEN,\");\n                    } else {\n                        // More instructions selected\n                        if (yesEntered(moreInfo)) {\n                            displayMoreDirections();\n                            // Player understand now?\n                            if (yesEntered(displayTextAndGetInput(\"UNDERSTAND? \"))) {\n                                System.out.println(\"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\");\n                                System.out.println();\n                                System.out.println(\"GOOD LUCK!!\");\n                                System.out.println();\n                                gameState = GAME_STATE.START_DELIVER;\n                            } else {\n                                // Not understood, essentially game over\n                                gameState = GAME_STATE.TOO_DIFFICULT;\n                            }\n                        } else {\n                            // no more directions were needed, start delivering pizza\n                            gameState = GAME_STATE.START_DELIVER;\n                        }\n                    }\n\n                    break;\n\n                // Too difficult to understand, game over!\n                case TOO_DIFFICULT:\n                    System.out.println(\"JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\");\n                    gameState = GAME_STATE.GAME_OVER;\n                    break;\n\n                // Delivering pizza\n                case START_DELIVER:\n                    // select a random house and \"order\" a pizza for them.\n                    currentHouseDelivery = (int) (Math.random()\n                            * (houses.length) + 1) - 1; // Deduct 1 for 0-based array\n\n                    System.out.println(\"HELLO \" + playerName + \"'S PIZZA.  THIS IS \"\n                            + houses[currentHouseDelivery] + \".\");\n                    System.out.println(\"  PLEASE SEND A PIZZA.\");\n                    gameState = GAME_STATE.DELIVER_PIZZA;\n                    break;\n\n                // Try and deliver the pizza\n                case DELIVER_PIZZA:\n\n                    String question = \"  DRIVER TO \" + playerName + \":  WHERE DOES \"\n                            + houses[currentHouseDelivery] + \" LIVE ? \";\n                    String answer = displayTextAndGetInput(question);\n\n                    // Convert x,y entered by player to grid position of a house\n                    int x = getDelimitedValue(answer, 0);\n                    int y = getDelimitedValue(answer, 1);\n                    int calculatedPos = (x + (y - 1) * 4) - 1;\n\n                    // Did the player select the right house to deliver?\n                    if (calculatedPos == currentHouseDelivery) {\n                        System.out.println(\"HELLO \" + playerName + \".  THIS IS \" + houses[currentHouseDelivery]\n                                + \", THANKS FOR THE PIZZA.\");\n                        pizzaDeliveryCount++;\n\n                        // Delivered enough pizza?\n\n                        if (pizzaDeliveryCount > MAX_DELIVERIES) {\n                            gameState = GAME_STATE.END_GAME;\n                        } else {\n                            gameState = GAME_STATE.START_DELIVER;\n                        }\n                    } else {\n                        System.out.println(\"THIS IS \" + houses[calculatedPos] + \".  I DID NOT ORDER A PIZZA.\");\n                        System.out.println(\"I LIVE AT \" + x + \",\" + y);\n                        // Don't change gameState so state is executed again\n                    }\n\n                    break;\n\n                // Sign off message for cases where the Chief is not upset\n                case END_GAME:\n                    if (yesEntered(displayTextAndGetInput(\"DO YOU WANT TO DELIVER MORE PIZZAS? \"))) {\n                        init();\n                        gameState = GAME_STATE.START_DELIVER;\n                    } else {\n                        System.out.println();\n                        System.out.println(\"O.K. \" + playerName + \", SEE YOU LATER!\");\n                        System.out.println();\n                        gameState = GAME_STATE.GAME_OVER;\n                    }\n                    break;\n\n                // GAME_OVER State does not specifically have a case\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void drawMap() {\n\n        System.out.println(\"MAP OF THE CITY OF HYATTSVILLE\");\n        System.out.println();\n        System.out.println(\" -----1-----2-----3-----4-----\");\n        int k = 3;\n        for (int i = 1; i < 5; i++) {\n            System.out.println(\"-\");\n            System.out.println(\"-\");\n            System.out.println(\"-\");\n            System.out.println(\"-\");\n\n            System.out.print(gridPos[k]);\n            int pos = 16 - 4 * i;\n            System.out.print(\"     \" + houses[pos]);\n            System.out.print(\"     \" + houses[pos + 1]);\n            System.out.print(\"     \" + houses[pos + 2]);\n            System.out.print(\"     \" + houses[pos + 3]);\n            System.out.println(\"     \" + gridPos[k]);\n            k = k - 1;\n        }\n        System.out.println(\"-\");\n        System.out.println(\"-\");\n        System.out.println(\"-\");\n        System.out.println(\"-\");\n        System.out.println(\" -----1-----2-----3-----4-----\");\n    }\n\n    /**\n     * Basic information about the game\n     */\n    private void intro() {\n        System.out.println(\"PIZZA\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println();\n        System.out.println(\"PIZZA DELIVERY GAME\");\n        System.out.println();\n    }\n\n    private void extendedIntro() {\n        System.out.println(\"THE OUTPUT IS A MAP OF THE HOMES WHERE\");\n        System.out.println(\"YOU ARE TO SEND PIZZAS.\");\n        System.out.println();\n        System.out.println(\"YOUR JOB IS TO GIVE A TRUCK DRIVER\");\n        System.out.println(\"THE LOCATION OR COORDINATES OF THE\");\n        System.out.println(\"HOME ORDERING THE PIZZA.\");\n        System.out.println();\n    }\n\n    private void displayMoreDirections() {\n        System.out.println();\n        System.out.println(\"SOMEBODY WILL ASK FOR A PIZZA TO BE\");\n        System.out.println(\"DELIVERED.  THEN A DELIVERY BOY WILL\");\n        System.out.println(\"ASK YOU FOR THE LOCATION.\");\n        System.out.println(\"     EXAMPLE:\");\n        System.out.println(\"THIS IS J.  PLEASE SEND A PIZZA.\");\n        System.out.println(\"DRIVER TO \" + playerName + \".  WHERE DOES J LIVE?\");\n        System.out.println(\"YOUR ANSWER WOULD BE 2,3\");\n        System.out.println();\n    }\n\n    private void init() {\n        pizzaDeliveryCount = 1;\n    }\n\n    /**\n     * Accepts a string delimited by comma's and returns the nth delimited\n     * value (starting at count 0).\n     *\n     * @param text - text with values separated by comma's\n     * @param pos  - which position to return a value for\n     * @return the int representation of the value\n     */\n    private int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        return Integer.parseInt(tokens[pos]);\n    }\n\n    /**\n     * Returns true if a given string is equal to at least one of the values specified in the call\n     * to the stringIsAnyValue method\n     *\n     * @param text string to search\n     * @return true if string is equal to one of the varargs\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * returns true if Y, YES, N, or NO was the compared value in text\n     * case-insensitive\n     *\n     * @param text search string\n     * @return true if one of the varargs was found in text\n     */\n    private boolean yesOrNoEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\", \"N\", \"NO\");\n    }\n\n    /**\n     * Returns true if a given string contains at least one of the varargs (2nd parameter).\n     * Note: Case insensitive comparison.\n     *\n     * @param text   string to search\n     * @param values varargs of type string containing values to compare\n     * @return true if one of the varargs arguments was found in text\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        // Cycle through the variable number of values and test each\n        for (String val : values) {\n            if (text.equalsIgnoreCase(val)) {\n                return true;\n            }\n        }\n\n        // no matches\n        return false;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n}\n"
  },
  {
    "path": "69_Pizza/java/src/PizzaGame.java",
    "content": "public class PizzaGame {\n\n    public static void main(String[] args) {\n\n        Pizza pizza = new Pizza();\n        pizza.play();\n    }\n}\n"
  },
  {
    "path": "69_Pizza/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "69_Pizza/javascript/pizza.html",
    "content": "<html>\n<head>\n<title>PIZZA</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"pizza.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "69_Pizza/javascript/pizza.js",
    "content": "// PIZZA\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar sa = [, \"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\",\"P\"];\nvar ma = [, \"1\",\"2\",\"3\",\"4\"];\nvar a = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"PIZZA\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"PIZZA DELIVERY GAME\\n\");\n    print(\"\\n\");\n    print(\"WHAT IS YOUR FIRST NAME\");\n    ns = await input();\n    print(\"\\n\");\n    print(\"HI, \" + ns + \". IN THIS GAME YOU ARE TO TAKE ORDERS\\n\");\n    print(\"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\\n\");\n    print(\"WHERE TO DELIVER THE ORDERED PIZZAS.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"MAP OF THE CITY OF HYATTSVILLE\\n\");\n    print(\"\\n\");\n    print(\" -----1-----2-----3-----4-----\\n\");\n    k = 4;\n    for (i = 1; i <= 4; i++) {\n        print(\"-\\n\");\n        print(\"-\\n\");\n        print(\"-\\n\");\n        print(\"-\\n\");\n        print(ma[k]);\n        s1 = 16 - 4 * i + 1;\n        print(\"     \" + sa[s1] + \"     \" + sa[s1 + 1] + \"     \" + sa[s1 + 2] + \"     \");\n        print(sa[s1 + 3] + \"     \" + ma[k] + \"\\n\");\n        k--;\n    }\n    print(\"-\\n\");\n    print(\"-\\n\");\n    print(\"-\\n\");\n    print(\"-\\n\");\n    print(\" -----1-----2-----3-----4-----\\n\");\n    print(\"\\n\");\n    print(\"THE OUTPUT IS A MAP OF THE HOMES WHERE\\n\");\n    print(\"YOU ARE TO SEND PIZZAS.\\n\");\n    print(\"\\n\");\n    print(\"YOUR JOB IS TO GIVE A TRUCK DRIVER\\n\");\n    print(\"THE LOCATION OR COORDINATES OF THE\\n\");\n    print(\"HOME ORDERING THE PIZZA.\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"DO YOU NEED MORE DIRECTIONS\");\n        str = await input();\n        if (str == \"YES\" || str == \"NO\")\n            break;\n        print(\"'YES' OR 'NO' PLEASE, NOW THEN, \");\n    }\n    if (str == \"YES\") {\n        print(\"\\n\");\n        print(\"SOMEBODY WILL ASK FOR A PIZZA TO BE\\n\");\n        print(\"DELIVERED.  THEN A DELIVERY BOY WILL\\n\");\n        print(\"ASK YOU FOR THE LOCATION.\\n\");\n        print(\"     EXAMPLE:\\n\");\n        print(\"THIS IS J.  PLEASE SEND A PIZZA.\\n\");\n        print(\"DRIVER TO \" + ns + \".  WHERE DOES J LIVE?\\n\");\n        print(\"YOUR ANSWER WOULD BE 2,3\\n\");\n        print(\"\\n\");\n        print(\"UNDERSTAND\");\n        str = await input();\n        if (str != \"YES\") {\n            print(\"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\");\n            return;\n        }\n        print(\"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\\n\");\n        print(\"\\n\");\n        print(\"GOOD LUCK!!\\n\");\n        print(\"\\n\");\n    }\n    while (1) {\n        for (i = 1; i <= 5; i++) {\n            s = Math.floor(Math.random() * 16 + 1);\n            print(\"\\n\");\n            print(\"HELLO \" + ns + \"'S PIZZA.  THIS IS \" + sa[s] + \".\\n\");\n            print(\"  PLEASE SEND A PIZZA.\\n\");\n            while (1) {\n                print(\"  DRIVER TO \" + ns + \":  WHERE DOES \" + sa[s] + \" LIVE\");\n                str = await input();\n                a[1] = parseInt(str);\n                a[2] = parseInt(str.substr(str.indexOf(\",\") + 1));\n                t = a[1] + (a[2] - 1) * 4;\n                if (t != s) {\n                    print(\"THIS IS \" + sa[t] + \". I DID NOT ORDER A PIZZA.\\n\");\n                    print(\"I LIVE AT \" + a[1] + \",\" + a[2] + \"\\n\");\n                } else {\n                    break;\n                }\n            }\n            print(\"HELLO \" + ns + \".  THIS IS \" + sa[s] + \", THANKS FOR THE PIZZA.\\n\");\n        }\n        print(\"\\n\");\n        print(\"DO YOU WANT TO DELIVER MORE PIZZAS\");\n        str = await input();\n        if (str != \"YES\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"O.K. \" + ns + \", SEE YOU LATER!\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "69_Pizza/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "69_Pizza/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "69_Pizza/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "69_Pizza/perl/pizza.pl",
    "content": "#!/usr/bin/perl\n#use strict;\n# Automatic converted by bas2perl.pl\n\nprint ' 'x33 . \"PIZZA\". \"\\n\";\nprint ' 'x15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\". \"\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nmy @S; my @M;\nprint \"PIZZA DELIVERY GAME\". \"\\n\"; print \"\\n\";\nprint \"WHAT IS YOUR FIRST NAME? \"; chomp($N = uc(<STDIN>)); print \"\\n\";\nprint \"HI, \". $N. \".  IN THIS GAME YOU ARE TO TAKE ORDERS\". \"\\n\";\nprint \"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\". \"\\n\";\nprint \"WHERE TO DELIVER THE ORDERED PIZZAS.\". \"\\n\"; print \"\\n\"; print \"\\n\";\nfor ($I=1; $I<=16; $I++) {\n$S[$I]= <DATA>; chomp($S[$I]);;\n}\nfor ($I=1; $I<=4; $I++) {\n$M[$I]= <DATA>; chomp($M[$I]);;\n}\n# TO DATA SEGMENT;\n# TO DATA SEGMENT;\nprint \"MAP OF THE CITY OF HYATTSVILLE\". \"\\n\"; print \"\\n\";\nprint \" -----1-----2-----3-----4-----\". \"\\n\";\n$K=4;\nfor ($I=1; $I<=4; $I++) {\nprint \"-\". \"\\n\"; print \"-\". \"\\n\"; print \"-\". \"\\n\"; print \"-\". \"\\n\";\nprint $M[$K];\n$S1=16-4*$I+1;\nprint \"     \". $S[$S1]. \"     \". $S[$S1+1]. \"     \". $S[$S1+2]. \"     \";\nprint $S[$S1+3]. \"     \". $M[$K]. \"\\n\";\n$K=$K-1;\n}\nprint \"-\". \"\\n\"; print \"-\". \"\\n\"; print \"-\". \"\\n\"; print \"-\". \"\\n\";\nprint \" -----1-----2-----3-----4-----\". \"\\n\"; print \"\\n\";\nprint \"THE OUTPUT IS A MAP OF THE HOMES WHERE\". \"\\n\";\nprint \"YOU ARE TO SEND PIZZAS.\". \"\\n\"; print \"\\n\";\nprint \"YOUR JOB IS TO GIVE A TRUCK DRIVER\". \"\\n\";\nprint \"THE LOCATION OR COORDINATES OF THE\". \"\\n\";\nprint \"HOME ORDERING THE PIZZA.\". \"\\n\"; print \"\\n\";\n\nLine520:\nprint \"DO YOU NEED MORE DIRECTIONS? \"; chomp($A = uc(<STDIN>));\nif ($A eq \"YES\") { goto Line590; }\nif ($A eq \"NO\") { goto Line750; }\nprint \"'YES' OR 'NO' PLEASE, NOW THEN,\". \"\\n\"; goto Line520;\n\nLine590:\nprint \"\\n\"; print \"SOMEBODY WILL ASK FOR A PIZZA TO BE\". \"\\n\";\nprint \"DELIVERED.  THEN A DELIVERY BOY WILL\". \"\\n\";\nprint \"ASK YOU FOR THE LOCATION.\". \"\\n\"; print \"     EXAMPLE:\". \"\\n\";\nprint \"THIS IS J.  PLEASE SEND A PIZZA.\". \"\\n\";\nprint \"DRIVER TO \". $N. \".  WHERE DOES J LIVE?\". \"\\n\";\nprint \"YOUR ANSWER WOULD BE 2,3\". \"\\n\"; print \"\\n\";\nprint \"UNDERSTAND? \"; chomp($A = uc(<STDIN>));\nif ($A eq \"YES\") { goto Line690; }\nprint \"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\". \"\\n\";\ngoto Line999;\n\nLine690:\nprint \"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\". \"\\n\"; print \"\\n\";\nprint \"GOOD LUCK!!\". \"\\n\"; print \"\\n\";\n\nLine750:\nfor ($I=1; $I<=5; $I++) {\n$S=int(rand(1)*16+1); print \"\\n\";\nprint \"HELLO \". $N. \"'S PIZZA.  THIS IS \". $S[$S]. \".\";\nprint \"  PLEASE SEND A PIZZA.\". \"\\n\";\n\nLine780:\nprint \"  DRIVER TO \". $N. \":  WHERE DOES \". $S[$S]. \" LIVE\";\nprint \"? \"; chomp($Inp_ = uc(<STDIN>)); ($A[1],$A[2])= split(/,/, $Inp_);\n$T=$A[1]+($A[2]-1)*4;\nif ($T eq $S) { goto Line920; }\nprint \"THIS IS \". $S[$T]. \".  I DID NOT ORDER A PIZZA.\". \"\\n\";\nprint \"I LIVE AT \". $A[1]. \",\". $A[2]. \"\\n\";\ngoto Line780;\n\nLine920:\nprint \"HELLO \". $N. \".  THIS IS \". $S[$S]. \", THANKS FOR THE PIZZA.\". \"\\n\";\n}\nprint \"\\n\"; print \"DO YOU WANT TO DELIVER MORE PIZZAS? \"; chomp($A = uc(<STDIN>));\nif ($A eq \"YES\") { goto Line750; }\nprint \"\\n\"; print \"O.K. \". $N. \", SEE YOU LATER!\". \"\\n\"; print \"\\n\";\n\nLine999:\nexit;\n\n\n\n__DATA__\nA\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\n1\n2\n3\n4\n"
  },
  {
    "path": "69_Pizza/pizza.bas",
    "content": "5 PRINT TAB(33);\"PIZZA\"\n10 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n15 PRINT: PRINT: PRINT\n20 DIM S$(16),M$(4)\n30 PRINT \"PIZZA DELIVERY GAME\": PRINT\n50 INPUT \"WHAT IS YOUR FIRST NAME\";N$: PRINT\n80 PRINT \"HI, \";N$;\".  IN THIS GAME YOU ARE TO TAKE ORDERS\"\n90 PRINT \"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\"\n100 PRINT \"WHERE TO DELIVER THE ORDERED PIZZAS.\": PRINT: PRINT\n140 FOR I=1 TO 16\n150 READ S$(I)\n160 NEXT I\n170 FOR I=1 TO 4\n180 READ M$(I)\n190 NEXT I\n200 DATA \"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\"\n210 DATA \"P\",\"1\",\"2\",\"3\",\"4\"\n230 PRINT \"MAP OF THE CITY OF HYATTSVILLE\": PRINT\n250 PRINT \" -----1-----2-----3-----4-----\"\n260 K=4\n270 FOR I=1 TO 4\n280 PRINT \"-\": PRINT \"-\": PRINT\"-\": PRINT \"-\"\n320 PRINT M$(K);\n330 S1=16-4*I+1\n340 PRINT \"     \";S$(S1);\"     \";S$(S1+1);\"     \";S$(S1+2);\"     \";\n350 PRINT S$(S1+3);\"     \";M$(K)\n380 K=K-1\n390 NEXT I\n400 PRINT \"-\": PRINT \"-\": PRINT \"-\": PRINT \"-\"\n440 PRINT \" -----1-----2-----3-----4-----\": PRINT\n460 PRINT \"THE OUTPUT IS A MAP OF THE HOMES WHERE\"\n470 PRINT \"YOU ARE TO SEND PIZZAS.\": PRINT\n490 PRINT \"YOUR JOB IS TO GIVE A TRUCK DRIVER\"\n500 PRINT \"THE LOCATION OR COORDINATES OF THE\"\n510 PRINT \"HOME ORDERING THE PIZZA.\": PRINT\n520 INPUT \"DO YOU NEED MORE DIRECTIONS\";A$\n530 IF A$=\"YES\" THEN 590\n540 IF A$=\"NO\" THEN 750\n550 PRINT \"'YES' OR 'NO' PLEASE, NOW THEN,\": GOTO 520\n590 PRINT: PRINT \"SOMEBODY WILL ASK FOR A PIZZA TO BE\"\n600 PRINT \"DELIVERED.  THEN A DELIVERY BOY WILL\"\n610 PRINT \"ASK YOU FOR THE LOCATION.\":PRINT \"     EXAMPLE:\"\n620 PRINT \"THIS IS J.  PLEASE SEND A PIZZA.\"\n640 PRINT \"DRIVER TO \";N$;\".  WHERE DOES J LIVE?\"\n650 PRINT \"YOUR ANSWER WOULD BE 2,3\": PRINT\n660 INPUT \"UNDERSTAND\";A$\n670 IF A$=\"YES\" THEN 690\n680 PRINT \"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\"\n685 GOTO 999\n690 PRINT \"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\": PRINT\n700 PRINT \"GOOD LUCK!!\": PRINT\n750 FOR I=1 TO 5\n760 S=INT(RND(1)*16+1): PRINT\n770 PRINT \"HELLO \";N$;\"'S PIZZA.  THIS IS \";S$(S);\".\";\n775 PRINT \"  PLEASE SEND A PIZZA.\"\n780 PRINT \"  DRIVER TO \";N$;\":  WHERE DOES \";S$(S);\" LIVE\";\n790 INPUT A(1),A(2)\n870 T=A(1)+(A(2)-1)*4\n880 IF T=S THEN 920\n890 PRINT \"THIS IS \";S$(T);\".  I DID NOT ORDER A PIZZA.\"\n900 PRINT \"I LIVE AT \";A(1);\",\";A(2)\n910 GOTO 780\n920 PRINT \"HELLO \"N$;\".  THIS IS \";S$(S);\", THANKS FOR THE PIZZA.\"\n930 NEXT I\n940 PRINT: INPUT \"DO YOU WANT TO DELIVER MORE PIZZAS\";A$\n960 IF A$=\"YES\" THEN 750\n970 PRINT: PRINT \"O.K. \";N$;\", SEE YOU LATER!\":PRINT\n999 END\n"
  },
  {
    "path": "69_Pizza/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "69_Pizza/python/pizza.py",
    "content": "\"\"\"\nPIZZA\n\nA pizza delivery simulation\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\n\nPAGE_WIDTH = 64\n\ncustomer_names = [chr(65 + x) for x in range(16)]\nstreet_names = [str(n) for n in range(1, 5)]\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n\ndef print_ticks() -> None:\n    for _ in range(4):\n        print(\"-\")\n\n\ndef print_ruler() -> None:\n    print(\" -----1-----2-----3-----4-----\")\n\n\ndef print_street(i: int) -> None:\n    street_number = 3 - i\n\n    street_name = street_names[street_number]\n    line = street_name\n\n    space = \" \" * 5\n    for customer_index in range(4):\n        line += space\n        customer_name = customer_names[4 * street_number + customer_index]\n        line += customer_name\n    line += space\n    line += street_name\n    print(line)\n\n\ndef print_map() -> None:\n    print(\"MAP OF THE CITY OF HYATTSVILLE\")\n    print()\n    print_ruler()\n    for i in range(4):\n        print_ticks()\n        print_street(i)\n    print_ticks()\n    print_ruler()\n    print()\n\n\ndef print_instructions() -> str:\n    print(\"PIZZA DELIVERY GAME\")\n    print()\n    print(\"WHAT IS YOUR FIRST NAME?\")\n    player_name = input()\n    print()\n    print(f\"HI, {player_name}.  IN THIS GAME YOU ARE TO TAKE ORDERS\")\n    print(\"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\")\n    print(\"WHERE TO DELIVER THE ORDERED PIZZAS.\")\n    print()\n    print()\n\n    print_map()\n\n    print(\"THE OUTPUT IS A MAP OF THE HOMES WHERE\")\n    print(\"YOU ARE TO SEND PIZZAS.\")\n    print()\n    print(\"YOUR JOB IS TO GIVE A TRUCK DRIVER\")\n    print(\"THE LOCATION OR COORDINATES OF THE\")\n    print(\"HOME ORDERING THE PIZZA.\")\n    print()\n\n    return player_name\n\n\ndef yes_no_prompt(msg: str) -> bool:\n    while True:\n        print(msg)\n        response = input().upper()\n\n        if response == \"YES\":\n            return True\n        elif response == \"NO\":\n            return False\n        print(\"'YES' OR 'NO' PLEASE, NOW THEN,\")\n\n\ndef print_more_directions(player_name: str) -> None:\n    print()\n    print(\"SOMEBODY WILL ASK FOR A PIZZA TO BE\")\n    print(\"DELIVERED.  THEN A DELIVERY BOY WILL\")\n    print(\"ASK YOU FOR THE LOCATION.\")\n    print(\"     EXAMPLE:\")\n    print(\"THIS IS J.  PLEASE SEND A PIZZA.\")\n    print(f\"DRIVER TO {player_name}.  WHERE DOES J LIVE?\")\n    print(\"YOUR ANSWER WOULD BE 2,3\")\n    print()\n\n\ndef calculate_customer_index(x: int, y: int) -> int:\n    return 4 * (y - 1) + x - 1\n\n\ndef deliver_to(customer_index, customer_name, player_name) -> bool:\n    print(f\"  DRIVER TO {player_name}:  WHERE DOES {customer_name} LIVE?\")\n\n    coords = input()\n    xc, yc = (int(c) for c in coords.split(\",\"))\n    delivery_index = calculate_customer_index(xc, yc)\n    if delivery_index == customer_index:\n        print(f\"HELLO {player_name}.  THIS IS {customer_name}, THANKS FOR THE PIZZA.\")\n        return True\n    else:\n        delivery_name = customer_names[delivery_index]\n        print(f\"THIS IS {delivery_name}.  I DID NOT ORDER A PIZZA.\")\n        print(f\"I LIVE AT {xc},{yc}\")\n        return False\n\n\ndef play_game(num_turns, player_name) -> None:\n    for _turn in range(num_turns):\n        x = random.randint(1, 4)\n        y = random.randint(1, 4)\n        customer_index = calculate_customer_index(x, y)\n        customer_name = customer_names[customer_index]\n\n        print()\n        print(\n            f\"HELLO {player_name}'S PIZZA.  THIS IS {customer_name}.  PLEASE SEND A PIZZA.\"\n        )\n        while True:\n            success = deliver_to(customer_index, customer_name, player_name)\n            if success:\n                break\n\n\ndef main() -> None:\n    print_header(\"PIZZA\")\n\n    player_name = print_instructions()\n\n    if yes_no_prompt(\"DO YOU NEED MORE DIRECTIONS?\"):\n        print_more_directions(player_name)\n\n        understand = yes_no_prompt(\"UNDERSTAND?\")\n\n        if not understand:\n            print(\"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\")\n            return\n\n    print(\"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\")\n    print()\n    print(\"GOOD LUCK!!\")\n    print()\n\n    num_turns = 5\n    while True:\n        play_game(num_turns, player_name)\n\n        print()\n        more = yes_no_prompt(\"DO YOU WANT TO DELIVER MORE PIZZAS?\")\n        if not more:\n            print(f\"O.K. {player_name}, SEE YOU LATER!\")\n            print()\n            return\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "69_Pizza/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "69_Pizza/ruby/pizza.rb",
    "content": "class Pizza\n  STREET_NAMES   = ['1', '2', '3', '4']\n  CUSTOMER_NAMES = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P']\n  def start\n    player_name = print_instructions\n    more_directions = yes_no_prompt(\"DO YOU NEED MORE DIRECTIONS?\")\n\n    if more_directions\n      print_more_directions(player_name)\n\n      understand = yes_no_prompt(\"UNDERSTAND?\")\n\n      if not understand\n        print(\"\\nTHIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\")\n        return\n      end\n\n      puts \"\\n\\nGOOD.  YOU ARE NOW READY TO START TAKING ORDERS. \\n\"\n      puts \"GOOD LUCK!!\"\n    end\n\n    while true\n      num_turns = 5\n      play_game(num_turns, player_name)\n\n      more = yes_no_prompt(\"DO YOU WANT TO DELIVER MORE PIZZAS?\")\n      if not more\n        puts \"\\nO.K. #{player_name}, SEE YOU LATER!\"\n        return\n      end\n    end\n  end\n\n  private\n    def print_street index\n      street_number = 3 - index\n  \n      street_name = STREET_NAMES[street_number]\n      line = street_name\n  \n      space = \" \" * 5\n      for customer_index in (0...4)\n        line += space\n        customer_name = CUSTOMER_NAMES[4 * street_number + customer_index]\n        line += customer_name\n      end\n      line += space\n      line += street_name\n      puts \"#{line}\"\n    end\n        \n    def print_map\n      puts \"MAP OF THE CITY OF HYATTSVILLE\\n\\n\" \n      print(\" -----1-----2-----3-----4-----\")\n      for i in (0...4)\n        for _ in (0...4)\n            puts \"-\"\n        end\n        print_street(i)\n      end\n      print(\" -----1-----2-----3-----4-----\")\n    end\n\n    def print_instructions\n      puts \"PIZZA DELIVERY GAME \\n\\n\"\n      print \"WHAT IS YOUR FIRST NAME? \"\n      player_name = gets.chomp!\n      puts \"\\nHi, #{player_name}. IN THIS GAME YOU ARE TO TAKE ORDERS\"\n      puts \"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\"\n      puts \"WHERE TO DELIVER THE ORDERED PIZZAS. \\n\\n\"\n\n      print_map\n\n      puts \"\\n\\nTHE OUTPUT IS A MAP OF THE HOMES WHERE\"\n      puts \"YOU ARE TO SEND PIZZAS.\"\n      puts \"YOUR JOB IS TO GIVE A TRUCK DRIVER\"\n      puts \"THE LOCATION OR COORDINATES OF THE\"\n      puts \"HOME ORDERING THE PIZZA.\"\n\n      return player_name\n    end\n\n    def yes_no_prompt msg\n      puts\n      while true\n        print \"#{msg} \"\n          \n        response = gets.chomp\n\n        if response == response.upcase\n          if response == \"YES\"\n            return true\n          elsif response == \"NO\"\n            return false\n          end\n        else\n          print \"'YES' OR 'NO' PLEASE, NOW THEN, \"\n        end\n\n      end\n    end\n\n    def print_more_directions player_name\n      puts \"\\nSOMEBODY WILL ASK FOR A PIZZA TO BE\"\n      puts \"DELIVERED.  THEN A DELIVERY BOY WILL\"\n      puts \"ASK YOU FOR THE LOCATION.\"\n      puts \"\\nEXAMPLE:\"\n      puts \"THIS IS J.  PLEASE SEND A PIZZA.\"\n      puts \"DRIVER TO #{player_name}.  WHERE DOES J LIVE?\"\n      puts \"YOUR ANSWER WOULD BE 2,3\"\n    end\n    \n    def calculate_customer_index x,y\n      return 4 * (y - 1) + x - 1\n    end\n\n    def deliver_to customer_index, customer_name, player_name\n      print \"  DRIVER TO #{player_name}:  WHERE DOES #{customer_name} LIVE? \"\n  \n      coords = gets.chomp!\n      xc, yc = coords.split(/,/).map(&:to_i)\n\n      puts \"#{xc}, #{yc}\"\n      delivery_index = calculate_customer_index(xc, yc)\n      if delivery_index == customer_index\n        puts \"HELLO #{player_name}.  THIS IS #{customer_name}, THANKS FOR THE PIZZA.\"\n        return true\n      else  \n          delivery_name = CUSTOMER_NAMES[delivery_index]\n          puts \"THIS IS #{defined?(delivery_name.to_i) ? \"Undefined\" : delivery_name.to_i}.  I DID NOT ORDER A PIZZA.\"\n          puts \"I LIVE AT #{xc},#{yc}\"\n          return false\n      end\n    end\n\n    def play_game num_turns, player_name\n      for _turn in (1..num_turns)\n        x = rand(1..4)\n        y = rand(1..4)\n        customer_index = calculate_customer_index(x, y)\n        customer_name = CUSTOMER_NAMES[customer_index]\n\n        puts \"\\nHELLO #{player_name}'S PIZZA.  THIS IS #{customer_name}. \\n  PLEASE SEND A PIZZA.\"\n\n        while true\n          success = deliver_to(customer_index, customer_name, player_name)\n          if success\n            break\n          end\n        end\n      end\n    end\nend\n\nif __FILE__ == $0\n  pizza = Pizza.new\n  pizza.start()\nend\n  "
  },
  {
    "path": "69_Pizza/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nanyhow = \"1.0.75\"\nfastrand = \"2.0.1\"\n"
  },
  {
    "path": "69_Pizza/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/).\n"
  },
  {
    "path": "69_Pizza/rust/src/main.rs",
    "content": "use anyhow::Result;\nuse std::io;\n\nfn print_centered(text: &str) {\n    println!(\"{:^72}\", text);\n}\n\nfn read_line() -> Result<String> {\n    let mut input = String::new();\n    io::stdin().read_line(&mut input)?;\n    input.truncate(input.trim_end().len());\n    Ok(input)\n}\n\nfn read_number() -> Result<u32> {\n    let line = read_line()?;\n    let num = line.parse()?;\n    Ok(num)\n}\n\nfn print_banner() {\n    print_centered(\"PIZZA\");\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    println!();\n    println!();\n    println!();\n}\n\nfn print_instructions() -> Result<String> {\n    println!(\"PIZZA DELIVERY GAME\");\n    println!();\n    println!(\"WHAT IS YOUR FIRST NAME\");\n\n    let name = read_line()?;\n    println!(\"HI, {name}.  IN THIS GAME YOU ARE TO TAKE ORDERS\");\n    println!(\"FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\");\n    println!(\"WHERE TO DELIVER THE ORDERED PIZZAS.\");\n    println!();\n    println!();\n\n    print_map();\n\n    println!(\"THE OUTPUT IS A MAP OF THE HOMES WHERE\");\n    println!(\"YOU ARE TO SEND PIZZAS.\");\n    println!();\n    println!(\"YOUR JOB IS TO GIVE A TRUCK DRIVER\");\n    println!(\"THE LOCATION OR COORDINATES OF THE\");\n    println!(\"HOME ORDERING THE PIZZA.\");\n    println!();\n\n    Ok(name)\n}\n\nfn print_ruler() {\n    println!(\" -----1-----2-----3-----4-----\");\n}\n\nfn print_ticks() {\n    println!(\"-\");\n    println!(\"-\");\n    println!(\"-\");\n    println!(\"-\");\n}\n\nfn print_street(i: u32) {\n    let street_number = 3 - i;\n    let street_name = (street_number + 1).to_string();\n\n    let mut line = street_name.clone();\n    let space = \"     \";\n    for customer_idx in 0..4 {\n        line.push_str(space);\n        let customer = 4 * street_number + customer_idx;\n        line.push(char::from_u32(65 + customer).unwrap());\n    }\n    line.push_str(space);\n    line.push_str(&street_name);\n    println!(\"{line}\");\n}\n\nfn print_map() {\n    println!(\"MAP OF THE CITY OF HYATTSVILLE\");\n    println!();\n    print_ruler();\n    for i in 0..4 {\n        print_ticks();\n        print_street(i);\n    }\n    print_ticks();\n    print_ruler();\n    println!();\n}\n\nfn yes_no_prompt(text: &str) -> Result<Option<bool>> {\n    println!(\"{text}\");\n    let input = read_line()?;\n    match input.as_str() {\n        \"YES\" => Ok(Some(true)),\n        \"NO\" => Ok(Some(false)),\n        _ => Ok(None),\n    }\n}\n\nfn play_game(turns: u32, player_name: &str) -> Result<()> {\n    for _ in 0..turns {\n        let customer = fastrand::char('A'..='P');\n        println!(\"HELLO {player_name}'S PIZZA.  THIS IS {customer}.\");\n        println!(\"  PLEASE SEND A PIZZA.\");\n        loop {\n            println!(\"  DRIVER TO {player_name}:  WHERE DOES {customer} LIVE\");\n\n            let x = read_number()?;\n            let y = read_number()?;\n\n            let input = x - 1 + (y - 1) * 4;\n            match char::from_u32(65 + input) {\n                Some(c) if c == customer => {\n                    println!(\"HELLO {player_name}.  THIS IS {customer}, THANKS FOR THE PIZZA.\");\n                    break;\n                }\n                Some(c @ 'A'..='P') => {\n                    println!(\"THIS IS {c}.  I DID NOT ORDER A PIZZA.\");\n                    println!(\"I LIVE AT {x},{y}\");\n                }\n                // this is out of bounds in the original game\n                _ => (),\n            }\n        }\n    }\n\n    Ok(())\n}\n\nfn main() -> Result<()> {\n    print_banner();\n    let player_name = print_instructions()?;\n    let more_directions = loop {\n        if let Some(x) = yes_no_prompt(\"DO YOU NEED MORE DIRECTIONS\")? {\n            break x;\n        } else {\n            println!(\"'YES' OR 'NO' PLEASE, NOW THEN,\");\n        }\n    };\n\n    if more_directions {\n        println!();\n        println!(\"SOMEBODY WILL ASK FOR A PIZZA TO BE\");\n        println!(\"DELIVERED.  THEN A DELIVERY BOY WILL\");\n        println!(\"ASK YOU FOR THE LOCATION.\");\n        println!(\"     EXAMPLE:\");\n        println!(\"THIS IS J.  PLEASE SEND A PIZZA.\");\n        println!(\"DRIVER TO {player_name}.  WHERE DOES J LIVE?\");\n        println!(\"YOUR ANSWER WOULD BE 2,3\");\n        println!();\n\n        if let Some(true) = yes_no_prompt(\"UNDERSTAND\")? {\n            println!(\"GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\");\n            println!();\n            println!(\"GOOD LUCK!!\");\n            println!();\n        } else {\n            println!(\"THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY\");\n            return Ok(());\n        }\n    }\n\n    loop {\n        play_game(5, &player_name)?;\n        println!();\n\n        if let Some(false) | None = yes_no_prompt(\"DO YOU WANT TO DELIVER MORE PIZZAS\")? {\n            println!();\n            println!(\"O.K. {player_name}, SEE YOU LATER!\");\n            println!();\n            return Ok(());\n        }\n    }\n}\n"
  },
  {
    "path": "69_Pizza/vbnet/Pizza.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Pizza\", \"Pizza.vbproj\", \"{395C3162-11F0-459B-9027-45A8ED6E4E8E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "69_Pizza/vbnet/Pizza.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Pizza</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "69_Pizza/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "70_Poetry/README.md",
    "content": "### Poetry\n\nThis program produces random verse which might loosely be considered in the Japanese Haiku style. It uses 20 phrases in four groups of five phrases each and generally cycles through the groups in order. It inserts commas (random — 19% of the time), indentation (random — 22% of the time), and starts new paragraphs (18% probability but at least once every 20 phrases).\n\nThe phrases in POETRY are somewhat suggestive of Edgar Allen Poe. Try it with phrases from computer technology, from love and romance, from four-year-old children, or from some other project. Send us the output.\n\nHere are some phrases from nature to try:\n```\nCarpet of ferns     Mighty Oaks\nMorning dew         Grace and beauty\nTang of dawn        Silently singing\nSwaying pines       Nature speaking\n\nEntrances me        Untouched, unspoiled\nSoothing me         Shades of green\nRustling leaves     Tranquility\nRadiates calm       …so peaceful\n```\n\nThe original author of this program is unknown. It was modified and reworked by Jim Bailey, Peggy Ewing, and Dave Ahl at DEC.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=128)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=143)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- The program begins by switching on `I`, which has not been initialized.  We should probably initialize this to 0, though this means the output always begins with the phrase \"midnight dreary\".\n\n- Though the program contains an END statement (line 999), it is unreachable.  The program continues to generate output until it is forcibly interrupted.\n"
  },
  {
    "path": "70_Poetry/csharp/Context.cs",
    "content": "namespace Poetry;\n\ninternal class Context\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    private int _phraseNumber;\n    private int _groupNumber;\n    private bool _skipComma;\n    private int _lineCount;\n    private bool _useGroup2;\n    private bool _atStartOfLine = true;\n\n    public Context(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    public int PhraseNumber => Math.Max(_phraseNumber - 1, 0); \n\n    public int GroupNumber \n    { \n        get\n        {\n            var value = _useGroup2 ? 2 : _groupNumber;\n            _useGroup2 = false;\n            return Math.Max(value - 1, 0);\n        }\n    }\n\n    public int PhraseCount { get; set; }\n    public bool GroupNumberIsValid => _groupNumber < 5;\n\n    public void WritePhrase()\n    {\n        Phrase.GetPhrase(this).Write(_io, this);\n        _atStartOfLine = false;\n    }\n\n    public void MaybeWriteComma()\n    {\n        if (!_skipComma && _random.NextFloat() <= 0.19F && PhraseCount != 0)\n        {\n            _io.Write(\",\");\n            PhraseCount = 2;\n        }\n        _skipComma = false;\n    }\n\n    public void WriteSpaceOrNewLine()\n    {\n        if (_random.NextFloat() <= 0.65F)\n        {\n            _io.Write(\" \");\n            PhraseCount += 1;\n        }\n        else\n        {\n            EndLine();\n            PhraseCount = 0;\n        }\n    }\n\n    public void Update(IRandom random)\n    {\n        _phraseNumber = random.Next(1, 6);\n        _groupNumber += 1;\n        _lineCount += 1;\n    }\n\n    public void MaybeIndent()\n    {\n        if (PhraseCount == 0 && _groupNumber % 2 == 0)\n        {\n            _io.Write(\"     \");\n        }\n    }\n    \n    public void ResetGroup()\n    {\n        _groupNumber = 0;\n        EndLine();\n    }\n\n    public bool MaybeCompleteStanza()\n    {\n        if (_lineCount > 20)\n        {\n            _io.WriteLine();\n            PhraseCount = _lineCount = 0;\n            _useGroup2 = true;\n            return true;\n        }\n\n        return false;\n    }\n\n    internal string MaybeCapitalise(string text) =>\n        _atStartOfLine ? (char.ToUpper(text[0]) + text[1..]) : text;\n\n    public void SkipNextComma() => _skipComma = true;\n\n    public void EndLine()\n    {\n        _io.WriteLine();\n        _atStartOfLine = true;\n    }\n}\n"
  },
  {
    "path": "70_Poetry/csharp/Phrase.cs",
    "content": "namespace Poetry;\n\ninternal class Phrase\n{\n    private readonly static Phrase[][] _phrases = new Phrase[][]\n    {\n        new Phrase[]\n        {\n            new(\"midnight dreary\"),\n            new(\"fiery eyes\"),\n            new(\"bird or fiend\"),\n            new(\"thing of evil\"),\n            new(\"prophet\")\n        },\n        new Phrase[]\n        {\n            new(\"beguiling me\", ctx => ctx.PhraseCount = 2),\n            new(\"thrilled me\"),\n            new(\"still sitting....\", ctx => ctx.SkipNextComma()),\n            new(\"never flitting\", ctx => ctx.PhraseCount = 2),\n            new(\"burned\")\n        },\n        new Phrase[]\n        {\n            new(\"and my soul\"),\n            new(\"darkness there\"),\n            new(\"shall be lifted\"),\n            new(\"quoth the raven\"),\n            new(ctx => ctx.PhraseCount != 0, \"sign of parting\")\n        },\n        new Phrase[]\n        {\n            new(\"nothing more\"),\n            new(\"yet again\"),\n            new(\"slowly creeping\"),\n            new(\"...evermore\"),\n            new(\"nevermore\")\n        }\n    };\n\n    private readonly Predicate<Context> _condition;\n    private readonly string _text;\n    private readonly Action<Context> _update;\n\n    private Phrase(Predicate<Context> condition, string text)\n        : this(condition, text, _ => { })\n    {\n    }\n\n    private Phrase(string text, Action<Context> update)\n        : this(_ => true, text, update)\n    {\n    }\n\n    private Phrase(string text)\n        : this(_ => true, text, _ => { })\n    {\n    }\n\n    private Phrase(Predicate<Context> condition, string text, Action<Context> update)\n    {\n        _condition = condition;\n        _text = text;\n        _update = update;\n    }\n\n    public static Phrase GetPhrase(Context context) => _phrases[context.GroupNumber][context.PhraseNumber];\n\n    public void Write(IReadWrite io, Context context)\n    {\n        if (_condition.Invoke(context))\n        {\n            io.Write(context.MaybeCapitalise(_text));\n        }\n\n        _update.Invoke(context);\n    }\n}"
  },
  {
    "path": "70_Poetry/csharp/Poem.cs",
    "content": "using static Poetry.Resources.Resource;\n\nnamespace Poetry;\n\ninternal class Poem\n{\n    internal static void Compose(IReadWrite io, IRandom random)\n    {\n        io.Write(Streams.Title);\n\n        var context = new Context(io, random);\n\n        while (true)\n        {\n            context.WritePhrase();\n            context.MaybeWriteComma();\n            context.WriteSpaceOrNewLine();\n\n            while (true)\n            {\n                context.Update(random);\n                context.MaybeIndent();\n\n                if (context.GroupNumberIsValid) { break; }\n\n                context.ResetGroup();\n\n                if (context.MaybeCompleteStanza()) { break; }\n            }\n        }\n    }\n}"
  },
  {
    "path": "70_Poetry/csharp/Poetry.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "70_Poetry/csharp/Poetry.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Poetry\", \"Poetry.csproj\", \"{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "70_Poetry/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using Poetry;\n\nPoem.Compose(new ConsoleIO(), new RandomNumberGenerator());\n"
  },
  {
    "path": "70_Poetry/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "70_Poetry/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Poetry.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Title => GetStream();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "70_Poetry/csharp/Resources/Title.txt",
    "content": "                              Poetry\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "70_Poetry/java/Poetry.java",
    "content": "/**\n * Game of Poetry\n * <p>\n * Based on the BASIC game of Poetry here\n * https://github.com/coding-horror/basic-computer-games/blob/main/70%20Poetry/poetry.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Poetry {\n\n  private final static double COMMA_RATE = 0.19;\n  private final static double SPACE_RATE = 0.65;\n  private final static int PARAGRAPH_RATE = 20;\n\n  private enum Step {\n    WORD_GROUP1, WORD_GROUP2, WORD_GROUP3, WORD_GROUP4, RANDOMIZE_COMMA,\n    RANDOMIZE_WHITESPACE, RANDOMIZE_COUNTERS\n  }\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private void showIntro() {\n\n    System.out.println(\" \".repeat(29) + \"POETRY\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    int groupIndex = 0;\n    int paragraphIndex = 0;\n    int punctuationIndex = 0;\n    int wordIndex = 1;\n\n    Step nextStep = Step.WORD_GROUP1;\n\n    // Begin outer while loop\n    while (true) {\n\n      switch (nextStep) {\n\n        case WORD_GROUP1:\n\n          if (wordIndex == 1) {\n\n            System.out.print(\"MIDNIGHT DREARY\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 2) {\n\n            System.out.print(\"FIERY EYES\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 3) {\n\n            System.out.print(\"BIRD OR FIEND\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 4) {\n\n            System.out.print(\"THING OF EVIL\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 5) {\n\n            System.out.print(\"PROPHET\");\n            nextStep = Step.RANDOMIZE_COMMA;\n          }\n          break;\n\n        case WORD_GROUP2:\n\n          if (wordIndex == 1) {\n\n            System.out.print(\"BEGUILING ME\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 2) {\n\n            System.out.print(\"THRILLED ME\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 3) {\n\n            System.out.print(\"STILL SITTING....\");\n            nextStep = Step.RANDOMIZE_WHITESPACE;\n\n          } else if (wordIndex == 4) {\n\n            System.out.print(\"NEVER FLITTING\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 5) {\n\n            System.out.print(\"BURNED\");\n            nextStep = Step.RANDOMIZE_COMMA;\n          }\n          break;\n\n        case WORD_GROUP3:\n\n          if (wordIndex == 1) {\n\n            System.out.print(\"AND MY SOUL\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 2) {\n\n            System.out.print(\"DARKNESS THERE\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 3) {\n\n            System.out.print(\"SHALL BE LIFTED\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 4) {\n\n            System.out.print(\"QUOTH THE RAVEN\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 5) {\n\n            if (punctuationIndex != 0) {\n\n              System.out.print(\"SIGN OF PARTING\");\n            }\n\n            nextStep = Step.RANDOMIZE_COMMA;\n          }\n          break;\n\n        case WORD_GROUP4:\n\n          if (wordIndex == 1) {\n\n            System.out.print(\"NOTHING MORE\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 2) {\n\n            System.out.print(\"YET AGAIN\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 3) {\n\n            System.out.print(\"SLOWLY CREEPING\");\n            nextStep = Step.RANDOMIZE_WHITESPACE;\n\n          } else if (wordIndex == 4) {\n\n            System.out.print(\"...EVERMORE\");\n            nextStep = Step.RANDOMIZE_COMMA;\n\n          } else if (wordIndex == 5) {\n\n            System.out.print(\"NEVERMORE\");\n            nextStep = Step.RANDOMIZE_COMMA;\n          }\n          break;\n\n        case RANDOMIZE_COMMA:\n\n          // Insert commas\n          if ((punctuationIndex != 0) && (Math.random() <= COMMA_RATE)) {\n\n            System.out.print(\",\");\n            punctuationIndex = 2;\n          }\n          nextStep = Step.RANDOMIZE_WHITESPACE;\n          break;\n\n\n        case RANDOMIZE_WHITESPACE:\n\n          // Insert spaces\n          if (Math.random() <= SPACE_RATE) {\n\n            System.out.print(\" \");\n            punctuationIndex++;\n\n          }\n          // Insert newlines\n          else {\n\n            System.out.println(\"\");\n            punctuationIndex = 0;\n          }\n          nextStep = Step.RANDOMIZE_COUNTERS;\n          break;\n\n        case RANDOMIZE_COUNTERS:\n\n          wordIndex = (int)((int)(10 * Math.random()) / 2) + 1;\n\n          groupIndex++;\n          paragraphIndex++;\n\n          if ((punctuationIndex == 0) && (groupIndex % 2 == 0)) {\n\n            System.out.print(\"     \");\n          }\n\n          if (groupIndex == 1) {\n\n            nextStep = Step.WORD_GROUP1;\n\n          } else if (groupIndex == 2) {\n\n            nextStep = Step.WORD_GROUP2;\n\n          } else if (groupIndex == 3) {\n\n            nextStep = Step.WORD_GROUP3;\n\n          } else if (groupIndex == 4) {\n\n            nextStep = Step.WORD_GROUP4;\n\n          } else if (groupIndex == 5) {\n\n            groupIndex = 0;\n            System.out.println(\"\");\n\n            if (paragraphIndex > PARAGRAPH_RATE) {\n\n              System.out.println(\"\");\n              punctuationIndex = 0;\n              paragraphIndex = 0;\n              nextStep = Step.WORD_GROUP2;\n\n            } else {\n\n              nextStep = Step.RANDOMIZE_COUNTERS;\n            }\n          }\n          break;\n\n        default:\n          System.out.println(\"INVALID STEP\");\n          break;\n      }\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    Poetry poetry = new Poetry();\n    poetry.play();\n\n  }  // End of method main\n\n}  // End of class Poetry\n"
  },
  {
    "path": "70_Poetry/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "70_Poetry/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "70_Poetry/javascript/poetry.html",
    "content": "<html>\n<head>\n<title>POETRY</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"poetry.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "70_Poetry/javascript/poetry.js",
    "content": "// POETRY\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"POETRY\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n\n    times = 0;\n\n    i = 1;\n    j = 1;\n    k = 0;\n    u = 0;\n    while (1) {\n        if (j == 1) {\n            switch (i) {\n                case 1:\n                    print(\"MIDNIGHT DREARY\");\n                    break;\n                case 2:\n                    print(\"FIERY EYES\");\n                    break;\n                case 3:\n                    print(\"BIRD OF FIEND\");\n                    break;\n                case 4:\n                    print(\"THING OF EVIL\");\n                    break;\n                case 5:\n                    print(\"PROPHET\");\n                    break;\n            }\n        } else if (j == 2) {\n            switch (i) {\n                case 1:\n                    print(\"BEGUILING ME\");\n                    u = 2;\n                    break;\n                case 2:\n                    print(\"THRILLED ME\");\n                    break;\n                case 3:\n                    print(\"STILL SITTING....\");\n                    u = 0;\n                    break;\n                case 4:\n                    print(\"NEVER FLITTING\");\n                    u = 2;\n                    break;\n                case 5:\n                    print(\"BURNED\");\n                    break;\n            }\n        } else if (j == 3) {\n            switch (i) {\n                case 1:\n                    print(\"AND MY SOUL\");\n                    break;\n                case 2:\n                    print(\"DARKNESS THERE\");\n                    break;\n                case 3:\n                    print(\"SHALL BE LIFTED\");\n                    break;\n                case 4:\n                    print(\"QUOTH THE RAVEN\");\n                    break;\n                case 5:\n                    if (u == 0)\n                        break;\n                    print(\"SIGN OF PARTING\");\n                    break;\n            }\n        } else if (j == 4) {\n            switch (i) {\n                case 1:\n                    print(\"NOTHING MORE\");\n                    break;\n                case 2:\n                    print(\"YET AGAIN\");\n                    break;\n                case 3:\n                    print(\"SLOWLY CREEPING\");\n                    break;\n                case 4:\n                    print(\"...EVERMORE\");\n                    break;\n                case 5:\n                    print(\"NEVERMORE\");\n                    break;\n            }\n        }\n        if (u != 0 && Math.random() <= 0.19) {\n            print(\",\");\n            u = 2;\n        }\n        if (Math.random() <= 0.65) {\n            print(\" \");\n            u++;\n        } else {\n            print(\"\\n\");\n            u = 0;\n        }\n        while (1) {\n            i = Math.floor(Math.floor(10 * Math.random()) / 2) + 1;\n            j++;\n            k++;\n            if (u == 0 && j % 2 == 0)\n                print(\"     \");\n            if (j != 5)\n                break;\n            j = 0;\n            print(\"\\n\");\n            if (k <= 20)\n                continue;\n            print(\"\\n\");\n            u = 0;\n            k = 0;\n            j = 2;\n            break;\n        }\n        if (u == 0 && k == 0 && j == 2 && ++times == 10)\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "70_Poetry/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "70_Poetry/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "70_Poetry/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "70_Poetry/perl/poetry.pl",
    "content": "#!/usr/bin/perl\n#use strict;\n# Automatic converted by bas2perl.pl\n# Too much spaguetti code to be properly converted.\n\n\nprint ' 'x 30 . \"POETRY\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nLine90:\nif ($I==1) { goto Line100; } elsif ($I==2) { goto Line101; } elsif ($I==3) { goto Line102; } elsif ($I==4) { goto Line103; } elsif ($I==5) { goto Line104; } ;\nLine100:\nprint \"MIDNIGHT DREARY\"; goto Line210;\nLine101:\nprint \"FIERY EYES\"; goto Line210;\nLine102:\nprint \"BIRD OR FIEND\"; goto Line210;\nLine103:\nprint \"THING OF EVIL\"; goto Line210;\nLine104:\nprint \"PROPHET\"; goto Line210;\nLine110:\nif ($I==1) { goto Line111; } elsif ($I==2) { goto Line112; } elsif ($I==3) { goto Line113; } elsif ($I==4) { goto Line114; } elsif ($I==5) { goto Line115; } ;\nLine111:\nprint \"BEGUILING ME\"; $U=2; goto Line210;\nLine112:\nprint \"THRILLED ME\"; goto Line210;\nLine113:\nprint \"STILL SITTING....\"; goto Line212;\nLine114:\nprint \"NEVER FLITTING\"; $U=2; goto Line210;\nLine115:\nprint \"BURNED\"; goto Line210;\nLine120:\nif ($I==1) { goto Line121; } elsif ($I==2) { goto Line122; } elsif ($I==3) { goto Line123; } elsif ($I==4) { goto Line124; } elsif ($I==5) { goto Line125; } ;\nLine121:\nprint \"AND MY SOUL\"; goto Line210;\nLine122:\nprint \"DARKNESS THERE\"; goto Line210;\nLine123:\nprint \"SHALL BE LIFTED\"; goto Line210;\nLine124:\nprint \"QUOTH THE RAVEN\"; goto Line210;\nLine125:\nif ($U==0) { goto Line210; }\nprint \"SIGN OF PARTING\"; goto Line210;\nLine130:\nif ($I==1) { goto Line131; } elsif ($I==2) { goto Line132; } elsif ($I==3) { goto Line133; } elsif ($I==4) { goto Line134; } elsif ($I==5) { goto Line135; } ;\nLine131:\nprint \"NOTHING MORE\"; goto Line210;\nLine132:\nprint \"YET AGAIN\"; goto Line210;\nLine133:\nprint \"SLOWLY CREEPING\"; goto Line210;\nLine134:\nprint \"...EVERMORE\"; goto Line210;\nLine135:\nprint \"NEVERMORE\";\nLine210:\nif ($U==0 || rand(1)>.19) { goto Line212; }\nprint \",\"; $U=2;\nLine212:\nif (rand(1)>.65) { goto Line214; }\nprint \" \"; $U=$U+1; goto Line215;\nLine214:\nprint \"\\n\"; $U=0;\nLine215:\n$I=int(int(10*rand(1))/2)+1;\n$J=$J+1; $K=$K+1;\nif ($U>0 || int($J/2)!=$J/2) { goto Line240; }\nprint \" \";\nLine240:\nif ($J==1) { goto Line90; } elsif ($J==2) { goto Line110; } elsif ($J==3) { goto Line120; } elsif ($J==4) { goto Line130; } elsif ($J==5) { goto Line250; } ;\nLine250:\n$J=0; print \"\\n\"; if ($K>20) { goto Line270; }\ngoto Line215;\nLine270:\nprint \"\\n\"; $U=0; $K=0; goto Line110;\nexit;\n"
  },
  {
    "path": "70_Poetry/poetry.bas",
    "content": "5 Y=RND(-1)\n6 REM FOR X = 1 TO 100\n7 REM PRINT RND(1);\",\"\n8 REM NEXT X\n9 REM GOTO 999\n10 PRINT TAB(30);\"POETRY\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n90 ON I GOTO 100,101,102,103,104\n100 PRINT \"MIDNIGHT DREARY\";:GOTO 210\n101 PRINT \"FIERY EYES\";:GOTO 210\n102 PRINT \"BIRD OR FIEND\";:GOTO 210\n103 PRINT \"THING OF EVIL\";:GOTO 210\n104 PRINT \"PROPHET\";:GOTO 210\n110 ON I GOTO 111,112,113,114,115\n111 PRINT \"BEGUILING ME\";:U=2:GOTO 210\n112 PRINT \"THRILLED ME\";:GOTO 210\n113 PRINT \"STILL SITTING....\";:GOTO 212\n114 PRINT \"NEVER FLITTING\";:U=2:GOTO 210\n115 PRINT \"BURNED\";:GOTO 210\n120 ON I GOTO 121,122,123,124,125\n121 PRINT \"AND MY SOUL\";:GOTO 210\n122 PRINT \"DARKNESS THERE\";:GOTO 210\n123 PRINT \"SHALL BE LIFTED\";:GOTO 210\n124 PRINT \"QUOTH THE RAVEN\";:GOTO 210\n125 IF U=0 THEN 210\n126 PRINT \"SIGN OF PARTING\";:GOTO 210\n130 ON I GOTO 131,132,133,134,135\n131 PRINT \"NOTHING MORE\";:GOTO 210\n132 PRINT \"YET AGAIN\";:GOTO 210\n133 PRINT \"SLOWLY CREEPING\";:GOTO 210\n134 PRINT \"...EVERMORE\";:GOTO 210\n135 PRINT \"NEVERMORE\";\n210 GOSUB 500 : IF U=0 OR X>.19 THEN 212\n211 PRINT \",\";:U=2\n212 GOSUB 500 : IF X>.65 THEN 214\n213 PRINT \" \";:U=U+1:GOTO 215\n214 PRINT : U=0\n215 GOSUB 500 : I=INT(INT(10*X)/2)+1\n220 J=J+1 : K=K+1\n225 REM PRINT \"I=\";I;\"; J=\";J;\"; K=\";K;\"; U=\";U\n230 IF U>0 OR INT(J/2)<>J/2 THEN 240\n235 PRINT \"     \";\n240 ON J GOTO 90,110,120,130,250\n250 J=0 : PRINT : IF K>20 THEN 270\n260 GOTO 215\n270 PRINT : U=0 : K=0 : GOTO 110\n500 X = RND(1)\n505 REM PRINT \"#\";X;\"#\"\n510 RETURN\n999 END\n"
  },
  {
    "path": "70_Poetry/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "70_Poetry/python/poetry.pl",
    "content": "#!/usr/bin/perl\n#use strict;\n# Automatic converted by bas2perl.pl\n# Too much spaguetti code to be properly converted.\n\n\nprint ' 'x 30 . \"POETRY\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nLine90:\nif ($I==1) { goto Line100; } elsif ($I==2) { goto Line101; } elsif ($I==3) { goto Line102; } elsif ($I==4) { goto Line103; } elsif ($I==5) { goto Line104; } ;\nLine100:\nprint \"MIDNIGHT DREARY\"; goto Line210;\nLine101:\nprint \"FIERY EYES\"; goto Line210;\nLine102:\nprint \"BIRD OR FIEND\"; goto Line210;\nLine103:\nprint \"THING OF EVIL\"; goto Line210;\nLine104:\nprint \"PROPHET\"; goto Line210;\nLine110:\nif ($I==1) { goto Line111; } elsif ($I==2) { goto Line112; } elsif ($I==3) { goto Line113; } elsif ($I==4) { goto Line114; } elsif ($I==5) { goto Line115; } ;\nLine111:\nprint \"BEGUILING ME\"; $U=2; goto Line210;\nLine112:\nprint \"THRILLED ME\"; goto Line210;\nLine113:\nprint \"STILL SITTING....\"; goto Line212;\nLine114:\nprint \"NEVER FLITTING\"; $U=2; goto Line210;\nLine115:\nprint \"BURNED\"; goto Line210;\nLine120:\nif ($I==1) { goto Line121; } elsif ($I==2) { goto Line122; } elsif ($I==3) { goto Line123; } elsif ($I==4) { goto Line124; } elsif ($I==5) { goto Line125; } ;\nLine121:\nprint \"AND MY SOUL\"; goto Line210;\nLine122:\nprint \"DARKNESS THERE\"; goto Line210;\nLine123:\nprint \"SHALL BE LIFTED\"; goto Line210;\nLine124:\nprint \"QUOTH THE RAVEN\"; goto Line210;\nLine125:\nif ($U==0) { goto Line210; }\nprint \"SIGN OF PARTING\"; goto Line210;\nLine130:\nif ($I==1) { goto Line131; } elsif ($I==2) { goto Line132; } elsif ($I==3) { goto Line133; } elsif ($I==4) { goto Line134; } elsif ($I==5) { goto Line135; } ;\nLine131:\nprint \"NOTHING MORE\"; goto Line210;\nLine132:\nprint \"YET AGAIN\"; goto Line210;\nLine133:\nprint \"SLOWLY CREEPING\"; goto Line210;\nLine134:\nprint \"...EVERMORE\"; goto Line210;\nLine135:\nprint \"NEVERMORE\";\nLine210:\nif ($U==0 || rand(1)>.19) { goto Line212; }\nprint \",\"; $U=2;\nLine212:\nif (rand(1)>.65) { goto Line214; }\nprint \" \"; $U=$U+1; goto Line215;\nLine214:\nprint \"\\n\"; $U=0;\nLine215:\n$I=int(int(10*rand(1))/2)+1;\n$J=$J+1; $K=$K+1;\nif ($U>0 || int($J/2)!=$J/2) { goto Line240; }\nprint \" \";\nLine240:\nif ($J==1) { goto Line90; } elsif ($J==2) { goto Line110; } elsif ($J==3) { goto Line120; } elsif ($J==4) { goto Line130; } elsif ($J==5) { goto Line250; } ;\nLine250:\n$J=0; print \"\\n\"; if ($K>20) { goto Line270; }\ngoto Line215;\nLine270:\nprint \"\\n\"; $U=0; $K=0; goto Line110;\nexit;\n"
  },
  {
    "path": "70_Poetry/python/poetry.py",
    "content": "\"\"\"\nPOETRY\n\nA poetry generator\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\nfrom dataclasses import dataclass\n\nPAGE_WIDTH = 64\n\n\n@dataclass\nclass State:\n    u: int = 0\n    i: int = 0\n    j: int = 0\n    k: int = 0\n    phrase: int = 1\n    line: str = \"\"\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef process_phrase_1(state: State) -> str:\n    line_1_options = [\n        \"MIDNIGHT DREARY\",\n        \"FIERY EYES\",\n        \"BIRD OR FIEND\",\n        \"THING OF EVIL\",\n        \"PROPHET\",\n    ]\n    state.line = state.line + line_1_options[state.i]\n    return state.line\n\n\ndef process_phrase_2(state: State) -> None:\n    line_2_options = [\n        (\"BEGUILING ME\", 2),\n        (\"THRILLED ME\", None),\n        (\"STILL SITTING....\", None),\n        (\"NEVER FLITTING\", 2),\n        (\"BURNED\", None),\n    ]\n    words, u_modifier = line_2_options[state.i]\n    state.line += words\n    if u_modifier is not None:\n        state.u = u_modifier\n\n\ndef process_phrase_3(state: State) -> None:\n    phrases = [\n        (False, \"AND MY SOUL\"),\n        (False, \"DARKNESS THERE\"),\n        (False, \"SHALL BE LIFTED\"),\n        (False, \"QUOTH THE RAVEN\"),\n        (True, \"SIGN OF PARTING\"),\n    ]\n\n    only_if_u, words = phrases[state.i]\n    if (not only_if_u) or (state.u > 0):\n        state.line = state.line + words\n\n\ndef process_phrase_4(state: State) -> None:\n    phrases = [\n        (\"NOTHING MORE\"),\n        (\"YET AGAIN\"),\n        (\"SLOWLY CREEPING\"),\n        (\"...EVERMORE\"),\n        (\"NEVERMORE\"),\n    ]\n\n    state.line += phrases[state.i]\n\n\ndef maybe_comma(state: State) -> None:\n    if len(state.line) > 0 and state.line[-1] == \".\":\n        # don't follow a period with a comma, ever\n        return\n\n    if state.u != 0 and random.random() <= 0.19:\n        state.line += \", \"\n        state.u = 2\n    if random.random() <= 0.65:\n        state.line += \" \"\n        state.u += 1\n    else:\n        print(state.line)\n        state.line = \"\"\n        state.u = 0\n\n\ndef pick_phrase(state: State) -> None:\n    state.i = random.randint(0, 4)\n    state.j += 1\n    state.k += 1\n\n    if state.u <= 0 and (state.j % 2) != 0:\n        # random indentation is fun!\n        state.line += \" \" * 5\n    state.phrase = state.j + 1\n\n\ndef main() -> None:\n    print_centered(\"POETRY\")\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n\n    state = State()\n\n    phrase_processors = {\n        1: process_phrase_1,\n        2: process_phrase_2,\n        3: process_phrase_3,\n        4: process_phrase_4,\n    }\n\n    while True:\n        if state.phrase >= 1 and state.phrase <= 4:\n            phrase_processors[state.phrase](state)\n            maybe_comma(state)\n        elif state.phrase == 5:\n            state.j = 0\n            print(state.line)\n            state.line = \"\"\n            if state.k > 20:\n                print()\n                state.u = 0\n                state.k = 0\n            else:\n                state.phrase = 2\n                continue\n        pick_phrase(state)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "70_Poetry/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "70_Poetry/ruby/poetry.rb",
    "content": "PAGE_WIDTH = 64\n\nclass State\n    attr_accessor :u, :i, :j, :k, :phrase, :line\n\n    def initialize\n        self.u = 0\n        self.i = 0\n        self.j = 0\n        self.k = 0\n        self.phrase = 1\n        self.line = \"\"\n    end\nend\n\n\ndef print_centered msg\n    spaces = \" \" * ((PAGE_WIDTH - msg.length).fdiv(2))\n    print(spaces + msg)\nend\n\ndef process_phrase_1 state\n    line_1_options = [\n        \"MIDNIGHT DREARY\",\n        \"FIERY EYES\",\n        \"BIRD OR FIEND\",\n        \"THING OF EVIL\",\n        \"PROPHET\"\n    ]\n\n    state.line = state.line + line_1_options[state.i]\n    return state.line\nend\n\ndef process_phrase_2 state\n    line_2_options = [\n        [\"BEGUILING ME\", 2],\n        [\"THRILLED ME\", nil],\n        [\"STILL SITTING....\", nil],\n        [\"NEVER FLITTING\", 2],\n        [\"BURNED\", nil]\n    ]\n    words, u_modifier = line_2_options[state.i]\n    state.line += words\n    if !u_modifier.nil?\n        state.u = u_modifier\n    end\nend\n\ndef process_phrase_3 state\n    phrases = [\n        [false, \"AND MY SOUL\"],\n        [false, \"DARKNESS THERE\"],\n        [false, \"SHALL BE LIFTED\"],\n        [false, \"QUOTH THE RAVEN\"],\n        [true, \"SIGN OF PARTING\"]\n    ]\n\n    only_if_u, words = phrases[state.i]\n    if !only_if_u || state.u > 0\n        state.line = state.line + words\n    end\nend\n\ndef process_phrase_4 state\n    phrases = [\n        \"NOTHING MORE\",\n        \"YET AGAIN\",\n        \"SLOWLY CREEPING\",\n        \"...EVERMORE\",\n        \"NEVERMORE\"\n    ]\n\n    state.line += phrases[state.i]\nend\n\ndef maybe_comma state\n    if state.line.length > 0 && state.line[-1] == \".\"\n        return\n    end\n\n    if state.u != 0 && Random.rand <= 0.19\n        state.line += \", \"\n        state.u = 2\n    end\n\n    if Random.rand <= 0.65\n        state.line += \" \"\n        state.u += 1\n    else\n        puts state.line\n        state.line = \"\"\n        state.u = 0\n    end\nend\n\ndef pick_phrase state\n    state.i = Random.rand(0..4)\n    state.j += 1\n    state.k += 1\n\n    if state.u <= 0 && (state.j % 2) != 0\n        state.line += (\" \" * 5)\n    end\n    state.phrase = state.j + 1\nend\n\ndef main\n    print_centered(\"POETRY\")\n    state = State.new\n    phrase_processors = {\n        '1' => 'process_phrase_1',\n        '2' => 'process_phrase_2',\n        '3' => 'process_phrase_3',\n        '4' => 'process_phrase_4'\n    }\n\n    while true\n        if state.phrase >= 1 && state.phrase <= 4\n            method(phrase_processors[state.phrase.to_s]).call(state)\n            maybe_comma state\n        elsif state.phrase == 5\n            state.j = 0\n            puts state.line\n            state.line = \"\"\n            if state.k > 20\n                puts \"\"\n                state.u = 0\n                state.k = 0\n            else\n                state.phrase = 2\n                next\n            end\n        end\n        pick_phrase state\n    end\nend\n\nif __FILE__ == $0\n    main\nend"
  },
  {
    "path": "70_Poetry/vbnet/Poetry.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Poetry\", \"Poetry.vbproj\", \"{422855D5-5841-40E0-AF1E-993FB25DE7B3}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "70_Poetry/vbnet/Poetry.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Poetry</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "70_Poetry/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "71_Poker/README.md",
    "content": "### Poker\n\nYou and the computer are opponents in this game of draw poker. At the start of the game, each player is given $200. The game ends when either player runs out of money, although if you go broke the computer will offer to buy back your wristwatch or diamond tie tack.\n\nThe computer opens the betting before the draw; you open the betting after the draw. If you don’t have a hand that’s worth anything and you want to fold, bet 0. Prior to the draw, to check the draw, you may bet .5. Of course, if the computer has made a bet, you must match it in order to draw or, if you have a good hand, you may raise the bet at any time.\n\nThe author is A. Christopher Hall of Trinity College, Hartford, Connecticut.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=129)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=144)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- If you bet more than the computer has, it will still see you, resulting in a negative balance.  (To handle this properly, the computer would need to go \"all in\" and reduce your bet to an amount it can match; or else lose the game, which is what happens to the human player in the same situation.)\n\n- If you are low on cash and sell your watch, then make a bet much smaller than the amount you just gained from the watch, it sometimes nonetheless tells you you \"blew your wad\" and ends the game.\n\n- When the watch is sold (in either direction), the buyer does not actually lose any money.\n\n- The code in the program about selling your tie tack is unreachable due to a logic bug.\n\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "71_Poker/csharp/Cards/Card.cs",
    "content": "namespace Poker.Cards;\n\ninternal record struct Card (Rank Rank, Suit Suit)\n{\n    public override string ToString() => $\"{Rank} of {Suit}\";\n\n    public static bool operator <(Card x, Card y) => x.Rank < y.Rank;\n    public static bool operator >(Card x, Card y) => x.Rank > y.Rank;\n\n    public static int operator -(Card x, Card y) => x.Rank - y.Rank;\n}\n"
  },
  {
    "path": "71_Poker/csharp/Cards/Deck.cs",
    "content": "using static Poker.Cards.Rank;\n\nnamespace Poker.Cards;\n\ninternal class Deck\n{\n    private readonly Card[] _cards;\n    private int _nextCard;\n\n    public Deck()\n    {\n        _cards = Ranks.SelectMany(r => Enum.GetValues<Suit>().Select(s => new Card(r, s))).ToArray();\n    }\n\n    public void Shuffle(IRandom _random)\n    {\n        for (int i = 0; i < _cards.Length; i++)\n        {\n            var j = _random.Next(_cards.Length);\n            (_cards[i], _cards[j]) = (_cards[j], _cards[i]);\n        }\n        _nextCard = 0;\n    }\n\n    public Card DealCard() => _cards[_nextCard++];\n\n    public Hand DealHand() => new Hand(Enumerable.Range(0, 5).Select(_ => DealCard()));\n}\n"
  },
  {
    "path": "71_Poker/csharp/Cards/Hand.cs",
    "content": "using System.Text;\nusing static Poker.Cards.HandRank;\nnamespace Poker.Cards;\n\ninternal class Hand\n{\n    public static readonly Hand Empty = new Hand();\n\n    private readonly Card[] _cards;\n\n    private Hand()\n    {\n        _cards = Array.Empty<Card>();\n        Rank = None;\n    }\n\n    public Hand(IEnumerable<Card> cards)\n        : this(cards, isAfterDraw: false)\n    {\n    }\n\n    private Hand(IEnumerable<Card> cards, bool isAfterDraw)\n    {\n        _cards = cards.ToArray();\n        (Rank, HighCard, KeepMask) = Analyze();\n\n        IsWeak = Rank < PartialStraight\n            || Rank == PartialStraight && isAfterDraw\n            || Rank <= TwoPair && HighCard.Rank <= 6;\n    }\n\n    public string Name => Rank.ToString(HighCard);\n    public HandRank Rank { get; }\n    public Card HighCard { get; }\n    public int KeepMask { get; set; }\n    public bool IsWeak { get; }\n\n    public Hand Replace(int cardNumber, Card newCard)\n    {\n        if (cardNumber < 1 || cardNumber > _cards.Length) { return this; }\n\n        _cards[cardNumber - 1] = newCard;\n        return new Hand(_cards, isAfterDraw: true);\n    }\n\n    private (HandRank, Card, int) Analyze()\n    {\n        var suitMatchCount = 0;\n        for (var i = 0; i < _cards.Length; i++)\n        {\n            if (i < _cards.Length-1 && _cards[i].Suit == _cards[i+1].Suit)\n            {\n                suitMatchCount++;\n            }\n        }\n        if (suitMatchCount == 4)\n        {\n            return (Flush, _cards[0], 0b11111);\n        }\n        var sortedCards = _cards.OrderBy(c => c.Rank).ToArray();\n\n        var handRank = Schmaltz;\n        var keepMask = 0;\n        Card highCard = default;\n        for (var i = 0; i < sortedCards.Length - 1; i++)\n        {\n            var matchesNextCard = sortedCards[i].Rank == sortedCards[i+1].Rank;\n            var matchesPreviousCard = i > 0 && sortedCards[i].Rank == sortedCards[i - 1].Rank;\n\n            if (matchesNextCard)\n            {\n                keepMask |= 0b11 << i;\n                highCard = sortedCards[i];\n                handRank = matchesPreviousCard switch\n                {\n                    _ when handRank < Pair => Pair,\n                    true when handRank == Pair => Three,\n                    _ when handRank == Pair => TwoPair,\n                    _ when handRank == TwoPair => FullHouse,\n                    true => Four,\n                    _ => FullHouse\n                };\n            }\n        }\n        if (keepMask == 0)\n        {\n            if (sortedCards[3] - sortedCards[0] == 3)\n            {\n                keepMask=0b1111;\n                handRank=PartialStraight;\n            }\n            if (sortedCards[4] - sortedCards[1] == 3)\n            {\n                if (handRank == PartialStraight)\n                {\n                    return (Straight, sortedCards[4], 0b11111);\n                }\n                handRank=PartialStraight;\n                keepMask=0b11110;\n            }\n        }\n        return handRank < PartialStraight\n            ? (Schmaltz, sortedCards[4], 0b11000)\n            : (handRank, highCard, keepMask);\n    }\n\n    public override string ToString()\n    {\n        var sb = new StringBuilder();\n        for (var i = 0; i < _cards.Length; i++)\n        {\n            var cardDisplay = $\" {i+1} --  {_cards[i]}\";\n            // Emulates the effect of the BASIC PRINT statement using the ',' to align text to 14-char print zones\n            sb.Append(cardDisplay.PadRight(cardDisplay.Length + 14 - cardDisplay.Length % 14));\n            if (i % 2 == 1)\n            {\n                sb.AppendLine();\n            }\n        }\n        sb.AppendLine();\n        return sb.ToString();\n    }\n\n    public static bool operator >(Hand x, Hand y) =>\n        x.Rank > y.Rank ||\n        x.Rank == y.Rank && x.HighCard > y.HighCard;\n\n    public static bool operator <(Hand x, Hand y) =>\n        x.Rank < y.Rank ||\n        x.Rank == y.Rank && x.HighCard < y.HighCard;\n}\n"
  },
  {
    "path": "71_Poker/csharp/Cards/HandRank.cs",
    "content": "namespace Poker.Cards;\n\ninternal class HandRank\n{\n    public static HandRank None = new(0, \"\");\n    public static HandRank Schmaltz = new(1, \"schmaltz, \", c => $\"{c.Rank} high\");\n    public static HandRank PartialStraight = new(2, \"\"); // The original code does not assign a display string here\n    public static HandRank Pair = new(3, \"a pair of \", c => $\"{c.Rank}'s\");\n    public static HandRank TwoPair = new(4, \"two pair, \", c => $\"{c.Rank}'s\");\n    public static HandRank Three = new(5, \"three \", c => $\"{c.Rank}'s\");\n    public static HandRank Straight = new(6, \"straight\", c => $\"{c.Rank} high\");\n    public static HandRank Flush = new(7, \"a flush in \", c => c.Suit.ToString());\n    public static HandRank FullHouse = new(8, \"full house, \", c => $\"{c.Rank}'s\");\n    public static HandRank Four = new(9, \"four \", c => $\"{c.Rank}'s\");\n    // The original code does not detect a straight flush or royal flush\n\n    private readonly int _value;\n    private readonly string _displayName;\n    private readonly Func<Card, string> _suffixSelector;\n\n    private HandRank(int value, string displayName, Func<Card, string>? suffixSelector = null)\n    {\n        _value = value;\n        _displayName = displayName;\n        _suffixSelector = suffixSelector ?? (_ => \"\");\n    }\n\n    public string ToString(Card highCard) => $\"{_displayName}{_suffixSelector.Invoke(highCard)}\";\n\n    public static bool operator >(HandRank x, HandRank y) => x._value > y._value;\n    public static bool operator <(HandRank x, HandRank y) => x._value < y._value;\n    public static bool operator >=(HandRank x, HandRank y) => x._value >= y._value;\n    public static bool operator <=(HandRank x, HandRank y) => x._value <= y._value;\n}\n"
  },
  {
    "path": "71_Poker/csharp/Cards/Rank.cs",
    "content": "namespace Poker.Cards;\n\ninternal struct Rank : IComparable<Rank>\n{\n    public static IEnumerable<Rank> Ranks => new[]\n    {\n        Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace\n    };\n\n    public static Rank Two = new(2);\n    public static Rank Three = new(3);\n    public static Rank Four = new(4);\n    public static Rank Five = new(5);\n    public static Rank Six = new(6);\n    public static Rank Seven = new(7);\n    public static Rank Eight = new(8);\n    public static Rank Nine = new(9);\n    public static Rank Ten = new(10);\n    public static Rank Jack = new(11, \"Jack\");\n    public static Rank Queen = new(12, \"Queen\");\n    public static Rank King = new(13, \"King\");\n    public static Rank Ace = new(14, \"Ace\");\n\n    private readonly int _value;\n    private readonly string _name;\n\n    private Rank(int value, string? name = null)\n    {\n        _value = value;\n        _name = name ?? $\" {value} \";\n    }\n\n    public override string ToString() => _name;\n\n    public int CompareTo(Rank other) => this - other;\n\n    public static bool operator <(Rank x, Rank y) => x._value < y._value;\n    public static bool operator >(Rank x, Rank y) => x._value > y._value;\n    public static bool operator ==(Rank x, Rank y) => x._value == y._value;\n    public static bool operator !=(Rank x, Rank y) => x._value != y._value;\n\n    public static int operator -(Rank x, Rank y) => x._value - y._value;\n\n    public static bool operator <=(Rank rank, int value) => rank._value <= value;\n    public static bool operator >=(Rank rank, int value) => rank._value >= value;\n\n    public override bool Equals(object? obj) => obj is Rank other && this == other;\n\n    public override int GetHashCode() => _value.GetHashCode();\n}\n"
  },
  {
    "path": "71_Poker/csharp/Cards/Suit.cs",
    "content": "namespace Poker.Cards;\n\ninternal enum Suit\n{\n    Clubs,\n    Diamonds,\n    Hearts,\n    Spades\n}\n"
  },
  {
    "path": "71_Poker/csharp/Game.cs",
    "content": "using Poker.Cards;\nusing Poker.Players;\nusing Poker.Resources;\n\nnamespace Poker;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    internal void Play()\n    {\n        _io.Write(Resource.Streams.Title);\n        _io.Write(Resource.Streams.Instructions);\n\n        var deck = new Deck();\n        var human = new Human(200, _io);\n        var computer = new Computer(200, _io, _random);\n        var table = new Table(_io, _random, deck, human, computer);\n\n        do\n        {\n            table.PlayHand();\n        } while (table.ShouldPlayAnotherHand());\n    }\n}\n"
  },
  {
    "path": "71_Poker/csharp/IReadWriteExtensions.cs",
    "content": "using Poker.Strategies;\nusing static System.StringComparison;\n\nnamespace Poker;\n\ninternal static class IReadWriteExtensions\n{\n    internal static bool ReadYesNo(this IReadWrite io, string prompt)\n    {\n        while (true)\n        {\n            var response = io.ReadString(prompt);\n            if (response.Equals(\"YES\", InvariantCultureIgnoreCase)) { return true; }\n            if (response.Equals(\"NO\", InvariantCultureIgnoreCase)) { return false; }\n            io.WriteLine(\"Answer Yes or No, please.\");\n        }\n    }\n\n    internal static float ReadNumber(this IReadWrite io) => io.ReadNumber(\"\");\n\n    internal static int ReadNumber(this IReadWrite io, string prompt, int max, string maxPrompt)\n    {\n        io.Write(prompt);\n        while (true)\n        {\n            var response = io.ReadNumber();\n            if (response <= max) { return (int)response; }\n            io.WriteLine(maxPrompt);\n        }\n    }\n\n    internal static Strategy ReadHumanStrategy(this IReadWrite io, bool noCurrentBets)\n    {\n        while(true)\n        {\n            io.WriteLine();\n            var bet = io.ReadNumber(\"What is your bet\");\n            if (bet != (int)bet)\n            {\n                if (noCurrentBets && bet == .5) { return Strategy.Check; }\n                io.WriteLine(\"No small change, please.\");\n                continue;\n            }\n            if (bet == 0) { return Strategy.Fold; }\n            return Strategy.Bet(bet);\n        }\n    }\n}"
  },
  {
    "path": "71_Poker/csharp/Players/Computer.cs",
    "content": "using Poker.Cards;\nusing Poker.Strategies;\nusing static System.StringComparison;\n\nnamespace Poker.Players;\n\ninternal class Computer : Player\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Computer(int bank, IReadWrite io, IRandom random)\n        : base(bank)\n    {\n        _io = io;\n        _random = random;\n        Strategy = Strategy.None;\n    }\n\n    public Strategy Strategy { get; set; }\n\n    public override void NewHand()\n    {\n        base.NewHand();\n\n        Strategy = (Hand.IsWeak, Hand.Rank < HandRank.Three, Hand.Rank < HandRank.FullHouse) switch\n        {\n            (true, _, _) when _random.Next(10) < 2 => Strategy.Bluff(23, 0b11100),\n            (true, _, _) when _random.Next(10) < 2 => Strategy.Bluff(23, 0b11110),\n            (true, _, _) when _random.Next(10) < 1 => Strategy.Bluff(23, 0b11111),\n            (true, _, _) => Strategy.Fold,\n            (false, true, _) => _random.Next(10) < 2 ? Strategy.Bluff(23) : Strategy.Check,\n            (false, false, true) => Strategy.Bet(35),\n            (false, false, false) => _random.Next(10) < 1 ? Strategy.Bet(35) : Strategy.Raise\n        };\n    }\n\n    protected override void DrawCards(Deck deck)\n    {\n        var keepMask = Strategy.KeepMask ?? Hand.KeepMask;\n        var count = 0;\n        for (var i = 1; i <= 5; i++)\n        {\n            if ((keepMask & (1 << (i - 1))) == 0)\n            {\n                Hand = Hand.Replace(i, deck.DealCard());\n                count++;\n            }\n        }\n\n        _io.WriteLine();\n        _io.Write($\"I am taking {count} card\");\n        if (count != 1)\n        {\n            _io.WriteLine(\"s\");\n        }\n\n        Strategy = (Hand.IsWeak, Hand.Rank < HandRank.Three, Hand.Rank < HandRank.FullHouse) switch\n        {\n            _ when Strategy is Bluff => Strategy.Bluff(28),\n            (true, _, _) => Strategy.Fold,\n            (false, true, _) => _random.Next(10) == 0 ? Strategy.Bet(19) : Strategy.Raise,\n            (false, false, true) => _random.Next(10) == 0 ? Strategy.Bet(11) : Strategy.Bet(19),\n            (false, false, false) => Strategy.Raise\n        };\n    }\n\n    public int GetWager(int wager)\n    {\n        wager += _random.Next(10);\n        if (Balance < Table.Human.Bet + wager)\n        {\n            if (Table.Human.Bet == 0) { return Balance; }\n\n            if (Balance >= Table.Human.Bet)\n            {\n                _io.WriteLine(\"I'll see you.\");\n                Bet = Table.Human.Bet;\n                Table.CollectBets();\n            }\n            else\n            {\n                RaiseFunds();\n            }\n        }\n\n        return wager;\n    }\n\n    public bool TryBuyWatch()\n    {\n        if (!Table.Human.HasWatch) { return false; }\n\n        var response = _io.ReadString(\"Would you like to sell your watch\");\n        if (response.StartsWith(\"N\", InvariantCultureIgnoreCase)) { return false; }\n\n        var (value, message) = (_random.Next(10) < 7) switch\n        {\n            true => (75, \"I'll give you $75 for it.\"),\n            false => (25, \"That's a pretty crummy watch - I'll give you $25.\")\n        };\n\n        _io.WriteLine(message);\n        Table.Human.SellWatch(value);\n        // The original code does not have the computer part with any money\n\n        return true;\n    }\n\n    public void RaiseFunds()\n    {\n        if (Table.Human.HasWatch) { return; }\n\n        var response = _io.ReadString(\"Would you like to buy back your watch for $50\");\n        if (response.StartsWith(\"N\", InvariantCultureIgnoreCase)) { return; }\n\n        // The original code does not deduct $50 from the player\n        Balance += 50;\n        Table.Human.ReceiveWatch();\n        IsBroke = true;\n    }\n\n    public void CheckFunds() { IsBroke = Balance <= Table.Ante; }\n\n    public override void TakeWinnings()\n    {\n        _io.WriteLine(\"I win.\");\n        base.TakeWinnings();\n    }\n}\n"
  },
  {
    "path": "71_Poker/csharp/Players/Human.cs",
    "content": "using Poker.Cards;\nusing Poker.Strategies;\n\nnamespace Poker.Players;\n\ninternal class Human : Player\n{\n    private readonly IReadWrite _io;\n\n    public Human(int bank, IReadWrite io)\n        : base(bank)\n    {\n        HasWatch = true;\n        _io = io;\n    }\n\n    public bool HasWatch { get; set; }\n\n    protected override void DrawCards(Deck deck)\n    {\n        var count = _io.ReadNumber(\"How many cards do you want\", 3, \"You can't draw more than three cards.\");\n        if (count == 0) { return; }\n\n        _io.WriteLine(\"What are their numbers:\");\n        for (var i = 1; i <= count; i++)\n        {\n            Hand = Hand.Replace((int)_io.ReadNumber(), deck.DealCard());\n        }\n\n        _io.WriteLine(\"Your new hand:\");\n        _io.Write(Hand);\n    }\n\n    internal bool SetWager()\n    {\n        var strategy = _io.ReadHumanStrategy(Table.Computer.Bet == 0 && Bet == 0);\n        if (strategy is Strategies.Bet or Check)\n        {\n            if (Bet + strategy.Value < Table.Computer.Bet)\n            {\n                _io.WriteLine(\"If you can't see my bet, then fold.\");\n                return false;\n            }\n            if (Balance - Bet - strategy.Value >= 0)\n            {\n                HasBet = true;\n                Bet += strategy.Value;\n                return true;\n            }\n            RaiseFunds();\n        }\n        else\n        {\n            Fold();\n            Table.CollectBets();\n        }\n        return false;\n    }\n\n    public void RaiseFunds()\n    {\n        _io.WriteLine();\n        _io.WriteLine(\"You can't bet with what you haven't got.\");\n\n        if (Table.Computer.TryBuyWatch()) { return; }\n\n        // The original program had some code about selling a tie tack, but due to a fault\n        // in the logic the code was unreachable. I've omitted it in this port.\n\n        IsBroke = true;\n    }\n\n    public void ReceiveWatch()\n    {\n        // In the original code the player does not pay any money to receive the watch back.\n        HasWatch = true;\n    }\n\n    public void SellWatch(int amount)\n    {\n        HasWatch = false;\n        Balance += amount;\n    }\n\n    public override void TakeWinnings()\n    {\n        _io.WriteLine(\"You win.\");\n        base.TakeWinnings();\n    }\n}\n"
  },
  {
    "path": "71_Poker/csharp/Players/Player.cs",
    "content": "using Poker.Cards;\n\nnamespace Poker.Players;\n\ninternal abstract class Player\n{\n    private Table? _table;\n    private bool _hasFolded;\n\n    protected Player(int bank)\n    {\n        Hand = Hand.Empty;\n        Balance = bank;\n    }\n\n    public Hand Hand { get; set; }\n    public int Balance { get; set; }\n    public bool HasBet { get; set; }\n    public int Bet { get; set; }\n    public bool HasFolded => _hasFolded;\n    public bool IsBroke { get; protected set; }\n\n    protected Table Table =>\n        _table ?? throw new InvalidOperationException(\"The player must be sitting at the table.\");\n\n    public void Sit(Table table) => _table = table;\n\n    public virtual void NewHand()\n    {\n        Bet = 0;\n        Hand = Table.Deck.DealHand();\n        _hasFolded = false;\n    }\n\n    public int AnteUp()\n    {\n        Balance -= Table.Ante;\n        return Table.Ante;\n    }\n\n    public void DrawCards()\n    {\n        Bet = 0;\n        DrawCards(Table.Deck);\n    }\n\n    protected abstract void DrawCards(Deck deck);\n\n    public virtual void TakeWinnings()\n    {\n        Balance += Table.Pot;\n        Table.Pot = 0;\n    }\n\n    public void Fold()\n    {\n        _hasFolded = true;\n    }\n}\n"
  },
  {
    "path": "71_Poker/csharp/Poker.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "71_Poker/csharp/Poker.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Poker\", \"Poker.csproj\", \"{CAEDA88F-1585-41AA-8213-40012B044FA9}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{CAEDA88F-1585-41AA-8213-40012B044FA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CAEDA88F-1585-41AA-8213-40012B044FA9}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CAEDA88F-1585-41AA-8213-40012B044FA9}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CAEDA88F-1585-41AA-8213-40012B044FA9}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "71_Poker/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using Poker;\n\nnew Game(new ConsoleIO(), new RandomNumberGenerator()).Play();"
  },
  {
    "path": "71_Poker/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "71_Poker/csharp/Resources/Instructions.txt",
    "content": "Welcome to the casino.  We each have $200.\nI will open the betting before the draw; you open after.\nTo fold bet 0; to check bet .5.\nEnough talk -- Let's get down to business.\n\n"
  },
  {
    "path": "71_Poker/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Poker.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Instructions => GetStream();\n        public static Stream Title => GetStream();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null)\n        => Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Poker.Resources.{name}.txt\")\n            ?? throw new ArgumentException($\"Resource stream {name} does not exist\", nameof(name));\n}"
  },
  {
    "path": "71_Poker/csharp/Resources/Title.txt",
    "content": "                                  Poker\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "71_Poker/csharp/Strategies/Bet.cs",
    "content": "namespace Poker.Strategies;\n\ninternal class Bet : Strategy\n{\n    public Bet(int amount) => Value = amount;\n\n    public override int Value { get; }\n}\n"
  },
  {
    "path": "71_Poker/csharp/Strategies/Bluff.cs",
    "content": "namespace Poker.Strategies;\n\ninternal class Bluff : Bet\n{\n    public Bluff(int amount, int? keepMask)\n        : base(amount)\n    {\n        KeepMask = keepMask;\n    }\n\n    public override int? KeepMask { get; }\n}"
  },
  {
    "path": "71_Poker/csharp/Strategies/Check.cs",
    "content": "namespace Poker.Strategies;\n\ninternal class Check : Strategy\n{\n    public override int Value => 0;\n}\n"
  },
  {
    "path": "71_Poker/csharp/Strategies/Fold.cs",
    "content": "namespace Poker.Strategies;\n\ninternal class Fold : Strategy\n{\n    public override int Value => -1;\n}\n"
  },
  {
    "path": "71_Poker/csharp/Strategies/None.cs",
    "content": "namespace Poker.Strategies;\n\ninternal class None : Strategy\n{\n    public override int Value => -1;\n}\n"
  },
  {
    "path": "71_Poker/csharp/Strategies/Raise.cs",
    "content": "namespace Poker.Strategies;\n\ninternal class Raise : Bet\n{\n    public Raise() : base(2) { }\n}\n"
  },
  {
    "path": "71_Poker/csharp/Strategies/Strategy.cs",
    "content": "namespace Poker.Strategies;\n\ninternal abstract class Strategy\n{\n    public static Strategy None = new None();\n    public static Strategy Fold = new Fold();\n    public static Strategy Check = new Check();\n    public static Strategy Raise = new Raise();\n    public static Strategy Bet(float amount) => new Bet((int)amount);\n    public static Strategy Bet(int amount) => new Bet(amount);\n    public static Strategy Bluff(int amount, int? keepMask = null) => new Bluff(amount, keepMask);\n\n    public abstract int Value { get; }\n    public virtual int? KeepMask { get; }\n}\n"
  },
  {
    "path": "71_Poker/csharp/Table.cs",
    "content": "using Poker.Cards;\nusing Poker.Players;\nusing Poker.Strategies;\n\nnamespace Poker;\n\ninternal class Table\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    public int Pot;\n\n    public Table(IReadWrite io, IRandom random, Deck deck, Human human, Computer computer)\n    {\n        _io = io;\n        _random = random;\n        Deck = deck;\n        Human = human;\n        Computer = computer;\n\n        human.Sit(this);\n        computer.Sit(this);\n    }\n\n    public int Ante { get; } = 5;\n    public Deck Deck { get; }\n    public Human Human { get; }\n    public Computer Computer { get; }\n\n    internal void PlayHand()\n    {\n        while (true)\n        {\n            _io.WriteLine();\n            Computer.CheckFunds();\n            if (Computer.IsBroke) { return; }\n\n            _io.WriteLine($\"The ante is ${Ante}.  I will deal:\");\n            _io.WriteLine();\n            if (Human.Balance <= Ante)\n            {\n                Human.RaiseFunds();\n                if (Human.IsBroke) { return; }\n            }\n\n            Deal(_random);\n\n            _io.WriteLine();\n            GetWagers(\"I'll open with ${0}\", \"I check.\", allowRaiseAfterCheck: true);\n            if (SomeoneIsBroke() || SomeoneHasFolded()) { return; }\n\n            Draw();\n\n            GetWagers();\n            if (SomeoneIsBroke()) { return; }\n            if (!Human.HasBet)\n            {\n                GetWagers(\"I'll bet ${0}\", \"I'll check\");\n            }\n            if (SomeoneIsBroke() || SomeoneHasFolded()) { return; }\n            if (GetWinner() is { } winner)\n            {\n                winner.TakeWinnings();\n                return;\n            }\n        }\n    }\n\n    private void Deal(IRandom random)\n    {\n        Deck.Shuffle(random);\n\n        Pot = Human.AnteUp() + Computer.AnteUp();\n\n        Human.NewHand();\n        Computer.NewHand();\n\n        _io.WriteLine(\"Your hand:\");\n        _io.Write(Human.Hand);\n    }\n\n    private void Draw()\n    {\n        _io.WriteLine();\n        _io.Write(\"Now we draw -- \");\n        Human.DrawCards();\n        Computer.DrawCards();\n        _io.WriteLine();\n    }\n\n    private void GetWagers(string betFormat, string checkMessage, bool allowRaiseAfterCheck = false)\n    {\n        if (Computer.Strategy is Bet)\n        {\n            Computer.Bet = Computer.GetWager(Computer.Strategy.Value);\n            if (Computer.IsBroke) { return; }\n\n            _io.WriteLine(betFormat, Computer.Bet);\n        }\n        else\n        {\n            _io.WriteLine(checkMessage);\n            if (!allowRaiseAfterCheck) { return; }\n        }\n\n        GetWagers();\n    }\n\n    private void GetWagers()\n    {\n        while (true)\n        {\n            Human.HasBet = false;\n            while (true)\n            {\n                if (Human.SetWager()) { break; }\n                if (Human.IsBroke || Human.HasFolded) { return; }\n            }\n            if (Human.Bet == Computer.Bet)\n            {\n                CollectBets();\n                return;\n            }\n            if (Computer.Strategy is Fold)\n            {\n                if (Human.Bet > 5)\n                {\n                    Computer.Fold();\n                    _io.WriteLine(\"I fold.\");\n                    return;\n                }\n            }\n            if (Human.Bet > 3 * Computer.Strategy.Value)\n            {\n                if (Computer.Strategy is not Raise)\n                {\n                    _io.WriteLine(\"I'll see you.\");\n                    Computer.Bet = Human.Bet;\n                    CollectBets();\n                    return;\n                }\n            }\n\n            var raise = Computer.GetWager(Human.Bet - Computer.Bet);\n            if (Computer.IsBroke) { return; }\n            _io.WriteLine($\"I'll see you, and raise you {raise}\");\n            Computer.Bet = Human.Bet + raise;\n        }\n    }\n\n    internal void CollectBets()\n    {\n        Human.Balance -= Human.Bet;\n        Computer.Balance -= Computer.Bet;\n        Pot += Human.Bet + Computer.Bet;\n    }\n\n    private bool SomeoneHasFolded()\n    {\n        if (Human.HasFolded)\n        {\n            _io.WriteLine();\n            Computer.TakeWinnings();\n        }\n        else if (Computer.HasFolded)\n        {\n            _io.WriteLine();\n            Human.TakeWinnings();\n        }\n        else\n        {\n            return false;\n        }\n\n        Pot = 0;\n        return true;\n    }\n\n    private bool SomeoneIsBroke() => Human.IsBroke || Computer.IsBroke;\n\n    private Player? GetWinner()\n    {\n        _io.WriteLine();\n        _io.WriteLine(\"Now we compare hands:\");\n        _io.WriteLine(\"My hand:\");\n        _io.Write(Computer.Hand);\n        _io.WriteLine();\n        _io.WriteLine($\"You have {Human.Hand.Name}\");\n        _io.WriteLine($\"and I have {Computer.Hand.Name}\");\n        if (Computer.Hand > Human.Hand) { return Computer; }\n        if (Human.Hand > Computer.Hand) { return Human; }\n        _io.WriteLine(\"The hand is drawn.\");\n        _io.WriteLine($\"All $ {Pot} remains in the pot.\");\n        return null;\n    }\n\n    internal bool ShouldPlayAnotherHand()\n    {\n        if (Computer.IsBroke)\n        {\n            _io.WriteLine(\"I'm busted.  Congratulations!\");\n            return true;\n        }\n\n        if (Human.IsBroke)\n        {\n            _io.WriteLine(\"Your wad is shot.  So long, sucker!\");\n            return true;\n        }\n\n        _io.WriteLine($\"Now I have $ {Computer.Balance} and you have $ {Human.Balance}\");\n        return _io.ReadYesNo(\"Do you wish to continue\");\n    }\n}"
  },
  {
    "path": "71_Poker/java/Poker.java",
    "content": "import java.util.Random;\nimport java.util.Scanner;\n\nimport static java.lang.System.out;\n\n/**\n * Port of CREATIVE COMPUTING Poker written in Commodore 64 Basic to plain Java\n *\n * Original source scanned from magazine: https://www.atariarchives.org/basicgames/showpage.php?page=129\n *\n * I based my port on the OCR'ed source code here: https://github.com/coding-horror/basic-computer-games/blob/main/71_Poker/poker.bas\n *\n * Why? Because I remember typing this into my C64 when I was a tiny little developer and having great fun playing it!\n *\n * Goal: Keep the algorithms and UX more or less as-is; Improve the control flow a bit (no goto in Java!) and rename some stuff to be easier to follow.\n *\n * Result: There are probably bugs, please let me know.\n */\npublic class Poker {\n\n\tpublic static void main(String[] args) {\n\t\tnew Poker().run();\n\t}\n\n\tfloat[] cards = new float[50]; // Index 1-5 = Human hand, index 6-10 = Computer hand\n\tfloat[] B = new float[15];\n\n\tfloat playerValuables = 1;\n\tfloat computerMoney = 200;\n\tfloat humanMoney = 200;\n\tfloat pot = 0;\n\n\tString J$ = \"\";\n\tfloat computerHandValue = 0;\n\n\tint K = 0;\n\tfloat G = 0;\n\tfloat T = 0;\n\tint M = 0;\n\tint D = 0;\n\n\tint U = 0;\n\tfloat N = 1;\n\n\tfloat I = 0;\n\n\tfloat X = 0;\n\n\tint Z = 0;\n\n\tString handDescription = \"\";\n\n\tfloat V;\n\n\tvoid run() {\n\t\tprintWelcome();\n\t\tplayRound();\n\t\tstartAgain();\n\t}\n\n\tvoid printWelcome() {\n\t\ttab(33);\n\t\tout.println(\"POKER\");\n\t\ttab(15);\n\t\tout.print(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tout.println();\n\t\tout.println();\n\t\tout.println();\n\t\tout.println(\"WELCOME TO THE CASINO.  WE EACH HAVE $200.\");\n\t\tout.println(\"I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.\");\n\t\tout.println(\"TO FOLD BET 0; TO CHECK BET .5.\");\n\t\tout.println(\"ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.\");\n\t\tout.println();\n\t}\n\n\tvoid tab(int number) {\n\t\tSystem.out.print(\"\\t\".repeat(number));\n\t}\n\n\tint random0to10() {\n\t\treturn new Random().nextInt(10);\n\t}\n\n\tint removeHundreds(long x) {\n\t\treturn _int(x - (100F * _int(x / 100F)));\n\t}\n\n\tvoid startAgain() {\n\t\tpot = 0;\n\t\tplayRound();\n\t}\n\n\tvoid playRound() {\n\t\tif (computerMoney <= 5) {\n\t\t\tcomputerBroke();\n\t\t}\n\n\t\tout.println(\"THE ANTE IS $5.  I WILL DEAL:\");\n\t\tout.println();\n\n\t\tif (humanMoney <= 5) {\n\t\t\tplayerBroke();\n\t\t}\n\n\t\tpot = pot + 10;\n\t\thumanMoney = humanMoney - 5;\n\t\tcomputerMoney = computerMoney - 5;\n\t\tfor (int Z = 1; Z < 10; Z++) {\n\t\t\tgenerateCards(Z);\n\t\t}\n\t\tout.println(\"YOUR HAND:\");\n\t\tN = 1;\n\t\tshowHand();\n\t\tN = 6;\n\t\tI = 2;\n\n\t\tdescribeHand();\n\n\t\tout.println();\n\n\t\tif (I != 6) {\n\t\t\tif (U >= 13) {\n\t\t\t\tif (U <= 16) {\n\t\t\t\t\tZ = 35;\n\t\t\t\t} else {\n\t\t\t\t\tZ = 2;\n\t\t\t\t\tif (random0to10() < 1) {\n\t\t\t\t\t\tZ = 35;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcomputerOpens();\n\t\t\t\tplayerMoves();\n\t\t\t} else if (random0to10() >= 2) {\n\t\t\t\tcomputerChecks();\n\t\t\t} else {\n\t\t\t\tI = 7;\n\t\t\t\tZ = 23;\n\t\t\t\tcomputerOpens();\n\t\t\t\tplayerMoves();\n\t\t\t}\n\t\t} else if (random0to10() <= 7) {\n\t\t\tif (random0to10() <= 7) {\n\t\t\t\tif (random0to10() >= 1) {\n\t\t\t\t\tZ = 1;\n\t\t\t\t\tK = 0;\n\t\t\t\t\tout.print(\"I CHECK. \");\n\t\t\t\t\tplayerMoves();\n\t\t\t\t} else {\n\t\t\t\t\tX = 11111;\n\t\t\t\t\tI = 7;\n\t\t\t\t\tZ = 23;\n\t\t\t\t\tcomputerOpens();\n\t\t\t\t\tplayerMoves();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tX = 11110;\n\t\t\t\tI = 7;\n\t\t\t\tZ = 23;\n\t\t\t\tcomputerOpens();\n\t\t\t\tplayerMoves();\n\t\t\t}\n\t\t} else {\n\t\t\tX = 11100;\n\t\t\tI = 7;\n\t\t\tZ = 23;\n\t\t\tcomputerOpens();\n\t\t\tplayerMoves();\n\t\t}\n\t}\n\n\tvoid playerMoves() {\n\t\tplayersTurn();\n\t\tcheckWinnerAfterFirstBet();\n\t\tpromptPlayerDrawCards();\n\t}\n\n\tvoid computerOpens() {\n\t\tV = Z + random0to10();\n\t\tcomputerMoves();\n\t\tout.print(\"I'LL OPEN WITH $\" + V);\n\t\tK = _int(V);\n\t}\n\n\t@SuppressWarnings(\"StatementWithEmptyBody\")\n\tvoid computerMoves() {\n\t\tif (computerMoney - G - V >= 0) {\n\t\t} else if (G != 0) {\n\t\t\tif (computerMoney - G >= 0) {\n\t\t\t\tcomputerSees();\n\t\t\t} else {\n\t\t\t\tcomputerBroke();\n\t\t\t}\n\t\t} else {\n\t\t\tV = computerMoney;\n\t\t}\n\t}\n\n\tvoid promptPlayerDrawCards() {\n\t\tout.println();\n\t\tout.println(\"NOW WE DRAW -- HOW MANY CARDS DO YOU WANT\");\n\t\tinputPlayerDrawCards();\n\t}\n\n\tvoid inputPlayerDrawCards() {\n\t\tT = Integer.parseInt(readString());\n\t\tif (T == 0) {\n\t\t\tcomputerDrawing();\n\t\t} else {\n\t\t\tZ = 10;\n\t\t\tif (T < 4) {\n\t\t\t\tplayerDrawsCards();\n\t\t\t} else {\n\t\t\t\tout.println(\"YOU CAN'T DRAW MORE THAN THREE CARDS.\");\n\t\t\t\tinputPlayerDrawCards();\n\t\t\t}\n\t\t}\n\t}\n\n\t// line # 980\n\tvoid computerDrawing() {\n\t\tZ = _int(10 + T);\n\t\tfor (U = 6; U <= 10; U++) {\n\t\t\tif (_int((float) (X / Math.pow(10F, (U - 6F)))) == (10 * (_int((float) (X / Math.pow(10, (U - 5))))))) {\n\t\t\t\tdrawNextCard();\n\t\t\t}\n\t\t}\n\t\tout.print(\"I AM TAKING \" + _int(Z - 10 - T) + \" CARD\");\n\t\tif (Z == 11 + T) {\n\t\t\tout.println();\n\t\t} else {\n\t\t\tout.println(\"S\");\n\t\t}\n\n\t\tN = 6;\n\t\tV = I;\n\t\tI = 1;\n\t\tdescribeHand();\n\t\tstartPlayerBettingAndReaction();\n\t}\n\n\tvoid drawNextCard() {\n\t\tZ = Z + 1;\n\t\tdrawCard();\n\t}\n\n\t@SuppressWarnings(\"StatementWithEmptyBody\")\n\tvoid drawCard() {\n\t\tcards[Z] = 100 * new Random().nextInt(4) + new Random().nextInt(100);\n\t\tif (_int(cards[Z] / 100) > 3) {\n\t\t\tdrawCard();\n\t\t} else if (cards[Z] - 100 * _int(cards[Z] / 100) > 12) {\n\t\t\tdrawCard();\n\t\t} else if (Z == 1) {\n\t\t} else {\n\t\t\tfor (K = 1; K <= Z - 1; K++) {\n\t\t\t\tif (cards[Z] == cards[K]) {\n\t\t\t\t\tdrawCard();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Z <= 10) {\n\t\t\t} else {\n\t\t\t\tN = cards[U];\n\t\t\t\tcards[U] = cards[Z];\n\t\t\t\tcards[Z] = N;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid playerDrawsCards() {\n\t\tout.println(\"WHAT ARE THEIR NUMBERS:\");\n\t\tfor (int Q = 1; Q <= T; Q++) {\n\t\t\tU = Integer.parseInt(readString());\n\t\t\tdrawNextCard();\n\t\t}\n\n\t\tout.println(\"YOUR NEW HAND:\");\n\t\tN = 1;\n\t\tshowHand();\n\t\tcomputerDrawing();\n\t}\n\n\tvoid startPlayerBettingAndReaction() {\n\t\tcomputerHandValue = U;\n\t\tM = D;\n\n\t\tif (V != 7) {\n\t\t\tif (I != 6) {\n\t\t\t\tif (U >= 13) {\n\t\t\t\t\tif (U >= 16) {\n\t\t\t\t\t\tZ = 2;\n\t\t\t\t\t\tplayerBetsAndComputerReacts();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tZ = 19;\n\t\t\t\t\t\tif (random0to10() == 8) {\n\t\t\t\t\t\t\tZ = 11;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplayerBetsAndComputerReacts();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tZ = 2;\n\t\t\t\t\tif (random0to10() == 6) {\n\t\t\t\t\t\tZ = 19;\n\t\t\t\t\t}\n\t\t\t\t\tplayerBetsAndComputerReacts();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tZ = 1;\n\t\t\t\tplayerBetsAndComputerReacts();\n\t\t\t}\n\t\t} else {\n\t\t\tZ = 28;\n\t\t\tplayerBetsAndComputerReacts();\n\t\t}\n\t}\n\n\tvoid playerBetsAndComputerReacts() {\n\t\tK = 0;\n\t\tplayersTurn();\n\t\tif (T != .5) {\n\t\t\tcheckWinnerAfterFirstBetAndCompareHands();\n\t\t} else if (V == 7 || I != 6) {\n\t\t\tcomputerOpens();\n\t\t\tpromptAndInputPlayerBet();\n\t\t\tcheckWinnerAfterFirstBetAndCompareHands();\n\t\t} else {\n\t\t\tout.println(\"I'LL CHECK\");\n\t\t\tcompareHands();\n\t\t}\n\t}\n\n\tvoid checkWinnerAfterFirstBetAndCompareHands() {\n\t\tcheckWinnerAfterFirstBet();\n\t\tcompareHands();\n\t}\n\n\tvoid compareHands() {\n\t\tout.println(\"NOW WE COMPARE HANDS:\");\n\t\tJ$ = handDescription;\n\t\tout.println(\"MY HAND:\");\n\t\tN = 6;\n\t\tshowHand();\n\t\tN = 1;\n\t\tdescribeHand();\n\t\tout.print(\"YOU HAVE \");\n\t\tK = D;\n\t\tprintHandDescriptionResult();\n\t\thandDescription = J$;\n\t\tK = M;\n\t\tout.print(\" AND I HAVE \");\n\t\tprintHandDescriptionResult();\n\t\tout.print(\". \");\n\t\tif (computerHandValue > U) {\n\t\t\tcomputerWins();\n\t\t} else if (U > computerHandValue) {\n\t\t\thumanWins();\n\t\t} else if (handDescription.contains(\"A FLUS\")) {\n\t\t\tsomeoneWinsWithFlush();\n\t\t} else if (removeHundreds(M) < removeHundreds(D)) {\n\t\t\thumanWins();\n\t\t} else if (removeHundreds(M) > removeHundreds(D)) {\n\t\t\tcomputerWins();\n\t\t} else {\n\t\t\thandIsDrawn();\n\t\t}\n\t}\n\n\tvoid printHandDescriptionResult() {\n\t\tout.print(handDescription);\n\t\tif (!handDescription.contains(\"A FLUS\")) {\n\t\t\tK = removeHundreds(K);\n\t\t\tprintCardValue();\n\t\t\tif (handDescription.contains(\"SCHMAL\")) {\n\t\t\t\tout.print(\" HIGH\");\n\t\t\t} else if (!handDescription.contains(\"STRAIG\")) {\n\t\t\t\tout.print(\"'S\");\n\t\t\t} else {\n\t\t\t\tout.print(\" HIGH\");\n\t\t\t}\n\t\t} else {\n\t\t\tK = K / 100;\n\t\t\tprintCardColor();\n\t\t\tout.println();\n\t\t}\n\t}\n\n\tvoid handIsDrawn() {\n\t\tout.print(\"THE HAND IS DRAWN.\");\n\t\tout.print(\"ALL $\" + pot + \" REMAINS IN THE POT.\");\n\t\tplayRound();\n\t}\n\n\tvoid someoneWinsWithFlush() {\n\t\tif (removeHundreds(M) > removeHundreds(D)) {\n\t\t\tcomputerWins();\n\t\t} else if (removeHundreds(D) > removeHundreds(M)) {\n\t\t\thumanWins();\n\t\t} else {\n\t\t\thandIsDrawn();\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"StatementWithEmptyBody\")\n\tvoid checkWinnerAfterFirstBet() {\n\t\tif (I != 3) {\n\t\t\tif (I != 4) {\n\t\t\t} else {\n\t\t\t\thumanWins();\n\t\t\t}\n\t\t} else {\n\t\t\tout.println();\n\t\t\tcomputerWins();\n\t\t}\n\t}\n\n\tvoid computerWins() {\n\t\tout.print(\". I WIN. \");\n\t\tcomputerMoney = computerMoney + pot;\n\t\tpotStatusAndNextRoundPrompt();\n\t}\n\n\tvoid potStatusAndNextRoundPrompt() {\n\t\tout.println(\"NOW I HAVE $\" + computerMoney + \" AND YOU HAVE $\" + humanMoney);\n\t\tout.print(\"DO YOU WISH TO CONTINUE\");\n\n\t\tif (yesFromPrompt()) {\n\t\t\tstartAgain();\n\t\t} else {\n\t\t\tSystem.exit(0);\n\t\t}\n\t}\n\n\tprivate boolean yesFromPrompt() {\n\t\tString h = readString();\n\t\tif (h != null) {\n\t\t\tif (h.toLowerCase().matches(\"y|yes|yep|affirmative|yay\")) {\n\t\t\t\treturn true;\n\t\t\t} else if (h.toLowerCase().matches(\"n|no|nope|fuck off|nay\")) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tout.println(\"ANSWER YES OR NO, PLEASE.\");\n\t\treturn yesFromPrompt();\n\t}\n\n\tvoid computerChecks() {\n\t\tZ = 0;\n\t\tK = 0;\n\t\tout.print(\"I CHECK. \");\n\t\tplayerMoves();\n\t}\n\n\tvoid humanWins() {\n\t\tout.println(\"YOU WIN.\");\n\t\thumanMoney = humanMoney + pot;\n\t\tpotStatusAndNextRoundPrompt();\n\t}\n\n\t// line # 1740\n\tvoid generateCards(int Z) {\n\t\tcards[Z] = (100 * new Random().nextInt(4)) + new Random().nextInt(100);\n\t\tif (_int(cards[Z] / 100) > 3) {\n\t\t\tgenerateCards(Z);\n\t\t\treturn;\n\t\t}\n\t\tif (cards[Z] - 100 * (_int(cards[Z] / 100)) > 12) {\n\t\t\tgenerateCards(Z);\n\t\t\treturn;\n\t\t}\n\t\tif (Z == 1) {return;}\n\t\tfor (int K = 1; K <= Z - 1; K++) {// TO Z-1\n\t\t\tif (cards[Z] == cards[K]) {\n\t\t\t\tgenerateCards(Z);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif (Z <= 10) {return;}\n\t\tfloat N = cards[U];\n\t\tcards[U] = cards[Z];\n\t\tcards[Z] = N;\n\t}\n\n\t// line # 1850\n\tvoid showHand() {\n\t\tfor (int cardNumber = _int(N); cardNumber <= N + 4; cardNumber++) {\n\t\t\tout.print(cardNumber + \"--  \");\n\t\t\tprintCardValueAtIndex(cardNumber);\n\t\t\tout.print(\" OF\");\n\t\t\tprintCardColorAtIndex(cardNumber);\n\t\t\tif (cardNumber / 2 == (cardNumber / 2)) {\n\t\t\t\tout.println();\n\t\t\t}\n\t\t}\n\t}\n\n\t// line # 1950\n\tvoid printCardValueAtIndex(int Z) {\n\t\tK = removeHundreds(_int(cards[Z]));\n\t\tprintCardValue();\n\t}\n\n\tvoid printCardValue() {\n\t\tif (K == 9) {\n\t\t\tout.print(\"JACK\");\n\t\t} else if (K == 10) {\n\t\t\tout.print(\"QUEEN\");\n\t\t} else if (K == 11) {\n\t\t\tout.print(\"KING\");\n\t\t} else if (K == 12) {\n\t\t\tout.print(\"ACE\");\n\t\t} else if (K < 9) {\n\t\t\tout.print(K + 2);\n\t\t}\n\t}\n\n\t// line # 2070\n\tvoid printCardColorAtIndex(int Z) {\n\t\tK = _int(cards[Z] / 100);\n\t\tprintCardColor();\n\t}\n\n\tvoid printCardColor() {\n\t\tif (K == 0) {\n\t\t\tout.print(\" CLUBS\");\n\t\t} else if (K == 1) {\n\t\t\tout.print(\" DIAMONDS\");\n\t\t} else if (K == 2) {\n\t\t\tout.print(\" HEARTS\");\n\t\t} else if (K == 3) {\n\t\t\tout.print(\" SPADES\");\n\t\t}\n\t}\n\n\t// line # 2170\n\tvoid describeHand() {\n\t\tU = 0;\n\t\tfor (Z = _int(N); Z <= N + 4; Z++) {\n\t\t\tB[Z] = removeHundreds(_int(cards[Z]));\n\t\t\tif (Z == N + 4) {continue;}\n\t\t\tif (_int(cards[Z] / 100) != _int(cards[Z + 1] / 100)) {continue;}\n\t\t\tU = U + 1;\n\t\t}\n\t\tif (U != 4) {\n\t\t\tfor (Z = _int(N); Z <= N + 3; Z++) {\n\t\t\t\tfor (K = Z + 1; K <= N + 4; K++) {\n\t\t\t\t\tif (B[Z] <= B[K]) {continue;}\n\t\t\t\t\tX = cards[Z];\n\t\t\t\t\tcards[Z] = cards[K];\n\t\t\t\t\tB[Z] = B[K];\n\t\t\t\t\tcards[K] = X;\n\t\t\t\t\tB[K] = cards[K] - 100 * _int(cards[K] / 100);\n\t\t\t\t}\n\t\t\t}\n\t\t\tX = 0;\n\t\t\tfor (Z = _int(N); Z <= N + 3; Z++) {\n\t\t\t\tif (B[Z] != B[Z + 1]) {continue;}\n\t\t\t\tX = (float) (X + 11 * Math.pow(10, (Z - N)));\n\t\t\t\tD = _int(cards[Z]);\n\n\t\t\t\tif (U >= 11) {\n\t\t\t\t\tif (U != 11) {\n\t\t\t\t\t\tif (U > 12) {\n\t\t\t\t\t\t\tif (B[Z] != B[Z - 1]) {\n\t\t\t\t\t\t\t\tfullHouse();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tU = 17;\n\t\t\t\t\t\t\t\thandDescription = \"FOUR \";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfullHouse();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (B[Z] != B[Z - 1]) {\n\t\t\t\t\t\thandDescription = \"TWO PAIR, \";\n\t\t\t\t\t\tU = 12;\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandDescription = \"THREE \";\n\t\t\t\t\t\tU = 13;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tU = 11;\n\t\t\t\t\thandDescription = \"A PAIR OF \";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (X != 0) {\n\t\t\t\tschmaltzHand();\n\t\t\t} else {\n\t\t\t\tif (B[_int(N)] + 3 == B[_int(N + 3)]) {\n\t\t\t\t\tX = 1111;\n\t\t\t\t\tU = 10;\n\t\t\t\t}\n\t\t\t\tif (B[_int(N + 1)] + 3 != B[_int(N + 4)]) {\n\t\t\t\t\tschmaltzHand();\n\t\t\t\t} else if (U != 10) {\n\t\t\t\t\tU = 10;\n\t\t\t\t\tX = 11110;\n\t\t\t\t\tschmaltzHand();\n\t\t\t\t} else {\n\t\t\t\t\tU = 14;\n\t\t\t\t\thandDescription = \"STRAIGHT\";\n\t\t\t\t\tX = 11111;\n\t\t\t\t\tD = _int(cards[_int(N + 4)]);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tX = 11111;\n\t\t\tD = _int(cards[_int(N)]);\n\t\t\thandDescription = \"A FLUSH IN\";\n\t\t\tU = 15;\n\t\t}\n\t}\n\n\tvoid schmaltzHand() {\n\t\tif (U >= 10) {\n\t\t\tif (U != 10) {\n\t\t\t\tif (U > 12) {return;}\n\t\t\t\tif (removeHundreds(D) <= 6) {\n\t\t\t\t\tI = 6;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (I == 1) {\n\t\t\t\t\tI = 6;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tD = _int(cards[_int(N + 4)]);\n\t\t\thandDescription = \"SCHMALTZ, \";\n\t\t\tU = 9;\n\t\t\tX = 11000;\n\t\t\tI = 6;\n\t\t}\n\t}\n\n\tvoid fullHouse() {\n\t\tU = 16;\n\t\thandDescription = \"FULL HOUSE, \";\n\t}\n\n\tvoid playersTurn() {\n\t\tG = 0;\n\t\tpromptAndInputPlayerBet();\n\t}\n\n\tString readString() {\n\t\tScanner sc = new Scanner(System.in);\n\t\treturn sc.nextLine();\n\t}\n\n\t@SuppressWarnings(\"StatementWithEmptyBody\")\n\tvoid promptAndInputPlayerBet() {\n\t\tout.println(\"WHAT IS YOUR BET\");\n\t\tT = readFloat();\n\t\tif (T - _int(T) == 0) {\n\t\t\tprocessPlayerBet();\n\t\t} else if (K != 0) {\n\t\t\tplayerBetInvalidAmount();\n\t\t} else if (G != 0) {\n\t\t\tplayerBetInvalidAmount();\n\t\t} else if (T == .5) {\n\t\t} else {\n\t\t\tplayerBetInvalidAmount();\n\t\t}\n\t}\n\n\tprivate float readFloat() {\n\t\ttry {\n\t\t\treturn Float.parseFloat(readString());\n\t\t} catch (Exception ex) {\n\t\t\tSystem.out.println(\"INVALID INPUT, PLEASE TYPE A FLOAT. \");\n\t\t\treturn readFloat();\n\t\t}\n\t}\n\n\tvoid playerBetInvalidAmount() {\n\t\tout.println(\"NO SMALL CHANGE, PLEASE.\");\n\t\tpromptAndInputPlayerBet();\n\t}\n\n\tvoid processPlayerBet() {\n\t\tif (humanMoney - G - T >= 0) {\n\t\t\thumanCanAffordBet();\n\t\t} else {\n\t\t\tplayerBroke();\n\t\t\tpromptAndInputPlayerBet();\n\t\t}\n\t}\n\n\tvoid humanCanAffordBet() {\n\t\tif (T != 0) {\n\t\t\tif (G + T >= K) {\n\t\t\t\tprocessComputerMove();\n\t\t\t} else {\n\t\t\t\tout.println(\"IF YOU CAN'T SEE MY BET, THEN FOLD.\");\n\t\t\t\tpromptAndInputPlayerBet();\n\t\t\t}\n\t\t} else {\n\t\t\tI = 3;\n\t\t\tmoveMoneyToPot();\n\t\t}\n\t}\n\n\tvoid processComputerMove() {\n\t\tG = G + T;\n\t\tif (G == K) {\n\t\t\tmoveMoneyToPot();\n\t\t} else if (Z != 1) {\n\t\t\tif (G > 3 * Z) {\n\t\t\t\tcomputerRaisesOrSees();\n\t\t\t} else {\n\t\t\t\tcomputerRaises();\n\t\t\t}\n\t\t} else if (G > 5) {\n\t\t\tif (T <= 25) {\n\t\t\t\tcomputerRaisesOrSees();\n\t\t\t} else {\n\t\t\t\tcomputerFolds();\n\t\t\t}\n\t\t} else {\n\t\t\tV = 5;\n\t\t\tif (G > 3 * Z) {\n\t\t\t\tcomputerRaisesOrSees();\n\t\t\t} else {\n\t\t\t\tcomputerRaises();\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid computerRaises() {\n\t\tV = G - K + random0to10();\n\t\tcomputerMoves();\n\t\tout.println(\"I'LL SEE YOU, AND RAISE YOU\" + V);\n\t\tK = _int(G + V);\n\t\tpromptAndInputPlayerBet();\n\t}\n\n\tvoid computerFolds() {\n\t\tI = 4;\n\t\tout.println(\"I FOLD.\");\n\t}\n\n\tvoid computerRaisesOrSees() {\n\t\tif (Z == 2) {\n\t\t\tcomputerRaises();\n\t\t} else {\n\t\t\tcomputerSees();\n\t\t}\n\t}\n\n\tvoid computerSees() {\n\t\tout.println(\"I'LL SEE YOU.\");\n\t\tK = _int(G);\n\t\tmoveMoneyToPot();\n\t}\n\n\tvoid moveMoneyToPot() {\n\t\thumanMoney = humanMoney - G;\n\t\tcomputerMoney = computerMoney - K;\n\t\tpot = pot + G + K;\n\t}\n\n\tvoid computerBusted() {\n\t\tout.println(\"I'M BUSTED.  CONGRATULATIONS!\");\n\t\tSystem.exit(0);\n\t}\n\n\t@SuppressWarnings(\"StatementWithEmptyBody\")\n\tprivate void computerBroke() {\n\t\tif ((playerValuables / 2) == _int(playerValuables / 2) && playerBuyBackWatch()) {\n\t\t} else if (playerValuables / 3 == _int(playerValuables / 3) && playerBuyBackTieRack()) {\n\t\t} else {\n\t\t\tcomputerBusted();\n\t\t}\n\t}\n\n\tprivate int _int(float v) {\n\t\treturn (int) Math.floor(v);\n\t}\n\n\tprivate boolean playerBuyBackWatch() {\n\t\tout.println(\"WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50\");\n\t\tif (yesFromPrompt()) {\n\t\t\tcomputerMoney = computerMoney + 50;\n\t\t\tplayerValuables = playerValuables / 2;\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean playerBuyBackTieRack() {\n\t\tout.println(\"WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50\");\n\t\tif (yesFromPrompt()) {\n\t\t\tcomputerMoney = computerMoney + 50;\n\t\t\tplayerValuables = playerValuables / 3;\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// line # 3830\n\t@SuppressWarnings(\"StatementWithEmptyBody\")\n\tvoid playerBroke() {\n\t\tout.println(\"YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.\");\n\t\tif (playerValuables / 2 != _int(playerValuables / 2) && playerSellWatch()) {\n\t\t} else if (playerValuables / 3 != _int(playerValuables / 3) && playerSellTieTack()) {\n\t\t} else {\n\t\t\tplayerBusted();\n\t\t}\n\t}\n\n\tprivate void playerBusted() {\n\t\tout.println(\"YOUR WAD IS SHOT. SO LONG, SUCKER!\");\n\t\tSystem.exit(0);\n\t}\n\n\tprivate boolean playerSellWatch() {\n\t\tout.println(\"WOULD YOU LIKE TO SELL YOUR WATCH\");\n\t\tif (yesFromPrompt()) {\n\t\t\tif (random0to10() < 7) {\n\t\t\t\tout.println(\"I'LL GIVE YOU $75 FOR IT.\");\n\t\t\t\thumanMoney = humanMoney + 75;\n\t\t\t} else {\n\t\t\t\tout.println(\"THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.\");\n\t\t\t\thumanMoney = humanMoney + 25;\n\t\t\t}\n\t\t\tplayerValuables = playerValuables * 2;\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean playerSellTieTack() {\n\t\tout.println(\"WILL YOU PART WITH THAT DIAMOND TIE TACK\");\n\n\t\tif (yesFromPrompt()) {\n\t\t\tif (random0to10() < 6) {\n\t\t\t\tout.println(\"YOU ARE NOW $100 RICHER.\");\n\t\t\t\thumanMoney = humanMoney + 100;\n\t\t\t} else {\n\t\t\t\tout.println(\"IT'S PASTE.  $25.\");\n\t\t\t\thumanMoney = humanMoney + 25;\n\t\t\t}\n\t\t\tplayerValuables = playerValuables * 3;\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "71_Poker/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "71_Poker/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "71_Poker/javascript/poker.html",
    "content": "<html>\n<head>\n<title>POKER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"poker.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "71_Poker/javascript/poker.js",
    "content": "// POKER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar aa = [];\nvar ba = [];\nvar b;\nvar c;\nvar d;\nvar g;\nvar i;\nvar k;\nvar m;\nvar n;\nvar p;\nvar s;\nvar u;\nvar v;\nvar x;\nvar z;\nvar hs;\nvar is;\nvar js;\nvar ks;\n\nfunction fna(x)\n{\n    return Math.floor(10 * Math.random());\n}\n\nfunction fnb(x)\n{\n    return x % 100;\n}\n\nfunction im_busted()\n{\n    print(\"I'M BUSTED.  CONGRATULATIONS!\\n\");\n}\n\n// 1740\nfunction deal_card()\n{\n    while (1) {\n        aa[z] = 100 * Math.floor(4 * Math.random()) + Math.floor(100 * Math.random());\n        if (Math.floor(aa[z] / 100) > 3)    // Invalid suit\n            continue;\n        if (aa[z] % 100 > 12) // Invalid number\n            continue;\n        if (z != 1) {\n            for (k = 1; k <= z - 1; k++) {\n                if (aa[z] == aa[k])\n                    break;\n            }\n            if (k <= z - 1) // Repeated card\n                continue;\n            if (z > 10) {\n                n = aa[u];\n                aa[u] = aa[z];\n                aa[z] = n;\n            }\n        }\n        return;\n    }\n}\n\n// 1850\nfunction show_cards()\n{\n    for (z = n; z <= n + 4; z++) {\n        print(\" \" + z + \"--  \");\n        k = fnb(aa[z]);\n        show_number();\n        print(\" OF\");\n        k = Math.floor(aa[z] / 100);\n        show_suit();\n        if (z % 2 == 0)\n            print(\"\\n\");\n    }\n    print(\"\\n\");\n}\n\n// 1950\nfunction show_number()\n{\n    if (k == 9)\n        print(\"JACK\");\n    if (k == 10)\n        print(\"QUEEN\");\n    if (k == 11)\n        print(\"KING\");\n    if (k == 12)\n        print(\"ACE\");\n    if (k < 9)\n        print(\" \" + (k + 2));\n}\n\n// 2070\nfunction show_suit()\n{\n    if (k == 0)\n        print(\" CLUBS\\t\");\n    if (k == 1)\n        print(\" DIAMONDS\\t\");\n    if (k == 2)\n        print(\" HEARTS\\t\");\n    if (k == 3)\n        print(\" SPADES\\t\");\n}\n\n// 2170\nfunction evaluate_hand()\n{\n    u = 0;\n    for (z = n; z <= n + 4; z++) {\n        ba[z] = fnb(aa[z]);\n        if (z != n + 4) {\n            if (Math.floor(aa[z] / 100) == Math.floor(aa[z + 1] / 100))\n                u++;\n        }\n    }\n    if (u == 4) {\n        x = 11111;\n        d = aa[n];\n        hs = \"A FLUS\";\n        is = \"H IN\";\n        u = 15;\n        return;\n    }\n    for (z = n; z <= n + 3; z++) {\n        for (k = z + 1; k <= n + 4; k++) {\n            if (ba[z] > ba[k]) {\n                x = aa[z];\n                aa[z] = aa[k];\n                ba[z] = ba[k];\n                aa[k] = x;\n                ba[k] = aa[k] - 100 * Math.floor(aa[k] / 100);\n            }\n        }\n    }\n    x = 0;\n    for (z = n; z <= n + 3; z++) {\n        if (ba[z] == ba[z + 1]) {\n            x = x + 11 * Math.pow(10, z - n);\n            d = aa[z];\n            if (u < 11) {\n                u = 11;\n                hs = \"A PAIR\";\n                is = \" OF \";\n            } else if (u == 11) {\n                if (ba[z] == ba[z - 1]) {\n                    hs = \"THREE\";\n                    is = \" \";\n                    u = 13;\n                } else {\n                    hs = \"TWO P\";\n                    is = \"AIR, \";\n                    u = 12;\n                }\n            } else if (u == 12) {\n                u = 16;\n                hs = \"FULL H\";\n                is = \"OUSE, \";\n            } else if (ba[z] == ba[z - 1]) {\n                u = 17;\n                hs = \"FOUR\";\n                is = \" \";\n            } else {\n                u = 16;\n                hs = \"FULL H\";\n                is = \"OUSE. \";\n            }\n        }\n    }\n    if (x == 0) {\n        if (ba[n] + 3 == ba[n + 3]) {\n            x = 1111;\n            u = 10;\n        }\n        if (ba[n + 1] + 3 == ba[n + 4]) {\n            if (u == 10) {\n                u = 14;\n                hs = \"STRAIG\";\n                is = \"HT\";\n                x = 11111;\n                d = aa[n + 4];\n                return;\n            }\n            u = 10;\n            x = 11110;\n        }\n    }\n    if (u < 10) {\n        d = aa[n + 4];\n        hs = \"SCHMAL\";\n        is = \"TZ, \";\n        u = 9;\n        x = 11000;\n        i = 6;\n        return;\n    }\n    if (u == 10) {\n        if (i == 1)\n            i = 6;\n        return;\n    }\n    if (u > 12)\n        return;\n    if (fnb(d) > 6)\n        return;\n    i = 6;\n}\n\nfunction get_prompt(question, def)\n{\n    var str;\n\n    str = window.prompt(question, def);\n    print(question + \"? \" + str + \"\\n\");\n    return str;\n}\n\nfunction player_low_in_money()\n{\n    print(\"\\n\");\n    print(\"YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.\\n\");\n    str = \"N\";\n    if (o % 2 != 0) {\n        str = get_prompt(\"WOULD YOU LIKE TO SELL YOUR WATCH\", \"YES\");\n        if (str.substr(0, 1) != \"N\") {\n            if (fna(0) < 7) {\n                print(\"I'LL GIVE YOU $75 FOR IT.\\n\");\n                s += 75;\n            } else {\n                print(\"THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.\\n\");\n                s += 25;\n            }\n            o *= 2;\n        }\n    }\n    if (o % 3 == 0 && str.substr(0, 1) == \"N\") {\n        str = get_prompt(\"WILL YOU PART WITH THAT DIAMOND TIE TACK\", \"YES\");\n        if (str.substr(0, 1) != \"N\") {\n            if (fna(0) < 6) {\n                print(\"YOU ARE NOW $100 RICHER.\\n\");\n                s += 100;\n            } else {\n                print(\"IT'S PASTE.  $25.\\n\");\n                s += 25;\n            }\n            o *= 3;\n        }\n    }\n    if (str.substr(0,1) == \"N\") {\n        print(\"YOUR WAD IS SHOT.  SO LONG, SUCKER!\\n\");\n        return true;\n    }\n    return false;\n}\n\nfunction computer_low_in_money()\n{\n    if (c - g - v >= 0)\n        return false;\n    if (g == 0) {\n        v = c;\n        return false;\n    }\n    if (c - g < 0) {\n        print(\"I'LL SEE YOU.\\n\");\n        k = g;\n        s = s - g;\n        c = c - k;\n        p = p + g + k;\n        return false;\n    }\n    js = \"N\";\n    if (o % 2 == 0) {\n        js = get_prompt(\"WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50\", \"YES\");\n        if (js.substr(0, 1) != \"N\") {\n            c += 50;\n            o /= 2;\n        }\n    }\n    if (js.substr(0, 1) == \"N\" && o % 3 == 0) {\n        js = get_prompt(\"WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50\", \"YES\");\n        if (js.substr(0, 1) != \"N\") {\n            c += 50;\n            o /= 3;\n        }\n    }\n    if (js.substr(0, 1) == \"N\") {\n        print(\"I'M BUSTED.  CONGRATULATIONS!\\n\");\n        return true;\n    }\n    return false;\n}\n\nfunction ask_for_bet()\n{\n    var forced;\n\n    if (t != Math.floor(t)) {\n        if (k != 0 || g != 0 || t != 0.5) {\n            print(\"NO SMALL CHANGE, PLEASE.\\n\");\n            return 0;\n        }\n        return 1;\n    }\n    if (s - g - t < 0) {\n        if (player_low_in_money())\n            return 2;\n        return 0;\n    }\n    if (t == 0) {\n        i = 3;\n    } else if (g + t < k) {\n        print(\"IF YOU CAN'T SEE MY BET, THEN FOLD.\\n\");\n        return 0;\n    } else {\n        g += t;\n        if (g != k) {\n            forced = false;\n            if (z != 1) {\n                if (g <= 3 * z)\n                    forced = true;\n            } else {\n                if (g <= 5) {\n                    if (z < 2) {\n                        v = 5;\n                        if (g <= 3 * z)\n                            forced = true;\n                    }\n                } else {\n                    if (z == 1 || t > 25) {\n                        i = 4;\n                        print(\"I FOLD.\\n\");\n                        return 1;\n                    }\n                }\n            }\n            if (forced || z == 2) {\n                v = g - k + fna(0);\n                if (computer_low_in_money())\n                    return 2;\n                print(\"I'LL SEE YOU, AND RAISE YOU \" + v + \"\\n\");\n                k = g + v;\n                return 0;\n            }\n            print(\"I'LL SEE YOU.\\n\");\n            k = g;\n        }\n    }\n    s -= g;\n    c -= k;\n    p += g + k;\n    return 1;\n}\n\nfunction check_for_win(type)\n{\n    if (type == 0 && i == 3 || type == 1) {\n        print(\"\\n\");\n        print(\"I WIN.\\n\");\n        c += p;\n    } else if (type == 0 && i == 4 || type == 2) {\n        print(\"\\n\");\n        print(\"YOU WIN.\\n\");\n        s += p;\n    } else {\n        return 0;\n    }\n    print(\"NOW I HAVE $\" + c + \" AND YOU HAVE $\" + s + \"\\n\");\n    return 1;\n}\n\nfunction show_hand()\n{\n    print(hs + is);\n    if (hs == \"A FLUS\") {\n        k = Math.floor(k / 100);\n        print(\"\\n\");\n        show_suit();\n        print(\"\\n\");\n    } else {\n        k = fnb(k);\n        show_number();\n        if (hs == \"SCHMAL\" || hs == \"STRAIG\")\n            print(\" HIGH\\n\");\n        else\n            print(\"'S\\n\");\n    }\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"POKER\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"WELCOME TO THE CASINO.  WE EACH HAVE $200.\\n\");\n    print(\"I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.\\n\");\n    print(\"TO FOLD BET 0; TO CHECK BET .5.\\n\");\n    print(\"ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.\\n\");\n    print(\"\\n\");\n    o = 1;\n    c = 200;\n    s = 200;\n    z = 0;\n    while (1) {\n        p = 0;\n        //\n        print(\"\\n\");\n        if (c <= 5) {\n            im_busted();\n            return;\n        }\n        print(\"THE ANTE IS $5, I WILL DEAL:\\n\");\n        print(\"\\n\");\n        if (s <= 5) {\n            if (player_low_in_money())\n                return;\n        }\n        p += 10;\n        s -= 5;\n        c -= 5;\n        for (z = 1; z <= 10; z++)\n            deal_card();\n        print(\"YOUR HAND:\\n\");\n        n = 1;\n        show_cards();\n        n = 6;\n        i = 2;\n        evaluate_hand();\n        print(\"\\n\");\n        first = true;\n        if (i == 6) {\n            if (fna(0) > 7) {\n                x = 11100;\n                i = 7;\n                z = 23;\n            } else if (fna(0) > 7) {\n                x = 11110;\n                i = 7;\n                z = 23;\n            } else if (fna(0) < 2) {\n                x = 11111;\n                i = 7;\n                z = 23;\n            } else {\n                z = 1;\n                k = 0;\n                print(\"I CHECK.\\n\");\n                first = false;\n            }\n        } else {\n            if (u < 13) {\n                if (fna(0) < 2) {\n                    i = 7;\n                    z = 23;\n                } else {\n                    z = 0;\n                    k = 0;\n                    print(\"I CHECK.\\n\");\n                    first = false;\n                }\n            } else if (u > 16) {\n                z = 2;\n                if (fna(0) < 1)\n                    z = 35;\n            } else {\n                z = 35;\n            }\n        }\n        if (first) {\n            v = z + fna(0);\n            g = 0;\n            if (computer_low_in_money())\n                return;\n            print(\"I'LL OPEN WITH $\" + v + \"\\n\");\n            k = v;\n        }\n        g = 0;\n        do {\n            print(\"\\nWHAT IS YOUR BET\");\n            t = parseFloat(await input());\n            status = ask_for_bet();\n        } while (status == 0) ;\n        if (status == 2)\n            return;\n        status = check_for_win(0);\n        if (status == 1) {\n            while (1) {\n                print(\"DO YOU WISH TO CONTINUE\");\n                hs = await input();\n                if (hs == \"YES\") {\n                    status = 1;\n                    break;\n                }\n                if (hs == \"NO\") {\n                    status = 2;\n                    break;\n                }\n                print(\"ANSWER YES OR NO, PLEASE.\\n\");\n            }\n        }\n        if (status == 2)\n            return;\n        if (status == 1) {\n            p = 0;\n            continue;\n        }\n        print(\"\\n\");\n        print(\"NOW WE DRAW -- HOW MANY CARDS DO YOU WANT\");\n        while (1) {\n            t = parseInt(await input());\n            if (t != 0) {\n                z = 10;\n                if (t >= 4) {\n                    print(\"YOU CAN'T DRAW MORE THAN THREE CARDS.\\n\");\n                    continue;\n                }\n                print(\"WHAT ARE THEIR NUMBERS:\\n\");\n                for (q = 1; q <= t; q++) {\n                    u = parseInt(await input());\n                    z++;\n                    deal_card();\n                }\n                print(\"YOUR NEW HAND:\\n\");\n                n = 1;\n                show_cards();\n            }\n            break;\n        }\n        z = 10 + t;\n        for (u = 6; u <= 10; u++) {\n            if (Math.floor(x / Math.pow(10, u - 6)) != 10 * Math.floor(x / Math.pow(10, u - 5)))\n                break;\n            z++;\n            deal_card();\n        }\n        print(\"\\n\");\n        print(\"I AM TAKING \" + (z - 10 - t) + \" CARD\");\n        if (z != 11 + t) {\n            print(\"S\");\n        }\n        print(\"\\n\");\n        n = 6;\n        v = i;\n        i = 1;\n        evaluate_hand();\n        b = u;\n        m = d;\n        if (v == 7) {\n            z = 28;\n        } else if (i == 6) {\n            z = 1;\n        } else {\n            if (u < 13) {\n                z = 2;\n                if (fna(0) == 6)\n                    z = 19;\n            } else if (u < 16) {\n                z = 19;\n                if (fna(0) == 8)\n                    z = 11;\n            } else {\n                z = 2;\n            }\n        }\n        k = 0;\n        g = 0;\n        do {\n            print(\"\\nWHAT IS YOUR BET\");\n            t = parseFloat(await input());\n            status = ask_for_bet();\n        } while (status == 0) ;\n        if (status == 2)\n            return;\n        if (t == 0.5) {\n            if (v != 7 && i == 6) {\n                print(\"I'LL CHECK\\n\");\n            } else {\n                v = z + fna(0);\n                if (computer_low_in_money())\n                    return;\n                print(\"I'LL BET $\" + v + \"\\n\");\n                k = v;\n                do {\n                    print(\"\\nWHAT IS YOUR BET\");\n                    t = parseFloat(await input());\n                    status = ask_for_bet();\n                } while (status == 0) ;\n                if (status == 2)\n                    return;\n                status = check_for_win(0);\n                if (status == 1) {\n                    while (1) {\n                        print(\"DO YOU WISH TO CONTINUE\");\n                        hs = await input();\n                        if (hs == \"YES\") {\n                            status = 1;\n                            break;\n                        }\n                        if (hs == \"NO\") {\n                            status = 2;\n                            break;\n                        }\n                        print(\"ANSWER YES OR NO, PLEASE.\\n\");\n                    }\n                }\n                if (status == 2)\n                    return;\n                if (status == 1) {\n                    p = 0;\n                    continue;\n                }\n            }\n        } else {\n            status = check_for_win(0);\n            if (status == 1) {\n                while (1) {\n                    print(\"DO YOU WISH TO CONTINUE\");\n                    hs = await input();\n                    if (hs == \"YES\") {\n                        status = 1;\n                        break;\n                    }\n                    if (hs == \"NO\") {\n                        status = 2;\n                        break;\n                    }\n                    print(\"ANSWER YES OR NO, PLEASE.\\n\");\n                }\n            }\n            if (status == 2)\n                return;\n            if (status == 1) {\n                p = 0;\n                continue;\n            }\n        }\n        print(\"\\n\");\n        print(\"NOW WE COMPARE HANDS:\\n\");\n        js = hs;\n        ks = is;\n        print(\"MY HAND:\\n\");\n        n = 6;\n        show_cards();\n        n = 1;\n        evaluate_hand();\n        print(\"\\n\");\n        print(\"YOU HAVE \");\n        k = d;\n        show_hand();\n        hs = js;\n        is = ks;\n        k = m;\n        print(\"AND I HAVE \");\n        show_hand();\n        status = 0;\n        if (b > u) {\n            status = 1;\n        } else if (u > b) {\n            status = 2;\n        } else {\n            if (hs != \"A FLUS\") {\n                if (fnb(m) < fnb(d))\n                    status = 2;\n                else if (fnb(m) > fnb(d))\n                    status = 1;\n            } else {\n                if (fnb(m) > fnb(d))\n                    status = 1;\n                else if (fnb(d) > fnb(m))\n                    status = 2;\n            }\n            if (status == 0) {\n                print(\"THE HAND IS DRAWN.\\n\");\n                print(\"ALL $\" + p + \" REMAINS IN THE POT.\\n\");\n                continue;\n            }\n        }\n        status = check_for_win(status);\n        if (status == 1) {\n            while (1) {\n                print(\"DO YOU WISH TO CONTINUE\");\n                hs = await input();\n                if (hs == \"YES\") {\n                    status = 1;\n                    break;\n                }\n                if (hs == \"NO\") {\n                    status = 2;\n                    break;\n                }\n                print(\"ANSWER YES OR NO, PLEASE.\\n\");\n            }\n        }\n        if (status == 2)\n            return;\n        if (status == 1) {\n            p = 0;\n            continue;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "71_Poker/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "71_Poker/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "71_Poker/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "71_Poker/poker.bas",
    "content": "2 PRINT TAB(33);\"POKER\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 DIM A(50),B(15)\n20 DEF FNA(X)=INT(10*RND(1))\n30 DEF FNB(X)=X-100*INT(X/100)\n40 PRINT \"WELCOME TO THE CASINO.  WE EACH HAVE $200.\"\n50 PRINT \"I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.\"\n60 PRINT \"TO FOLD BET 0; TO CHECK BET .5.\"\n70 PRINT \"ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.\"\n80 PRINT\n90 LET O=1\n100 LET C=200\n110 LET S=200\n120 LET P=0\n130 REM\n140 PRINT\n150 IF C<=5 THEN 3670\n160 PRINT \"THE ANTE IS $5.  I WILL DEAL:\"\n170 PRINT\n180 IF S>5 THEN 200\n190 GOSUB 3830\n200 LET P=P+10\n210 LET S=S-5\n220 LET C=C-5\n230 FOR Z=1 TO 10\n240 GOSUB 1740\n250 NEXT Z\n260 PRINT \"YOUR HAND:\"\n270 N=1\n280 GOSUB 1850\n290 N=6\n300 I=2\n310 GOSUB 2170\n320 PRINT\n330 IF I<>6 THEN 470\n340 IF FNA(0)<=7 THEN 370\n350 LET X=11100\n360 GOTO 420\n370 IF FNA(0)<=7 THEN 400\n380 LET X=11110\n390 GOTO 420\n400 IF FNA(0)>=1 THEN 450\n410 X=11111\n420 I=7\n430 Z=23\n440 GOTO 580\n450 Z=1\n460 GOTO 510\n470 IF U>=13 THEN 540\n480 IF FNA(0)>=2 THEN 500\n490 GOTO 420\n500 Z=0\n510 K=0\n520 PRINT \"I CHECK.\"\n530 GOTO 620\n540 IF U<=16 THEN 570\n550 Z=2\n560 IF FNA(0)>=1 THEN 580\n570 Z=35\n580 V=Z+FNA(0)\n590 GOSUB 3480\n600 PRINT \"I'LL OPEN WITH $\"V\n610 K=V\n620 GOSUB 3050\n630 GOSUB 650\n640 GOTO 820\n650 IF I<>3 THEN 760\n660 PRINT\n670 PRINT \"I WIN.\"\n680 C=C+P\n690 PRINT \"NOW I HAVE $\"C\"AND YOU HAVE $\"S\n700 PRINT \"DO YOU WISH TO CONTINUE\";\n710 INPUT H$\n720 IF H$=\"YES\" THEN 120\n730 IF H$=\"NO\" THEN 4100\n740 PRINT \"ANSWER YES OR NO, PLEASE.\"\n750 GOTO 700\n760 IF I<>4 THEN 810\n770 PRINT\n780 PRINT \"YOU WIN.\"\n790 S=S+P\n800 GOTO 690\n810 RETURN\n820 PRINT\n830 PRINT \"NOW WE DRAW -- HOW MANY CARDS DO YOU WANT\";\n840 INPUT T\n850 IF T=0 THEN 980\n860 Z=10\n870 IF T<4 THEN 900\n880 PRINT \"YOU CAN'T DRAW MORE THAN THREE CARDS.\"\n890 GOTO 840\n900 PRINT \"WHAT ARE THEIR NUMBERS:\"\n910 FOR Q=1 TO T\n920 INPUT U\n930 GOSUB 1730\n940 NEXT Q\n950 PRINT \"YOUR NEW HAND:\"\n960 N=1\n970 GOSUB 1850\n980 Z=10+T\n990 FOR U=6 TO 10\n1000 IF INT(X/10^(U-6))<>10*INT(X/10^(U-5)) THEN 1020\n1010 GOSUB 1730\n1020 NEXT U\n1030 PRINT\n1040 PRINT \"I AM TAKING\"Z-10-T\"CARD\";\n1050 IF Z=11+T THEN 1090\n1060 PRINT \"S\"\n1070 PRINT\n1080 GOTO 1100\n1090 PRINT\n1100 N=6\n1110 V=I\n1120 I=1\n1130 GOSUB 2170\n1140 B=U\n1150 M=D\n1160 IF V<>7 THEN 1190\n1170 Z=28\n1180 GOTO 1330\n1190 IF I<>6 THEN 1220\n1200 Z=1\n1210 GOTO 1330\n1220 IF U>=13 THEN 1270\n1230 Z=2\n1240 IF FNA(0)<>6 THEN 1260\n1250 Z=19\n1260 GOTO 1330\n1270 IF U>=16 THEN 1320\n1280 Z=19\n1290 IF FNA(0)<>8 THEN 1310\n1300 Z=11\n1310 GOTO 1330\n1320 Z=2\n1330 K=0\n1340 GOSUB 3050\n1350 IF T<>.5 THEN 1450\n1360 IF V=7 THEN 1400\n1370 IF I<>6 THEN 1400\n1380 PRINT \"I'LL CHECK\"\n1390 GOTO 1460\n1400 V=Z+FNA(0)\n1410 GOSUB 3480\n1420 PRINT \"I'LL BET $\"V\n1430 K=V\n1440 GOSUB 3060\n1450 GOSUB 650\n1460 PRINT\n1470 PRINT \"NOW WE COMPARE HANDS:\"\n1480 J$=H$\n1490 K$=I$\n1500 PRINT \"MY HAND:\"\n1510 N=6\n1520 GOSUB 1850\n1530 N=1\n1540 GOSUB 2170\n1550 PRINT\n1560 PRINT \"YOU HAVE \";\n1570 K=D\n1580 GOSUB 3690\n1590 H$=J$\n1600 I$=K$\n1610 K=M\n1620 PRINT \"AND I HAVE \";\n1630 GOSUB 3690\n1640 IF B>U THEN 670\n1650 IF U>B THEN 780\n1660 IF H$=\"A FLUS\" THEN 1700\n1662 IF FNB(M)<FNB(D) THEN 780\n1664 IF FNB(M)>FNB(D) THEN 670\n1670 PRINT \"THE HAND IS DRAWN.\"\n1680 PRINT \"ALL $\"P\"REMAINS IN THE POT.\"\n1690 GOTO 140\n1700 IF FNB(M)>FNB(D) THEN 670\n1710 IF FNB(D)>FNB(M) THEN 780\n1720 GOTO 1670\n1730 Z=Z+1\n1740 A(Z)=100*INT(4*RND(1))+INT(100*RND(1))\n1750 IF INT(A(Z)/100)>3 THEN 1740\n1760 IF A(Z)-100*INT(A(Z)/100)>12 THEN 1740\n1765 IF Z=1 THEN 1840\n1770 FOR K=1 TO Z-1\n1780 IF A(Z)=A(K) THEN 1740\n1790 NEXT K\n1800 IF Z<=10 THEN 1840\n1810 N=A(U)\n1820 A(U)=A(Z)\n1830 A(Z)=N\n1840 RETURN\n1850 FOR Z=N TO N+4\n1860 PRINT Z\"--  \";\n1870 GOSUB 1950\n1880 PRINT \" OF\";\n1890 GOSUB 2070\n1900 IF Z/2<>INT(Z/2) THEN 1920\n1910 PRINT\n1920 NEXT Z\n1930 PRINT\n1940 RETURN\n1950 K=FNB(A(Z))\n1960 IF K<>9 THEN 1980\n1970 PRINT \"JACK\";\n1980 IF K<>10 THEN 2000\n1990 PRINT \"QUEEN\";\n2000 IF K<>11 THEN 2020\n2010 PRINT \"KING\";\n2020 IF K<>12 THEN 2040\n2030 PRINT \"ACE\";\n2040 IF K>=9 THEN 2060\n2050 PRINT K+2;\n2060 RETURN\n2070 K=INT(A(Z)/100)\n2080 IF K<>0 THEN 2100\n2090 PRINT \" CLUBS\",\n2100 IF K<>1 THEN 2120\n2110 PRINT \" DIAMONDS\",\n2120 IF K<>2 THEN 2140\n2130 PRINT \" HEARTS\",\n2140 IF K<>3 THEN 2160\n2150 PRINT \" SPADES\",\n2160 RETURN\n2170 U=0\n2180 FOR Z=N TO N+4\n2190 B(Z)=FNB(A(Z))\n2200 IF Z=N+4 THEN 2230\n2210 IF INT(A(Z)/100)<>INT(A(Z+1)/100) THEN 2230\n2220 U=U+1\n2230 NEXT Z\n2240 IF U<>4 THEN 2310\n2250 X=11111\n2260 D=A(N)\n2270 H$=\"A FLUS\"\n2280 I$=\"H IN\"\n2290 U=15\n2300 RETURN\n2310 FOR Z=N TO N+3\n2320 FOR K=Z+1 TO N+4\n2330 IF B(Z)<=B(K) THEN 2390\n2340 X=A(Z)\n2350 A(Z)=A(K)\n2360 B(Z)=B(K)\n2370 A(K)=X\n2380 B(K)=A(K)-100*INT(A(K)/100)\n2390 NEXT K\n2400 NEXT Z\n2410 X=0\n2420 FOR Z=N TO N+3\n2430 IF B(Z)<>B(Z+1) THEN 2470\n2440 X=X+11*10^(Z-N)\n2450 D=A(Z)\n2460 GOSUB 2760\n2470 NEXT Z\n2480 IF X<>0 THEN 2620\n2490 IF B(N)+3<>B(N+3) THEN 2520\n2500 X=1111\n2510 U=10\n2520 IF B(N+1)+3<>B(N+4) THEN 2620\n2530 IF U<>10 THEN 2600\n2540 U=14\n2550 H$=\"STRAIG\"\n2560 I$=\"HT\"\n2570 X=11111\n2580 D=A(N+4)\n2590 RETURN\n2600 U=10\n2610 X=11110\n2620 IF U>=10 THEN 2690\n2630 D=A(N+4)\n2640 H$=\"SCHMAL\"\n2650 I$=\"TZ, \"\n2660 U=9\n2670 X=11000\n2680 GOTO 2740\n2690 IF U<>10 THEN 2720\n2700 IF I=1 THEN 2740\n2710 GOTO 2750\n2720 IF U>12 THEN 2750\n2730 IF FNB(D)>6 THEN 2750\n2740 I=6\n2750 RETURN\n2760 IF U>=11 THEN 2810\n2770 U=11\n2780 H$=\"A PAIR\"\n2790 I$=\" OF \"\n2800 RETURN\n2810 IF U<>11 THEN 2910\n2820 IF B(Z)<>B(Z-1) THEN 2870\n2830 H$=\"THREE\"\n2840 I$=\" \"\n2850 U=13\n2860 RETURN\n2870 H$=\"TWO P\"\n2880 I$=\"AIR, \"\n2890 U=12\n2900 RETURN\n2910 IF U>12 THEN 2960\n2920 U=16\n2930 H$=\"FULL H\"\n2940 I$=\"OUSE, \"\n2950 RETURN\n2960 IF B(Z)<>B(Z-1) THEN 3010\n2970 U=17\n2980 H$=\"FOUR\"\n2990 I$=\" \"\n3000 RETURN\n3010 U=16\n3020 H$=\"FULL H\"\n3030 I$=\"OUSE, \"\n3040 RETURN\n3050 G=0\n3060 PRINT:PRINT \"WHAT IS YOUR BET\";\n3070 INPUT T\n3080 IF T-INT(T)=0 THEN 3140\n3090 IF K<>0 THEN 3120\n3100 IF G<>0 THEN 3120\n3110 IF T=.5 THEN 3410\n3120 PRINT \"NO SMALL CHANGE, PLEASE.\"\n3130 GOTO 3060\n3140 IF S-G-T>=0 THEN 3170\n3150 GOSUB 3830\n3160 GOTO 3060\n3170 IF T<>0 THEN 3200\n3180 I=3\n3190 GOTO 3380\n3200 IF G+T>=K THEN 3230\n3210 PRINT \"IF YOU CAN'T SEE MY BET, THEN FOLD.\"\n3220 GOTO 3060\n3230 G=G+T\n3240 IF G=K THEN 3380\n3250 IF Z<>1 THEN 3420\n3260 IF G>5 THEN 3300\n3270 IF Z>=2 THEN 3350\n3280 V=5\n3290 GOTO 3420\n3300 IF Z=1 THEN 3320\n3310 IF T<=25 THEN 3350\n3320 I=4\n3330 PRINT \"I FOLD.\"\n3340 RETURN\n3350 IF Z=2 THEN 3430\n3360 PRINT \"I'LL SEE YOU.\"\n3370 K=G\n3380 S=S-G\n3390 C=C-K\n3400 P=P+G+K\n3410 RETURN\n3420 IF G>3*Z THEN 3350\n3430 V=G-K+FNA(0)\n3440 GOSUB 3480\n3450 PRINT \"I'LL SEE YOU, AND RAISE YOU\"V\n3460 K=G+V\n3470 GOTO 3060\n3480 IF C-G-V>=0 THEN 3660\n3490 IF G<>0 THEN 3520\n3500 V=C\n3510 RETURN\n3520 IF C-G>=0 THEN 3360\n3530 IF (O/2)<>INT(O/2) THEN 3600\n3540 PRINT \"WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50\";\n3550 INPUT J$\n3560 IF LEFT$(J$,1)=\"N\" THEN 3600\n3570 C=C+50\n3580 O=O/2\n3590 RETURN\n3600 IF O/3<>INT(O/3) THEN 3670\n3610 PRINT \"WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50\";\n3620 INPUT J$\n3630 IF LEFT$(J$,1)=\"N\" THEN 3670\n3640 C=C+50\n3650 O=O/3\n3660 RETURN\n3670 PRINT \"I'M BUSTED.  CONGRATULATIONS!\"\n3680 STOP\n3690 PRINT H$;I$;\n3700 IF H$<>\"A FLUS\" THEN 3750\n3710 K=INT(K/100)\n3720 GOSUB 2080\n3730 PRINT\n3740 RETURN\n3750 K=FNB(K)\n3760 GOSUB 1960\n3770 IF H$=\"SCHMAL\" THEN 3790\n3780 IF H$<>\"STRAIG\" THEN 3810\n3790 PRINT \" HIGH\"\n3800 RETURN\n3810 PRINT \"'S\"\n3820 RETURN\n3830 PRINT\n3840 PRINT \"YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.\"\n3850 IF O/2=INT(O/2) THEN 3970\n3860 PRINT \"WOULD YOU LIKE TO SELL YOUR WATCH\";\n3870 INPUT J$\n3880 IF LEFT$(J$,1)=\"N\" THEN 3970\n3890 IF FNA(0)>=7 THEN 3930\n3900 PRINT \"I'LL GIVE YOU $75 FOR IT.\"\n3910 S=S+75\n3920 GOTO 3950\n3930 PRINT \"THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.\"\n3940 S=S+25\n3950 O=O*2\n3960 RETURN\n3970 IF O/3<>INT(O/3) THEN 4090\n3980 PRINT \"WILL YOU PART WITH THAT DIAMOND TIE TACK\":\n3990 INPUT J$\n4000 IF LEFT$(J$,1)=\"N\" THEN 4080\n4010 IF FNA(0)>=6 THEN 4050\n4020 PRINT \"YOU ARE NOW $100 RICHER.\"\n4030 S=S+100\n4040 GOTO 4070\n4050 PRINT \"IT'S PASTE.  $25.\"\n4060 S=S+25\n4070 O=O*3\n4080 RETURN\n4090 PRINT \"YOUR WAD IS SHOT.  SO LONG, SUCKER!\"\n4100 END\n"
  },
  {
    "path": "71_Poker/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "71_Poker/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "71_Poker/vbnet/Poker.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Poker\", \"Poker.vbproj\", \"{107C29F8-C499-4E4A-B162-324CA17AA57F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{107C29F8-C499-4E4A-B162-324CA17AA57F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{107C29F8-C499-4E4A-B162-324CA17AA57F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{107C29F8-C499-4E4A-B162-324CA17AA57F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{107C29F8-C499-4E4A-B162-324CA17AA57F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "71_Poker/vbnet/Poker.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Poker</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "71_Poker/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "72_Queen/README.md",
    "content": "### Queen\n\nThis game is based on the permissible moves of the chess queen — i.e., along any vertical, horizontal, or diagonal. In this game, the queen can only move to the left, down, and diagonally down to the left.\n\nThe object of the game is to place the queen (one only) in the lower left-hand square (no. 158), by alternating moves between you and the computer. The one to place the queen there wins.\n\nYou go first and place the queen in any one of the squares on the top row or the right-hand column. That is your first move. The computer is beatable, but it takes some figuring. See if you can devise a winning strategy.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=133)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=148)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "72_Queen/csharp/Computer.cs",
    "content": "namespace Queen;\n\ninternal class Computer\n{\n    private static readonly HashSet<Position> _randomiseFrom = new() { 41, 44, 73, 75, 126, 127 };\n    private static readonly HashSet<Position> _desirable = new() { 73, 75, 126, 127, 158 };\n    private readonly IRandom _random;\n\n    public Computer(IRandom random)\n    {\n        _random = random;\n    }\n\n    public Position GetMove(Position from)\n        => from + (_randomiseFrom.Contains(from) ? _random.NextMove() : FindMove(from));\n\n    private Move FindMove(Position from)\n    {\n        for (int i = 7; i > 0; i--)\n        {\n            if (IsOptimal(Move.Left, out var move)) { return move; }\n            if (IsOptimal(Move.Down, out move)) { return move; }\n            if (IsOptimal(Move.DownLeft, out move)) { return move; }\n\n            bool IsOptimal(Move direction, out Move move)\n            {\n                move = direction * i;\n                return _desirable.Contains(from + move);\n            }\n        }\n\n        return _random.NextMove();\n    }\n}\n"
  },
  {
    "path": "72_Queen/csharp/Game.cs",
    "content": "namespace Queen;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    private readonly Computer _computer;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n        _computer = new Computer(random);\n    }\n\n    internal void PlaySeries()\n    {\n        _io.Write(Streams.Title);\n        if (_io.ReadYesNo(Prompts.Instructions)) { _io.Write(Streams.Instructions); }\n\n        while (true)\n        {\n            var result = PlayGame();\n            _io.Write(result switch\n            {\n                Result.HumanForfeits => Streams.Forfeit,\n                Result.HumanWins => Streams.Congratulations,\n                Result.ComputerWins => Streams.IWin,\n                _ => throw new InvalidOperationException($\"Unexpected result {result}\")\n            });\n\n            if (!_io.ReadYesNo(Prompts.Anyone)) { break; }\n        }\n\n        _io.Write(Streams.Thanks);\n    }\n\n    private Result PlayGame()\n    {\n        _io.Write(Streams.Board);\n        var humanPosition = _io.ReadPosition(Prompts.Start, p => p.IsStart, Streams.IllegalStart, repeatPrompt: true);\n        if (humanPosition.IsZero) { return Result.HumanForfeits; }\n\n        while (true)\n        {\n            var computerPosition = _computer.GetMove(humanPosition);\n            _io.Write(Strings.ComputerMove(computerPosition));\n            if (computerPosition.IsEnd) { return Result.ComputerWins; }\n\n            humanPosition = _io.ReadPosition(Prompts.Move, p => (p - computerPosition).IsValid, Streams.IllegalMove);\n            if (humanPosition.IsZero) { return Result.HumanForfeits; }\n            if (humanPosition.IsEnd) { return Result.HumanWins; }\n        }\n    }\n\n    private enum Result { ComputerWins, HumanWins, HumanForfeits };\n}\n"
  },
  {
    "path": "72_Queen/csharp/IOExtensions.cs",
    "content": "namespace Queen;\n\ninternal static class IOExtensions\n{\n    internal static bool ReadYesNo(this IReadWrite io, string prompt)\n    {\n        while (true)\n        {\n            var answer = io.ReadString(prompt).ToLower();\n            if (answer == \"yes\") { return true; }\n            if (answer == \"no\") { return false; }\n\n            io.Write(Streams.YesOrNo);\n        }\n    }\n\n    internal static Position ReadPosition(\n        this IReadWrite io,\n        string prompt,\n        Predicate<Position> isValid,\n        Stream error,\n        bool repeatPrompt = false)\n    {\n        while (true)\n        {\n            var response = io.ReadNumber(prompt);\n            var number = (int)response;\n            var position = new Position(number);\n            if (number == response && (position.IsZero || isValid(position)))\n            {\n                return position;\n            }\n\n            io.Write(error);\n            if (!repeatPrompt) { prompt = \"\"; }\n        }\n    }\n}\n"
  },
  {
    "path": "72_Queen/csharp/Move.cs",
    "content": "namespace Queen;\n\ninternal record struct Move(int Diagonal, int Row)\n{\n    public static readonly Move Left = new(1, 0);\n    public static readonly Move DownLeft = new(2, 1);\n    public static readonly Move Down = new(1, 1);\n\n    public bool IsValid => Diagonal > 0 && (IsLeft || IsDown || IsDownLeft);\n    private bool IsLeft => Row == 0;\n    private bool IsDown => Row == Diagonal;\n    private bool IsDownLeft => Row * 2 == Diagonal;\n\n    public static Move operator *(Move move, int scale) => new(move.Diagonal * scale, move.Row * scale);\n}"
  },
  {
    "path": "72_Queen/csharp/Position.cs",
    "content": "namespace Queen;\n\ninternal record struct Position(int Diagonal, int Row)\n{\n    public static readonly Position Zero = new(0);\n\n    public Position(int number)\n        : this(Diagonal: number / 10, Row: number % 10)\n    {\n    }\n\n    public bool IsZero => Row == 0 && Diagonal == 0;\n    public bool IsStart => Row == 1 || Row == Diagonal;\n    public bool IsEnd => Row == 8 && Diagonal == 15;\n\n    public override string ToString() => $\"{Diagonal}{Row}\";\n\n    public static implicit operator Position(int value) => new(value);\n\n    public static Position operator +(Position position, Move move)\n        => new(Diagonal: position.Diagonal + move.Diagonal, Row: position.Row + move.Row);\n    public static Move operator -(Position to, Position from)\n        => new(Diagonal: to.Diagonal - from.Diagonal, Row: to.Row - from.Row);\n}\n"
  },
  {
    "path": "72_Queen/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using static Queen.Resources.Resource;\n\nusing Queen;\n\nnew Game(new ConsoleIO(), new RandomNumberGenerator()).PlaySeries();"
  },
  {
    "path": "72_Queen/csharp/Queen.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "72_Queen/csharp/Queen.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Queen\", \"Queen.csproj\", \"{34BFC22A-4459-416E-B271-1E276689AC29}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{34BFC22A-4459-416E-B271-1E276689AC29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{34BFC22A-4459-416E-B271-1E276689AC29}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{34BFC22A-4459-416E-B271-1E276689AC29}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{34BFC22A-4459-416E-B271-1E276689AC29}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "72_Queen/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "72_Queen/csharp/RandomExtensions.cs",
    "content": "namespace Queen;\n\ninternal static class RandomExtensions\n{\n    internal static Move NextMove(this IRandom random)\n        => random.NextFloat() switch\n        {\n            > 0.6F => Move.Down,\n            > 0.3F => Move.DownLeft,\n            _ => Move.Left\n        };\n}\n"
  },
  {
    "path": "72_Queen/csharp/Resources/AnyonePrompt.txt",
    "content": "Anyone else care to try"
  },
  {
    "path": "72_Queen/csharp/Resources/Board.txt",
    "content": "\n \n 81  71  61  51  41  31  21  11\n\n\n 92  82  72  62  52  42  32  22\n\n\n 103  93  83  73  63  53  43  33\n\n\n 114  104  94  84  74  64  54  44\n\n\n 125  115  105  95  85  75  65  55\n\n\n 136  126  116  106  96  86  76  66\n\n\n 147  137  127  117  107  97  87  77\n\n\n 158  148  138  128  118  108  98  88\n\n\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/ComputerMove.txt",
    "content": "Computer moves to square {0}\n"
  },
  {
    "path": "72_Queen/csharp/Resources/Congratulations.txt",
    "content": "\nC O N G R A T U L A T I O N S . . .\n\nYou have won--very well played.\nIt looks like I have met my match.\nThanks for playing--I can't win all the time.\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/Forfeit.txt",
    "content": "\nIt looks like I have won by forfeit.\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/IWin.txt",
    "content": "\nNice try, but it looks like I have won.\nThanks for playing.\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/IllegalMove.txt",
    "content": "\nY O U   C H E A T . . .  Try again"
  },
  {
    "path": "72_Queen/csharp/Resources/IllegalStart.txt",
    "content": "Please read the instructions again.\nYou have begun illegally.\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/Instructions.txt",
    "content": "We are going to play a game based on one of the chess\nmoves.  Our queen will be able to move only to the left,\ndown, or diagonally down and to the left.\n\nThe object of the game is to place the queen in the lower\nleft hand square by alternating moves between you and the\ncomputer.  The first one to place the queen there wins.\n\nYou go first and place the queen in any one of the squares\non the top row or right hand column.\nThat will be your first move.\nWe alternate moves.\nYou may forfeit by typing '0' as your move.\nBe sure to press the return key after each response.\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/InstructionsPrompt.txt",
    "content": "Do you want instructions"
  },
  {
    "path": "72_Queen/csharp/Resources/MovePrompt.txt",
    "content": "What is your move"
  },
  {
    "path": "72_Queen/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Queen.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Title => GetStream();\n        public static Stream Instructions => GetStream();\n        public static Stream YesOrNo => GetStream();\n        public static Stream Board => GetStream();\n        public static Stream IllegalStart => GetStream();\n        public static Stream IllegalMove => GetStream();\n        public static Stream Forfeit => GetStream();\n        public static Stream IWin => GetStream();\n        public static Stream Congratulations => GetStream();\n        public static Stream Thanks => GetStream();\n    }\n\n    internal static class Prompts\n    {\n        public static string Instructions => GetPrompt();\n        public static string Start => GetPrompt();\n        public static string Move => GetPrompt();\n        public static string Anyone => GetPrompt();\n    }\n\n    internal static class Strings\n    {\n        public static string ComputerMove(Position position) => string.Format(GetString(), position);\n    }\n\n    private static string GetPrompt([CallerMemberName] string? name = null) => GetString($\"{name}Prompt\");\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "72_Queen/csharp/Resources/StartPrompt.txt",
    "content": "Where would you like to start"
  },
  {
    "path": "72_Queen/csharp/Resources/Thanks.txt",
    "content": "\n\nOk --- thanks again."
  },
  {
    "path": "72_Queen/csharp/Resources/Title.txt",
    "content": "                                  Queen\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "72_Queen/csharp/Resources/YesOrNo.txt",
    "content": "Please answer 'Yes' or 'No'.\n"
  },
  {
    "path": "72_Queen/java/Queen.java",
    "content": "import java.util.List;\nimport java.util.Optional;\nimport java.util.Scanner;\n\n/**\n * QUEEN\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class Queen {\n\n    public static final int WINNING_POSITION = 158;\n    public static final int FORFEIT_MOVE = 0;\n\n    // @formatter:off\n    private static final int[] S = {\n             81,  71,  61,  51,  41,  31, 21, 11,\n             92,  82,  72,  62,  52,  42, 32, 22,\n            103,  93,  83,  73,  63,  53, 43, 33,\n            114, 104,  94,  84,  74,  64, 54, 44,\n            125, 115, 105,  95,  85,  75, 65, 55,\n            136, 126, 116, 106,  96,  86, 76, 66,\n            147, 137, 127, 117, 107,  97, 87, 77,\n            158, 148, 138, 128, 118, 108, 98, 88\n    };\n    // @formatter:on\n\n    private static final Scanner scanner = new Scanner(System.in);\n\n\n    public static void main(String[] args) {\n        printWithTab(\"QUEEN\", 33);\n        printWithTab(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", 15);\n        System.out.println(\"\\n\\n\");\n\n        askAndShowInstructions();\n\n        boolean anotherGame;\n        do {\n            printBoard();\n\n            Move firstMove = getUserFirstMove();\n            if (firstMove.move == 0) {\n                printWonByForfeit();\n            }\n\n            if (isTopmostRowOrRightmostColumn(firstMove)) {\n                playOneGame(firstMove);\n            }\n\n            anotherGame = askForAnotherGame();\n\n        } while (anotherGame);\n\n\n        System.out.println(\"\\nOK --- THANKS AGAIN.\");\n    }\n\n    /**\n     * Play one game starting with the first move from the user\n     */\n    private static void playOneGame(Move firstMove) {\n        boolean gameInProgress = true;\n        Move userMove = firstMove;\n\n        while (gameInProgress) {\n\n            if (userMove.move == WINNING_POSITION) {\n                //players wins\n                printCongratulatoryMessage();\n                gameInProgress = false;\n            } else {\n\n                ComputerMove computerMove = getComputerMove(userMove);\n\n                System.out.printf(\"COMPUTER MOVES TO SQUARE %d\\n\", computerMove.move);\n\n                if (computerMove.move == WINNING_POSITION) {\n                    printComputerWins();\n                    gameInProgress = false;\n                } else {\n                    userMove = getValidUserMove(computerMove);\n\n                    if (userMove.move == FORFEIT_MOVE) {\n                        printWonByForfeit();\n                        gameInProgress = false;\n                    } else if (userMove.move == WINNING_POSITION) {\n                        printCongratulatoryMessage();\n                        gameInProgress = false;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Get the user's first move\n     */\n    private static Move getUserFirstMove() {\n        boolean validMove;\n        Move move;\n        do {\n            System.out.print(\"WHERE WOULD YOU LIKE TO START? \");\n            int movePosition = scanner.nextInt();\n            move = new Move(movePosition);\n            validMove = false;\n            if (!isTopmostRowOrRightmostColumn(move)) {\n                System.out.println(\"PLEASE READ THE DIRECTIONS AGAIN.\");\n                System.out.println(\"YOU HAVE BEGUN ILLEGALLY.\");\n                System.out.println();\n            } else {\n                validMove = true;\n            }\n            scanner.nextLine();\n        } while (!validMove);\n        return move;\n    }\n\n    /**\n     * Prompt and get a valid move from the user. Uses the computer's latest move to validate the next move.\n     */\n    private static Move getValidUserMove(ComputerMove latestComputerMove) {\n        boolean validUserMove = false;\n        Move userMove = null;\n        while (!validUserMove) {\n            userMove = getUserMove();\n            if (!validateUserMove(userMove, latestComputerMove)) {\n                System.out.println(\"\\nY O U   C H E A T . . .  TRY AGAIN\");\n            } else {\n                validUserMove = true;\n            }\n        }\n        return userMove;\n    }\n\n    private static void printWonByForfeit() {\n        System.out.println(\"\\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\\n\");\n    }\n\n    private static boolean validateUserMove(Move userMove, ComputerMove computerMove) {\n        if (userMove.move <= computerMove.move) {\n            return false;\n        }\n\n        if (userMove.move == FORFEIT_MOVE || userMove.move == WINNING_POSITION) {\n            return true;\n        }\n\n        int tensValueUser = userMove.move / 10;\n        int unitsValueUser = userMove.move - (tensValueUser * 10);\n        int unitsValueComputer = computerMove.u;\n        int tensValueComputer = computerMove.t;\n        int p = unitsValueUser - unitsValueComputer;\n        if (p != 0) {\n            if ((tensValueUser - tensValueComputer) != p) {\n                return (tensValueUser - tensValueComputer) == 2 * p;\n            } else {\n                return true;\n            }\n        } else {\n            int l = tensValueUser - tensValueComputer;\n            return l > 0;\n        }\n    }\n\n    private static Move getUserMove() {\n        System.out.print(\"WHAT IS YOUR MOVE? \");\n        int movePosition = scanner.nextInt();\n        scanner.nextLine();\n        return new Move(movePosition);\n    }\n\n    private static void printComputerWins() {\n        System.out.println(\"\\nNICE TRY, BUT IT LOOKS LIKE I HAVE WON.\");\n        System.out.println(\"THANKS FOR PLAYING.\\n\");\n    }\n\n    private static boolean askForAnotherGame() {\n        System.out.print(\"ANYONE ELSE CARE TO TRY? \");\n        do {\n            String response = Queen.scanner.nextLine();\n            if (response.equals(\"NO\")) {\n                return false;\n            } else if (response.equals(\"YES\")) {\n                return true;\n            } else {\n                System.out.println(\"PLEASE ANSWER 'YES' OR 'NO'.\");\n            }\n        } while (true);\n    }\n\n    private static boolean isTopmostRowOrRightmostColumn(Move move) {\n        return move.unitsPlaceValue == 1 || move.unitsPlaceValue == move.tensPlaceValue;\n    }\n\n    private static ComputerMove getComputerMove(Move userMove) {\n        int unitsValueUser = userMove.unitsPlaceValue;\n        int tensValueUser = userMove.tensPlaceValue;\n\n        List<Integer> moveRandomlyFromPositions = List.of(41, 44, 73, 75, 126, 127);\n\n        if (moveRandomlyFromPositions.contains(userMove.move)) {\n            //random move\n            return getMovePositionInRandomDirection(unitsValueUser, tensValueUser);\n        } else {\n\n            for (int k = 7; k >= 1; k--) {\n                // consider same row first, left-most position\n                Optional<ComputerMove> move = evaluatePositionAndGetMove(unitsValueUser, tensValueUser + k);\n                if (move.isPresent()) return move.get();\n\n                //try same column, bottom-most\n                move = evaluatePositionAndGetMove(unitsValueUser + k, tensValueUser + k);\n                if (move.isPresent()) return move.get();\n\n                //now left-most at the bottom-most\n                move = evaluatePositionAndGetMove(unitsValueUser + k, tensValueUser + k + k);\n                if (move.isPresent()) return move.get();\n            }\n\n            //else move one step in a random direction\n            return getMovePositionInRandomDirection(unitsValueUser, tensValueUser);\n        }\n\n    }\n\n    private static Optional<ComputerMove> evaluatePositionAndGetMove(int newUnitsValue, int newTensValue) {\n        EvaluationResult result = evaluateComputerMove(newUnitsValue, newTensValue);\n        if (result.favourablePosition) {\n            return Optional.of(new ComputerMove(result.move));\n        }\n        return Optional.empty();\n    }\n\n    private static EvaluationResult evaluateComputerMove(int u, int t) {\n        int m = 10 * t + u;\n        if (m == 158 || m == 127 || m == 126 || m == 75 || m == 73) {\n            return new EvaluationResult(m, true);\n        } else {\n            return new EvaluationResult(m, false);\n        }\n    }\n\n    private static void printCongratulatoryMessage() {\n        System.out.println();\n        System.out.println(\"C O N G R A T U L A T I O N S . . .\");\n        System.out.println();\n        System.out.println(\"YOU HAVE WON--VERY WELL PLAYED.\");\n        System.out.println(\"IT LOOKS LIKE I HAVE MET MY MATCH.\");\n        System.out.println(\"THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\");\n        System.out.println();\n\n    }\n\n    private static ComputerMove getMovePositionInRandomDirection(int u1, int t1) {\n        double randomValue = Math.random();\n\n        if (randomValue > 0.6) {\n            // Move directly down\n            return new ComputerMove(calculateMove(u1, t1, 1, 1));\n        } else if (randomValue > 0.3) {\n            // Move down left\n            return new ComputerMove(calculateMove(u1, t1, 1, 2));\n        } else {\n            // Move left\n            return new ComputerMove(calculateMove(u1, t1, 0, 1));\n        }\n    }\n\n    private static int calculateMove(int u, int t, int uChange, int tChange) {\n        int newU = u + uChange;\n        int newT = t + tChange;\n        return 10 * newT + newU; // Combine units and tens to corresponding position value\n    }\n\n\n    private static void printBoard() {\n        System.out.println();\n        for (int A = 0; A <= 7; A++) {\n            for (int B = 0; B <= 7; B++) {\n                int I = 8 * A + B;\n                System.out.printf(\" %d \", S[I]);\n            }\n            System.out.println();\n            System.out.println();\n            System.out.println();\n        }\n        System.out.println();\n    }\n\n    private static void askAndShowInstructions() {\n        do {\n            System.out.print(\"DO YOU WANT INSTRUCTIONS? \");\n            String wish = scanner.nextLine();\n            if (wish.equals(\"NO\")) {\n                break;\n            } else if (wish.equals(\"YES\")) {\n                showInstructions();\n                break;\n            } else {\n                System.out.println(\"PLEASE ANSWER 'YES' OR 'NO'.\");\n            }\n        } while (true);\n    }\n\n    private static void printWithTab(String message, int tab) {\n        for (int i = 0; i < tab; i++) {\n            System.out.print(\" \");\n        }\n        System.out.println(message);\n    }\n\n\n    private static void showInstructions() {\n        System.out.println(\"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\");\n        System.out.println(\"MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\");\n        System.out.println(\"DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\");\n        System.out.println();\n        System.out.println(\"THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\");\n        System.out.println(\"LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\");\n        System.out.println(\"COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\");\n        System.out.println();\n        System.out.println(\"YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\");\n        System.out.println(\"ON THE TOP ROW OR RIGHT HAND COLUMN.\");\n        System.out.println(\"THAT WILL BE YOUR FIRST MOVE.\");\n        System.out.println(\"WE ALTERNATE MOVES.\");\n        System.out.println(\"YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\");\n        System.out.println(\"BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\");\n        System.out.println();\n    }\n\n\n    private static class ComputerMove {\n        private final int move;\n        private final int u;\n        private final int t;\n\n        private ComputerMove(int move) {\n            this.move = move;\n            this.t = move / 10;\n            this.u = move - (t * 10);\n        }\n\n    }\n\n    private static class EvaluationResult {\n        private final int move;\n        private final boolean favourablePosition;\n\n        public EvaluationResult(int move, boolean favourablePosition) {\n            this.move = move;\n            this.favourablePosition = favourablePosition;\n        }\n\n\n    }\n\n    private static class Move {\n        private final int move;\n        private final int unitsPlaceValue;\n        private final int tensPlaceValue;\n\n        private Move(int move) {\n            this.move = move;\n            this.tensPlaceValue = move / 10;\n            this.unitsPlaceValue = move % 10;\n        }\n\n    }\n}\n"
  },
  {
    "path": "72_Queen/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "72_Queen/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "72_Queen/javascript/queen.html",
    "content": "<html>\n<head>\n<title>QUEEN</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"queen.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "72_Queen/javascript/queen.js",
    "content": "// QUEEN\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar sa = [,81,  71,  61,  51,  41,  31,  21,  11,\n           92,  82,  72,  62,  52,  42,  32,  22,\n          103,  93,  83,  73,  63,  53,  43,  33,\n          114, 104,  94,  84,  74,  64,  54,  44,\n          125, 115, 105,  95,  85,  75,  65,  55,\n          136, 126, 116, 106,  96,  86,  76,  66,\n          147, 137, 127, 117, 107,  97,  87,  77,\n          158, 148, 138, 128, 118, 108,  98,  88];\n\nvar m;\nvar m1;\nvar u;\nvar t;\nvar u1;\nvar t1;\n\nfunction show_instructions()\n{\n    print(\"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\\n\");\n    print(\"MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\\n\");\n    print(\"DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\\n\");\n    print(\"\\n\");\n    print(\"THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\\n\");\n    print(\"LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\\n\");\n    print(\"COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\\n\");\n    print(\"\\n\");\n    print(\"YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\\n\");\n    print(\"ON THE TOP ROW OR RIGHT HAND COLUMN.\\n\");\n    print(\"THAT WILL BE YOUR FIRST MOVE.\\n\");\n    print(\"WE ALTERNATE MOVES.\\n\");\n    print(\"YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\\n\");\n    print(\"BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nfunction show_map()\n{\n    print(\"\\n\");\n    for (var a = 0; a <= 7; a++) {\n        for (var b = 1; b <= 8; b++) {\n            i = 8 * a + b;\n            print(\" \" + sa[i] + \" \");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n    print(\"\\n\");\n}\n\nfunction test_move()\n{\n    m = 10 * t + u;\n    if (m == 158 || m == 127 || m == 126 || m == 75 || m == 73)\n        return true;\n    return false;\n}\n\nfunction random_move()\n{\n    // Random move\n    z = Math.random();\n    if (z > 0.6) {\n        u = u1 + 1;\n        t = t1 + 1;\n    } else if (z > 0.3) {\n        u = u1 + 1;\n        t = t1 + 2;\n    } else {\n        u = u1;\n        t = t1 + 1;\n    }\n    m = 10 * t + u;\n}\n\nfunction computer_move()\n{\n    if (m1 == 41 || m1 == 44 || m1 == 73 || m1 == 75 || m1 == 126 || m1 == 127) {\n        random_move();\n        return;\n    }\n    for (k = 7; k >= 1; k--) {\n        u = u1;\n        t = t1 + k;\n        if (test_move())\n            return;\n        u += k;\n        if (test_move())\n            return;\n        t += k;\n        if (test_move())\n            return;\n    }\n    random_move();\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"QUEEN\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n\n    while (1) {\n        print(\"DO YOU WANT INSTRUCTIONS\");\n        str = await input();\n        if (str == \"YES\" || str == \"NO\")\n            break;\n        print(\"PLEASE ANSWER 'YES' OR 'NO'.\\n\");\n    }\n    if (str == \"YES\")\n        show_instructions();\n    while (1) {\n        show_map();\n        while (1) {\n            print(\"WHERE WOULD YOU LIKE TO START\");\n            m1 = parseInt(await input());\n            if (m1 == 0) {\n                print(\"\\n\");\n                print(\"IT LOOKS LIKE I HAVE WON BY FORFEIT.\\n\");\n                print(\"\\n\");\n                break;\n            }\n            t1 = Math.floor(m1 / 10);\n            u1 = m1 - 10 * t1;\n            if (u1 == 1 || u1 == t1)\n                break;\n            print(\"PLEASE READ THE DIRECTIONS AGAIN.\\n\");\n            print(\"YOU HAVE BEGUN ILLEGALLY.\\n\");\n            print(\"\\n\");\n        }\n        while (m1) {\n            if (m1 == 158) {\n                print(\"\\n\");\n                print(\"C O N G R A T U L A T I O N S . . .\\n\");\n                print(\"\\n\");\n                print(\"YOU HAVE WON--VERY WELL PLAYED.\\n\");\n                print(\"IT LOOKS LIKE I HAVE MET MY MATCH.\\n\");\n                print(\"THANKS FOR PLAYING--I CAN'T WIN ALL THE TIME.\\n\");\n                print(\"\\n\");\n                break;\n            }\n            computer_move();\n            print(\"COMPUTER MOVES TO SQUARE \" + m + \"\\n\");\n            if (m == 158) {\n                print(\"\\n\");\n                print(\"NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\\n\");\n                print(\"THANKS FOR PLAYING.\\n\");\n                print(\"\\n\");\n                break;\n            }\n            print(\"WHAT IS YOUR MOVE\");\n            while (1) {\n                m1 = parseInt(await input());\n                if (m1 == 0)\n                    break;\n                t1 = Math.floor(m1 / 10);\n                u1 = m1 - 10 * t1;\n                p = u1 - u;\n                l = t1 - t;\n                if (m1 <= m || p == 0 && l <= 0 || p != 0 && l != p && l != 2 * p) {\n                    print(\"\\n\");\n                    print(\"Y O U   C H E A T . . .  TRY AGAIN\");\n                    continue;\n                }\n                break;\n            }\n            if (m1 == 0) {\n                print(\"\\n\");\n                print(\"IT LOOKS LIKE I HAVE WON BY FORFEIT.\\n\");\n                print(\"\\n\");\n                break;\n            }\n        }\n        while (1) {\n            print(\"ANYONE ELSE CARE TO TRY\");\n            str = await input();\n            print(\"\\n\");\n            if (str == \"YES\" || str == \"NO\")\n                break;\n            print(\"PLEASE ANSWER 'YES' OR 'NO'.\\n\");\n        }\n        if (str != \"YES\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"OK --- THANKS AGAIN.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "72_Queen/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "72_Queen/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "72_Queen/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "72_Queen/perl/queen.pl",
    "content": "#!/usr/bin/env perl\nuse v5.24;\nuse warnings;\nuse experimental 'signatures';\nno warnings 'experimental::signatures';\n\nuse constant TARGET => 158;\n\nmain(@ARGV);\n\nsub main (@args) {\n   welcome();\n   help() if ask_yes_no('DO YOU WANT INSTRUCTIONS');\n   do { one_match() } while ask_yes_no('ANYONE ELSE CARE TO TRY');\n   __exit();\n}\n\nsub one_match {\n   print_board();\n\n   # the player can choose the starting position in the top row or the\n   # right column\n   my $move = ask_first_move() or return forfeit();\n\n   # we alternate moves between computer or player from now on\n   while ('playing') {\n      $move = computer_move($move);\n      say \"COMPUTER MOVES TO SQUARE $move\";\n      return print_computer_victory() if $move == TARGET;\n\n      $move = ask_player_move($move) or return forfeit();\n      return print_player_victory() if $move == TARGET;\n   }\n}\n\nsub is_valid_move ($move, $current, $skip_prevalidation = 0) {\n\n   # pre-validation is needed for moves coming from the user\n   if (! $skip_prevalidation) {\n      state $valid_position = { map { $_ => 1 } board_identifiers() };\n      return 0 unless $move =~ m{\\A [1-9]\\d+ \\z}mxs;\n      return 1 if $move == 0;\n      return 0 unless $valid_position->{$move};\n      return 0 if $move <= $current;\n   }\n\n   # the move might be valid in general, let's check from $current\n   my $delta = $move - $current;\n\n   # a valid move differs from the current position by a multiple of 10,\n   # or 11, or 21. If dividing by all of them yields a remainder, then\n   # the move is not valid\n   return 0 if $delta % 10 && $delta % 11 && $delta % 21;\n\n   # otherwise it is\n   return 1;\n}\n\nsub ask_player_move ($current) {\n   while ('necessary') {\n      my $move = ask_input('WHAT IS YOUR MOVE');\n      return $move if is_valid_move($move, $current);\n      say \"\\nY O U   C H E A T . . .  TRY AGAIN\";\n   }\n}\n\nsub computer_move ($current) {\n\n   # this game has some optimal/safe positions from where it's possible\n   # to win with the right strategy. We will aim for them, if possible\n   state $optimals = [ 158, 127, 126, 75, 73 ];\n   for my $optimal ($optimals->@*) {\n\n      # moves can only increase, if we did not find any optimal move so far\n      # then there's no point going on\n      last if $optimal <= $current;\n\n      # computer moves are \"syntactically\" valid, skip pre-validation\n      return $optimal if is_valid_move($optimal, $current, 'skip');\n\n   }\n\n   # cannot reach an optimal position... resort to randomness\n   my $z = rand();\n   return $current + 11 if $z > 0.6; # move down\n   return $current + 21 if $z > 0.3; # move diagonally\n   return $current + 10;           ; # move horizontally\n}\n\nsub board_identifiers {\n   return (\n      81,   71,  61,  51,  41,  31,  21,  11,\n      92,   82,  72,  62,  52,  42,  32,  22,\n      103,  93,  83,  73,  63,  53,  43,  33,\n      114, 104,  94,  84,  74,  64,  54,  44,\n      125, 115, 105,  95,  85,  75,  65,  55,\n      136, 126, 116, 106,  96,  86,  76,  66,\n      147, 137, 127, 117, 107,  97,  87,  77,\n      158, 148, 138, 128, 118, 108,  98,  88,\n   );\n}\n\nsub print_player_victory {\n   print <<'END';\n\nC O N G R A T U L A T I O N S . . .\n\nYOU HAVE WON--VERY WELL PLAYED.\nIT LOOKS LIKE I HAVE MET MY MATCH.\nTHANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\n\nEND\n}\n\nsub print_computer_victory {\n   print <<'END';\n\nNICE TRY, BUT IT LOOKS LIKE I HAVE WON.\nTHANKS FOR PLAYING.\n\nEND\n}\n\nsub forfeit { say \"\\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\\n\" }\n\nsub ask_input ($prompt) {\n   print \"$prompt? \";\n   defined(my $input = <STDIN>) or __exit();\n\n   # remove spaces from the input (including newlines), they are not used\n   $input =~ s{\\s+}{}gmxs;\n\n   return $input;\n}\n\nsub ask_yes_no ($prompt) {\n   while ('necessary') {\n      my $input = ask_input($prompt);\n      return 1 if $input =~ m{\\A (?: yes | y) \\z}imxs;\n      return 0 if $input =~ m{\\A (?:  no | n) \\z}imxs;\n      say q{PLEASE ANSWER 'YES' OR 'NO'.};\n   }\n}\n\nsub ask_first_move {\n   while ('necessary') {\n      my $input = ask_input('WHERE WOULD YOU LIKE TO START');\n      if ($input =~ m{\\A (?: 0 | [1-9]\\d+) \\z}mxs) {\n         return 0 unless $input;\n         my $diagonal = int($input / 10);\n         my $row = $input % 10;\n         return $input if $row == 1 || $row == $diagonal;\n      }\n      say <<'END'\nPLEASE READ THE DIRECTIONS AGAIN.\nYOU HAVE BEGUN ILLEGALLY.\n\nEND\n   }\n}\n\nsub __exit {\n   say \"\\nOK --- THANKS AGAIN.\";\n   exit 0;\n}\n\nsub welcome {\n   print <<'END'\n                                 QUEEN\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nEND\n}\n\nsub help {\n   print <<'END';\nWE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\nMOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\nDOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\n\nTHE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\nLEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\nCOMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\n\nYOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\nON THE TOP ROW OR RIGHT HAND COLUMN.\nTHAT WILL BE YOUR FIRST MOVE.\nWE ALTERNATE MOVES.\nYOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\nBE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\n\n\nEND\n}\n\nsub print_board {\n   say '';\n   my @ids = board_identifiers();\n   my $row_template = join '  ', ($ENV{ORIGINAL} ? '%d' : '%3d') x 8;\n   for my $A (0 .. 7) {\n      my $start = $A * 8;\n      my @range = $start .. $start + 7;\n      say ' ', sprintf $row_template, @ids[@range];\n      say \"\\n\";\n   }\n   say '';\n}\n"
  },
  {
    "path": "72_Queen/python/.flake8",
    "content": "[flake8]\nmax-line-length = 88\nselect = C,E,F,W,B,B950\nextend-ignore = E203, E501\n"
  },
  {
    "path": "72_Queen/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/) by Christopher Phan.\nSupports Python version 3.8 or later.\n"
  },
  {
    "path": "72_Queen/python/queen.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nImplementation of Queens game in Python 3.\n\nOriginal game in BASIC by David Ahl in _BASIC Comuter Games_, published in 1978,\nas reproduced here:\n    https://www.atariarchives.org/basicgames/showpage.php?page=133\n\nPort to Python 3 by Christopher L. Phan <https://chrisphan.com>\n\nSupports Python version 3.8 or later.\n\"\"\"\n\nfrom random import random\nfrom typing import Final, FrozenSet, Optional, Tuple\n\n########################################################################################\n#                                  Optional configs\n########################################################################################\n# You can edit these variables to change the behavior of the game.\n#\n# The original implementation has a bug that allows a player to move off the board,\n# e.g. start at the nonexistant space 91. Change the variable FIX_BOARD_BUG to ``True``\n# to fix this behavior.\n#\n\nFIX_BOARD_BUG: Final[bool] = False\n\n# In the original implementation, the board is only printed once. Change the variable\n# SHOW_BOARD_ALWAYS to ``True`` to display the board every time.\n\nSHOW_BOARD_ALWAYS: Final[bool] = False\n\n# In the original implementaiton, the board is printed a bit wonky because of the\n# differing widths of the numbers. Change the variable ALIGNED_BOARD to ``True`` to\n# fix this.\n\nALIGNED_BOARD: Final[bool] = False\n\n########################################################################################\n\nINSTR_TXT: Final[\n    str\n] = \"\"\"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\nMOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\nDOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\n\nTHE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\nLEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\nCOMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\n\nYOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\nON THE TOP ROW OR RIGHT HAND COLUMN.\nTHAT WILL BE YOUR FIRST MOVE.\nWE ALTERNATE MOVES.\nYOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\nBE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\n\n\"\"\"\n\n\nWIN_MSG: Final[\n    str\n] = \"\"\"C O N G R A T U L A T I O N S . . .\n\nYOU HAVE WON--VERY WELL PLAYED.\nIT LOOKS LIKE I HAVE MET MY MATCH.\nTHANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\n\n\"\"\"\n\nLOSE_MSG: Final[\n    str\n] = \"\"\"\nNICE TRY, BUT IT LOOKS LIKE I HAVE WON.\nTHANKS FOR PLAYING.\n\n\"\"\"\n\n\ndef loc_to_num(location: Tuple[int, int], fix_align: bool = False) -> str:\n    \"\"\"Convert a position given by row, column into a space number.\"\"\"\n    row, col = location\n    out_str: str = f\"{row + 8 - col}{row + 1}\"\n    return out_str if not fix_align or len(out_str) == 3 else f\"{out_str} \"\n\n\nGAME_BOARD: Final[str] = (\n    \"\\n\"\n    + \"\\n\\n\\n\".join(\n        \"\".join(f\" {loc_to_num((row, col), ALIGNED_BOARD)} \" for col in range(8))\n        for row in range(8)\n    )\n    + \"\\n\\n\\n\"\n)\n\n\ndef num_to_loc(num: int) -> Tuple[int, int]:\n    \"\"\"Convert a space number into a position given by row, column.\"\"\"\n    row: int = num % 10 - 1\n    col: int = row + 8 - (num - row - 1) // 10\n    return row, col\n\n\n# The win location\nWIN_LOC: Final[Tuple[int, int]] = (7, 0)\n\n# These are the places (other than the win condition) that the computer will always\n# try to move into.\nCOMPUTER_SAFE_SPOTS: Final[FrozenSet[Tuple[int, int]]] = frozenset(\n    [\n        (2, 3),\n        (4, 5),\n        (5, 1),\n        (6, 2),\n    ]\n)\n\n# These are the places that the computer will always try to move into.\nCOMPUTER_PREF_MOVES: Final[FrozenSet[Tuple[int, int]]] = (\n    COMPUTER_SAFE_SPOTS | frozenset([WIN_LOC])\n)\n\n# These are the locations (not including the win location) from which either player can\n# force a win (but the computer will always choose one of the COMPUTER_PREF_MOVES).\nSAFE_SPOTS: Final[FrozenSet[Tuple[int, int]]] = COMPUTER_SAFE_SPOTS | frozenset(\n    [\n        (0, 4),\n        (3, 7),\n    ]\n)\n\n\ndef intro() -> None:\n    \"\"\"Print the intro and print instructions if desired.\"\"\"\n    print(\" \" * 33 + \"Queen\")\n    print(\" \" * 15 + \"Creative Computing  Morristown, New Jersey\")\n    print(\"\\n\" * 2)\n    if ask(\"DO YOU WANT INSTRUCTIONS\"):\n        print(INSTR_TXT)\n\n\ndef get_move(current_loc: Optional[Tuple[int, int]]) -> Tuple[int, int]:\n    \"\"\"Get the next move from the player.\"\"\"\n    prompt: str\n    player_resp: str\n    move_raw: int\n    new_row: int\n    new_col: int\n    if current_loc is None:  # It's the first turn\n        prompt = \"WHERE WOULD YOU LIKE TO START? \"\n    else:\n        prompt = \"WHAT IS YOUR MOVE? \"\n        row, col = current_loc\n    while True:\n        player_resp = input(prompt).strip()\n        try:\n            move_raw = int(player_resp)\n            if move_raw == 0:  # Forfeit\n                return 8, 8\n            new_row, new_col = num_to_loc(move_raw)\n            if current_loc is None:\n                if (new_row == 0 or new_col == 7) and (\n                    not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)\n                ):\n                    return new_row, new_col\n                else:\n                    prompt = (\n                        \"PLEASE READ THE DIRECTIONS AGAIN.\\n\"\n                        \"YOU HAVE BEGUN ILLEGALLY.\\n\\n\"\n                        \"WHERE WOULD YOU LIKE TO START? \"\n                    )\n            elif (\n                (new_row == row and new_col < col)  # move left\n                or (new_col == col and new_row > row)  # move down\n                or (new_row - row == col - new_col)  # move diag left and down\n            ) and (not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)):\n                return new_row, new_col\n            else:\n                prompt = \"Y O U   C H E A T . . .  TRY AGAIN? \"\n\n        except ValueError:\n            prompt = \"!NUMBER EXPECTED - RETRY INPUT LINE\\n? \"\n\n\ndef random_computer_move(location: Tuple[int, int]) -> Tuple[int, int]:\n    \"\"\"Make a random move.\"\"\"\n    row, col = location\n    if (z := random()) > 0.6:\n        # Move down one space\n        return row + 1, col\n    elif z > 0.3:\n        # Move diagonaly (left and down) one space\n        return row + 1, col - 1\n    else:\n        # Move left one space\n        return row, col - 1\n\n\ndef computer_move(location: Tuple[int, int]) -> Tuple[int, int]:\n    \"\"\"Get the computer's move.\"\"\"\n    # If the player has made an optimal move, then choose a random move\n    if location in SAFE_SPOTS:\n        return random_computer_move(location)\n    # We don't need to implmement the logic of checking for the player's win,\n    # because that is checked before this function is called.\n    row, col = location\n    for k in range(7, 0, -1):\n        # If the computer can move left k spaces and end in up in a safe spot or win,\n        # do it.\n        if (new_loc := (row, col - k)) in COMPUTER_PREF_MOVES:\n            return new_loc\n        # If the computer can move down k spaces and end up in a safe spot or win, do it.\n        if (new_loc := (row + k, col)) in COMPUTER_PREF_MOVES:\n            return new_loc\n        # If the computer can move diagonally k spaces and end up in a safe spot or win,\n        # do it.\n        if (new_loc := (row + k, col - k)) in COMPUTER_PREF_MOVES:\n            return new_loc\n        # As a fallback, do a random move. (NOTE: This shouldn't actally happen--it\n        # should always be possible to make an optimal move if the player doesn't play\n        # in a location in SAFE_SPOTS.\n    return random_computer_move(location)\n\n\ndef main_game() -> None:\n    \"\"\"Execute the main game.\"\"\"\n    game_over: bool = False\n    location: Optional[Tuple[int, int]] = None  # Indicate it is the first turn\n    while not game_over:\n        location = get_move(location)\n        if location == (8, 8):  # (8, 8) is returned when the player enters 0\n            print(\"\\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\\n\")\n            game_over = True\n        elif location == WIN_LOC:  # Player wins (in lower left corner)\n            print(WIN_MSG)\n            game_over = True\n        else:\n            location = computer_move(location)\n            print(f\"COMPUTER MOVES TO SQUARE {loc_to_num(location)}\")\n            if location == WIN_LOC:  # Computer wins (in lower left corner)\n                print(LOSE_MSG)\n                game_over = True\n        # The default behavior is not to show the board each turn, but\n        # this can be modified by changing a flag at the start of the file.\n        if not game_over and SHOW_BOARD_ALWAYS:\n            print(GAME_BOARD)\n\n\ndef ask(prompt: str) -> bool:\n    \"\"\"Ask a yes/no question until user gives an understandable response.\"\"\"\n    inpt: str\n    while True:\n        # Normalize input to uppercase, no whitespace, then get first character\n        inpt = input(f\"{prompt}? \").upper().strip()[0]\n        print()\n        if inpt == \"N\":\n            return False\n        elif inpt == \"Y\":\n            return True\n        print(\"PLEASE ANSWER 'YES' OR 'NO'.\")\n    return False\n\n\nif __name__ == \"__main__\":\n    intro()\n    still_playing: bool = True\n    while still_playing:\n        print(GAME_BOARD)\n        main_game()\n        still_playing = ask(\"ANYONE ELSE CARE TO TRY\")\n    print(\"\\nOK --- THANKS AGAIN.\")\n"
  },
  {
    "path": "72_Queen/queen.bas",
    "content": "1 PRINT TAB(33);\"QUEEN\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n10 DIM S(64)\n11 FOR I=1 TO 64\n12 READ S(I)\n13 NEXT I\n14 DATA  81,  71,  61,  51,  41,  31,  21,  11\n15 DATA  92,  82,  72,  62,  52,  42,  32,  22\n16 DATA 103,  93,  83,  73,  63,  53,  43,  33\n17 DATA 114, 104,  94,  84,  74,  64,  54,  44\n18 DATA 125, 115, 105,  95,  85,  75,  65,  55\n19 DATA 136, 126, 116, 106,  96,  86,  76,  66\n20 DATA 147, 137, 127, 117, 107,  97,  87,  77\n21 DATA 158, 148, 138, 128, 118, 108,  98,  88\n22 INPUT \"DO YOU WANT INSTRUCTIONS\";W$\n23 IF W$=\"NO\" THEN 30\n24 IF W$=\"YES\" THEN 28\n25 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.\"\n26 GOTO 22\n28 GOSUB 5000\n29 GOTO 100\n30 GOSUB 5160\n90 REM     ERROR CHECKS\n100 PRINT \"WHERE WOULD YOU LIKE TO START\";\n110 INPUT M1\n115 IF M1=0 THEN 232\n120 T1=INT(M1/10)\n130 U1=M1-10*T1\n140 IF U1=1 THEN 200\n150 IF U1=T1 THEN 200\n160 PRINT \"PLEASE READ THE DIRECTIONS AGAIN.\"\n170 PRINT \"YOU HAVE BEGUN ILLEGALLY.\"\n175 PRINT\n180 GOTO 100\n200 GOSUB 2000\n210 PRINT \"COMPUTER MOVES TO SQUARE\";M\n215 IF M=158 THEN 3400\n220 PRINT \"WHAT IS YOUR MOVE\";\n230 INPUT M1\n231 IF M1<>0 THEN 239\n232 PRINT\n233 PRINT \"IT LOOKS LIKE I HAVE WON BY FORFEIT.\"\n234 PRINT\n235 GOTO 4000\n239 IF M1<=M THEN 3200\n240 T1=INT(M1/10)\n250 U1=M1-10*T1\n260 P=U1-U\n270 IF P<>0 THEN 300\n280 L=T1-T\n290 IF L<=0 THEN 3200\n295 GOTO 200\n300 IF T1-T <>P THEN 320\n310 GOTO 200\n320 IF T1-T <>2*P THEN 3200\n330 GOTO 200\n1990 REM     LOCATE MOVE FOR COMPUTER\n2000 IF M1=41 THEN 2180\n2010 IF M1=44 THEN 2180\n2020 IF M1=73 THEN 2180\n2030 IF M1=75 THEN 2180\n2040 IF M1=126 THEN 2180\n2050 IF M1=127 THEN 2180\n2060 IF M1=158 THEN 3300\n2065 C=0\n2070 FOR K=7 TO 1 STEP -1\n2080 U=U1\n2090 T=T1+K\n2100 GOSUB 3500\n2105 IF C=1 THEN 2160\n2110 U=U+K\n2120 GOSUB 3500\n2125 IF C=1 THEN 2160\n2130 T=T+K\n2140 GOSUB 3500\n2145 IF C=1 THEN 2160\n2150 NEXT K\n2155 GOTO 2180\n2160 C=0\n2170 RETURN\n2180 GOSUB 3000\n2190 RETURN\n2990 REM     RANDOM MOVE\n3000 Z=RND(1)\n3010 IF Z>.6 THEN 3110\n3020 IF Z>.3 THEN 3070\n3030 U=U1\n3040 T=T1+1\n3050 M=10*T+U\n3060 RETURN\n3070 U=U1+1\n3080 T=T1+2\n3090 M=10*T+U\n3100 RETURN\n3110 U=U1+1\n3120 T=T1+1\n3130 M=10*T+U\n3140 RETURN\n3190 REM     ILLEGAL MOVE MESSAGE\n3200 PRINT\n3210 PRINT \"Y O U   C H E A T . . .  TRY AGAIN\";\n3220 GOTO 230\n3290 REM     PLAYER WINS\n3300 PRINT\n3310 PRINT \"C O N G R A T U L A T I O N S . . .\"\n3320 PRINT\n3330 PRINT \"YOU HAVE WON--VERY WELL PLAYED.\"\n3340 PRINT \"IT LOOKS LIKE I HAVE MET MY MATCH.\"\n3350 PRINT \"THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\"\n3360 PRINT\n3370 GOTO 4000\n3390 REM     COMPUTER WINS\n3400 PRINT\n3410 PRINT \"NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\"\n3420 PRINT \"THANKS FOR PLAYING.\"\n3430 PRINT\n3440 GOTO 4000\n3490 REM     TEST FOR COMPUTER MOVE\n3500 M=10*T+U\n3510 IF M=158 THEN 3570\n3520 IF M=127 THEN 3570\n3530 IF M=126 THEN 3570\n3540 IF M=75 THEN 3570\n3550 IF M=73 THEN 3570\n3560 RETURN\n3570 C=1\n3580 GOTO 3560\n3990 REM     ANOTHER GAME???\n4000 PRINT \"ANYONE ELSE CARE TO TRY\";\n4010 INPUT Q$\n4020 PRINT\n4030 IF Q$=\"YES\" THEN 30\n4040 IF Q$=\"NO\" THEN 4050\n4042 PRINT \"PLEASE ANSWER 'YES' OR 'NO'.\"\n4045 GOTO 4000\n4050 PRINT:PRINT \"OK --- THANKS AGAIN.\"\n4060 STOP\n4990 REM     DIRECTIONS\n5000 PRINT \"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\"\n5010 PRINT \"MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\"\n5020 PRINT \"DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\"\n5030 PRINT\n5040 PRINT \"THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\"\n5050 PRINT \"LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\"\n5060 PRINT \"COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\"\n5070 PRINT\n5080 PRINT \"YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\"\n5090 PRINT \"ON THE TOP ROW OR RIGHT HAND COLUMN.\"\n5100 PRINT \"THAT WILL BE YOUR FIRST MOVE.\"\n5110 PRINT \"WE ALTERNATE MOVES.\"\n5120 PRINT \"YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\"\n5130 PRINT \"BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\"\n5140 PRINT\n5150 PRINT\n5160 PRINT\n5170 FOR A=0 TO 7\n5180 FOR B=1 TO 8\n5185 I=8*A+B\n5190 PRINT S(I);\n5200 NEXT B\n5210 PRINT\n5220 PRINT\n5230 PRINT\n5240 NEXT A\n5250 PRINT\n5260 RETURN\n9999 END\n"
  },
  {
    "path": "72_Queen/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "72_Queen/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "72_Queen/rust/src/ai.rs",
    "content": "use crate::util;\n\nconst PREFERRED_MOVES: [u8; 5] = [158, 72, 75, 126, 127];\nconst SAFE_MOVES: [u8; 2] = [44, 41];\n\npub fn get_computer_move(loc: u8) -> u8 {\n    if SAFE_MOVES.contains(&loc) {\n        return random_move(loc);\n    }\n\n    for m in PREFERRED_MOVES {\n        if util::is_move_legal(loc, m) && m != loc {\n            return m;\n        }\n    }\n\n    random_move(loc)\n}\n\nfn random_move(l: u8) -> u8 {\n    let r: f32 = rand::random();\n\n    if r > 0.6 {\n        l + 11\n    } else if r > 0.3 {\n        l + 21\n    } else {\n        l + 10\n    }\n}\n"
  },
  {
    "path": "72_Queen/rust/src/game.rs",
    "content": "use crate::{\n    ai,\n    util::{self, prompt, PromptResult::*},\n};\n\npub struct Game {\n    blocks: [u8; 64],\n    location: Option<u8>,\n    player_move: bool,\n    show_board: bool,\n    forfeit: bool,\n}\n\nimpl Game {\n    pub fn new() -> Self {\n        let mut blocks = [0 as u8; 64];\n\n        let mut block = 91;\n        let mut i = 0;\n\n        for _ in 0..8 {\n            for _ in 0..8 {\n                block -= 10;\n                blocks[i] = block;\n                i += 1;\n            }\n            block += 91;\n        }\n\n        Game {\n            blocks,\n            location: None,\n            player_move: true,\n            show_board: false,\n            forfeit: false,\n        }\n    }\n\n    pub fn update(&mut self) -> bool {\n        let mut still_going = true;\n\n        if let Some(l) = self.location {\n            if self.show_board {\n                self.draw(l);\n            }\n\n            match self.player_move {\n                true => self.player_move(l),\n                false => {\n                    std::thread::sleep(std::time::Duration::from_secs(1));\n                    let loc = ai::get_computer_move(l);\n                    println!(\"COMPUTER MOVES TO SQUARE {}\", loc);\n                    self.location = Some(loc);\n                }\n            }\n\n            still_going = self.check_location();\n        } else {\n            self.set_start_location();\n        }\n        self.player_move = !self.player_move;\n        still_going\n    }\n\n    fn set_start_location(&mut self) {\n        self.draw(0);\n\n        if let YesNo(yes) = prompt(Some(false), \"UPDATE BOARD?\") {\n            self.show_board = yes;\n        }\n\n        loop {\n            if let Numeric(n) = prompt(Some(true), \"WHERE WOULD YOU LIKE TO START?\") {\n                let n = n as u8;\n\n                if util::is_legal_start(n) {\n                    self.location = Some(n);\n                    break;\n                } else {\n                    println!(\"PLEASE READ THE DIRECTIONS AGAIN.\\nYOU HAVE BEGUN ILLEGALLY.\\n\")\n                }\n            }\n        }\n    }\n\n    fn player_move(&mut self, loc: u8) {\n        loop {\n            if let Numeric(n) = prompt(Some(true), \"WHAT IS YOUR MOVE?\") {\n                if n == 0 {\n                    self.forfeit = true;\n                    break;\n                }\n\n                let n = n as u8;\n\n                if util::is_move_legal(loc, n) {\n                    self.location = Some(n);\n                    break;\n                } else {\n                    println!(\"Y O U   C H E A T . . .  TRY AGAIN? \");\n                }\n            }\n        }\n    }\n\n    fn check_location(&self) -> bool {\n        if self.location == Some(158) {\n            util::print_gameover(self.player_move, self.forfeit);\n            return false;\n        }\n\n        true\n    }\n\n    fn draw(&self, loc: u8) {\n        let draw_h_border = |top: Option<bool>| {\n            let corners;\n\n            if let Some(top) = top {\n                if top {\n                    corners = (\"┌\", \"┐\", \"┬\");\n                } else {\n                    corners = (\"└\", \"┘\", \"┴\");\n                }\n            } else {\n                corners = (\"├\", \"┤\", \"┼\");\n            }\n\n            print!(\"{}\", corners.0);\n\n            for i in 0..8 {\n                let corner = if i == 7 { corners.1 } else { corners.2 };\n\n                print!(\"───{}\", corner);\n            }\n            println!();\n        };\n\n        draw_h_border(Some(true));\n\n        let mut column = 0;\n        let mut row = 0;\n\n        for block in self.blocks.iter() {\n            let block = *block as u8;\n\n            let n = if block == loc {\n                format!(\"│{}\", \"*Q*\".to_string())\n            } else {\n                let b = block.to_string();\n\n                if block > 99 {\n                    format!(\"│{}\", b)\n                } else {\n                    format!(\"│{} \", b)\n                }\n            };\n\n            print!(\"{}\", n);\n\n            column += 1;\n\n            if column != 1 && (column % 8) == 0 {\n                column = 0;\n                row += 1;\n\n                print!(\"│\");\n                println!();\n\n                if row == 8 {\n                    draw_h_border(Some(false));\n                } else {\n                    draw_h_border(None);\n                }\n            }\n        }\n\n        println!();\n    }\n}\n"
  },
  {
    "path": "72_Queen/rust/src/main.rs",
    "content": "use crate::{\n    game::Game,\n    util::{prompt, PromptResult::*},\n};\n\nmod game;\nmod util;\nmod ai;\n\nfn main() {\n    util::intro();\n\n    loop {\n        let mut game = Game::new();\n\n        loop {\n            if !game.update() {\n                break;\n            }\n        }\n\n        if let YesNo(y) = prompt(Some(false), \"\\nANYONE ELSE CARE TO TRY?\") {\n            if !y {\n                println!(\"OK --- THANKS AGAIN.\");\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "72_Queen/rust/src/util.rs",
    "content": "use std::io;\n\npub enum PromptResult {\n    Normal(String),\n    YesNo(bool),\n    Numeric(i32),\n}\n\npub fn prompt(is_numeric: Option<bool>, msg: &str) -> PromptResult {\n    use PromptResult::*;\n\n    println!(\"{msg}\");\n\n    loop {\n        let mut input = String::new();\n\n        io::stdin()\n            .read_line(&mut input)\n            .expect(\"**Failed to read input**\");\n\n        if let Some(is_numeric) = is_numeric {\n            let input = input.trim();\n\n            if is_numeric {\n                if let Ok(n) = input.parse::<i32>() {\n                    return Numeric(n);\n                }\n                println!(\"PLEASE ENTER A VALID NUMBER!\");\n            } else {\n                match input.to_uppercase().as_str() {\n                    \"YES\" | \"Y\" => return YesNo(true),\n                    \"NO\" | \"N\" => return YesNo(false),\n                    _ => println!(\"PLEASE ENTER (Y)ES OR (N)O.\"),\n                }\n            }\n        } else {\n            return Normal(input);\n        }\n    }\n}\n\npub fn is_move_legal(loc: u8, mov: u8) -> bool {\n    let dt: i32 = mov as i32 - loc as i32;\n\n    if dt.is_negative() {\n        return false;\n    }\n\n    if (dt % 21) == 0 || (dt % 10) == 0 || (dt % 11) == 0 {\n        return true;\n    }\n\n    false\n}\n\npub fn is_legal_start(loc: u8) -> bool {\n    let mut legal_spots = Vec::new();\n    let start: u8 = 11;\n\n    legal_spots.push(start);\n\n    for i in 1..=7 {\n        legal_spots.push(start + (10 * i));\n    }\n\n    for i in 1..=7 {\n        legal_spots.push(start + (11 * i));\n    }\n\n    if legal_spots.contains(&loc) {\n        true\n    } else {\n        false\n    }\n}\n\npub fn print_gameover(win: bool, forfeit: bool) {\n    if win {\n        println!(\"C O N G R A T U L A T I O N S . . .\\nYOU HAVE WON--VERY WELL PLAYED.\");\n        println!(\n            \"IT LOOKS LIKE I HAVE MET MY MATCH.\\nTHANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\\n\",\n        );\n    } else {\n        if forfeit {\n            println!(\"IT LOOKS LIKE I HAVE WON BY FORFEIT.\\n\");\n        } else {\n            println!(\"NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\\nTHANKS FOR PLAYING.\");\n        }\n    }\n}\n\npub fn intro() {\n    println!(\"\\n\\n\\t\\tQUEEN\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n\n    if let PromptResult::YesNo(yes) = prompt(Some(false), \"DO YOU WANT INSTRUCTIONS?\") {\n        if yes {\n            println!(\n                r#\"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\nMOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\nDOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\nTHE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\nLEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\nCOMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\nYOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\nON THE TOP ROW OR RIGHT HAND COLUMN.\nTHAT WILL BE YOUR FIRST MOVE.\nWE ALTERNATE MOVES.\nYOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\nBE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\"#\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "72_Queen/vbnet/Queen.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Queen\", \"Queen.vbproj\", \"{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "72_Queen/vbnet/Queen.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Queen</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "72_Queen/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "73_Reverse/README.md",
    "content": "### Reverse\n\nThe game of REVERSE requires you to arrange a list of numbers in numerical order from left to right. To move, you tell the computer how many numbers (counting from the left) to reverse. For example, if the current list is:\n```\n    2 3 4 5 1 6 7 8 9\n```\n\nand you reverse 4, the result will be:\n```\n    5 4 3 2 1 6 7 8 9\n```\nNow if you reverse 5, you win!\n\nThere are many ways to beat the game, but approaches tend to be either algorithmic or heuristic. The game thus offers the player a chance to play with these concepts in a practical (rather than theoretical) context.\n\nAn algorithmic approach guarantees a solution in a predictable number of moves, given the number of items in the list. For example, one method guarantees a solution in 2N - 3 moves when teh list contains N numbers. The essence of an algorithmic approach is that you know in advance what your next move will be. Once could easily program a computer to do this.\n\nA heuristic approach takes advantage of “partial orderings” in the list at any moment. Using this type of approach, your next move is dependent on the way the list currently appears. This way of solving the problem does not guarantee a solution in a predictable number of moves, but if you are lucky and clever, you may come out ahead of the algorithmic solutions. One could not so easily program this method.\n\nIn practice, many players adopt a “mixed” strategy, with both algorithmic and heuristic features. Is this better than either “pure” strategy?\n\nThe program was created by Peter Sessions of People’s Computer Company and the notes above adapted from his original write-up.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=135)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=150)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "73_Reverse/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse/Program.cs",
    "content": "﻿using System;\n\nnamespace Reverse\n{\n    class Program\n    {\n        private static int arrayLength = 9;\n        static void Main(string[] args)\n        {\n            PrintTitle();\n            Console.Write(\"DO YOU WANT THE RULES? \");\n            var needRulesInput = Console.ReadLine();\n            Console.WriteLine();\n            if (string.Equals(needRulesInput, \"YES\", StringComparison.OrdinalIgnoreCase))\n            {\n                DisplayRules();\n            }\n\n            var tryAgain = string.Empty;\n            while (!string.Equals(tryAgain, \"NO\", StringComparison.OrdinalIgnoreCase))\n            {\n                var reverser = new Reverser(arrayLength);\n\n                Console.WriteLine(\"HERE WE GO ... THE LIST IS:\");\n                PrintList(reverser.GetArrayString());\n                var arrayIsInAscendingOrder = false;\n                var numberOfMoves = 0;\n                while (arrayIsInAscendingOrder == false)\n                {\n                    int index = ReadNextInput();\n\n                    if (index == 0)\n                    {\n                        break;\n                    }\n\n                    reverser.Reverse(index);\n                    PrintList(reverser.GetArrayString());\n                    arrayIsInAscendingOrder = reverser.IsArrayInAscendingOrder();\n                    numberOfMoves++;\n                }\n\n                if (arrayIsInAscendingOrder)\n                {\n                    Console.WriteLine($\"YOU WON IT IN {numberOfMoves} MOVES!!!\");\n\n                }\n\n                Console.WriteLine();\n                Console.WriteLine();\n                Console.Write(\"TRY AGAIN (YES OR NO) \");\n                tryAgain = Console.ReadLine();\n            }\n\n            Console.WriteLine();\n            Console.WriteLine(\"OK HOPE YOU HAD FUN!!\");\n        }\n\n        private static int ReadNextInput()\n        {\n            Console.Write(\"HOW MANY SHALL I REVERSE? \");\n            var input = ReadIntegerInput();\n            while (input > 9 || input < 0)\n            {\n                if (input > 9)\n                {\n                    Console.WriteLine($\"OOPS! TOO MANY! I CAN REVERSE AT MOST {arrayLength}\");\n                }\n\n                if (input < 0)\n                {\n                    Console.WriteLine($\"OOPS! TOO FEW! I CAN REVERSE BETWEEN 1 AND {arrayLength}\");\n                }\n                Console.Write(\"HOW MANY SHALL I REVERSE? \");\n                input = ReadIntegerInput();\n            }\n\n            return input;\n        }\n\n        private static int ReadIntegerInput()\n        {\n            var input = Console.ReadLine();\n            int.TryParse(input, out var index);\n            return index;\n        }\n\n        private static void PrintList(string list)\n        {\n            Console.WriteLine();\n            Console.WriteLine(list);\n            Console.WriteLine();\n        }\n\n        private static void PrintTitle()\n        {\n            Console.WriteLine(\"\\t\\t   REVERSE\");\n            Console.WriteLine(\"  CREATIVE COMPUTING  MORRISTON, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"REVERSE -- A GAME OF SKILL\");\n            Console.WriteLine();\n        }\n\n        private static void DisplayRules()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE\");\n            Console.WriteLine(\"TO DO IS ARRANGE A LIST OF NUMBERS (1 THOUGH 9 )\");\n            Console.WriteLine(\"IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU\");\n            Console.WriteLine(\"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\");\n            Console.WriteLine(\"REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:\");\n            Console.WriteLine();\n            Console.WriteLine(\"2 3 4 5 1 6 7 8 9\");\n            Console.WriteLine();\n            Console.WriteLine(\"AND YOU REVERSE 4, THE RESULT WILL BE:\");\n            Console.WriteLine();\n            Console.WriteLine(\"5 4 3 2 1 6 7 8 9\");\n            Console.WriteLine();\n            Console.WriteLine(\"NOW IF YOU REVERSE 5, YOU WIN!\");\n            Console.WriteLine();\n            Console.WriteLine(\"1 2 3 4 5 6 7 8 9\");\n            Console.WriteLine();\n            Console.WriteLine(\"NO DOUBT YOU WILL LIKE THIS GAME, BUT \");\n            Console.WriteLine(\"IF YOU WANT TO QUIT, REVERSE 0 (ZERO)\");\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n    }\n}\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse/Reverse.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse/Reverser.cs",
    "content": "﻿using System;\nusing System.Text;\n\nnamespace Reverse\n{\n    public class Reverser\n    {\n        protected int[] _array;\n\n        public Reverser(int arraySize)\n        {\n            _array = CreateRandomArray(arraySize);\n        }\n\n        public void Reverse(int index)\n        {\n            if (index > _array.Length)\n            {\n                return;\n            }\n\n            for (int i = 0; i < index / 2; i++)\n            {\n                int temp = _array[i];\n                int upperIndex = index - 1 - i;\n                _array[i] = _array[upperIndex];\n                _array[upperIndex] = temp;\n            }\n        }\n\n        public bool IsArrayInAscendingOrder()\n        {\n            for (int i = 1; i < _array.Length; i++)\n            {\n                if (_array[i] < _array[i - 1])\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        private int[] CreateRandomArray(int size)\n        {\n            if (size < 1)\n            {\n                throw new ArgumentOutOfRangeException(nameof(size), \"Array size must be a positive integer\");\n            }\n\n            var array = new int[size];\n            for (int i = 1; i <= size; i++)\n            {\n                array[i - 1] = i;\n            }\n\n            var rnd = new Random();\n\n            for (int i = size; i > 1;)\n            {\n                int k = rnd.Next(i);\n                --i;\n                int temp = array[i];\n                array[i] = array[k];\n                array[k] = temp;\n            }\n            return array;\n        }\n\n        public string GetArrayString()\n        {\n            var sb = new StringBuilder();\n\n            foreach (int i in _array)\n            {\n                sb.Append(\" \" + i + \" \");\n            }\n\n            return sb.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse.Tests/Generators/PositiveIntegerGenerator.cs",
    "content": "﻿using FsCheck;\n\nnamespace Reverse.Tests.Generators\n{\n    public static class PositiveIntegerGenerator\n    {\n        public static Arbitrary<int> Generate() =>\n            Arb.Default.Int32().Filter(x => x > 0);\n    }\n}\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse.Tests/Reverse.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net5.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FsCheck.Xunit\" Version=\"2.16.4\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.9.4\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.3\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"3.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Reverse\\Reverse.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse.Tests/ReverserTests.cs",
    "content": "using FsCheck.Xunit;\nusing Reverse.Tests.Generators;\nusing System;\nusing System.Linq;\nusing Xunit;\n\nnamespace Reverse.Tests\n{\n    public class ReverserTests\n    {\n        [Fact]\n        public void Constructor_CannotAcceptNumberLessThanZero()\n        {\n            Action action = () => new Reverser(0);\n\n            Assert.Throws<ArgumentOutOfRangeException>(action);\n        }\n\n        [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })]\n        public void Constructor_CreatesRandomArrayOfSpecifiedLength(int size)\n        {\n            var sut = new TestReverser(size);\n\n            Assert.Equal(size, sut.GetArray().Length);\n        }\n\n        [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })]\n        public void ConstructorArray_MaxElementValueIsEqualToSize(int size)\n        {\n            var sut = new TestReverser(size);\n\n            Assert.Equal(size, sut.GetArray().Max());\n        }\n\n        [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })]\n        public void ConstructorArray_ReturnsRandomArrayWithDistinctElements(int size)\n        {\n            var sut = new TestReverser(size);\n            var array = sut.GetArray();\n            var arrayGroup = array.GroupBy(x => x);\n            var duplicateFound = arrayGroup.Any(x => x.Count() > 1);\n\n            Assert.False(duplicateFound);\n        }\n\n        [Theory]\n        [InlineData(new int[] { 1 }, new int[] { 1 })]\n        [InlineData(new int[] { 1, 2 }, new int[] { 2, 1 })]\n        [InlineData(new int[] { 1, 2, 3 }, new int[] { 3, 2, 1 })]\n        public void Reverse_WillReverseEntireArray(int[] input, int[] output)\n        {\n            var sut = new TestReverser(1);\n            sut.SetArray(input);\n\n            sut.Reverse(input.Length);\n\n            Assert.True(sut.GetArray().SequenceEqual(output));\n        }\n\n        [Fact]\n        public void Reverse_WithSpecifiedIndex_ReversesItemsUpToThatIndex()\n        {\n            var input = new int[] { 1, 2, 3, 4 };\n            var output = new int[] { 2, 1, 3, 4 };\n            var sut = new TestReverser(1);\n            sut.SetArray(input);\n\n            sut.Reverse(2);\n\n            Assert.True(sut.GetArray().SequenceEqual(output));\n        }\n\n        [Fact]\n        public void Reverse_WithIndexOne_DoesNothing()\n        {\n            var input = new int[] { 1, 2 };\n            var output = new int[] { 1, 2 };\n            var sut = new TestReverser(1);\n            sut.SetArray(input);\n\n            sut.Reverse(1);\n\n            Assert.True(sut.GetArray().SequenceEqual(output));\n        }\n\n        [Fact]\n        public void Reverse_WithIndexGreaterThanArrayLength_DoesNothing()\n        {\n            var input = new int[] { 1, 2 };\n            var output = new int[] { 1, 2 };\n            var sut = new TestReverser(1);\n            sut.SetArray(input);\n\n            sut.Reverse(sut.GetArray().Length + 1);\n\n            Assert.True(sut.GetArray().SequenceEqual(output));\n        }\n\n        [Fact]\n        public void Reverse_WithIndexLessThanZero_DoesNothing()\n        {\n            var input = new int[] { 1, 2 };\n            var output = new int[] { 1, 2 };\n            var sut = new TestReverser(1);\n            sut.SetArray(input);\n\n            sut.Reverse(-1);\n\n            Assert.True(sut.GetArray().SequenceEqual(output));\n        }\n\n        [Theory]\n        [InlineData(new int[] { 1 })]\n        [InlineData(new int[] { 1, 2 })]\n        [InlineData(new int[] { 1, 1 })]\n        public void IsArrayInAscendingOrder_WhenArrayElementsAreInNumericAscendingOrder_ReturnsTrue(int[] input)\n        {\n            var sut = new TestReverser(1);\n            sut.SetArray(input);\n\n            var result = sut.IsArrayInAscendingOrder();\n\n            Assert.True(result);\n        }\n\n        [Fact]\n        public void IsArrayInOrder_WhenArrayElementsAreNotInNumericAscendingOrder_ReturnsFalse()\n        {\n            var sut = new TestReverser(1);\n            sut.SetArray(new int[] { 2, 1 });\n\n            var result = sut.IsArrayInAscendingOrder();\n\n            Assert.False(result);\n        }\n\n        [Fact]\n        public void GetArrayString_ReturnsSpaceSeparatedElementsOfArrayInStringFormat()\n        {\n            var sut = new TestReverser(1);\n            sut.SetArray(new int[] { 1, 2 });\n\n            var result = sut.GetArrayString();\n\n            Assert.Equal(\" 1  2 \", result);\n        }\n    }\n}\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse.Tests/TestReverser.cs",
    "content": "﻿namespace Reverse.Tests\n{\n    internal class TestReverser : Reverser\n    {\n        public TestReverser(int arraySize) : base(arraySize) { }\n\n        public int[] GetArray()\n        {\n            return _array;\n        }\n\n        public void SetArray(int[] array)\n        {\n            _array = array;\n        }\n    }\n}\n"
  },
  {
    "path": "73_Reverse/csharp/Reverse.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.32002.261\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Reverse\", \"Reverse\\Reverse.csproj\", \"{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Reverse.Tests\", \"Reverse.Tests\\Reverse.Tests.csproj\", \"{96E824F8-0353-4FF2-9FEA-F850E2BE7312}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1DCA2723-D126-4B37-A698-D40DA03643A9}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "73_Reverse/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "73_Reverse/java/Reverse.java",
    "content": "import java.util.Scanner;\nimport java.lang.Math;\n\n/**\n * Game of Reverse\n * <p>\n * Based on the BASIC game of Reverse here\n * https://github.com/coding-horror/basic-computer-games/blob/main/73%20Reverse/reverse.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Reverse {\n\n  private final int NUMBER_COUNT = 9;\n\n  private final Scanner scan;  // For user input\n\n  private enum Step {\n    INITIALIZE, PERFORM_REVERSE, TRY_AGAIN, END_GAME\n  }\n\n  public Reverse() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Reverse\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private static void showIntro() {\n\n    System.out.println(\" \".repeat(31) + \"REVERSE\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n    System.out.println(\"REVERSE -- A GAME OF SKILL\");\n    System.out.println(\"\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    int index = 0;\n    int numMoves = 0;\n    int numReverse = 0;\n    int tempVal = 0;\n    int[] numList = new int[NUMBER_COUNT + 1];\n\n    Step nextStep = Step.INITIALIZE;\n\n    String userResponse = \"\";\n\n    System.out.print(\"DO YOU WANT THE RULES? \");\n    userResponse = scan.nextLine();\n\n    if (!userResponse.toUpperCase().equals(\"NO\")) {\n\n      this.printRules();\n    }\n\n    // Begin outer while loop\n    while (true) {\n\n    // Begin outer switch\n    switch (nextStep) {\n\n      case INITIALIZE:\n\n        // Make a random list of numbers\n       numList[1] = (int)((NUMBER_COUNT - 1) * Math.random() + 2);\n\n         for (index = 2; index <= NUMBER_COUNT; index++) {\n\n          // Keep generating lists if there are duplicates\n          while (true) {\n\n            numList[index] = (int)(NUMBER_COUNT * Math.random() + 1);\n\n            // Search for duplicates\n            if (!this.findDuplicates(numList, index)) {\n              break;\n            }\n          }\n        }\n\n        System.out.println(\"\");\n        System.out.println(\"HERE WE GO ... THE LIST IS:\");\n\n        numMoves = 0;\n\n        this.printBoard(numList);\n\n        nextStep = Step.PERFORM_REVERSE;\n        break;\n\n      case PERFORM_REVERSE:\n\n        System.out.print(\"HOW MANY SHALL I REVERSE? \");\n        numReverse = Integer.parseInt(scan.nextLine());\n\n        if (numReverse == 0) {\n\n          nextStep = Step.TRY_AGAIN;\n\n        } else if (numReverse > NUMBER_COUNT) {\n\n          System.out.println(\"OOPS! TOO MANY! I CAN REVERSE AT MOST \" + NUMBER_COUNT);\n          nextStep = Step.PERFORM_REVERSE;\n\n        } else {\n\n          numMoves++;\n\n          for (index = 1; index <= (int)(numReverse / 2.0); index++) {\n\n            tempVal = numList[index];\n            numList[index] = numList[numReverse - index + 1];\n            numList[numReverse - index + 1] = tempVal;\n          }\n\n          this.printBoard(numList);\n\n          nextStep = Step.TRY_AGAIN;\n\n          // Check for a win\n          for (index = 1; index <= NUMBER_COUNT; index++) {\n\n            if (numList[index] != index) {\n              nextStep = Step.PERFORM_REVERSE;\n            }\n          }\n\n          if (nextStep == Step.TRY_AGAIN) {\n            System.out.println(\"YOU WON IT IN \" + numMoves + \" MOVES!!!\");\n            System.out.println(\"\");\n          }\n        }\n        break;\n\n      case TRY_AGAIN:\n\n        System.out.println(\"\");\n        System.out.print(\"TRY AGAIN (YES OR NO)? \");\n        userResponse = scan.nextLine();\n\n        if (userResponse.toUpperCase().equals(\"YES\")) {\n          nextStep = Step.INITIALIZE;\n        } else {\n          nextStep = Step.END_GAME;\n        }\n        break;\n\n      case END_GAME:\n\n        System.out.println(\"\");\n        System.out.println(\"O.K. HOPE YOU HAD FUN!!\");\n        return;\n\n      default:\n\n        System.out.println(\"INVALID STEP\");\n        break;\n\n      }  // End outer switch\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public boolean findDuplicates(int[] board, int length) {\n\n    int index = 0;\n\n    for (index = 1; index <= length - 1; index++) {\n\n      // Identify duplicates\n      if (board[length] == board[index]) {\n\n        return true;  // Found a duplicate\n      }\n    }\n\n    return false;  // No duplicates found\n\n  }  // End of method findDuplicates\n\n  public void printBoard(int[] board) {\n\n    int index = 0;\n\n    System.out.println(\"\");\n\n    for (index = 1; index <= NUMBER_COUNT; index++) {\n\n      System.out.format(\"%2d\", board[index]);\n    }\n\n    System.out.println(\"\\n\");\n\n  }  // End of method printBoard\n\n  public void printRules() {\n\n    System.out.println(\"\");\n    System.out.println(\"THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE\");\n    System.out.println(\"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH \" + NUMBER_COUNT + \")\");\n    System.out.println(\"IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\");\n    System.out.println(\"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\");\n    System.out.println(\"REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\");\n    System.out.println(\"\");\n    System.out.println(\"2 3 4 5 1 6 7 8 9\");\n    System.out.println(\"\");\n    System.out.println(\"AND YOU REVERSE 4, THE RESULT WILL BE:\");\n    System.out.println(\"\");\n    System.out.println(\"5 4 3 2 1 6 7 8 9\");\n    System.out.println(\"\");\n    System.out.println(\"NOW IF YOU REVERSE 5, YOU WIN!\");\n    System.out.println(\"\");\n    System.out.println(\"1 2 3 4 5 6 7 8 9\");\n    System.out.println(\"\");\n    System.out.println(\"NO DOUBT YOU WILL LIKE THIS GAME, BUT\");\n    System.out.println(\"IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\");\n    System.out.println(\"\");\n\n  }  // End of method printRules\n\n  public static void main(String[] args) {\n\n    Reverse game = new Reverse();\n    game.play();\n\n  }  // End of method main\n\n}  // End of class Reverse\n"
  },
  {
    "path": "73_Reverse/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "73_Reverse/javascript/reverse.html",
    "content": "<html>\n<head>\n<title>REVERSE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"reverse.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "73_Reverse/javascript/reverse.js",
    "content": "// REVERSE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar a = [];\nvar n;\n\n// Subroutine to print the rules\nfunction print_rules()\n{\n    print(\"\\n\");\n    print(\"THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE\\n\");\n    print(\"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH \" + n + \")\\n\");\n    print(\"IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\\n\");\n    print(\"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\\n\");\n    print(\"REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\\n\");\n    print(\"\\n\");\n    print(\"2 3 4 5 1 6 7 8 9\\n\");\n    print(\"\\n\");\n    print(\"AND YOU REVERSE 4, THE RESULT WILL BE:\\n\");\n    print(\"\\n\");\n    print(\"5 4 3 2 1 6 7 8 9\\n\");\n    print(\"\\n\");\n    print(\"NOW IF YOU REVERSE 5, YOU WIN!\\n\");\n    print(\"\\n\");\n    print(\"1 2 3 4 5 6 7 8 9\\n\");\n    print(\"\\n\");\n    print(\"NO DOUBT YOU WILL LIKE THIS GAME, BUT\\n\");\n    print(\"IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\\n\");\n    print(\"\\n\");\n}\n\n// Subroutine to print list\nfunction print_list()\n{\n    print(\"\\n\");\n    for (k = 1; k <= n; k++)\n        print(\" \" + a[k] + \" \");\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"REVERSE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"REVERSE -- A GAME OF SKILL\\n\");\n    print(\"\\n\");\n    for (i = 0; i <= 20; i++)\n        a[i] = 0;\n    // *** N=NUMBER OF NUMBER\n    n = 9;\n    print(\"DO YOU WANT THE RULES? (YES OR NO)\");\n    str = await input();\n    if (str.toUpperCase() === \"YES\" || str.toUpperCase() === \"Y\")\n        print_rules();\n    while (1) {\n        // *** Make a random list a(1) to a(n)\n        a[1] = Math.floor((n - 1) * Math.random() + 2);\n        for (k = 2; k <= n; k++) {\n            do {\n                a[k] = Math.floor(n * Math.random() + 1);\n                for (j = 1; j <= k - 1; j++) {\n                    if (a[k] == a[j])\n                        break;\n                }\n            } while (j <= k - 1) ;\n        }\n        // *** Print original list and start game\n        print(\"\\n\");\n        print(\"HERE WE GO ... THE LIST IS:\\n\");\n        t = 0;\n        print_list();\n        while (1) {\n            while (1) {\n                print(\"HOW MANY SHALL I REVERSE\");\n                r = parseInt(await input());\n                if (r == 0)\n                    break;\n                if (r <= n)\n                    break;\n                print(\"OOPS! WRONG! I CAN REVERSE AT MOST \" + n + \"\\n\");\n            }\n            if (r == 0)\n                break;\n            t++;\n            // *** Reverse r numbers and print new list\n            for (k = 1; k <= Math.floor(r / 2); k++) {\n                z = a[k];\n                a[k] = a[r - k + 1];\n                a[r - k + 1] = z;\n            }\n            print_list();\n            // *** Check for a win\n            for (k = 1; k <= n; k++) {\n                if (a[k] != k)\n                    break;\n            }\n            if (k > n) {\n                print(\"YOU WON IT IN \" + t + \" MOVES!!!\\n\");\n                print(\"\\n\");\n                break;\n            }\n        }\n        print(\"\\n\");\n        print(\"TRY AGAIN? (YES OR NO)\");\n        str = await input();\n        if (str.toUpperCase() === \"NO\" || str.toUpperCase() === \"N\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"O.K. HOPE YOU HAD FUN!!\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "73_Reverse/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "73_Reverse/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "73_Reverse/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "73_Reverse/perl/reverse.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse List::Util qw{ shuffle };   # Shuffle an array.\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\n# Manifest constant for size of list.\nuse constant NUMBER_OF_NUMBERS  => 9;\n\nprint <<'EOD';\n                                REVERSE\n               Creative Computing  Morristown, New Jersey\n\n\n\nReverse -- a game of skill\n\nEOD\n\n# Display the rules if desired. There is no straightforward way to\n# interpolate a manifest constant into a string, but @{[ ... ]} will\n# interpolate any expression.\nprint <<\"EOD\" if get_yes_no( 'Do you want the rules' );\n\nThis is the game of 'Reverse'.  To win, all you have\nto do is arrange a list of numbers (1 through @{[ NUMBER_OF_NUMBERS ]})\nin numerical order from left to right.  To move, you\ntell me how many numbers (counting from the left) to\nreverse.  For example, if the current list is:\n\n2 3 4 5 1 6 7 8 9\n\nand you reverse 4, the result will be:\n\n5 4 3 2 1 6 7 8 9\n\nNow if you reverse 5, you win!\n\n1 2 3 4 5 6 7 8 9\n\nNo doubt you will like this game, but\nif you want to quit, reverse 0 (zero).\n\nEOD\n\nwhile ( 1 ) {   # Iterate until something interrupts us.\n\n    # Populate the list with the integers from 1, shuffled. If we\n    # accidentally generate a winning list, just redo the loop.\n    my @list = shuffle( 1 .. NUMBER_OF_NUMBERS );\n    redo if is_win( \\@list );\n\n    print <<\"EOD\";\n\nHere we go ... The list is:\nEOD\n\n    my $moves = 0;  # Move counter\n\n    while ( 1 ) {   # Iterate until something interrupts us.\n        print <<\"EOD\";\n\n@list\n\nEOD\n\n        # Read the number of values to reverse. Zero is special-cased to\n        # take us out of this loop.\n        last unless my $max_index = get_input(\n            'How many shall I reverse (0 to quit)? ',\n            sub {\n                return m/ \\A [0-9]+ \\z /smx &&\n                    $ARG <= NUMBER_OF_NUMBERS;\n            },\n            \"Oops! Too many! I can reverse at most \" .\n                NUMBER_OF_NUMBERS,\n        );\n\n        --$max_index;   # Convert number to reverse to upper index\n\n        # Use a Perl array slice and the reverse() built-in to reverse\n        # the beginning of the list.\n        @list[ 0 .. $max_index ] = reverse @list[ 0 .. $max_index ];\n\n        $moves++;   # Count a move\n\n        # If we have not won, iterate again.\n        next unless is_win( \\@list );\n\n        # Announce the win, and drop out of the loop.\n        print <<\"EOD\";\n\nYou won it in $moves moves!!!\nEOD\n        last;\n    }\n\n    # Drop out of this loop unless the player wants to play again.\n    say '';\n    last unless get_yes_no( 'Try again' );\n}\n\nprint <<'EOD';\n\nO.K. Hope you had fun!!\nEOD\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n# Determine if a given list represents a win. The argument is a\n# reference to the array containing the list. We return a true value for\n# a win, or a false value otherwise.\nsub is_win {\n    my ( $list ) = @_;\n    my $expect = 1; # We expect the first element to be 1;\n\n    # Iterate over the array.\n    foreach my $element ( @{ $list } ) {\n\n        # If the element does not have the expected value, we return\n        # false. We post-increment the expected value en passant.\n        $element == $expect++\n            or return 0;\n    }\n\n    # All elements had the expected value, so we won. Return a true\n    # value.\n    return 1;\n}\n\n__END__\n\n=head1 TITLE\n\nreverse.pl - Play the game 'reverse' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n reverse.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of C<reverse>, which is the 73rd entry in\nBasic Computer Games.\n\nThe cool thing about this port is the fact that, in a language with\narray slices, list assignments, and a C<reverse()> built-in, the\nreversal is a single assignment statement.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "73_Reverse/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "73_Reverse/python/reverse.py",
    "content": "#!/usr/bin/env python3\nimport random\nimport textwrap\n\nNUMCNT = 9  # How many numbers are we playing with?\n\n\ndef main() -> None:\n    print(\"REVERSE\".center(72))\n    print(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".center(72))\n    print()\n    print()\n    print(\"REVERSE -- A GAME OF SKILL\")\n    print()\n\n    if not input(\"DO YOU WANT THE RULES? (yes/no) \").lower().startswith(\"n\"):\n        print_rules()\n\n    while True:\n        game_loop()\n\n        if not input(\"TRY AGAIN? (yes/no) \").lower().startswith(\"y\"):\n            return\n\n\ndef game_loop() -> None:\n    \"\"\"Play the main game.\"\"\"\n    # Make a random list from 1 to NUMCNT\n    numbers = list(range(1, NUMCNT + 1))\n    random.shuffle(numbers)\n\n    # Print original list and start the game\n    print()\n    print(\"HERE WE GO ... THE LIST IS:\")\n    print_list(numbers)\n\n    turns = 0\n    while True:\n        try:\n            howmany = int(input(\"HOW MANY SHALL I REVERSE? \"))\n            assert howmany >= 0\n        except (ValueError, AssertionError):\n            continue\n\n        if howmany == 0:\n            return\n\n        if howmany > NUMCNT:\n            print(\"OOPS! WRONG! I CAN REVERSE AT MOST\", NUMCNT)\n            continue\n\n        turns += 1\n\n        # Reverse as many items as requested.\n        newnums = numbers[:howmany]\n        newnums.reverse()\n        newnums.extend(numbers[howmany:])\n        numbers = newnums\n\n        print_list(numbers)\n\n        # Check for a win\n        if all(numbers[i] == i + 1 for i in range(NUMCNT)):\n            print(f\"YOU WON IT IN {turns} MOVES!\")\n            print()\n            return\n\n\ndef print_list(numbers) -> None:\n    print(\" \".join(map(str, numbers)))\n\n\ndef print_rules() -> None:\n    help = textwrap.dedent(\n        \"\"\"\n        THIS IS THE GAME OF \"REVERSE\".  TO WIN, ALL YOU HAVE\n        TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH {})\n        IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\n        TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\n        REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\n\n        2 3 4 5 1 6 7 8 9\n\n        AND YOU REVERSE 4, THE RESULT WILL BE:\n\n        5 4 3 2 1 6 7 8 9\n\n        NOW IF YOU REVERSE 5, YOU WIN!\n\n        1 2 3 4 5 6 7 8 9\n\n        NO DOUBT YOU WILL LIKE THIS GAME, BUT\n        IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\n        \"\"\".format(\n            NUMCNT\n        )\n    )\n    print(help)\n    print()\n\n\nif __name__ == \"__main__\":\n    try:\n        main()\n    except KeyboardInterrupt:\n        pass\n"
  },
  {
    "path": "73_Reverse/reverse.bas",
    "content": "10 PRINT TAB(32);\"REVERSE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"REVERSE -- A GAME OF SKILL\": PRINT\n130 DIM A(20)\n140 REM *** N=NUMBER OF NUMBERS\n150 N=9\n160 PRINT \"DO YOU WANT THE RULES\";\n170 INPUT A$\n180 IF A$=\"NO\" THEN 210\n190 GOSUB 710\n200 REM *** MAKE A RANDOM LIST A(1) TO A(N)\n210 A(1)=INT((N-1)*RND(1)+2)\n220 FOR K=2 TO N\n230 A(K)=INT(N*RND(1)+1)\n240 FOR J=1 TO K-1\n250 IF A(K)=A(J) THEN 230\n260 NEXT J:NEXT K\n280 REM *** PRINT ORIGINAL LIST AND START GAME\n290 PRINT: PRINT \"HERE WE GO ... THE LIST IS:\"\n310 T=0\n320 GOSUB 610\n330 PRINT \"HOW MANY SHALL I REVERSE\";\n340 INPUT R\n350 IF R=0 THEN 520\n360 IF R<=N THEN 390\n370 PRINT \"OOPS! TOO MANY! I CAN REVERSE AT MOST\";N:GOTO 330\n390 T=T+1\n400 REM *** REVERSE R NUMBERS AND PRINT NEW LIST\n410 FOR K=1 TO INT(R/2)\n420 Z=A(K)\n430 A(K)=A(R-K+1)\n440 A(R-K+1)=Z\n450 NEXT K\n460 GOSUB 610\n470 REM *** CHECK FOR A WIN\n480 FOR K=1 TO N\n490 IF A(K)<>K THEN 330\n500 NEXT K\n510 PRINT \"YOU WON IT IN\";T;\"MOVES!!!\":PRINT\n520 PRINT\n530 PRINT \"TRY AGAIN (YES OR NO)\";\n540 INPUT A$\n550 IF A$=\"YES\" THEN 210\n560 PRINT: PRINT \"O.K. HOPE YOU HAD FUN!!\":GOTO 999\n600 REM *** SUBROUTINE TO PRINT LIST\n610 PRINT:FOR K=1 TO N:PRINT A(K);:NEXT K\n650 PRINT:PRINT:RETURN\n700 REM *** SUBROUTINE TO PRINT THE RULES\n710 PRINT:PRINT \"THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE\"\n720 PRINT \"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH\";N;\")\"\n730 PRINT \"IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\"\n740 PRINT \"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\"\n750 PRINT \"REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\"\n760 PRINT:PRINT \"2 3 4 5 1 6 7 8 9\"\n770 PRINT:PRINT \"AND YOU REVERSE 4, THE RESULT WILL BE:\"\n780 PRINT:PRINT \"5 4 3 2 1 6 7 8 9\"\n790 PRINT:PRINT \"NOW IF YOU REVERSE 5, YOU WIN!\"\n800 PRINT:PRINT \"1 2 3 4 5 6 7 8 9\":PRINT\n810 PRINT \"NO DOUBT YOU WILL LIKE THIS GAME, BUT\"\n820 PRINT \"IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\":PRINT: RETURN\n999 END\n"
  },
  {
    "path": "73_Reverse/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "73_Reverse/ruby/reverse.rb",
    "content": "ARRAYSIZE = 9\n$digitArray = Array.new(ARRAYSIZE)\n$winningArray = Array.new(ARRAYSIZE)\n\n# Method to print the rules\ndef displayTheRules\n    puts \"This is the game of 'Reverse'.  to win, all you have\"\n    puts \"to do is arrange a list of numbers (1 through \" + ARRAYSIZE.to_s + \")\"\n    puts \"in numerical order from left to right.  to move, you\"\n    puts \"tell me how many numbers (counting from the left) to\"\n    puts \"reverse.  For example, if the current list is:\"\n    puts \"2 3 4 5 1 6 7 8 9\"\n    puts \"and you reverse 4, the result will be:\"\n    puts \"5 4 3 2 1 6 7 8 9\"\n    puts \"Now if you reverse 5, you win!\"\n    puts \"1 2 3 4 5 6 7 8 9\"\n    puts \"No doubt you will like this game, but\"\n    puts \"if you want to quit, reverse 0 (zero).\"\nend\n\n# Method to print the list\ndef printList\n    puts \"\\n\" + $digitArray.join(\" \") + \"\\n\\n\"\nend\n\n# Zero-based arrays contain digits 1-9\n# Make a random array and an ordered winning answer array A[0] to A[N]\ndef makeRandomList\n    for kIndex in 0..ARRAYSIZE-1 do\n        $digitArray[kIndex] = kIndex+1\n        $winningArray[kIndex] = kIndex+1\n    end\n    # now randomize the digit array order\n    $digitArray.shuffle!\nend\n\ndef checkForWin? (triesSoFar)\n    # Check for a win (all array elements in order)\n    if $digitArray == $winningArray then\n        puts \"You won it in \" + triesSoFar.to_s + \" moves!!!\\n\\n\"\n        puts \"try again (yes or no)?\"\n        tryAgain = gets.strip.upcase\n        if tryAgain == \"YES\" then\n            return true\n        end\n        puts \"\\nO.K. Hope you had fun!!\"\n        exit\n    end\n    return false\nend\n\ndef reverseIt (howManyToReverse, triesSoFar)\n    # REVERSE R NUMBERS AND PRINT NEW LIST\n\n    # extract and reverse the first howManyToReverse elements of the array\n    subArray = $digitArray.take(howManyToReverse)\n    subArray.reverse!\n\n    # get the remaining elements of the original array\n    endArray = $digitArray.slice(howManyToReverse, ARRAYSIZE)\n    # append those elements to the reversed elements\n    $digitArray = subArray.concat(endArray)\n\n    # if we got all in order, randomize again\n    isWinner = checkForWin?(triesSoFar)\n    if isWinner == true then\n        makeRandomList\n    end\n    printList # always print the newly ordered list\n    return isWinner\nend\n\ndef askHowManyToReverse\n    puts \"How many shall I reverse?\";\n    rNumber = gets.to_i\n    if rNumber > 0 then\n        if rNumber > ARRAYSIZE then\n            puts \"Oops! Too many! I can reverse at most \" + ARRAYSIZE.to_s\n        end\n    else\n        rNumber = 0 # zero or negative values end the game\n    end\n    return rNumber\nend\n\nputs \"REVERSE\"\nputs \"Creative Computing  Morristown, New Jersey\\n\\n\\n\"\nputs \"REVERSE -- A game of skill\\n\\n\"\n\nputs \"Do you want the rules?\"\nwantRules = gets.strip.upcase\nif wantRules == \"YES\" then\n    displayTheRules\nend\n\nmakeRandomList\nhowManyTries = 0\nputs \"\\nHere we go ... the list is:\"\nprintList # display the initial list\n# start the game loop\nr = askHowManyToReverse\nwhile r != 0 do # zero will end the game\n    if r <= ARRAYSIZE then\n        howManyTries = howManyTries+1\n        if reverseIt(r, howManyTries) then\n            howManyTries = 0\n        end\n    end\n    r = askHowManyToReverse\nend\n"
  },
  {
    "path": "73_Reverse/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nrand = \"0.9.0\""
  },
  {
    "path": "73_Reverse/rust/src/main.rs",
    "content": "/** REVERSE GAME \n * https://github.com/marquesrs/basic-computer-games/blob/main/73_Reverse/reverse.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 03/03/25\n*/\n\nuse rand::Rng;\nuse std::io::Write;\n\nfn input(msg: &str) -> String {\n    print!(\"{}\", msg);\n    let _ =std::io::stdout().flush().unwrap();\n    let mut input = String::new();\n    std::io::stdin().read_line(&mut input).unwrap();\n    return input.trim().to_uppercase();\n}\n\nfn main() {\n    // 10 PRINT TAB(32);\"REVERSE\"\n    // 20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    // 30 PRINT:PRINT:PRINT\n    // 100 PRINT \"REVERSE -- A GAME OF SKILL\": PRINT\n    print!(\"{}\", format!(\"{}{}{}{}{}{}{}{}\",\n        \" \".repeat(31),\n        \"REVERSE\",\n        \"\\n\",\n        \" \".repeat(14),\n        \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\",\n        \"\\n\\n\\n\",\n        \"REVERSE -- A GAME OF SKILL\\n\",\n        \"\\n\"\n    ));\n\n    // 130 DIM A(20)\n    let mut a = vec![0; 20];\n    \n    // 140 REM *** N=NUMBER OF NUMBERS\n    // 150 N=9\n    let n = 9;\n    \n    // 160 PRINT \"DO YOU WANT THE RULES\";\n    // 170 INPUT A$\n    let opt = input(\"DO YOU WANT THE RULES (YES OR NO)? \");\n\n    \n    if opt == \"YES\" || opt == \"Y\" {\n        // 190 GOSUB 710        \n        sub1(n);\n    }\n    // 180 IF A$=\"NO\" THEN 210\n    'c : loop {\n        // 200 REM *** MAKE A RANDOM LIST A(1) TO A(N)\n        // 210 A(1)=INT((N-1)*RND(1)+2)\n        // element 0\n        a[0] = ((n-1) as f32 * rand::rng().random_range(0.0..=1.0) + 2.0) as i32;\n    \n        // 220 FOR K=2 TO N\n        for k in 2..=n {\n            'a : loop {\n                // element k\n                // 230 A(K)=INT(N*RND(1)+1)\n                a[k-1] = (n as f32 * rand::rng().random_range(0.0..=1.0) + 1.0) as i32;\n                \n                // element 0 to k-1\n                // 240 FOR J=1 TO K-1\n                for j in 1..k {\n                    // 250 IF A(K)=A(J) THEN 230\n                    if a[k-1] == a[j-1] {\n                        continue 'a;\n                    }\n                    // 260 NEXT J:\n                }\n                break;\n            }\n            //NEXT K\n        }    \n\n        // 280 REM *** PRINT ORIGINAL LIST AND START GAME\n        // 290 PRINT: PRINT \"HERE WE GO ... THE LIST IS:\"\n        print!(\"\\nHERE WE GO ... THE LIST IS:\\n\");\n\n        // 310 T=0\n        let mut t = 0;\n\n        // 320 GOSUB 610\n        sub2(&a, n);\n\n        'b : loop {\n            // 330 PRINT \"HOW MANY SHALL I REVERSE\";\n            // 340 INPUT R\n            let r = input(\"HOW MANY SHALL I REVERSE: \").parse::<usize>().unwrap();\n\n            // 350 IF R=0 THEN 520\n            if r == 0 {\n                if replay() { continue 'c; }\n                else { break 'c; }\n            }\n            // 360 IF R<=N THEN 390\n            if r <= n {\n                // 390 T=T+1\n                t = t + 1;\n\n                // 400 REM *** REVERSE R NUMBERS AND PRINT NEW LIST\n                // 410 FOR K=1 TO INT(R/2)\n                for k in 1..=((r/2) as usize) {\n                    // 420 Z=A(K)\n                    let z = a[k-1];\n                    // 430 A(K)=A(R-K+1)\n                    a[k-1] = a[r-k];\n                    // 440 A(R-K+1)=Z\n                    a[r-k] = z;\n\n                    // 450 NEXT K\n                }\n                // 460 GOSUB 610\n                sub2(&a, n);\n\n                // 470 REM *** CHECK FOR A WIN\n                // 480 FOR K=1 TO N\n                for k in 1..=n {\n                    // 490 IF A(K)<>K THEN 330\n                    if a[k-1] != k as i32 {\n                        continue 'b;\n                    }\n                    // 500 NEXT K\n                }\n                // 510 PRINT \"YOU WON IT IN\";T;\"MOVES!!!\":PRINT\n                print!(\"{}{}{}\", \"YOU WON IT IN \", t, \" MOVES!!!\\n\\n\");\n\n                if replay() { continue 'c; }\n                else { break 'c; }\n            }\n            else {\n                // 370 PRINT \"OOPS! TOO MANY! I CAN REVERSE AT MOST\";N:GOTO 330\n                print!(\"OOPS! TOO MANY! I CAN REVERSE AT MOST {n}\");\n            }\n        }\n    }\n    // 999 END\n}\n\n// 600 REM *** SUBROUTINE TO PRINT LIST\nfn sub2(a: &Vec<i32>, n: usize) {\n    // 610 PRINT:FOR K=1 TO N:PRINT A(K);:NEXT K\n    // 650 PRINT:PRINT:RETURN\n    for k in 1..=n {\n        print!(\"{} \", a[k-1]);\n    }\n    print!(\"\\n\\n\");\n}\n\n// 700 REM *** SUBROUTINE TO PRINT THE RULES\nfn sub1(n: usize) {\n    // 710 PRINT:PRINT \"THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE\"\n    // 720 PRINT \"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH\";N;\")\"\n    // 730 PRINT \"IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\"\n    // 740 PRINT \"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\"\n    // 750 PRINT \"REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\"\n    // 760 PRINT:PRINT \"2 3 4 5 1 6 7 8 9\"\n    // 770 PRINT:PRINT \"AND YOU REVERSE 4, THE RESULT WILL BE:\"\n    // 780 PRINT:PRINT \"5 4 3 2 1 6 7 8 9\"\n    // 790 PRINT:PRINT \"NOW IF YOU REVERSE 5, YOU WIN!\"\n    // 800 PRINT:PRINT \"1 2 3 4 5 6 7 8 9\":PRINT\n    // 810 PRINT \"NO DOUBT YOU WILL LIKE THIS GAME, BUT\"\n    // 820 PRINT \"IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\":PRINT: RETURN\n\n    print!(\"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}\", \n        \"\\n\",\n        \"THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE\\n\",\n        \"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH \",\n        n,\n        \")\\n\",\n        \"IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU\\n\",\n        \"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\\n\",\n        \"REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:\\n\",\n        \"\\n\",\n        \"2 3 4 5 1 6 7 8 9\\n\",\n        \"\\n\",\n        \"AND YOU REVERSE 4, THE RESULT WILL BE:\\n\",\n        \"\\n\",\n        \"5 4 3 2 1 6 7 8 9\\n\",\n        \"\\n\",\n        \"NOW IF YOU REVERSE 5, YOU WIN!\\n\",\n        \"\\n\",\n        \"1 2 3 4 5 6 7 8 9\\n\",\n        \"\\n\",\n        \"NO DOUBT YOU WILL LIKE THIS GAME, BUT\\n\",\n        \"IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\\n\",\n        \"\\n\",\n    )\n}\n\nfn replay() -> bool {\n    // 520 PRINT\n    // 530 PRINT \"TRY AGAIN (YES OR NO)\";\n    // 540 INPUT A$\n    let r = input(\"\\nTRY AGAIN (YES OR NO): \");\n    // 550 IF A$=\"YES\" THEN 210\n    if r == \"YES\" || r == \"Y\" {\n        return true;\n    }\n    else {\n        // 560 PRINT: PRINT \"O.K. HOPE YOU HAD FUN!!\":GOTO 999\n        println!(\"\\nO.K. HOPE YOU HAD FUN!!\");\n        return false; \n    }\n}"
  },
  {
    "path": "73_Reverse/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "73_Reverse/vbnet/Reverse.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Reverse\", \"Reverse.vbproj\", \"{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "73_Reverse/vbnet/Reverse.vb",
    "content": "Imports System\r\n\r\nModule Reverse\r\n\r\n\r\n    '  VB.NET Port of Reverse from book BASIC COMPUTER GAMES.\r\n    '  Console app for .NET Core 3.1\r\n    '  Some simplification and error checking was added.\r\n    '  David Widel\r\n\r\n    Const NumberOfDigits As Integer = 9\r\n\r\n    Private Numbers As New Generic.List(Of Integer)\r\n\r\n\r\n\r\n    Sub Main(args As String())\r\n\r\n        DisplayIntro()\r\n\r\n        Console.WriteLine(\"DO YOU WANT THE RULES? (Y/N)\")\r\n        If Console.ReadKey(True).Key = ConsoleKey.Y Then\r\n            DisplayRules()\r\n        End If\r\n\r\n\r\n\r\n        Dim playing As Boolean = True\r\n\r\n        Do While (playing)  ' New game loop.\r\n\r\n            InitializeRandomNumberList()\r\n\r\n            Console.WriteLine(\"HERE WE GO ... THE LIST IS:\")\r\n            DisplayNumbers()\r\n\r\n            Dim Counter As Integer = 0\r\n\r\n            While True ' Turn loop.\r\n\r\n                Dim ReverseNumber As Integer = GetHowManyToReverse()\r\n                If ReverseNumber = 0 Then\r\n                    If Not TryAgain() Then\r\n                        playing = False\r\n                    End If\r\n                    Continue Do\r\n                End If\r\n\r\n                PerformReverse(ReverseNumber)\r\n                Counter += 1\r\n                DisplayNumbers()\r\n\r\n                If DidPlayerWin() Then\r\n                    Console.WriteLine(\"YOU WON IN \" & Counter.ToString & \" MOVES\")\r\n                    If Not TryAgain() Then\r\n                        Console.WriteLine(\"O.K. HOPE YOU HAD FUN!!\")\r\n                        playing = False\r\n                    End If\r\n                    Continue Do\r\n                End If\r\n\r\n            End While\r\n\r\n        Loop\r\n\r\n\r\n\r\n\r\n    End Sub\r\n\r\n    Sub DisplayIntro()\r\n        Console.WriteLine(\"REVERSE\")\r\n        Console.WriteLine(\"CREATIVE COMPUTING    MORRISTOWN, NEW JERSEY\")\r\n        Console.WriteLine(\"REVERSE -- A GAME OF SKILL\")\r\n\r\n\r\n    End Sub\r\n\r\n    Sub DisplayRules()\r\n\r\n        Console.WriteLine(\"THIS IS THE GAME OF REVERSE. TO WIN, ALL YOU HAVE\")\r\n        Console.WriteLine(\"TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH \" & NumberOfDigits.ToString & \")\")\r\n        Console.WriteLine(\"IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU\")\r\n        Console.WriteLine(\"TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\")\r\n        Console.WriteLine(\"REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:\")\r\n        Console.WriteLine()\r\n        Console.WriteLine(\"2 3 4 5 1 6 7 8 9\")\r\n        Console.WriteLine()\r\n        Console.WriteLine(\"AND YOU REVERSE 4, THE RESULT WILL BE:\")\r\n        Console.WriteLine()\r\n        Console.WriteLine(\"5 4 3 2 1 6 7 8 9\")\r\n        Console.WriteLine()\r\n        Console.WriteLine(\"NOW IF YOU REVERSE 5, YOU WIN!\")\r\n        Console.WriteLine()\r\n        Console.WriteLine(\"1 2 3 4 5 6 7 8 9\")\r\n        Console.WriteLine()\r\n        Console.WriteLine()\r\n        Console.WriteLine()\r\n        Console.WriteLine(\"NO DOUBT YOU WILL LIKE THIS GAME, BUT\")\r\n        Console.WriteLine(\"IF YOU WANT TO QUIT, REVERSE O (ZERO).\")\r\n        Console.WriteLine()\r\n\r\n    End Sub\r\n\r\n    Sub InitializeRandomNumberList()\r\n\r\n        Dim R As New Random\r\n        Numbers.Clear()\r\n\r\n        Do Until Numbers.Count = NumberOfDigits\r\n\r\n            Dim NewNumber = R.Next(1, NumberOfDigits + 1) 'Lower bound is inclusive, Upper bound is exclusive\r\n\r\n            If Not Numbers.Contains(NewNumber) Then\r\n                Numbers.Add(NewNumber)\r\n            End If\r\n\r\n        Loop\r\n\r\n\r\n        If DidPlayerWin() Then\r\n            Numbers.Reverse()\r\n        End If\r\n\r\n    End Sub\r\n\r\n    Private Sub DisplayNumbers()\r\n        For i As Integer = 0 To Numbers.Count - 1\r\n            Console.Write(Numbers(i).ToString(\" #\"))\r\n        Next\r\n        Console.WriteLine()\r\n    End Sub\r\n\r\n    Function GetHowManyToReverse() As Integer\r\n        Console.WriteLine(\"HOW MANY SHALL I REVERSE?\")\r\n\r\n        Do\r\n\r\n            Dim K = Console.ReadLine\r\n            Dim ReverseNumber As Integer\r\n\r\n            If Integer.TryParse(K, ReverseNumber) Then\r\n                If ReverseNumber <= NumberOfDigits Then\r\n                    Return ReverseNumber\r\n                Else\r\n                    Console.WriteLine(\"OOPS! TOO MANY! I CAN REVERSE AT MOST \" & NumberOfDigits.ToString)\r\n                End If\r\n            Else\r\n                'Added check.\r\n                Console.WriteLine(\"OOPS! NUMBERS PLEASE!\")\r\n            End If\r\n\r\n        Loop\r\n\r\n    End Function\r\n\r\n    Sub PerformReverse(ReverseNumber As Integer)\r\n\r\n        ' We will make pointers to the 2 digits to swap, swap them, and converge the pointers.\r\n        Dim LowerPointer As Integer = 1\r\n        Dim UpperPointer As Integer = ReverseNumber\r\n\r\n        Do\r\n            'Since our list begins at 0 we must always subtract one to access a digit.\r\n            Dim temp As Integer = Numbers(LowerPointer - 1)\r\n            Numbers(LowerPointer - 1) = Numbers(UpperPointer - 1)\r\n            Numbers(UpperPointer - 1) = temp\r\n            LowerPointer += 1\r\n            UpperPointer -= 1\r\n\r\n        Loop Until UpperPointer <= LowerPointer\r\n\r\n    End Sub\r\n\r\n    Function DidPlayerWin() As Boolean\r\n        For i As Integer = 0 To Numbers.Count - 2\r\n            If Numbers(i) > Numbers(i + 1) Then Return False\r\n        Next\r\n        Return True\r\n    End Function\r\n\r\n\r\n    Private Function TryAgain() As Boolean\r\n        Console.WriteLine(\"TRY AGAIN? (Y OR N)\")\r\n        If Console.ReadKey(True).Key = ConsoleKey.Y Then\r\n            Return True\r\n        Else\r\n            Return False\r\n        End If\r\n    End Function\r\n\r\n\r\n\r\n\r\nEnd Module\r\n"
  },
  {
    "path": "73_Reverse/vbnet/Reverse.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Reverse</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/README.md",
    "content": "### Rock, Scissors, Paper\n\nRemember the game of rock-scissors-paper. You and your opponent make a motion three times with your fists and then either show:\n- a flat hand (paper)\n- fist (rock)\n- two fingers (scissors)\n\nDepending upon what is shown, the game is a tie (both show the same) or one person wins. Paper wraps up rock, so it wins. Scissors cut paper, so they win. And rock breaks scissors, so it wins.\n\nIn this computerized version of rock-scissors-paper, you can play up to ten games vs. the computer.\n\nCharles Lund wrote this game while at the American School in The Hague, Netherlands.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=137)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=152)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/Choice.cs",
    "content": "namespace RockScissorsPaper\n{\n    public class Choice\n    {\n        public string Selector {get; private set; }\n        public string Name { get; private set; }\n        internal Choice CanBeat { get; set; }\n\n        public Choice(string selector, string name) {\n            Selector = selector;\n            Name = name;\n        }\n\n        public bool Beats(Choice choice)\n        {\n            return choice == CanBeat;\n        }\n    }\n}\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/Choices.cs",
    "content": "using System;\n\nnamespace RockScissorsPaper\n{\n    public class Choices\n    {\n        public static readonly Choice Rock = new Choice(\"3\", \"Rock\");\n        public static readonly Choice Scissors = new Choice(\"2\", \"Scissors\");\n        public static readonly Choice Paper = new Choice(\"1\", \"Paper\");\n\n        private static readonly Choice[] _allChoices;\n        private static readonly Random _random = new Random();\n\n        static Choices()\n        {\n            Rock.CanBeat = Scissors;\n            Scissors.CanBeat = Paper;\n            Paper.CanBeat = Rock;\n\n            _allChoices = new[] { Rock, Scissors, Paper };\n        }\n\n        public static Choice GetRandom()\n        {\n            return _allChoices[_random.Next(_allChoices.GetLength(0))];\n        }\n\n        public static bool TryGetBySelector(string selector, out Choice choice)\n        {\n            foreach (var possibleChoice in _allChoices)\n            {\n                if (string.Equals(possibleChoice.Selector, selector))\n                {\n                    choice = possibleChoice;\n                    return true;\n                }\n            }\n            choice = null;\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/Game.cs",
    "content": "using System;\nusing System.Linq;\n\nnamespace RockScissorsPaper\n{\n    public class Game\n    {\n        public int ComputerWins { get; private set; }\n        public int HumanWins { get; private set; }\n        public int TieGames { get; private set; }\n\n        public void PlayGame()\n        {\n            var computerChoice = Choices.GetRandom();\n            var humanChoice = GetHumanChoice();\n\n            Console.WriteLine(\"This is my choice...\");\n            Console.WriteLine(\"...{0}\", computerChoice.Name);\n\n            if (humanChoice.Beats(computerChoice))\n            {\n                Console.WriteLine(\"You win!!!\");\n                HumanWins++;\n            }\n            else if (computerChoice.Beats(humanChoice))\n            {\n                Console.WriteLine(\"Wow!  I win!!!\");\n                ComputerWins++;\n            }\n            else\n            {\n                Console.WriteLine(\"Tie game.  No winner.\");\n                TieGames++;\n            }\n        }\n\n        public void WriteFinalScore()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"Here is the final game score:\");\n            Console.WriteLine(\"I have won {0} game(s).\", ComputerWins);\n            Console.WriteLine(\"You have one {0} game(s).\", HumanWins);\n            Console.WriteLine(\"And {0} game(s) ended in a tie.\", TieGames);\n        }\n\n        public Choice GetHumanChoice()\n        {\n            while (true)\n            {\n                Console.WriteLine(\"3=Rock...2=Scissors...1=Paper\");\n                Console.WriteLine(\"1...2...3...What's your choice\");\n                if (Choices.TryGetBySelector(Console.ReadLine(), out var choice))\n                    return choice;\n                Console.WriteLine(\"Invalid.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace RockScissorsPaper\n{\n    static class Program\n    {\n        static void Main(string[] args)\n        {\n            Console.WriteLine(\"GAME OF ROCK, SCISSORS, PAPER\");\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n\n            var numberOfGames = GetNumberOfGames();\n\n            var game = new Game();\n            for (var gameNumber = 1; gameNumber <= numberOfGames; gameNumber++) {\n                Console.WriteLine();\n                Console.WriteLine(\"Game number {0}\", gameNumber);\n\n                game.PlayGame();\n            }\n\n            game.WriteFinalScore();\n\n            Console.WriteLine();\n            Console.WriteLine(\"Thanks for playing!!\");\n        }\n\n        static int GetNumberOfGames()\n        {\n            while (true) {\n                Console.WriteLine(\"How many games\");\n                if (int.TryParse(Console.ReadLine(), out var number))\n                {\n                    if (number < 11 && number > 0)\n                        return number;\n                    Console.WriteLine(\"Sorry, but we aren't allowed to play that many.\");\n                }\n                else\n                {\n                    Console.WriteLine(\"Sorry, I didn't understand.\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/RockScissorsPaper.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <RootNamespace>RockScissorsPaper</RootNamespace>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/csharp/RockScissorsPaper.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"RockScissorsPaper\", \"RockScissorsPaper.csproj\", \"{162F12A7-72D0-44C8-9854-EA50C707690F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{162F12A7-72D0-44C8-9854-EA50C707690F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{162F12A7-72D0-44C8-9854-EA50C707690F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{162F12A7-72D0-44C8-9854-EA50C707690F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{162F12A7-72D0-44C8-9854-EA50C707690F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/java/src/RockScissors.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Rock Scissors Paper\n * <p>\n * Based on the Basic game of Rock Scissors here\n * https://github.com/coding-horror/basic-computer-games/blob/main/74%20Rock%20Scissors%20Paper/rockscissors.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\npublic class RockScissors {\n\n    public static final int MAX_GAMES = 10;\n\n    public static final int PAPER = 1;\n    public static final int SCISSORS = 2;\n    public static final int ROCK = 3;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        START_GAME,\n        GET_NUMBER_GAMES,\n        START_ROUND,\n        PLAY_ROUND,\n        GAME_RESULT,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private enum WINNER {\n        COMPUTER,\n        PLAYER\n    }\n\n    private WINNER gameWinner;\n\n    int playerWins;\n    int computerWins;\n    int numberOfGames;\n    int currentGameCount;\n    int computersChoice;\n\n    public RockScissors() {\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.START_GAME;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case START_GAME:\n                    intro();\n                    currentGameCount = 0;\n                    gameState = GAME_STATE.GET_NUMBER_GAMES;\n\n                    break;\n\n                case GET_NUMBER_GAMES:\n                    numberOfGames = displayTextAndGetNumber(\"HOW MANY GAMES? \");\n                    if (numberOfGames <= MAX_GAMES) {\n                        gameState = GAME_STATE.START_ROUND;\n                    } else {\n                        System.out.println(\"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\");\n                    }\n                    break;\n\n                case START_ROUND:\n                    currentGameCount++;\n                    if (currentGameCount > numberOfGames) {\n                        gameState = GAME_STATE.GAME_RESULT;\n                        break;\n                    }\n                    System.out.println(\"GAME NUMBER: \" + (currentGameCount));\n                    computersChoice = (int) (Math.random() * 3) + 1;\n                    gameState = GAME_STATE.PLAY_ROUND;\n\n                case PLAY_ROUND:\n                    System.out.println(\"3=ROCK...2=SCISSORS...1=PAPER\");\n                    int playersChoice = displayTextAndGetNumber(\"1...2...3...WHAT'S YOUR CHOICE? \");\n                    if (playersChoice >= PAPER && playersChoice <= ROCK) {\n                        switch (computersChoice) {\n                            case PAPER:\n                                System.out.println(\"...PAPER\");\n                                break;\n                            case SCISSORS:\n                                System.out.println(\"...SCISSORS\");\n                                break;\n                            case ROCK:\n                                System.out.println(\"...ROCK\");\n                                break;\n                        }\n\n                        if (playersChoice == computersChoice) {\n                            System.out.println(\"TIE GAME.  NO WINNER.\");\n                        } else {\n                            switch (playersChoice) {\n                                case PAPER:\n                                    if (computersChoice == SCISSORS) {\n                                        gameWinner = WINNER.COMPUTER;\n                                    } else if (computersChoice == ROCK) {\n                                        // Don't need to re-assign here, as its initialized to\n                                        // false I'd argue this aids readability.\n                                        gameWinner = WINNER.PLAYER;\n                                    }\n                                    break;\n                                case SCISSORS:\n                                    if (computersChoice == ROCK) {\n                                        gameWinner = WINNER.COMPUTER;\n                                    } else if (computersChoice == PAPER) {\n                                        // Don't need to re-assign here, as its initialized to\n                                        // false I'd argue this aids readability.\n                                        gameWinner = WINNER.PLAYER;\n                                    }\n                                    break;\n                                case ROCK:\n                                    if (computersChoice == PAPER) {\n                                        gameWinner = WINNER.COMPUTER;\n                                    } else if (computersChoice == SCISSORS) {\n                                        // Don't need to re-assign here, as its initialized to\n                                        // false I'd argue this aids readability.\n                                        gameWinner = WINNER.PLAYER;\n                                    }\n                                    break;\n                            }\n\n                            if (gameWinner == WINNER.COMPUTER) {\n                                System.out.println(\"WOW!  I WIN!!!\");\n                                computerWins++;\n                            } else {\n                                System.out.println(\"YOU WIN!!!\");\n                                playerWins++;\n                            }\n                        }\n                        gameState = GAME_STATE.START_ROUND;\n                    } else {\n                        System.out.println(\"INVALID.\");\n                    }\n\n                    break;\n\n                case GAME_RESULT:\n                    System.out.println();\n                    System.out.println(\"HERE IS THE FINAL GAME SCORE:\");\n                    System.out.println(\"I HAVE WON \" + computerWins + \" GAME\" + (computerWins != 1 ? \"S.\" : \".\"));\n                    System.out.println(\"YOU HAVE WON \" + playerWins + \" GAME\" + (playerWins != 1 ? \"S.\" : \".\"));\n                    int tiedGames = numberOfGames - (computerWins + playerWins);\n                    System.out.println(\"AND \" + tiedGames + \" GAME\" + (tiedGames != 1 ? \"S \" : \" \") + \"ENDED IN A TIE.\");\n                    System.out.println();\n                    System.out.println(\"THANKS FOR PLAYING!!\");\n                    gameState = GAME_STATE.GAME_OVER;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(addSpaces(21) + \"GAME OF ROCK, SCISSORS, PAPER\");\n        System.out.println(addSpaces(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.nextLine();\n    }\n\n    /**\n     * Return a string of x spaces\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String addSpaces(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    public static void main(String[] args) {\n\n        RockScissors rockScissors = new RockScissors();\n        rockScissors.play();\n    }\n}\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/javascript/rockscissors.mjs",
    "content": "#!/usr/bin/env node\n// ROCK, SCISSORS, PAPER\n//\n// Converted from BASIC to Javascript by Alexander Wunschik (mojoaxel)\n\nimport { println, tab, input } from '../../00_Common/javascript/common.mjs';\n\nlet userWins = 0;\nlet computerWins = 0;\nlet ties = 0;\n\n// 30 INPUT \"HOW MANY GAMES\";Q\n// 40 IF Q<11 THEN 60\n// 50 PRINT \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\": GOTO 30\n// 60 FOR G=1 TO Q\nasync function getGameCount() {\n\tlet gameCount = await input(\"HOW MANY GAMES\");\n\tif (gameCount > 10) {\n\t\tprintln(\"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\");\n\t\treturn await getGameCount();\n\t}\n\treturn gameCount;\n}\n\n// #90 PRINT \"3=ROCK...2=SCISSORS...1=PAPER\"\n// #100 INPUT \"1...2...3...WHAT'S YOUR CHOICE\";K\n// #110 IF (K-1)*(K-2)*(K-3)<>0 THEN PRINT \"INVALID.\": GOTO 90\nasync function getUserInput() {\n\tprintln(\"3=ROCK...2=SCISSORS...1=PAPER\");\n\tconst userChoice = await input(\"1...2...3...WHAT'S YOUR CHOICE\");\n\tif (userChoice < 1 || userChoice > 3) {\n\t\tprintln(\"INVALID.\");\n\t\treturn await getUserInput();\n\t}\n\treturn userChoice;\n}\n\nasync function game() {\n\t// 10 PRINT TAB(21);\"GAME OF ROCK, SCISSORS, PAPER\"\n\t// 20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n\t// 25 PRINT:PRINT:PRINT\n\tprintln(tab(21), 'GAME OF ROCK, SCISSORS, PAPER');\n\tprintln(tab(15), 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY');\n\tprintln('\\n\\n');\n\n\tlet gameCount = await getGameCount();\n\n\tasync function playGame(gameNumber) {\n\t\t// 70 PRINT: PRINT \"GAME NUMBER\";G\n\t\tprintln(\"\\nGAME NUMBER \", gameNumber);\n\n\t\tconst ROCK = 3;\n\t\tconst SCISSORS = 2;\n\t\tconst PAPER = 1;\n\n\t\tconst usersChoice = await getUserInput();\n\n\t\t// 80 X=INT(RND(1)*3+1)\n\t\tconst computersChoice = Math.floor(Math.random()*3) + 1;\n\n\t\t// 120 PRINT \"THIS IS MY CHOICE...\"\n\t\t// 130 ON X GOTO 140,150,160\n\t\t// 140 PRINT \"...PAPER\": GOTO 170\n\t\t// 150 PRINT \"...SCISSORS\": GOTO 170\n\t\t// 160 PRINT \"...ROCK\"\n\t\tprintln(\"THIS IS MY CHOICE...\", \n\t\t\tcomputersChoice === PAPER ? \"...PAPER\" : \n\t\t\t\tcomputersChoice === SCISSORS ? \"...SCISSORS\" : \n\t\t\t\t\t\"...ROCK\");\n\n\n\t\t// 170 IF X=K THEN 250\n\t\t// 180 IF X>K THEN 230\n\t\t// 190 IF X=1 THEN 210\n\t\t// 200 PRINT \"YOU WIN!!!\":H=H+1: GOTO 260\n\t\t// 210 IF K<>3 THEN 200\n\t\t// 220 PRINT \"WOW!  I WIN!!!\":C=C+1:GOTO 260\n\t\t// 230 IF K<>1 OR X<>3 THEN 220\n\t\t// 240 GOTO 200\n\t\t// 250 PRINT \"TIE GAME.  NO WINNER.\"\n\t\tif (computersChoice == usersChoice) {\n\t\t\tprintln(\"TIE GAME.  NO WINNER.\");\n\t\t\tties++;\n\t\t} else if (\n\t\t\t(computersChoice == ROCK && usersChoice == SCISSORS) ||\n\t\t\t(computersChoice == PAPER && usersChoice == ROCK) ||\n\t\t\t(computersChoice == SCISSORS && usersChoice == PAPER)\n\t\t) {\n\t\t\tprintln(\"WOW!  I WIN!!!\");\n\t\t\tcomputerWins++;\n\t\t} else {\n\t\t\tprintln(\"YOU WIN!!!\");\n\t\t\tuserWins++;\n\t\t}\n\t}\n\n\tfor (let gameNumber = 1; gameNumber <= gameCount; gameNumber++) {\n\t\tawait playGame(gameNumber);\n\t\t// 260 NEXT G\n\t}\n\n\t// 270 PRINT: PRINT \"HERE IS THE FINAL GAME SCORE:\"\n\t// 280 PRINT \"I HAVE WON\";C;\"GAME(S).\"\n\t// 290 PRINT \"YOU HAVE WON\";H;\"GAME(S).\"\n\t// 300 PRINT \"AND\";Q-(C+H20);\"GAME(S) ENDED IN A TIE.\"\n\tprintln(\"\\nHERE IS THE FINAL GAME SCORE:\");\n\tprintln(`I HAVE WON ${computerWins} GAME(S).`);\n\tprintln(`YOU HAVE WON ${userWins} GAME(S).`);\n\tprintln(`AND ${ties} GAME(S) ENDED IN A TIE.`);\n\n\t// 310 PRINT: PRINT \"THANKS FOR PLAYING!!\"\n\tprintln(\"\\nTHANKS FOR PLAYING!!\");\n\t\n\t// 320 END\n\tprocess.exit(0);\n}\ngame();\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/lua/rockscissors.lua",
    "content": "-- rockscissors.lua\n-- Ported by Brian Wilkins (BrianWilkinsFL)\n-- Utilized has_key again and choice. A lot of these basic programs\n-- follow a similar choice structure so I think I'll use these functions alot.\n\nfunction getInput(prompt)\n    io.write(prompt)\n    io.flush()\n    local input = io.read(\"l\") \n    if not input then  --- test for EOF\n        print(\"GOODBYE\")\n        os.exit(0)\n    end\n    return input\nend\n\nfunction has_key(table, key)\n   return table[key]~=nil\nend\n \nfunction choice(prompt, table)\n   resp = getInput(prompt)\n   while not has_key(table, resp) do\n      print(\"INVALID.\")\n      resp = getInput(prompt)\n   end\n   return resp\nend\n\nfunction playGame(n)\n   local computerWins = 0\n   local humanWins = 0\n   itemChoices = {\n        [\"1\"] = \"PAPER\",\n        [\"2\"] = \"SCISSORS\",\n        [\"3\"] = \"ROCK\",\n   }\n   print(\"GAME NUMBER \" .. n)\n\n   math.randomseed(os.time())\n   computerChoice = math.random(1,3)\n  \n   humanChoice = choice(\"3=ROCK...2=SCISSORS...1=PAPER\\n1...2...3...WHAT'S YOUR CHOICE? \", itemChoices)\n   humanChoice = tonumber(humanChoice)\n   print(\"THIS IS MY CHOICE...\")\n\n   print(\"... \" .. itemChoices[tostring(computerChoice)])\n\n   -- Working around a Lua thing where I can't seem to interact\n   -- with function values outside of the function itself\n   -- So the total wins are calculated outside of this function\n   -- and summarized. \n   if computerChoice == humanChoice then \n      print(\"TIE GAME.  NO WINNER.\")\n   elseif computerChoice > humanChoice then\n      if humanChoice ~=1 or computerChoice ~= 3 then \n         computerWins = 1\n         print(\"WOW!  I WIN!!!\")\n      else\n         humanWins = 1\n         print(\"YOU WIN!!!\")\n      end\n   elseif computerChoice == 1 then\n      if humanChoice ~= 3 then\n         humanWins = 1\n         print(\"YOU WIN!!!\")\n      else\n         computerWins = 1\n         print(\"WOW! I WIN!!!\")\n      end\n   end\n   return computerWins, humanWins\nend\n\nlocal games = 0\nwhile games == 0 or games >= 11 do\n   resp = getInput(\"HOW MANY GAMES? \")\n   \n   assert(tonumber(resp))\n   games = tonumber(resp)\n   if games < 11 then break end\n   \n   print(\"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\")\nend\n\ntotalComputerWins = 0\ntotalHumanWins = 0\n\nfor n=1, games, 1 do\n   computerWins, humanWins = playGame(n)\n   totalComputerWins = totalComputerWins + computerWins\n   totalHumanWins = totalHumanWins + humanWins\nend\n\nprint(\"HERE IS THE FINAL GAME SCORE:\")\nprint(\"I HAVE WON \" .. totalComputerWins .. \" GAME(S).\")\nprint(\"YOU HAVE WON \" .. totalHumanWins ..\" GAME(S).\")\nprint(\"AND \" .. games-(totalComputerWins+totalHumanWins) .. \" GAME(S) ENDED IN A TIE.\")\nprint(\"THANKS FOR PLAYING!!\")"
  },
  {
    "path": "74_Rock_Scissors_Paper/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/perl/rockscissors.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\n\nprint ' 'x 21 . \"GAME OF ROCK, SCISSORS, PAPER\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\n\nmy $Q=0;\nmy $C=0;\nmy $H=0;\n\ndo {\n\tprint \"HOW MANY GAMES? \"; chomp($Q = <STDIN>);\n\tif ($Q>10) { print \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\\n\"; }\n\t} until ($Q<11);\n\nfor (my $G=1; $G<=$Q; $G++) {\n\tprint \"\\n\"; print \"GAME NUMBER $G\\n\";\n\tmy $X=int(rand(1)*3+1);\n\n\tmy $K=0;\n\tdo {\n\t\tprint \"3=ROCK...2=SCISSORS...1=PAPER\\n\";\n\t\tprint \"1...2...3...WHAT'S YOUR CHOICE? \"; chomp($K = <STDIN>);\n\t\tif (($K-1)*($K-2)*($K-3)!=0) { print \"INVALID.\\n\"; $K=0; }\n\t\t} until ($K!=0);\n\n\n\tprint \"THIS IS MY CHOICE...\\n\";\n\tif ($X==1) { print \"...PAPER\\n\"; }\n\tif ($X==2) { print \"...SCISSORS\\n\"; }\n\tif ($X==3) { print \"...ROCK\\n\"; }\n\n\t#Original logic too complex...\n\tif ($X==$K) { print \"TIE GAME. NO WINNER.\\n\"; next; }\n\tmy $Who=0;\n\tif ($X==1 && $K==3) { $Who=1; } #Paper wins over rock.\n\tif ($X==2 && $K==1) { $Who=1; } #Scissors wins over paper.\n\tif ($X==3 && $K==2) { $Who=1; } #Rock wins over scissors.\n\tif ($Who==1) {\n\t\tprint \"WOW! I WIN!!!\\n\"; $C=$C+1;\n\t\t} else {\n\t\tprint \"YOU WIN!!!\\n\"; $H=$H+1;\n\t\t}\n\t}\n\nprint \"\\n\"; print \"HERE IS THE FINAL GAME SCORE:\\n\";\nprint \"I HAVE WON $C GAME(S).\\n\";\nprint \"YOU HAVE WON $H GAME(S).\\n\";\nprint \"AND \".($Q-($C+$H)).\" GAME(S) ENDED IN A TIE.\\n\";\nprint \"\\n\"; print \"THANKS FOR PLAYING!!\\n\";\nexit;\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/python/rockscissors.py",
    "content": "#!/usr/bin/env python3\n# ROCKSCISSORS\n#\n# Converted from BASIC to Python by Trevor Hobson\n\nimport random\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n\n    while True:\n        try:\n            games = int(input(\"How many games? \"))\n            if games >= 11:\n                print(\"Sorry, but we aren't allowed to play that many.\")\n            else:\n                break\n\n        except ValueError:\n            print(\"Please enter a number.\")\n\n    won_computer = 0\n    won_human = 0\n\n    for game in range(games):\n        print(\"\\nGame number\", game + 1)\n        guess_computer = random.randint(1, 3)\n        print(\"3=Rock...2=Scissors...1=Paper\")\n        guess_human = 0\n        while guess_human == 0:\n            try:\n                guess_human = int(input(\"1...2...3...What's your choice \"))\n                if guess_human not in [1, 2, 3]:\n                    guess_human = 0\n                    print(\"Invalid\")\n\n            except ValueError:\n                print(\"Please enter a number.\")\n        print(\"This is my choice...\")\n        if guess_computer == 1:\n            print(\"...Paper\")\n        elif guess_computer == 2:\n            print(\"...Scissors\")\n        elif guess_computer == 3:\n            print(\"...Rock\")\n        if (\n            guess_computer != guess_human\n            and guess_computer > guess_human\n            and (guess_human != 1 or guess_computer != 3)\n            or guess_computer != guess_human\n            and guess_computer <= guess_human\n            and guess_computer == 1\n            and guess_human == 3\n        ):\n            print(\"Wow! I win!!!\")\n            won_computer = won_computer + 1\n        elif (\n            guess_computer != guess_human\n            and guess_computer > guess_human\n            or guess_computer != guess_human\n            and guess_computer == 1\n        ):\n            print(\"You win!!!\")\n            won_human = won_human + 1\n        elif guess_computer == guess_human:\n            print(\"Tie Game. No winner\")\n    print(\"\\nHere is the final game score:\")\n    print(\"I have won\", won_computer, \"game(s).\")\n    print(\"You have won\", won_human, \"game(s).\")\n    print(\"and\", games - (won_computer + won_human), \"game(s) ended in a tie.\")\n    print(\"\\nThanks for playing!!\\n\")\n\n\ndef main() -> None:\n    print(\" \" * 21 + \"GAME OF ROCK, SCISSORS, PAPER\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n\n    keep_playing = True\n    while keep_playing:\n\n        play_game()\n\n        keep_playing = input(\"Play again? (yes or no) \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/rockscissors.bas",
    "content": "10 PRINT TAB(21);\"GAME OF ROCK, SCISSORS, PAPER\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n25 PRINT:PRINT:PRINT\n30 INPUT \"HOW MANY GAMES\";Q\n40 IF Q<11 THEN 60\n50 PRINT \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\": GOTO 30\n60 FOR G=1 TO Q\n70 PRINT: PRINT \"GAME NUMBER\";G\n80 X=INT(RND(1)*3+1)\n90 PRINT \"3=ROCK...2=SCISSORS...1=PAPER\"\n100 INPUT \"1...2...3...WHAT'S YOUR CHOICE\";K\n110 IF (K-1)*(K-2)*(K-3)<>0 THEN PRINT \"INVALID.\": GOTO 90\n120 PRINT \"THIS IS MY CHOICE...\"\n130 ON X GOTO 140,150,160\n140 PRINT \"...PAPER\": GOTO 170\n150 PRINT \"...SCISSORS\": GOTO 170\n160 PRINT \"...ROCK\"\n170 IF X=K THEN 250\n180 IF X>K THEN 230\n190 IF X=1 THEN 210\n200 PRINT \"YOU WIN!!!\":H=H+1: GOTO 260\n210 IF K<>3 THEN 200\n220 PRINT \"WOW!  I WIN!!!\":C=C+1:GOTO 260\n230 IF K<>1 OR X<>3 THEN 220\n240 GOTO 200\n250 PRINT \"TIE GAME.  NO WINNER.\"\n260 NEXT G\n270 PRINT: PRINT \"HERE IS THE FINAL GAME SCORE:\"\n280 PRINT \"I HAVE WON\";C;\"GAME(S).\"\n290 PRINT \"YOU HAVE WON\";H;\"GAME(S).\"\n300 PRINT \"AND\";Q-(C+H);\"GAME(S) ENDED IN A TIE.\"\n310 PRINT: PRINT \"THANKS FOR PLAYING!!\"\n320 END\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/ruby/rockscissors.rb",
    "content": "SCREEN_WIDTH = 72\n\nMOVE_WORDS = {\n  1 => 'PAPER',\n  2 => 'SCISSORS',\n  3 => 'ROCK'\n}\n\nWIN_TABLE = {\n  1 => 3,\n  2 => 1,\n  3 => 2\n}\n\ndef center_text(text)\n  text.rjust((SCREEN_WIDTH / 2) + (text.size / 2))\nend\n\ndef ask_for_number_of_games\n  loop do\n    puts \"HOW MANY GAMES\"\n    response = STDIN.gets.to_i\n    return response if response > 0 and response < 11\n    puts \"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\"\n  end\nend\n\ndef ask_for_human_move\n  loop do\n    puts \"3=ROCK...2=SCISSORS...1=PAPER\"\n    puts \"1...2...3...WHAT'S YOUR CHOICE\"\n    response = STDIN.gets.to_i\n    return response if [1,2,3].include?(response)\n    puts \"INVALID\"\n  end\nend\n\ndef calculate_result(human_move, computer_move)\n  return 'TIE' if human_move == computer_move\n  return 'WIN' if WIN_TABLE[human_move] == computer_move\n  'LOSE'\nend\n\nputs center_text('GAME OF ROCK, SCISSORS, PAPER')\nputs center_text('CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY')\nputs\nputs\nputs\n\nnumber_of_games = ask_for_number_of_games\ngames_won = 0\ngames_lost = 0\n\nnumber_of_games.times do |game_number|\n  puts\n  puts \"GAME NUMBER #{game_number + 1}\"\n  computer_move = rand(3) + 1\n  human_move = ask_for_human_move\n  puts \"THIS IS MY CHOICE...\"\n  puts \"...#{MOVE_WORDS[computer_move]}\"\n\n  case calculate_result(human_move, computer_move)\n  when 'WIN'\n    puts \"YOU WIN!!!\"\n    games_won += 1\n  when 'TIE'\n    puts \"TIE GAME.  NO WINNER.\"\n  when 'LOSE'\n    puts \"WOW!  I WIN!!!\"\n    games_lost = games_lost += 1\n  end\nend\n\nputs\nputs \"HERE IS THE FINAL GAME SCORE:\"\nputs \"I HAVE WON #{games_lost} GAME(S).\"\nputs \"YOU HAVE WON #{games_won} GAME(S).\"\nputs \"AND #{number_of_games - (games_lost + games_won)} GAME(S) ENDED IN A TIE.\"\nputs \"THANKS FOR PLAYING!!\"\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/rust/Cargo.toml",
    "content": "[package]\nname = \"rock_scissors_paper\"\nversion = \"1.0.0\"\nedition = \"2021\"\n\n[dependencies]\ntext_io = \"0.1.10\"\nstrum = \"0.24\"\nstrum_macros = \"0.24\"\nnanorand = \"0.6.1\"\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/rust/src/main.rs",
    "content": "/*\n * Rock paper scissors\n * Originally from the wonderful book: _Basic Computer Games_\n * Port to Rust By David Lotts\n*/\nuse nanorand::{tls::TlsWyRand, Rng};\nuse std::io::{self, Write};\nuse strum::EnumCount;\nuse strum_macros::{Display, EnumCount, FromRepr};\nuse text_io::try_read;\nfn main() {\n    let mut computer_wins = 0;\n    let mut human_wins = 0;\n    let mut rng = nanorand::tls_rng();\n    println!(\"{:>21}\", \"GAME OF ROCK, SCISSORS, PAPER\");\n    println!(\"{:>15}\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    print!(\"\\n\\n\\n\");\n    // pass by reference in rust! input() modifies this variable.\n    let mut qty_games = 0;\n    loop {\n        input_int(\"HOW MANY GAMES\", &mut qty_games);\n        if qty_games < 11 {\n            break;\n        }\n        println!(\"SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\");\n    }\n    for game_number in 1..=qty_games {\n        println!();\n        println!(\"GAME NUMBER {}\", game_number);\n        let mut your_choice = 0;\n        loop {\n            println!(\"3=ROCK...2=SCISSORS...1=PAPER\");\n            input_int(\"1...2...3...WHAT'S YOUR CHOICE\", &mut your_choice);\n            // interesting validation in original BASIC: IF (K-1)*(K-2)*(K-3)==0\n            if (1..=3).contains(&your_choice) {\n                break;\n            }\n            println!(\"INVALID.\");\n        }\n        // Convert number to enum.  Note the type change.  Really it is a new variable.\n        let your_choice = Choice::from_repr((your_choice - 1) as usize).unwrap();\n        let my_choice = Choice::new_random(&mut rng);\n\n        println!(\"THIS IS MY CHOICE...\");\n        println!(\"...{}\", my_choice.to_string());\n        let winner = Winner::decide_winner(my_choice, your_choice);\n        println!(\n            \"{}\",\n            match winner {\n                Winner::Tie => {\n                    \"TIE GAME.  NO WINNER.\"\n                }\n                Winner::Computer => {\n                    computer_wins = computer_wins + 1;\n                    \"WOW!  I WIN!!!\"\n                }\n                Winner::Human => {\n                    human_wins = human_wins + 1;\n                    \"YOU WIN!!!\"\n                }\n            }\n        )\n    }\n    println!();\n    println!(\"HERE IS THE FINAL GAME SCORE:\");\n    println!(\"I HAVE WON {} GAME(S).\", computer_wins);\n    println!(\"YOU HAVE WON {} GAME(S).\", human_wins);\n    println!(\n        \"AND {} GAME(S) ENDED IN A TIE.\",\n        qty_games - (computer_wins + human_wins)\n    );\n    println!();\n    println!(\"THANKS FOR PLAYING!!\");\n}\n\n#[derive(FromRepr, Debug, PartialEq, EnumCount, Display)]\npub enum Choice {\n    PAPER,\n    SCISSORS,\n    ROCK,\n}\n\nimpl Choice {\n    /// Returns randomly selected paper..rock.\n    fn new_random(rng: &mut TlsWyRand) -> Choice {\n        Choice::from_repr(rng.generate_range(0..Choice::COUNT)).unwrap()\n    }\n}\n\n#[derive(FromRepr, Debug, PartialEq, EnumCount)]\npub enum Winner {\n    Human,\n    Computer,\n    Tie,\n}\n\nimpl Winner {\n    /// take opponent's choices and decide the winner\n    // I really learned alot about enums here, and now you can too!\n    // Originally I broke this out for auto testing.\n    pub fn decide_winner(my_choice: Choice, your_choice: Choice) -> Winner {\n        let my_choice = my_choice as u8;\n        let your_choice = your_choice as u8;\n        if my_choice == your_choice {\n            return Winner::Tie;\n        }\n        // wordy but clear way:\n        //    if (my_choice == 1 && your_choice == 3) || (my_choice > your_choice)\n        // consice but opaque way:\n        if 1 == (3 + my_choice - your_choice) % 3 {\n            return Winner::Computer;\n        }\n        return Winner::Human;\n    }\n}\n\n/// print the prompt, wait for a number and newline.  Loop if invalid.\nfn input_int(prompt: &str, number: &mut i32) {\n    loop {\n        print!(\"{} ? \", prompt);\n        io::stdout().flush().unwrap();\n        if let Ok(n) = try_read!() {\n            *number = n;\n            return;\n        }\n    }\n}\n\n/// Test winner decider for every case.\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn winner_test() {\n        use super::*;\n        use Choice::*;\n        use Winner::*; //decide_winner(my_choice=computer, your_choice=human)\n        assert_eq!(Winner::decide_winner(PAPER, PAPER), Tie);\n        assert_eq!(Winner::decide_winner(PAPER, SCISSORS), Human);\n        assert_eq!(Winner::decide_winner(PAPER, ROCK), Computer);\n        assert_eq!(Winner::decide_winner(SCISSORS, PAPER), Computer);\n        assert_eq!(Winner::decide_winner(SCISSORS, SCISSORS), Tie);\n        assert_eq!(Winner::decide_winner(SCISSORS, ROCK), Human);\n        assert_eq!(Winner::decide_winner(ROCK, PAPER), Human);\n        assert_eq!(Winner::decide_winner(ROCK, SCISSORS), Computer);\n        assert_eq!(Winner::decide_winner(ROCK, ROCK), Tie);\n    }\n}\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"RockScissorsPaper\", \"RockScissorsPaper.vbproj\", \"{05C592E9-1A74-4812-88CF-3B078A315378}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{05C592E9-1A74-4812-88CF-3B078A315378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{05C592E9-1A74-4812-88CF-3B078A315378}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{05C592E9-1A74-4812-88CF-3B078A315378}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{05C592E9-1A74-4812-88CF-3B078A315378}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>RockScissorsPaper</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "75_Roulette/README.md",
    "content": "### Roulette\n\nThis game simulates an American Roulette wheel; “American” because it has 38 number compartments (1 to 36, 0 and 00). The European wheel has 37 numbers (1 to 36 and 0). The Bahamas, Puerto Rico, and South American countries are slowly switching to the American wheel because it gives the house a bigger percentage. Odd and even numbers alternate around the wheel, as do red and black. The layout of the wheel insures a highly random number pattern. In fact, roulette wheels are sometimes used to generate tables of random numbers.\n\nIn this game, you may bet from $5 to $500 and you may bet on red or black, odd or even, first or second 18 numbers, a column, or single number. You may place any number of bets on each spin of the wheel.\n\nThere is no long-range winning strategy for playing roulette. However, a good strategy is that of “doubling.” First spin, bet $1 on an even/odds bet (odd, even, red, or black). If you lose, double your bet again to $2. If you lose again, double to $4. Continue to double until you win (i.e, you break even on a losing sequence). As soon as you win, bet $1 again, and after every win, bet $1. Do not ever bet more than $1 unless you are recuperating losses by doubling. Do not ever bet anything but the even odds bets. Good luck!\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=138)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=153)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n- The program keeps a count of how often each number comes up in array `X`, but never makes use of this information.\n"
  },
  {
    "path": "75_Roulette/csharp/Bet.cs",
    "content": "namespace Roulette;\n\ninternal record struct Bet(BetType Type, int Number, int Wager)\n{\n    public int Payout => Wager * Type.Payout;\n}\n"
  },
  {
    "path": "75_Roulette/csharp/BetType.cs",
    "content": "namespace Roulette;\n\ninternal record struct BetType(int Value)\n{\n    public static implicit operator BetType(int value) => new(value);\n\n    public int Payout => Value switch\n        {\n            <= 36 or >= 49 => 35,\n            <= 42 => 2,\n            <= 48 => 1\n        };\n}\n"
  },
  {
    "path": "75_Roulette/csharp/Croupier.cs",
    "content": "namespace Roulette;\n\ninternal class Croupier\n{\n    private const int _initialHouse = 100_000;\n    private const int _initialPlayer = 1_000;\n\n    private int _house = _initialHouse;\n    private int _player = _initialPlayer;\n\n    public string Totals => Strings.Totals(_house, _player);\n    public bool PlayerIsBroke => _player <= 0;\n    public bool HouseIsBroke => _house <= 0;\n\n    internal string Pay(Bet bet)\n    {\n        _house -= bet.Payout;\n        _player += bet.Payout;\n\n        if (_house <= 0)\n        {\n            _player = _initialHouse + _initialPlayer;\n        }\n\n        return Strings.Win(bet);\n    }\n\n    internal string Take(Bet bet)\n    {\n        _house += bet.Wager;\n        _player -= bet.Wager;\n\n        return Strings.Lose(bet);\n    }\n\n    public void CutCheck(IReadWrite io, IRandom random)\n    {\n        var name = io.ReadString(Prompts.Check);\n        io.Write(Strings.Check(random, name, _player));\n    }\n}\n"
  },
  {
    "path": "75_Roulette/csharp/Game.cs",
    "content": "namespace Roulette;\n\ninternal class Game\n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n    private readonly Table _table;\n    private readonly Croupier _croupier;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n        _croupier = new();\n        _table = new(_croupier, io, random);\n    }\n\n    public void Play()\n    {\n        _io.Write(Streams.Title);\n        if (!_io.ReadString(Prompts.Instructions).ToLowerInvariant().StartsWith('n'))\n        {\n            _io.Write(Streams.Instructions);\n        }\n\n        while (_table.Play());\n\n        if (_croupier.PlayerIsBroke)\n        {\n            _io.Write(Streams.LastDollar);\n            _io.Write(Streams.Thanks);\n            return;\n        }\n\n        if (_croupier.HouseIsBroke)\n        {\n            _io.Write(Streams.BrokeHouse);\n        }\n\n        _croupier.CutCheck(_io, _random);\n    }\n}\n"
  },
  {
    "path": "75_Roulette/csharp/IOExtensions.cs",
    "content": "namespace Roulette;\n\ninternal static class IOExtensions\n{\n    internal static int ReadBetCount(this IReadWrite io)\n    {\n        while (true)\n        {\n            var betCount = io.ReadNumber(Prompts.HowManyBets);\n            if (betCount.IsValidInt(1)) { return (int)betCount; }\n        }\n    }\n\n    internal static Bet ReadBet(this IReadWrite io, int number)\n    {\n        while (true)\n        {\n            var (type, amount) = io.Read2Numbers(Prompts.Bet(number));\n\n            if (type.IsValidInt(1, 50) && amount.IsValidInt(5, 500))\n            {\n                return new()\n                {\n                    Type = (int)type, \n                    Number = number, \n                    Wager = (int)amount\n                };\n            }\n        }\n    }\n\n    internal static bool IsValidInt(this float value, int minValue, int maxValue = int.MaxValue)\n        => value == (int)value && value >= minValue && value <= maxValue;\n}"
  },
  {
    "path": "75_Roulette/csharp/Program.cs",
    "content": "global using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using static Roulette.Resources.Resource;\nusing Roulette;\n\nnew Game(new ConsoleIO(), new RandomNumberGenerator()).Play();\n"
  },
  {
    "path": "75_Roulette/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/AgainPrompt.txt",
    "content": "Again"
  },
  {
    "path": "75_Roulette/csharp/Resources/BetAlready.txt",
    "content": "You made that bet once already,dum-dum"
  },
  {
    "path": "75_Roulette/csharp/Resources/BetPrompt.txt",
    "content": "Number {0} "
  },
  {
    "path": "75_Roulette/csharp/Resources/BrokeHouse.txt",
    "content": "You broke the house!\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Check.txt",
    "content": "\n------------------------------------------------------------------------Check No.  {0}\n\n                                        {1:MMMM d',' yyyy}\n\n\nPay to the order of-----{2}-----$  {3}\n\n\n              The Memory Bank of New YORK\n\n                                          The Computer\n                                        ----------X-----\n\n--------------------------------------------------------------Come back soon!\n\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/CheckPrompt.txt",
    "content": "To whom shall I make the check"
  },
  {
    "path": "75_Roulette/csharp/Resources/HowManyBetsPrompt.txt",
    "content": "How many bets"
  },
  {
    "path": "75_Roulette/csharp/Resources/Instructions.txt",
    "content": "\nThis is the betting layout\n  (*=RED)\n\n 1*    2     3*\n 4     5*    6 \n 7*    8     9*\n10    11    12*\n---------------\n13    14*   15 \n16*   17    18*\n19*   20    21*\n22    23*   24 \n---------------\n25*   26    27*\n28    29    30*\n31    32*   33 \n34*   35    36*\n---------------\n    00    0    \n\nTypes of bets\n\nThe numbers 1 to 36 signify a straight bet\non that number.\nThese pay off 35:1\n\nThe 2:1 bets are:\n 37) 1-12     40) First column\n 38) 13-24    41) Second column\n 39) 25-36    42) Third column\n\nThe even money bets are:\n 43) 1-18     46) Odd\n 44) 19-36    47) Red\n 45) Even     48) Black\n\n49)0 and 50)00 pay off 35:1\nNote: 0 and 00 do not count under any\n      bets except their own.\n\nWhen I ask for each bet, type the number\nand the amount, separated by a comma.\nFor example: to bet $500 on Black, type 48,500\nwhen I ask for a bet.\n\nThe minimum bet is $5, the maximum is $500.\n\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/InstructionsPrompt.txt",
    "content": "Do you want instructions"
  },
  {
    "path": "75_Roulette/csharp/Resources/LastDollar.txt",
    "content": "Oops! you just spent your last dollar!\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Outcome.txt",
    "content": "You {0} {1} dollars on bet {2}\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing Games.Common.Randomness;\n\nnamespace Roulette.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Title => GetStream();\n        public static Stream Instructions => GetStream();\n        public static Stream BetAlready => GetStream();\n        public static Stream Spinning => GetStream();\n        public static Stream LastDollar => GetStream();\n        public static Stream BrokeHouse => GetStream();\n        public static Stream Thanks => GetStream();\n    }\n\n    internal static class Strings\n    {\n        public static string Black(int number) => Slot(number);\n        public static string Red(int number) => Slot(number);\n        private static string Slot(int number, [CallerMemberName] string? colour = null)\n            => string.Format(GetString(), number, colour);\n\n        public static string Lose(Bet bet) => Outcome(bet.Wager, bet.Number);\n        public static string Win(Bet bet) => Outcome(bet.Payout, bet.Number);\n        private static string Outcome(int amount, int number, [CallerMemberName] string? winlose = null)\n            => string.Format(GetString(), winlose, amount, number);\n\n        public static string Totals(int me, int you) => string.Format(GetString(), me, you);\n\n        public static string Check(IRandom random, string payee, int amount)\n            => string.Format(GetString(), random.Next(100), DateTime.Now, payee, amount);\n    }\n\n    internal static class Prompts\n    {\n        public static string Instructions => GetPrompt();\n        public static string HowManyBets => GetPrompt();\n        public static string Bet(int number) => string.Format(GetPrompt(), number);\n        public static string Again => GetPrompt();\n        public static string Check => GetPrompt();\n    }\n\n    private static string GetPrompt([CallerMemberName] string? name = null) => GetString($\"{name}Prompt\");\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "75_Roulette/csharp/Resources/Slot.txt",
    "content": " {0} {1}\n\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Spinning.txt",
    "content": "Spinning\n\n\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Thanks.txt",
    "content": "Thanks for you money.\nI'll use it to buy a solid gold roulette WHEEL\n\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Title.txt",
    "content": "                                Roulette\n               Creative Computing  Morristown, New Jersey\n\n\n\nWelcome to the roulette table\n\n"
  },
  {
    "path": "75_Roulette/csharp/Resources/Totals.txt",
    "content": "\nTotals        Me            You\n               {0,-14}{1}\n"
  },
  {
    "path": "75_Roulette/csharp/Roulette.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net7.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "75_Roulette/csharp/Roulette.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Roulette\", \"Roulette.csproj\", \"{9FC3EC1F-2052-4D08-901C-5184E17740FC}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "75_Roulette/csharp/Slot.cs",
    "content": "using System.Collections.Immutable;\n\nnamespace Roulette;\n\ninternal class Slot\n{\n    private readonly ImmutableHashSet<BetType> _coveringBets;\n\n    public Slot (string name, params BetType[] coveringBets)\n    {\n        Name = name;\n        _coveringBets = coveringBets.ToImmutableHashSet();\n    }\n\n    public string Name { get; }\n\n    public bool IsCoveredBy(Bet bet) => _coveringBets.Contains(bet.Type);\n}\n"
  },
  {
    "path": "75_Roulette/csharp/Table.cs",
    "content": "namespace Roulette;\n\ninternal class Table\n{\n    private readonly IReadWrite _io;\n    private readonly Wheel _wheel;\n    private readonly Croupier _croupier;\n\n    public Table(Croupier croupier, IReadWrite io, IRandom random)\n    {\n        _croupier = croupier;\n        _io = io;\n        _wheel = new(random);\n    }\n\n    public bool Play()\n    {\n        var bets = AcceptBets();\n        var slot = SpinWheel();\n        SettleBets(bets, slot);\n\n        _io.Write(_croupier.Totals);\n\n        if (_croupier.PlayerIsBroke || _croupier.HouseIsBroke) { return false; }\n\n        return _io.ReadString(Prompts.Again).ToLowerInvariant().StartsWith('y');\n    }\n\n    private Slot SpinWheel()\n    {\n        _io.Write(Streams.Spinning);\n        var slot = _wheel.Spin();\n        _io.Write(slot.Name);\n        return slot;\n    }\n\n    private IReadOnlyList<Bet> AcceptBets()\n    {\n        var betCount = _io.ReadBetCount();\n        var betTypes = new HashSet<BetType>();\n        var bets = new List<Bet>();\n        for (int i = 1; i <= betCount; i++)\n        {\n            while (!TryAdd(_io.ReadBet(i)))\n            {\n                _io.Write(Streams.BetAlready);\n            }\n        }\n\n        return bets.AsReadOnly();\n\n        bool TryAdd(Bet bet)\n        {\n            if (betTypes.Add(bet.Type))\n            {\n                bets.Add(bet);\n                return true;\n            }\n\n            return false;\n        }\n    }\n\n    private void SettleBets(IReadOnlyList<Bet> bets, Slot slot)\n    {\n        foreach (var bet in bets)\n        {\n            _io.Write(slot.IsCoveredBy(bet) ? _croupier.Pay(bet) : _croupier.Take(bet));\n        }\n    }\n}\n"
  },
  {
    "path": "75_Roulette/csharp/Wheel.cs",
    "content": "using System.Collections.Immutable;\n\nnamespace Roulette;\n\ninternal class Wheel\n{\n    private static readonly ImmutableArray<Slot> _slots = ImmutableArray.Create(\n        new Slot(Strings.Red(1), 1, 37, 40, 43, 46, 47),\n        new Slot(Strings.Black(2), 2, 37, 41, 43, 45, 48),\n        new Slot(Strings.Red(3), 3, 37, 42, 43, 46, 47),\n        new Slot(Strings.Black(4), 4, 37, 40, 43, 45, 48),\n        new Slot(Strings.Red(5), 5, 37, 41, 43, 46, 47),\n        new Slot(Strings.Black(6), 6, 37, 42, 43, 45, 48),\n        new Slot(Strings.Red(7), 7, 37, 40, 43, 46, 47),\n        new Slot(Strings.Black(8), 8, 37, 41, 43, 45, 48),\n        new Slot(Strings.Red(9), 9, 37, 42, 43, 46, 47),\n        new Slot(Strings.Black(10), 10, 37, 40, 43, 45, 48),\n        new Slot(Strings.Black(11), 11, 37, 41, 43, 46, 48),\n        new Slot(Strings.Red(12), 12, 37, 42, 43, 45, 47),\n        new Slot(Strings.Black(13), 13, 38, 40, 43, 46, 48),\n        new Slot(Strings.Red(14), 14, 38, 41, 43, 45, 47),\n        new Slot(Strings.Black(15), 15, 38, 42, 43, 46, 48),\n        new Slot(Strings.Red(16), 16, 38, 40, 43, 45, 47),\n        new Slot(Strings.Black(17), 17, 38, 41, 43, 46, 48),\n        new Slot(Strings.Red(18), 18, 38, 42, 43, 45, 47),\n        new Slot(Strings.Red(19), 19, 38, 40, 44, 46, 47),\n        new Slot(Strings.Black(20), 20, 38, 41, 44, 45, 48),\n        new Slot(Strings.Red(21), 21, 38, 42, 44, 46, 47),\n        new Slot(Strings.Black(22), 22, 38, 40, 44, 45, 48),\n        new Slot(Strings.Red(23), 23, 38, 41, 44, 46, 47),\n        new Slot(Strings.Black(24), 24, 38, 42, 44, 45, 48),\n        new Slot(Strings.Red(25), 25, 39, 40, 44, 46, 47),\n        new Slot(Strings.Black(26), 26, 39, 41, 44, 45, 48),\n        new Slot(Strings.Red(27), 27, 39, 42, 44, 46, 47),\n        new Slot(Strings.Black(28), 28, 39, 40, 44, 45, 48),\n        new Slot(Strings.Black(29), 29, 39, 41, 44, 46, 48),\n        new Slot(Strings.Red(30), 30, 39, 42, 44, 45, 47),\n        new Slot(Strings.Black(31), 31, 39, 40, 44, 46, 48),\n        new Slot(Strings.Red(32), 32, 39, 41, 44, 45, 47),\n        new Slot(Strings.Black(33), 33, 39, 42, 44, 46, 48),\n        new Slot(Strings.Red(34), 34, 39, 40, 44, 45, 47),\n        new Slot(Strings.Black(35), 35, 39, 41, 44, 46, 48),\n        new Slot(Strings.Red(36), 36, 39, 42, 44, 45, 47),\n        new Slot(\"0\", 49),\n        new Slot(\"00\", 50));\n    \n    private readonly IRandom _random;\n\n    public Wheel(IRandom random) => _random = random;\n\n    public Slot Spin() => _slots[_random.Next(_slots.Length)];\n}\n"
  },
  {
    "path": "75_Roulette/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n\nTwo versions of Roulette has been contributed. They are indicated within given sub-folders\n\n- [oop](./oop) - Conversion by Andrew McGuinness (andrew@arobeia.co.uk)\n- [iterative](./iterative) - Conversion by Thomas Kwashnak ([Github](https://github.com/LittleTealeaf)).\n    - Implements features from JDK 17.\n    - Does make use of some object oriented programming, but acts as a more iterative solution.\n"
  },
  {
    "path": "75_Roulette/java/iterative/Roulette.java",
    "content": "import java.io.InputStream;\nimport java.io.PrintStream;\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Random;\nimport java.util.Scanner;\nimport java.util.Set;\n\npublic class Roulette {\n\n    private static Set<Integer> RED_NUMBERS;\n\n    static {\n        RED_NUMBERS = Set.of(1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36);\n    }\n\n    private PrintStream out;\n    private Scanner scanner;\n    private int houseBalance, playerBalance;\n    private Random random;\n\n    public Roulette(PrintStream out, InputStream in) {\n        this.out = out;\n        this.scanner = new Scanner(in);\n        houseBalance = 100000;\n        playerBalance = 1000;\n        random = new Random();\n    }\n\n    public static void main(String[] args) {\n        new Roulette(System.out, System.in).play();\n    }\n\n    public void play() {\n        out.println(\"                                ROULETTE\");\n        out.println(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        out.println(\"WELCOME TO THE ROULETTE TABLE\\n\");\n        out.print(\"DO YOU WANT INSTRUCTIONS? \");\n        if (scanner.nextLine().toLowerCase().charAt(0) != 'n') {\n            printInstructions();\n        }\n\n        do {\n\n            Bet[] bets = queryBets();\n\n            out.print(\"SPINNING...\\n\\n\");\n            int result = random.nextInt(1, 39);\n\n            /*\n            Equivalent to following line\n            if(result == 37) {\n                out.println(\"00\");\n            } else if(result == 38) {\n                out.println(\"0\");\n            } else if(RED_NUMBERS.contains(result)) {\n                out.println(result + \" RED\");\n            } else {\n                out.println(result + \" BLACK\");\n            }\n             */\n            out.println(switch (result) {\n                case 37 -> \"00\";\n                case 38 -> \"0\";\n                default -> result + (RED_NUMBERS.contains(result) ? \" RED\" : \" BLACK\");\n            });\n\n            betResults(bets, result);\n            out.println();\n\n            out.println(\"TOTALS:\\tME\\t\\tYOU\");\n            out.format(\"\\t\\t%5d\\t%d\\n\", houseBalance, playerBalance);\n        } while (playAgain());\n        if (playerBalance <= 0) {\n            out.println(\"THANKS FOR YOUR MONEY\\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\");\n        } else {\n            printCheck();\n        }\n        out.println(\"COME BACK SOON!\");\n    }\n\n    public void printInstructions() {\n        out.println();\n        out.println(\"THIS IS THE BETTING LAYOUT\");\n        out.println(\"  (*=RED)\");\n        out.println();\n        out.println(\" 1*    2     3*\");\n        out.println(\" 4     5*    6 \");\n        out.println(\" 7*    8     9*\");\n        out.println(\"10    11    12*\");\n        out.println(\"---------------\");\n        out.println(\"13    14*   15 \");\n        out.println(\"16*   17    18*\");\n        out.println(\"19*   20    21*\");\n        out.println(\"22    23*   24 \");\n        out.println(\"---------------\");\n        out.println(\"25*   26    27*\");\n        out.println(\"28    29    30*\");\n        out.println(\"31    32*   33 \");\n        out.println(\"34*   35    36*\");\n        out.println(\"---------------\");\n        out.println(\"    00    0    \");\n        out.println();\n        out.println(\"TYPES OF BETS\");\n        out.println();\n        out.println(\"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\");\n        out.println(\"ON THAT NUMBER.\");\n        out.println(\"THESE PAY OFF 35:1\");\n        out.println();\n        out.println(\"THE 2:1 BETS ARE:\");\n        out.println(\" 37) 1-12     40) FIRST COLUMN\");\n        out.println(\" 38) 13-24    41) SECOND COLUMN\");\n        out.println(\" 39) 25-36    42) THIRD COLUMN\");\n        out.println();\n        out.println(\"THE EVEN MONEY BETS ARE:\");\n        out.println(\" 43) 1-18     46) ODD\");\n        out.println(\" 44) 19-36    47) RED\");\n        out.println(\" 45) EVEN     48) BLACK\");\n        out.println();\n        out.println(\" 49)0 AND 50)00 PAY OFF 35:1\");\n        out.println(\" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\");\n        out.println(\"       BETS EXCEPT THEIR OWN.\");\n        out.println();\n        out.println(\"WHEN I ASK FOR EACH BET, TYPE THE NUMBER\");\n        out.println(\"AND THE AMOUNT, SEPARATED BY A COMMA.\");\n        out.println(\"FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\");\n        out.println(\"WHEN I ASK FOR A BET.\");\n        out.println();\n        out.println(\"THE MINIMUM BET IS $5, THE MAXIMUM IS $500.\");\n    }\n\n    private Bet[] queryBets() {\n        int numBets = -1;\n        while (numBets < 1) {\n            out.print(\"HOW MANY BETS? \");\n            try {\n                numBets = Integer.parseInt(scanner.nextLine());\n            } catch (NumberFormatException ignored) {\n            }\n        }\n\n        Bet[] bets = new Bet[numBets];\n\n        for (int i = 0; i < numBets; i++) {\n            while (bets[i] == null) {\n                try {\n                    out.print(\"NUMBER\" + (i + 1) + \"? \");\n                    String[] values = scanner.nextLine().split(\",\");\n                    int betNumber = Integer.parseInt(values[0]);\n                    int betValue = Integer.parseInt(values[1]);\n\n                    for (int j = 0; j < i; j++) {\n                        if (bets[j].num == betNumber) {\n                            out.println(\"YOU MADE THAT BET ONCE ALREADY,DUM-DUM\");\n                            betNumber = -1; //Since -1 is out of the range, this will throw it out at the end\n                        }\n                    }\n\n                    if (betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) {\n                        bets[i] = new Bet(betNumber,betValue);\n                    }\n                } catch (Exception ignored) {\n                }\n            }\n        }\n        return bets;\n    }\n\n    private void betResults(Bet[] bets, int num) {\n        for (int i = 0; i < bets.length; i++) {\n            Bet bet = bets[i];\n            /*\n            Using a switch statement of ternary operators that check if a certain condition is met based on the bet value\n            Returns the coefficient that the bet amount should be multiplied by to get the resulting value\n             */\n            int coefficient = switch (bet.num) {\n                case 37 -> (num <= 12) ? 2 : -1;\n                case 38 -> (num > 12 && num <= 24) ? 2 : -1;\n                case 39 -> (num > 24 && num < 37) ? 2 : -1;\n                case 40 -> (num < 37 && num % 3 == 1) ? 2 : -1;\n                case 41 -> (num < 37 && num % 3 == 2) ? 2 : -1;\n                case 42 -> (num < 37 && num % 3 == 0) ? 2 : -1;\n                case 43 -> (num <= 18) ? 1 : -1;\n                case 44 -> (num > 18 && num <= 36) ? 1 : -1;\n                case 45 -> (num % 2 == 0) ? 1 : -1;\n                case 46 -> (num % 2 == 1) ? 1 : -1;\n                case 47 -> RED_NUMBERS.contains(num) ? 1 : -1;\n                case 48 -> !RED_NUMBERS.contains(num) ? 1 : -1;\n                case 49 -> (num == 37) ? 35 : -1;\n                case 50 -> (num == 38) ? 35 : -1;\n                default -> (bet.num < 49 && bet.num == num) ? 35 : -1;\n            };\n\n            int betResult = bet.amount * coefficient;\n\n            if (betResult < 0) {\n                out.println(\"YOU LOSE \" + -betResult + \" DOLLARS ON BET \" + (i + 1));\n            } else {\n                out.println(\"YOU WIN \" + betResult + \" DOLLARS ON BET \" + (i + 1));\n            }\n\n            playerBalance += betResult;\n            houseBalance -= betResult;\n        }\n    }\n\n    private boolean playAgain() {\n\n        if (playerBalance <= 0) {\n            out.println(\"OOPS! YOU JUST SPENT YOUR LAST DOLLAR!\");\n            return false;\n        } else if (houseBalance <= 0) {\n            out.println(\"YOU BROKE THE HOUSE!\");\n            playerBalance = 101000;\n            houseBalance = 0;\n            return false;\n        } else {\n            out.println(\"PLAY AGAIN?\");\n            return scanner.nextLine().toLowerCase().charAt(0) == 'y';\n        }\n    }\n\n    private void printCheck() {\n        out.print(\"TO WHOM SHALL I MAKE THE CHECK? \");\n        String name = scanner.nextLine();\n\n        out.println();\n        for (int i = 0; i < 72; i++) {\n            out.print(\"-\");\n        }\n        out.println();\n\n        for (int i = 0; i < 50; i++) {\n            out.print(\" \");\n        }\n        out.println(\"CHECK NO. \" + random.nextInt(0, 100));\n\n        for (int i = 0; i < 40; i++) {\n            out.print(\" \");\n        }\n        out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE));\n        out.println();\n\n        out.println(\"PAY TO THE ORDER OF -----\" + name + \"----- $\" + (playerBalance));\n        out.println();\n\n        for (int i = 0; i < 40; i++) {\n            out.print(\" \");\n        }\n        out.println(\"THE MEMORY BANK OF NEW YORK\");\n\n        for (int i = 0; i < 40; i++) {\n            out.print(\" \");\n        }\n        out.println(\"THE COMPUTER\");\n\n        for (int i = 0; i < 40; i++) {\n            out.print(\" \");\n        }\n        out.println(\"----------X-----\");\n\n        for (int i = 0; i < 72; i++) {\n            out.print(\"-\");\n        }\n        out.println();\n    }\n\n    public class Bet {\n\n        final int num, amount;\n\n        public Bet(int num, int amount) {\n            this.num = num;\n            this.amount = amount;\n        }\n    }\n}\n"
  },
  {
    "path": "75_Roulette/java/oop/Bet.java",
    "content": "/* A bet has a target (the code entered, which is 1-36, or special values for\n * the various groups, zero and double-zero), and an amount in dollars\n */\n\npublic class Bet {\n    public int target;\n    public int amount;\n\n    /* bet on a target, of an amount */\n    public Bet(int on, int of) {\n        target = on; amount = of;\n    }\n\n    /* check if this is a valid bet - on a real target and of a valid amount */\n    public boolean isValid() {\n        return ((target > 0) && (target <= 50) &&\n                (amount >= 5) && (amount <= 500));\n    }\n\n    /* utility to return either the odds amount in the case of a win, or zero for a loss */\n    private int m(boolean isWon, int odds) {\n        return isWon? odds: 0;\n    }\n\n    /* look at the wheel to see if this bet won.\n     * returns 0 if it didn't, or the odds if it did\n     */\n    public int winsOn(Wheel w) {\n        if (target < 37) {\n            // A number bet 1-36 wins at odds of 35 if it is the exact number\n            return m(w.isNumber() && (w.number() == target), 35);\n        } else\n            switch (target) {\n            case 37:   // 1-12, odds of 2\n                return m(w.isNumber() && (w.number() <= 12), 2);\n            case 38:   // 13-24, odds of 2\n                return m(w.isNumber() && (w.number() > 12) && (w.number() <= 24), 2);\n            case 39:   // 25-36, odds of 2\n                return m(w.isNumber() && (w.number() > 24), 2);\n            case 40:   // Column 1, odds of 2\n                return m(w.isNumber() && ((w.number() % 3) == 1), 2);\n            case 41:   // Column 2, odds of 2\n                return m(w.isNumber() && ((w.number() % 3) == 2), 2);\n            case 42:   // Column 3, odds of 2\n                return m(w.isNumber() && ((w.number() % 3) == 0), 2);\n            case 43:   // 1-18, odds of 1\n                return m(w.isNumber() && (w.number() <= 18), 1);\n            case 44:   // 19-36, odds of 1\n                return m(w.isNumber() && (w.number() > 18), 1);\n            case 45:   // even, odds of 1\n                return m(w.isNumber() && ((w.number() %2) == 0), 1);\n            case 46:   // odd, odds of 1\n                return m(w.isNumber() && ((w.number() %2) == 1), 1);\n            case 47:   // red, odds of 1\n                return m(w.isNumber() && (w.color() == Wheel.BLACK), 1);\n            case 48:   // black, odds of 1\n                return m(w.isNumber() && (w.color() == Wheel.RED), 1);\n            case 49: // single zero, odds of 35\n                return m(w.value().equals(\"0\"), 35);\n            case 50: // double zero, odds of 35\n                return m(w.value().equals(\"00\"), 35);\n            }\n        throw new RuntimeException(\"Program Error - invalid bet\");\n    }\n}\n"
  },
  {
    "path": "75_Roulette/java/oop/Roulette.java",
    "content": "import java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintStream;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.Random;\nimport java.time.LocalDate;\nimport java.time.format.DateTimeFormatter;\nimport java.time.format.FormatStyle;\n\npublic class Roulette {\n    public static void main(String args[]) throws Exception {\n        Roulette r = new Roulette();\n        r.play();\n    }\n\n    private BufferedReader reader;\n    private PrintStream writer;\n\n    private int house;      // how much money does the house have\n    private int player;     // how much money does the player have\n    private Wheel wheel = new Wheel();\n\n    public Roulette() {\n        reader = new BufferedReader(new InputStreamReader(System.in));\n        writer = System.out;\n        house = 100000;\n        player = 1000;\n    }\n\n    // for a test / cheat mode -- set the random number generator to a known value\n    private void setSeed(long l) {\n        wheel.setSeed(l);\n    }\n\n    public void play() {\n        try {\n            intro();\n            writer.println(\"WELCOME TO THE ROULETTE TABLE\\n\" +\n                           \"DO YOU WANT INSTRUCTIONS\");\n            String instr = reader.readLine();\n            if (!instr.toUpperCase().startsWith(\"N\"))\n                instructions();\n\n            while (betAndSpin()) { // returns true if the game is to continue\n            }\n\n            if (player <= 0) {\n                // player ran out of money\n                writer.println(\"THANKS FOR YOUR MONEY.\\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\");\n            } else {\n                // player has money -- print them a check\n                writer.println(\"TO WHOM SHALL I MAKE THE CHECK\");\n\n                String payee = reader.readLine();\n\n                writer.println(\"-\".repeat(72));\n                tab(50); writer.println(\"CHECK NO. \" + (new Random().nextInt(100) + 1));\n                writer.println();\n                tab(40); writer.println(LocalDate.now().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)));\n                writer.println(\"\\n\\nPAY TO THE ORDER OF-----\" + payee + \"-----$ \" + player);\n                writer.print(\"\\n\\n\");\n                tab(10); writer.println(\"THE MEMORY BANK OF NEW YORK\\n\");\n                tab(40); writer.println(\"THE COMPUTER\");\n                tab(40); writer.println(\"----------X-----\\n\");\n                writer.println(\"-\".repeat(72));\n                writer.println(\"COME BACK SOON!\\n\");\n            }\n        }\n        catch (IOException e) {\n            // this should not happen\n            System.err.println(\"System error:\\n\" + e);\n        }\n    }\n\n    /* Write the starting introduction */\n    private void intro() throws IOException {\n        tab(32); writer.println(\"ROULETTE\");\n        tab(15); writer.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\");\n    }\n\n    /* Display the game instructions */\n    private void instructions() {\n        String[] instLines = new String[] {\n            \"THIS IS THE BETTING LAYOUT\",\n            \"  (*=RED)\",\n            \"\" ,\n            \" 1*    2     3*\",\n            \" 4     5*    6 \",\n            \" 7*    8     9*\",\n            \"10    11    12*\",\n            \"---------------\",\n            \"13    14*   15 \",\n            \"16*   17    18*\",\n            \"19*   20    21*\",\n            \"22    23*   24 \",\n            \"---------------\",\n            \"25*   26    27*\",\n            \"28    29    30*\",\n            \"31    32*   33 \",\n            \"34*   35    36*\",\n            \"---------------\",\n            \"    00    0    \",\n            \"\" ,\n            \"TYPES OF BETS\",\n            \"\"  ,\n            \"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\",\n            \"ON THAT NUMBER.\",\n            \"THESE PAY OFF 35:1\",\n            \"\"  ,\n            \"THE 2:1 BETS ARE:\",\n            \" 37) 1-12     40) FIRST COLUMN\",\n            \" 38) 13-24    41) SECOND COLUMN\",\n            \" 39) 25-36    42) THIRD COLUMN\",\n            \"\"  ,\n            \"THE EVEN MONEY BETS ARE:\",\n            \" 43) 1-18     46) ODD\",\n            \" 44) 19-36    47) RED\",\n            \" 45) EVEN     48) BLACK\",\n            \"\",\n            \" 49)0 AND 50)00 PAY OFF 35:1\",\n            \" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\",\n            \"       BETS EXCEPT THEIR OWN.\",\n            \"\",\n            \"WHEN I ASK FOR EACH BET, TYPE THE NUMBER\",\n            \"AND THE AMOUNT, SEPARATED BY A COMMA.\",\n            \"FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\",\n            \"WHEN I ASK FOR A BET.\",\n            \"\",\n            \"THE MINIMUM BET IS $5, THE MAXIMUM IS $500.\",\n            \"\" };\n        writer.println(String.join(\"\\n\", instLines));\n    }\n\n    /* Take a set of bets from the player, then spin the wheel and work out the winnings *\n     * This returns true if the game is to continue afterwards\n     */\n    private boolean betAndSpin() throws IOException {\n        int betCount = 0;\n\n        while (betCount == 0) {   // keep asking how many bets until we get a good answer\n            try {\n                writer.println(\"HOW MANY BETS\");\n                String howMany = reader.readLine();\n                betCount = Integer.parseInt(howMany.strip());\n\n                if ((betCount < 1) || (betCount > 100)) betCount = 0; // bad -- set zero and ask again\n            }\n            catch (NumberFormatException e) {\n                // this happens if the input is not a number\n                writer.println(\"INPUT ERROR\");\n            }\n        }\n\n        HashSet<Integer> betsMade = new HashSet<>(); // Bet targets already made, so we can spot repeats\n        ArrayList<Bet> bets = new ArrayList<>();     // All the bets for this round\n\n        while (bets.size() < betCount) {\n            Bet bet = new Bet(0, 0);                 // an invalid bet to hold the place\n            while (!bet.isValid()) {                 // keep asking until it is valid\n                try {\n                    writer.println(\"NUMBER \" + (bets.size() + 1));\n                    String fields[] = reader.readLine().split(\",\");\n                    if (fields.length == 2) {\n                        bet = new Bet(Integer.parseInt(fields[0].strip()),\n                                      Integer.parseInt(fields[1].strip()));\n                    }\n                }\n                catch (NumberFormatException e) {\n                    writer.println(\"INPUT ERROR\");\n                }\n            }\n\n            // Check if there is already a bet on the same target\n            if (betsMade.contains(bet.target)) {\n                writer.println(\"YOU MADE THAT BET ONCE ALREADY,DUM-DUM\");\n            } else {\n                betsMade.add(bet.target); // note this target has now been bet on\n                bets.add(bet);\n            }\n        }\n\n        writer.println(\"SPINNING\\n\\n\");\n\n        wheel.spin(); // this deliberately takes some random amount of time\n\n        writer.println(wheel.value());\n\n        // go through the bets, and evaluate each one\n        int betNumber = 1;\n        for (Bet b : bets) {\n            int multiplier = b.winsOn(wheel);\n            if (multiplier == 0) {\n                // lost the amount of the bet\n                writer.println(\"YOU LOSE \" + b.amount + \" DOLLARS ON BET \" + betNumber);\n                house += b.amount;\n                player -= b.amount;\n            } else {\n                // won the amount of the bet, multiplied by the odds\n                int winnings = b.amount * multiplier;\n                writer.println(\"YOU WIN \" + winnings + \" DOLLARS ON BET \" + betNumber);\n                house -= winnings;\n                player += winnings;\n            }\n            ++betNumber;\n        }\n\n        writer.println(\"\\nTOTALS:\\tME\\tYOU\\n\\t\" + house + \"\\t\" + player);\n\n        if (player <= 0) {\n            writer.println(\"OOPS! YOU JUST SPENT YOUR LAST DOLLAR\");\n            return false;     // do not repeat since the player has no more money\n        }\n        if (house <= 0) {\n            writer.println(\"YOU BROKE THE HOUSE!\");\n            player = 101000;  // can't win more than the house started with\n            return false;     // do not repeat since the house has no more money\n        }\n\n        // player still has money, and the house still has money, so ask the player\n        // if they want to continue\n        writer.println(\"AGAIN\");\n        String doContinue = reader.readLine();\n\n        // repeat if the answer was not \"n\" or \"no\"\n        return (!doContinue.toUpperCase().startsWith(\"N\"));\n    }\n\n    // utility to print n spaces for formatting\n    private void tab(int n) {\n        writer.print(\" \".repeat(n));\n    }\n}\n"
  },
  {
    "path": "75_Roulette/java/oop/Wheel.java",
    "content": "import java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Random;\n\n// The roulette wheel\npublic class Wheel {\n    // List the numbers which are black\n    private HashSet<Integer> black = new HashSet<>(Arrays.asList(new Integer[] { 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36 }));\n\n    private Random random = new Random();\n    private int pocket = 38;\n\n    public static final int ZERO=0;\n    public static final int BLACK=1;\n    public static final int RED=2;\n\n    // Set up a wheel. You call \"spin\", and then can check the result.\n    public Wheel() {\n    }\n\n    // Cheat / test mode\n    void setSeed(long l) {\n        random.setSeed(l);\n    }\n\n    // Spin the wheel onto a new random value.\n    public void spin() {\n        // keep spinning for a while\n        do {\n            try {\n                // 1 second delay. Where it stops, nobody knows\n                Thread.sleep(1000);\n            }\n            catch (InterruptedException e) {}\n\n            pocket = random.nextInt(38) + 1;\n        } while (random.nextInt(4) > 0); // keep spinning until it stops\n    }\n\n    // The string representation of the number; 1-36, 0, or 00\n    public String value() {\n        if (pocket == 37) return \"0\";\n        else if (pocket == 38) return \"00\";\n        else return String.valueOf(pocket);\n    }\n\n    // True if either 0 or 00 is hit\n    public boolean zero() {\n        return (pocket > 36);\n    }\n\n    // True if anything other than 0 or 00 is hit\n    public boolean isNumber() {\n        return (pocket < 37);\n    }\n\n    // The number rolled\n    public int number() {\n        if (zero()) return 0;\n        else return pocket;\n    }\n\n    // Either ZERO, BLACK, or RED\n    public int color() {\n        if (zero()) return ZERO;\n        else if (black.contains(pocket)) return BLACK;\n        else return RED;\n    }\n}\n"
  },
  {
    "path": "75_Roulette/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "75_Roulette/javascript/roulette.html",
    "content": "<html>\n<head>\n<title>ROULETTE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"roulette.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "75_Roulette/javascript/roulette.js",
    "content": "// ROULETTE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar ba = [];\nvar ca = [];\nvar ta = [];\nvar xa = [];\nvar aa = [];\n\nvar numbers = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];\n\n// Main program\nasync function main()\n{\n    print(tab(32) + \"ROULETTE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // Roulette\n    // David Joslin\n    print(\"WELCOME TO THE ROULETTE TABLE\\n\");\n    print(\"\\n\");\n    print(\"DO YOU WANT INSTRUCTIONS\");\n    str = await input();\n    if (str.substr(0, 1) != \"N\") {\n        print(\"\\n\");\n        print(\"THIS IS THE BETTING LAYOUT\\n\");\n        print(\"  (*=RED)\\n\");\n        print(\"\\n\");\n        print(\" 1*    2     3*\\n\");\n        print(\" 4     5*    6 \\n\");\n        print(\" 7*    8     9*\\n\");\n        print(\"10    11    12*\\n\");\n        print(\"---------------\\n\");\n        print(\"13    14*   15 \\n\");\n        print(\"16*   17    18*\\n\");\n        print(\"19*   20    21*\\n\");\n        print(\"22    23*   24 \\n\");\n        print(\"---------------\\n\");\n        print(\"25*   26    27*\\n\");\n        print(\"28    29    30*\\n\");\n        print(\"31    32*   33 \\n\");\n        print(\"34*   35    36*\\n\");\n        print(\"---------------\\n\");\n        print(\"    00    0    \\n\");\n        print(\"\\n\");\n        print(\"TYPES OF BETS\\n\");\n        print(\"\\n\");\n        print(\"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\\n\");\n        print(\"ON THAT NUMBER.\\n\");\n        print(\"THESE PAY OFF 35:1\\n\");\n        print(\"\\n\");\n        print(\"THE 2:1 BETS ARE:\\n\");\n        print(\" 37) 1-12     40) FIRST COLUMN\\n\");\n        print(\" 38) 13-24    41) SECOND COLUMN\\n\");\n        print(\" 39) 25-36    42) THIRD COLUMN\\n\");\n        print(\"\\n\");\n        print(\"THE EVEN MONEY BETS ARE:\\n\");\n        print(\" 43) 1-18     46) ODD\\n\");\n        print(\" 44) 19-36    47) RED\\n\");\n        print(\" 45) EVEN     48) BLACK\\n\");\n        print(\"\\n\");\n        print(\" 49)0 AND 50)00 PAY OFF 35:1\\n\");\n        print(\" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\\n\");\n        print(\"       BETS EXCEPT THEIR OWN.\\n\");\n        print(\"\\n\");\n        print(\"WHEN I ASK FOR EACH BET, TYPE THE NUMBER\\n\");\n        print(\"AND THE AMOUNT, SEPARATED BY A COMMA.\\n\");\n        print(\"FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\\n\");\n        print(\"WHEN I ASK FOR A BET.\\n\");\n        print(\"\\n\");\n        print(\"THE MINIMUM BET IS $5, THE MAXIMUM IS $500.\\n\");\n        print(\"\\n\");\n    }\n    // Program begins here\n    // Type of bet(number) odds\n    for (i = 1; i <= 100; i++) {\n        ba[i] = 0;\n        ca[i] = 0;\n        ta[i] = 0;\n    }\n    for (i = 1; i <= 38; i++)\n        xa[i] = 0;\n    p = 1000;\n    d = 100000;\n    while (1) {\n        do {\n            print(\"HOW MANY BETS\");\n            y = parseInt(await input());\n        } while (y < 1) ;\n        for (i = 1; i <= 50; i++) {\n            aa[i] = 0;\n        }\n        for (c = 1; c <= y; c++) {\n            while (1) {\n                print(\"NUMBER \" + c + \" \");\n                str = await input();\n                x = parseInt(str);\n                z = parseInt(str.substr(str.indexOf(\",\") + 1));\n                ba[c] = z;\n                ta[c] = x;\n                if (x < 1 || x > 50)\n                    continue;\n                if (z < 1)\n                    continue;\n                if (z < 5 || z > 500)\n                    continue;\n                if (aa[x] != 0) {\n                    print(\"YOU MADE THAT BET ONCE ALREADY,DUM-DUM\\n\");\n                    continue;\n                }\n                aa[x] = 1;\n                break;\n            }\n        }\n        print(\"SPINNING\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        do {\n            s = Math.floor(Math.random() * 100);\n        } while (s == 0 || s > 38) ;\n        xa[s]++;    // Not used\n        if (s > 37) {\n            print(\"00\\n\");\n        } else if (s == 37) {\n            print(\"0\\n\");\n        } else {\n            for (i1 = 1; i1 <= 18; i1++) {\n                if (s == numbers[i1 - 1])\n                    break;\n            }\n            if (i1 <= 18)\n                print(s + \" RED\\n\");\n            else\n                print(s + \" BLACK\\n\");\n        }\n        print(\"\\n\");\n        for (c = 1; c <= y; c++) {\n            won = 0;\n            switch (ta[c]) {\n                case 37:    // 1-12 (37) 2:1\n                    if (s > 12) {\n                        won = -ba[c];\n                    } else {\n                        won = ba[c] * 2;\n                    }\n                    break;\n                case 38:    // 13-24 (38) 2:1\n                    if (s > 12 && s < 25) {\n                        won = ba[c] * 2;\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 39:    // 25-36 (39) 2:1\n                    if (s > 24 && s < 37) {\n                        won = ba[c] * 2;\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 40:    // First column (40) 2:1\n                    if (s < 37 && s % 3 == 1) {\n                        won = ba[c] * 2;\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 41:    // Second column (41) 2:1\n                    if (s < 37 && s % 3 == 2) {\n                        won = ba[c] * 2;\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 42:    // Third column (42) 2:1\n                    if (s < 37 && s % 3 == 0) {\n                        won = ba[c] * 2;\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 43:    // 1-18 (43) 1:1\n                    if (s < 19) {\n                        won = ba[c];\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 44:    // 19-36 (44) 1:1\n                    if (s > 18 && s < 37) {\n                        won = ba[c];\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 45:    // Even (45) 1:1\n                    if (s < 37 && s % 2 == 0) {\n                        won = ba[c];\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 46:    // Odd (46) 1:1\n                    if (s < 37 && s % 2 != 0) {\n                        won = ba[c];\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 47:    // Red (47) 1:1\n                    for (i = 1; i <= 18; i++) {\n                        if (s == numbers[i - 1])\n                            break;\n                    }\n                    if (i <= 18) {\n                        won = ba[c];\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n                case 48:    // Black (48) 1:1\n                    for (i = 1; i <= 18; i++) {\n                        if (s == numbers[i - 1])\n                            break;\n                    }\n                    if (i <= 18 || s > 36) {\n                        won = -ba[c];\n                    } else {\n                        won = ba[c];\n                    }\n                    break;\n                default:    // 1-36,0,00 (1-36,49,50) 35:1\n                    if (ta[c] < 49 && ta[c] == s\n                        || ta[c] == 49 && s == 37\n                        || ta[c] == 50 && s == 38) {\n                        won = ba[c] * 35;\n                    } else {\n                        won = -ba[c];\n                    }\n                    break;\n            }\n            d -= won;\n            p += won;\n            if (won < 0) {\n                print(\"YOU LOSE \" + -won + \" DOLLARS ON BET \" + c + \"\\n\");\n            } else {\n                print(\"YOU WIN \" + won + \" DOLLARS ON BET \" + c + \"\\n\");\n            }\n        }\n        print(\"\\n\");\n        print(\"TOTALS:\\tME\\tYOU\\n\");\n        print(\" \\t\" + d + \"\\t\" + p + \"\\n\");\n        if (p <= 0) {\n            print(\"OOPS! YOU JUST SPENT YOUR LAST DOLLAR!\\n\");\n            break;\n        } else if (d <= 0) {\n            print(\"YOU BROKE THE HOUSE!\\n\");\n            p = 101000;\n        }\n        print(\"AGAIN\");\n        str = await input();\n        if (str.substr(0, 1) != \"Y\")\n            break;\n    }\n    if (p < 1) {\n        print(\"THANKS FOR YOUR MONEY.\\n\");\n        print(\"I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\\n\");\n    } else {\n        print(\"TO WHOM SHALL I MAKE THE CHECK\");\n        str = await input();\n        print(\"\\n\");\n        for (i = 1; i <= 72; i++)\n            print(\"-\");\n        print(\"\\n\");\n        print(tab(50) + \"CHECK NO. \" + Math.floor(Math.random() * 100) + \"\\n\");\n        print(\"\\n\");\n        print(tab(40) + new Date().toDateString());\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"PAY TO THE ORDER OF-----\" + str + \"-----$ \" + p + \"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(tab(10) + \"\\tTHE MEMORY BANK OF NEW YORK\\n\");\n        print(\"\\n\");\n        print(tab(40) + \"\\tTHE COMPUTER\\n\");\n        print(tab(40) + \"----------X-----\\n\");\n        print(\"\\n\");\n        for (i = 1; i <= 72; i++)\n            print(\"-\");\n        print(\"\\n\");\n        print(\"COME BACK SOON!\\n\");\n    }\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "75_Roulette/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "75_Roulette/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "75_Roulette/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nThis conversion consists of three files in `75_Roulette/perl/`:\n\n- `roulette.pl` is the port of the BASIC to Perl;\n- `roulette-test.t` is a Perl test for correctness of display and payout;\n- `make-roulette-test.pl` generates roulette-test.t from roulette.bas.\n\nThe ported version of the game numbers the slots from 0 rather than 1, and uses a dispatch table to figure out the payout.\n\nThe Perl test loads `roulette.pl` and verifies the Perl slot display and payout logic against the BASIC for all combinations of slots and bets. If any tests fail that fact will be noted at the end of the output.\n\nThe test code is generated by reading the BASIC, retaining only the slot display and payout logic (based on line numbers), and wrapping this in code that generates all combinations of bet and spin result. The result is run, and the result is captured and parsed to produce `roulette-test.t`. `make-roulette-test.pl` has some command-line options that may be of interest. `--help` will display the documentation.\n"
  },
  {
    "path": "75_Roulette/perl/make-roulette-test.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.014;\t# For s///r\n\nuse strict;\nuse warnings;\n\nuse File::Temp;\nuse Getopt::Long 2.33 qw{ :config auto_version };\nuse IPC::Cmd qw{ can_run };\t# Core as of Perl 5.9.5.\nuse Pod::Usage;\n\nour $VERSION = '0.000_01';\n\nmy %opt = (\n    program\t=> find_basic(),\n    output\t=> make_default_output(),\n);\n\nGetOptions( \\%opt,\n    qw{ output=s program=s },\n    help => sub { pod2usage( { -verbose => 2 } ) },\n) or pod2usage( { -verbose => 0 } );\n\ndie \"No default BASIC found; you must specify --program\\n\"\n    unless defined $opt{program};\n\nmy $game_dir = ( File::Spec->splitdir( $0 ) )[0];\nmy $basic_file = File::Spec->catfile( $game_dir, 'roulette.bas' );\nopen my $basic_handle, '<', $basic_file\n    or die \"Unable to open $basic_file: $!\\n\";\n\nmy $munged = File::Temp->new();\n\nprint { $munged } <<'EOD';\n1000 Y=50\n1010 DIM B(100),C(100),T(100)\n1090 FOR S=1 TO 38\n1095 PRINT \"SPIN \";S\n1100 FOR C=1 TO Y\n1110 B(C)=1\n1120 T(C)=C\n1130 NEXT C\nEOD\n\ntranscribe( $basic_file, $basic_handle, $munged, 1860, 2810 );\ntranscribe( $basic_file, $basic_handle, $munged, 2950 );\n\nsay { $munged } '4000 NEXT S';\n\n$munged->flush();\n\nif ( $opt{output} ne '-' ) {\n    my $dir = ( File::Spec->splitpath( $0 ) )[1];\n    my $fn = File::Spec->rel2abs( $opt{output}, $dir );\n    $fn = File::Spec->abs2rel( $fn );\n    open my $fh, '>', $fn\n\tor die \"Unable to open $fn: $!\\n\";\n    warn \"Writing $fn\\n\";\n    select $fh;\n}\n\nprint <<'EOD';\npackage main;\n\nuse 5.010;\n\nuse strict;\nuse warnings;\n\nuse File::Spec;\nuse Test::More 0.88;\t# Because of done_testing();\n\nEOD\n\nprint <<\"EOD\";\n# NOTE: This file is generated by $0.\n# Any edits made to it will be lost the next time it is regenerated.\n# Caveat coder.\n\nEOD\n\nprint <<'EOD';\nmy $dir = ( File::Spec->splitpath( $0 ) )[1];\nmy $script = File::Spec->catfile( $dir, 'roulette.pl' );\n{\n    # Modern Perls do not have . in @INC, but we need it there to load a\n    # relative path.\n    local @INC = ( File::Spec->curdir(), @INC );\n    require $script;\t# Load game as module\n}\n\nEOD\n\nmy $spin;\nmy $name;\nforeach ( `$opt{program} @{[ $munged->filename() ]}` ) {\n    s/\\N{U+1D}/ /smxg;\t# Artifact of the BASIC I'm using.\n    s/ \\s+ \\z //smx;\n    s/ \\A \\s+ //smx;\n    if ( $_ eq '' ) {\n\t# Ignore empty lines.\n    } elsif ( m/ \\A SPIN \\s* ( [0-9]+ ) /smx ) {\n\t$spin = $1 - 1;\t# BASIC is 1-based, but Perl is 0-based\n    } elsif ( m/ \\A YOU \\s+ WIN \\s* ( [0-9]+ ) \\s*\n\tDOLLARS \\s+ ON \\s+ BET \\s* ( [0-9]+ ) /smx ) {\n\tsay \"is payout( $spin, $2 ), $1, 'Spin $spin ($name), bet $2 pays $1';\";\n    } elsif ( m/ \\A YOU \\s+ LOSE \\s* ( [0-9]+ ) \\s*\n\tDOLLARS \\s+ ON \\s+ BET \\s* ( [0-9]+ ) /smx ) {\n\tsay \"is payout( $spin, $2 ), -$1, 'Spin $spin ($name), bet $2 pays -$1';\";\n    } elsif ( m/ \\A \\s* ( [0-9]+ ) (?: \\s* ( [[:alpha:]]+ ) )? \\z /smx ) {\n\t$name = $2 ? sprintf( '%d %s', $1, ucfirst lc $2 ) : $1;\n\tsay \"is format_spin( $spin ), '$name', 'Spin $spin is $name';\";\n    } else {\n\tdie \"Unexpected input $_\";\n    }\n}\n\nprint <<'EOD';\n\ndone_testing;\n\n1;\n\n# ex: set textwidth=72 :\nEOD\n\nsub find_basic {\n    # yabasic seems not to work\n    foreach my $prog ( qw{ basic cbmbasic } ) {\n\treturn $prog if can_run( $prog )\n    }\n    return undef;\n}\n\nsub make_default_output {\n    ( my $rslt = $0 ) =~ s/ [.] pl \\z /.t/smx;\n    $rslt =~ s/ .* \\b make- //smx;\n    return $rslt;\n}\n\nsub transcribe {\n    my ( $in_file, $in_handle, $out_handle, $first_line, $last_line ) = @_;\n    $last_line //= $first_line;\n\n    while ( <$in_handle> ) {\n\tm/ \\A \\s* ( [0-9]+ )+ \\s /smx\n\t    or next;\n\t$1 < $first_line\n\t    and next;\n\tsay { $out_handle } sprintf '%04d REM BEGIN VERBATIM FROM %s',\n\t$first_line - 10, $in_file;\n\tprint { $out_handle } $_;\n\tlast;\n    }\n    while ( <$in_handle> ) {\n\tm/ \\A \\s* ( [0-9]+ )+ \\s /smx\n\t    and $1 > $last_line\n\t    and last;\n\tprint { $out_handle } $_;\n    }\n    say { $out_handle } sprintf '%04d REM END VERBATIM FROM %s',\n\t$last_line + 10, $in_file;\n\n    return;\n}\n\n__END__\n\n=head1 TITLE\n\nmake-roulette-test.pl - Generate the tests for 75_Roulette/perl/roulette.pl\n\n=head1 SYNOPSIS\n\n perl 75_Roulette/perl/make-roulette-test.pl\n perl 75_Roulette/perl/make-roulette-test.pl --program mybasic\n perl 75_Roulette/perl/make-roulette-test.pl --help\n perl 75_Roulette/perl/make-roulette-test.pl --version\n\n=head1 OPTIONS\n\n<<< replace boiler plate >>>\n\n=head2 --help\n\nThis option displays the documentation for this script. The script then\nexits.\n\n=head2 --output\n\n --output fubar.t\n\nThis option specifies the output file. This needs to be in the same\ndirectory as F<roulette.pl>, and defaults to that directory. A single\ndash (C<'-'>) is special-cased to send the output to standard out.\n\nThe default is C<--output=test-roulette.t>.\n\n=head2 --program\n\n --program my_basic\n\nThis option specifies the name of your BASIC interpreter. This must be\nthe name of an executable file in your PATH (aliases do not work).\n\nThe default is the first-found in the list C<qw{ basic cbmbasic }>.\n\n=head2 --version\n\nThis option displays the version of this script. The script then exits.\n\n=head1 DETAILS\n\nThis Perl script generates F<roulette-test.t>, which tests\nF<roulette.pl>. The latter is expected to be written as a modulino.\n\nThis script assumes that:\n\n=over\n\n=item * it is in the same directory as F<roulette.pl>;\n\n=item * F<roulette.bas> is in the first-level subdirectory under the current directory;\n\n=back\n\nThe generated test assumes that it is in the same directory as\nF<roulette.pl>.\n\nThis script works by abstracting the internals of F<roulette.bas> and\nwrapping them in a loop that generates all possible spins, and places\nall possible bets on each spin. The generated BASIC is written to a\ntemporary file, and executed by a BASIC interpreter. The output is\nparsed and used to generate the output.\n\nObviously there is some ad-hocery going on, and this script has only\nbeen tested under C<cbmbasic>, which was what I had on hand.\n\nB<Caveat:> the abstraction process is driven by BASIC line numbers. Any\nchange of these puts the ad-hocery at risk.\n\n=head1 AUTHOR\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set textwidth=72 :\n"
  },
  {
    "path": "75_Roulette/perl/roulette-test.t",
    "content": "package main;\n\nuse 5.010;\n\nuse strict;\nuse warnings;\n\nuse File::Spec;\nuse Test::More 0.88;\t# Because of done_testing();\n\n# NOTE: This file is generated by 75_Roulette/perl/make-roulette-test.pl.\n# Any edits made to it will be lost the next time it is regenerated.\n# Caveat coder.\n\nmy $dir = ( File::Spec->splitpath( $0 ) )[1];\nmy $script = File::Spec->catfile( $dir, 'roulette.pl' );\n{\n    # Modern Perls do not have . in @INC, but we need it there to load a\n    # relative path.\n    local @INC = ( File::Spec->curdir(), @INC );\n    require $script;\t# Load game as module\n}\n\nis format_spin( 0 ), '1 Red', 'Spin 0 is 1 Red';\nis payout( 0, 1 ), 35, 'Spin 0 (1 Red), bet 1 pays 35';\nis payout( 0, 2 ), -1, 'Spin 0 (1 Red), bet 2 pays -1';\nis payout( 0, 3 ), -1, 'Spin 0 (1 Red), bet 3 pays -1';\nis payout( 0, 4 ), -1, 'Spin 0 (1 Red), bet 4 pays -1';\nis payout( 0, 5 ), -1, 'Spin 0 (1 Red), bet 5 pays -1';\nis payout( 0, 6 ), -1, 'Spin 0 (1 Red), bet 6 pays -1';\nis payout( 0, 7 ), -1, 'Spin 0 (1 Red), bet 7 pays -1';\nis payout( 0, 8 ), -1, 'Spin 0 (1 Red), bet 8 pays -1';\nis payout( 0, 9 ), -1, 'Spin 0 (1 Red), bet 9 pays -1';\nis payout( 0, 10 ), -1, 'Spin 0 (1 Red), bet 10 pays -1';\nis payout( 0, 11 ), -1, 'Spin 0 (1 Red), bet 11 pays -1';\nis payout( 0, 12 ), -1, 'Spin 0 (1 Red), bet 12 pays -1';\nis payout( 0, 13 ), -1, 'Spin 0 (1 Red), bet 13 pays -1';\nis payout( 0, 14 ), -1, 'Spin 0 (1 Red), bet 14 pays -1';\nis payout( 0, 15 ), -1, 'Spin 0 (1 Red), bet 15 pays -1';\nis payout( 0, 16 ), -1, 'Spin 0 (1 Red), bet 16 pays -1';\nis payout( 0, 17 ), -1, 'Spin 0 (1 Red), bet 17 pays -1';\nis payout( 0, 18 ), -1, 'Spin 0 (1 Red), bet 18 pays -1';\nis payout( 0, 19 ), -1, 'Spin 0 (1 Red), bet 19 pays -1';\nis payout( 0, 20 ), -1, 'Spin 0 (1 Red), bet 20 pays -1';\nis payout( 0, 21 ), -1, 'Spin 0 (1 Red), bet 21 pays -1';\nis payout( 0, 22 ), -1, 'Spin 0 (1 Red), bet 22 pays -1';\nis payout( 0, 23 ), -1, 'Spin 0 (1 Red), bet 23 pays -1';\nis payout( 0, 24 ), -1, 'Spin 0 (1 Red), bet 24 pays -1';\nis payout( 0, 25 ), -1, 'Spin 0 (1 Red), bet 25 pays -1';\nis payout( 0, 26 ), -1, 'Spin 0 (1 Red), bet 26 pays -1';\nis payout( 0, 27 ), -1, 'Spin 0 (1 Red), bet 27 pays -1';\nis payout( 0, 28 ), -1, 'Spin 0 (1 Red), bet 28 pays -1';\nis payout( 0, 29 ), -1, 'Spin 0 (1 Red), bet 29 pays -1';\nis payout( 0, 30 ), -1, 'Spin 0 (1 Red), bet 30 pays -1';\nis payout( 0, 31 ), -1, 'Spin 0 (1 Red), bet 31 pays -1';\nis payout( 0, 32 ), -1, 'Spin 0 (1 Red), bet 32 pays -1';\nis payout( 0, 33 ), -1, 'Spin 0 (1 Red), bet 33 pays -1';\nis payout( 0, 34 ), -1, 'Spin 0 (1 Red), bet 34 pays -1';\nis payout( 0, 35 ), -1, 'Spin 0 (1 Red), bet 35 pays -1';\nis payout( 0, 36 ), -1, 'Spin 0 (1 Red), bet 36 pays -1';\nis payout( 0, 37 ), 2, 'Spin 0 (1 Red), bet 37 pays 2';\nis payout( 0, 38 ), -1, 'Spin 0 (1 Red), bet 38 pays -1';\nis payout( 0, 39 ), -1, 'Spin 0 (1 Red), bet 39 pays -1';\nis payout( 0, 40 ), 2, 'Spin 0 (1 Red), bet 40 pays 2';\nis payout( 0, 41 ), -1, 'Spin 0 (1 Red), bet 41 pays -1';\nis payout( 0, 42 ), -1, 'Spin 0 (1 Red), bet 42 pays -1';\nis payout( 0, 43 ), 1, 'Spin 0 (1 Red), bet 43 pays 1';\nis payout( 0, 44 ), -1, 'Spin 0 (1 Red), bet 44 pays -1';\nis payout( 0, 45 ), -1, 'Spin 0 (1 Red), bet 45 pays -1';\nis payout( 0, 46 ), 1, 'Spin 0 (1 Red), bet 46 pays 1';\nis payout( 0, 47 ), 1, 'Spin 0 (1 Red), bet 47 pays 1';\nis payout( 0, 48 ), -1, 'Spin 0 (1 Red), bet 48 pays -1';\nis payout( 0, 49 ), -1, 'Spin 0 (1 Red), bet 49 pays -1';\nis payout( 0, 50 ), -1, 'Spin 0 (1 Red), bet 50 pays -1';\nis format_spin( 1 ), '2 Black', 'Spin 1 is 2 Black';\nis payout( 1, 1 ), -1, 'Spin 1 (2 Black), bet 1 pays -1';\nis payout( 1, 2 ), 35, 'Spin 1 (2 Black), bet 2 pays 35';\nis payout( 1, 3 ), -1, 'Spin 1 (2 Black), bet 3 pays -1';\nis payout( 1, 4 ), -1, 'Spin 1 (2 Black), bet 4 pays -1';\nis payout( 1, 5 ), -1, 'Spin 1 (2 Black), bet 5 pays -1';\nis payout( 1, 6 ), -1, 'Spin 1 (2 Black), bet 6 pays -1';\nis payout( 1, 7 ), -1, 'Spin 1 (2 Black), bet 7 pays -1';\nis payout( 1, 8 ), -1, 'Spin 1 (2 Black), bet 8 pays -1';\nis payout( 1, 9 ), -1, 'Spin 1 (2 Black), bet 9 pays -1';\nis payout( 1, 10 ), -1, 'Spin 1 (2 Black), bet 10 pays -1';\nis payout( 1, 11 ), -1, 'Spin 1 (2 Black), bet 11 pays -1';\nis payout( 1, 12 ), -1, 'Spin 1 (2 Black), bet 12 pays -1';\nis payout( 1, 13 ), -1, 'Spin 1 (2 Black), bet 13 pays -1';\nis payout( 1, 14 ), -1, 'Spin 1 (2 Black), bet 14 pays -1';\nis payout( 1, 15 ), -1, 'Spin 1 (2 Black), bet 15 pays -1';\nis payout( 1, 16 ), -1, 'Spin 1 (2 Black), bet 16 pays -1';\nis payout( 1, 17 ), -1, 'Spin 1 (2 Black), bet 17 pays -1';\nis payout( 1, 18 ), -1, 'Spin 1 (2 Black), bet 18 pays -1';\nis payout( 1, 19 ), -1, 'Spin 1 (2 Black), bet 19 pays -1';\nis payout( 1, 20 ), -1, 'Spin 1 (2 Black), bet 20 pays -1';\nis payout( 1, 21 ), -1, 'Spin 1 (2 Black), bet 21 pays -1';\nis payout( 1, 22 ), -1, 'Spin 1 (2 Black), bet 22 pays -1';\nis payout( 1, 23 ), -1, 'Spin 1 (2 Black), bet 23 pays -1';\nis payout( 1, 24 ), -1, 'Spin 1 (2 Black), bet 24 pays -1';\nis payout( 1, 25 ), -1, 'Spin 1 (2 Black), bet 25 pays -1';\nis payout( 1, 26 ), -1, 'Spin 1 (2 Black), bet 26 pays -1';\nis payout( 1, 27 ), -1, 'Spin 1 (2 Black), bet 27 pays -1';\nis payout( 1, 28 ), -1, 'Spin 1 (2 Black), bet 28 pays -1';\nis payout( 1, 29 ), -1, 'Spin 1 (2 Black), bet 29 pays -1';\nis payout( 1, 30 ), -1, 'Spin 1 (2 Black), bet 30 pays -1';\nis payout( 1, 31 ), -1, 'Spin 1 (2 Black), bet 31 pays -1';\nis payout( 1, 32 ), -1, 'Spin 1 (2 Black), bet 32 pays -1';\nis payout( 1, 33 ), -1, 'Spin 1 (2 Black), bet 33 pays -1';\nis payout( 1, 34 ), -1, 'Spin 1 (2 Black), bet 34 pays -1';\nis payout( 1, 35 ), -1, 'Spin 1 (2 Black), bet 35 pays -1';\nis payout( 1, 36 ), -1, 'Spin 1 (2 Black), bet 36 pays -1';\nis payout( 1, 37 ), 2, 'Spin 1 (2 Black), bet 37 pays 2';\nis payout( 1, 38 ), -1, 'Spin 1 (2 Black), bet 38 pays -1';\nis payout( 1, 39 ), -1, 'Spin 1 (2 Black), bet 39 pays -1';\nis payout( 1, 40 ), -1, 'Spin 1 (2 Black), bet 40 pays -1';\nis payout( 1, 41 ), 2, 'Spin 1 (2 Black), bet 41 pays 2';\nis payout( 1, 42 ), -1, 'Spin 1 (2 Black), bet 42 pays -1';\nis payout( 1, 43 ), 1, 'Spin 1 (2 Black), bet 43 pays 1';\nis payout( 1, 44 ), -1, 'Spin 1 (2 Black), bet 44 pays -1';\nis payout( 1, 45 ), 1, 'Spin 1 (2 Black), bet 45 pays 1';\nis payout( 1, 46 ), -1, 'Spin 1 (2 Black), bet 46 pays -1';\nis payout( 1, 47 ), -1, 'Spin 1 (2 Black), bet 47 pays -1';\nis payout( 1, 48 ), 1, 'Spin 1 (2 Black), bet 48 pays 1';\nis payout( 1, 49 ), -1, 'Spin 1 (2 Black), bet 49 pays -1';\nis payout( 1, 50 ), -1, 'Spin 1 (2 Black), bet 50 pays -1';\nis format_spin( 2 ), '3 Red', 'Spin 2 is 3 Red';\nis payout( 2, 1 ), -1, 'Spin 2 (3 Red), bet 1 pays -1';\nis payout( 2, 2 ), -1, 'Spin 2 (3 Red), bet 2 pays -1';\nis payout( 2, 3 ), 35, 'Spin 2 (3 Red), bet 3 pays 35';\nis payout( 2, 4 ), -1, 'Spin 2 (3 Red), bet 4 pays -1';\nis payout( 2, 5 ), -1, 'Spin 2 (3 Red), bet 5 pays -1';\nis payout( 2, 6 ), -1, 'Spin 2 (3 Red), bet 6 pays -1';\nis payout( 2, 7 ), -1, 'Spin 2 (3 Red), bet 7 pays -1';\nis payout( 2, 8 ), -1, 'Spin 2 (3 Red), bet 8 pays -1';\nis payout( 2, 9 ), -1, 'Spin 2 (3 Red), bet 9 pays -1';\nis payout( 2, 10 ), -1, 'Spin 2 (3 Red), bet 10 pays -1';\nis payout( 2, 11 ), -1, 'Spin 2 (3 Red), bet 11 pays -1';\nis payout( 2, 12 ), -1, 'Spin 2 (3 Red), bet 12 pays -1';\nis payout( 2, 13 ), -1, 'Spin 2 (3 Red), bet 13 pays -1';\nis payout( 2, 14 ), -1, 'Spin 2 (3 Red), bet 14 pays -1';\nis payout( 2, 15 ), -1, 'Spin 2 (3 Red), bet 15 pays -1';\nis payout( 2, 16 ), -1, 'Spin 2 (3 Red), bet 16 pays -1';\nis payout( 2, 17 ), -1, 'Spin 2 (3 Red), bet 17 pays -1';\nis payout( 2, 18 ), -1, 'Spin 2 (3 Red), bet 18 pays -1';\nis payout( 2, 19 ), -1, 'Spin 2 (3 Red), bet 19 pays -1';\nis payout( 2, 20 ), -1, 'Spin 2 (3 Red), bet 20 pays -1';\nis payout( 2, 21 ), -1, 'Spin 2 (3 Red), bet 21 pays -1';\nis payout( 2, 22 ), -1, 'Spin 2 (3 Red), bet 22 pays -1';\nis payout( 2, 23 ), -1, 'Spin 2 (3 Red), bet 23 pays -1';\nis payout( 2, 24 ), -1, 'Spin 2 (3 Red), bet 24 pays -1';\nis payout( 2, 25 ), -1, 'Spin 2 (3 Red), bet 25 pays -1';\nis payout( 2, 26 ), -1, 'Spin 2 (3 Red), bet 26 pays -1';\nis payout( 2, 27 ), -1, 'Spin 2 (3 Red), bet 27 pays -1';\nis payout( 2, 28 ), -1, 'Spin 2 (3 Red), bet 28 pays -1';\nis payout( 2, 29 ), -1, 'Spin 2 (3 Red), bet 29 pays -1';\nis payout( 2, 30 ), -1, 'Spin 2 (3 Red), bet 30 pays -1';\nis payout( 2, 31 ), -1, 'Spin 2 (3 Red), bet 31 pays -1';\nis payout( 2, 32 ), -1, 'Spin 2 (3 Red), bet 32 pays -1';\nis payout( 2, 33 ), -1, 'Spin 2 (3 Red), bet 33 pays -1';\nis payout( 2, 34 ), -1, 'Spin 2 (3 Red), bet 34 pays -1';\nis payout( 2, 35 ), -1, 'Spin 2 (3 Red), bet 35 pays -1';\nis payout( 2, 36 ), -1, 'Spin 2 (3 Red), bet 36 pays -1';\nis payout( 2, 37 ), 2, 'Spin 2 (3 Red), bet 37 pays 2';\nis payout( 2, 38 ), -1, 'Spin 2 (3 Red), bet 38 pays -1';\nis payout( 2, 39 ), -1, 'Spin 2 (3 Red), bet 39 pays -1';\nis payout( 2, 40 ), -1, 'Spin 2 (3 Red), bet 40 pays -1';\nis payout( 2, 41 ), -1, 'Spin 2 (3 Red), bet 41 pays -1';\nis payout( 2, 42 ), 2, 'Spin 2 (3 Red), bet 42 pays 2';\nis payout( 2, 43 ), 1, 'Spin 2 (3 Red), bet 43 pays 1';\nis payout( 2, 44 ), -1, 'Spin 2 (3 Red), bet 44 pays -1';\nis payout( 2, 45 ), -1, 'Spin 2 (3 Red), bet 45 pays -1';\nis payout( 2, 46 ), 1, 'Spin 2 (3 Red), bet 46 pays 1';\nis payout( 2, 47 ), 1, 'Spin 2 (3 Red), bet 47 pays 1';\nis payout( 2, 48 ), -1, 'Spin 2 (3 Red), bet 48 pays -1';\nis payout( 2, 49 ), -1, 'Spin 2 (3 Red), bet 49 pays -1';\nis payout( 2, 50 ), -1, 'Spin 2 (3 Red), bet 50 pays -1';\nis format_spin( 3 ), '4 Black', 'Spin 3 is 4 Black';\nis payout( 3, 1 ), -1, 'Spin 3 (4 Black), bet 1 pays -1';\nis payout( 3, 2 ), -1, 'Spin 3 (4 Black), bet 2 pays -1';\nis payout( 3, 3 ), -1, 'Spin 3 (4 Black), bet 3 pays -1';\nis payout( 3, 4 ), 35, 'Spin 3 (4 Black), bet 4 pays 35';\nis payout( 3, 5 ), -1, 'Spin 3 (4 Black), bet 5 pays -1';\nis payout( 3, 6 ), -1, 'Spin 3 (4 Black), bet 6 pays -1';\nis payout( 3, 7 ), -1, 'Spin 3 (4 Black), bet 7 pays -1';\nis payout( 3, 8 ), -1, 'Spin 3 (4 Black), bet 8 pays -1';\nis payout( 3, 9 ), -1, 'Spin 3 (4 Black), bet 9 pays -1';\nis payout( 3, 10 ), -1, 'Spin 3 (4 Black), bet 10 pays -1';\nis payout( 3, 11 ), -1, 'Spin 3 (4 Black), bet 11 pays -1';\nis payout( 3, 12 ), -1, 'Spin 3 (4 Black), bet 12 pays -1';\nis payout( 3, 13 ), -1, 'Spin 3 (4 Black), bet 13 pays -1';\nis payout( 3, 14 ), -1, 'Spin 3 (4 Black), bet 14 pays -1';\nis payout( 3, 15 ), -1, 'Spin 3 (4 Black), bet 15 pays -1';\nis payout( 3, 16 ), -1, 'Spin 3 (4 Black), bet 16 pays -1';\nis payout( 3, 17 ), -1, 'Spin 3 (4 Black), bet 17 pays -1';\nis payout( 3, 18 ), -1, 'Spin 3 (4 Black), bet 18 pays -1';\nis payout( 3, 19 ), -1, 'Spin 3 (4 Black), bet 19 pays -1';\nis payout( 3, 20 ), -1, 'Spin 3 (4 Black), bet 20 pays -1';\nis payout( 3, 21 ), -1, 'Spin 3 (4 Black), bet 21 pays -1';\nis payout( 3, 22 ), -1, 'Spin 3 (4 Black), bet 22 pays -1';\nis payout( 3, 23 ), -1, 'Spin 3 (4 Black), bet 23 pays -1';\nis payout( 3, 24 ), -1, 'Spin 3 (4 Black), bet 24 pays -1';\nis payout( 3, 25 ), -1, 'Spin 3 (4 Black), bet 25 pays -1';\nis payout( 3, 26 ), -1, 'Spin 3 (4 Black), bet 26 pays -1';\nis payout( 3, 27 ), -1, 'Spin 3 (4 Black), bet 27 pays -1';\nis payout( 3, 28 ), -1, 'Spin 3 (4 Black), bet 28 pays -1';\nis payout( 3, 29 ), -1, 'Spin 3 (4 Black), bet 29 pays -1';\nis payout( 3, 30 ), -1, 'Spin 3 (4 Black), bet 30 pays -1';\nis payout( 3, 31 ), -1, 'Spin 3 (4 Black), bet 31 pays -1';\nis payout( 3, 32 ), -1, 'Spin 3 (4 Black), bet 32 pays -1';\nis payout( 3, 33 ), -1, 'Spin 3 (4 Black), bet 33 pays -1';\nis payout( 3, 34 ), -1, 'Spin 3 (4 Black), bet 34 pays -1';\nis payout( 3, 35 ), -1, 'Spin 3 (4 Black), bet 35 pays -1';\nis payout( 3, 36 ), -1, 'Spin 3 (4 Black), bet 36 pays -1';\nis payout( 3, 37 ), 2, 'Spin 3 (4 Black), bet 37 pays 2';\nis payout( 3, 38 ), -1, 'Spin 3 (4 Black), bet 38 pays -1';\nis payout( 3, 39 ), -1, 'Spin 3 (4 Black), bet 39 pays -1';\nis payout( 3, 40 ), 2, 'Spin 3 (4 Black), bet 40 pays 2';\nis payout( 3, 41 ), -1, 'Spin 3 (4 Black), bet 41 pays -1';\nis payout( 3, 42 ), -1, 'Spin 3 (4 Black), bet 42 pays -1';\nis payout( 3, 43 ), 1, 'Spin 3 (4 Black), bet 43 pays 1';\nis payout( 3, 44 ), -1, 'Spin 3 (4 Black), bet 44 pays -1';\nis payout( 3, 45 ), 1, 'Spin 3 (4 Black), bet 45 pays 1';\nis payout( 3, 46 ), -1, 'Spin 3 (4 Black), bet 46 pays -1';\nis payout( 3, 47 ), -1, 'Spin 3 (4 Black), bet 47 pays -1';\nis payout( 3, 48 ), 1, 'Spin 3 (4 Black), bet 48 pays 1';\nis payout( 3, 49 ), -1, 'Spin 3 (4 Black), bet 49 pays -1';\nis payout( 3, 50 ), -1, 'Spin 3 (4 Black), bet 50 pays -1';\nis format_spin( 4 ), '5 Red', 'Spin 4 is 5 Red';\nis payout( 4, 1 ), -1, 'Spin 4 (5 Red), bet 1 pays -1';\nis payout( 4, 2 ), -1, 'Spin 4 (5 Red), bet 2 pays -1';\nis payout( 4, 3 ), -1, 'Spin 4 (5 Red), bet 3 pays -1';\nis payout( 4, 4 ), -1, 'Spin 4 (5 Red), bet 4 pays -1';\nis payout( 4, 5 ), 35, 'Spin 4 (5 Red), bet 5 pays 35';\nis payout( 4, 6 ), -1, 'Spin 4 (5 Red), bet 6 pays -1';\nis payout( 4, 7 ), -1, 'Spin 4 (5 Red), bet 7 pays -1';\nis payout( 4, 8 ), -1, 'Spin 4 (5 Red), bet 8 pays -1';\nis payout( 4, 9 ), -1, 'Spin 4 (5 Red), bet 9 pays -1';\nis payout( 4, 10 ), -1, 'Spin 4 (5 Red), bet 10 pays -1';\nis payout( 4, 11 ), -1, 'Spin 4 (5 Red), bet 11 pays -1';\nis payout( 4, 12 ), -1, 'Spin 4 (5 Red), bet 12 pays -1';\nis payout( 4, 13 ), -1, 'Spin 4 (5 Red), bet 13 pays -1';\nis payout( 4, 14 ), -1, 'Spin 4 (5 Red), bet 14 pays -1';\nis payout( 4, 15 ), -1, 'Spin 4 (5 Red), bet 15 pays -1';\nis payout( 4, 16 ), -1, 'Spin 4 (5 Red), bet 16 pays -1';\nis payout( 4, 17 ), -1, 'Spin 4 (5 Red), bet 17 pays -1';\nis payout( 4, 18 ), -1, 'Spin 4 (5 Red), bet 18 pays -1';\nis payout( 4, 19 ), -1, 'Spin 4 (5 Red), bet 19 pays -1';\nis payout( 4, 20 ), -1, 'Spin 4 (5 Red), bet 20 pays -1';\nis payout( 4, 21 ), -1, 'Spin 4 (5 Red), bet 21 pays -1';\nis payout( 4, 22 ), -1, 'Spin 4 (5 Red), bet 22 pays -1';\nis payout( 4, 23 ), -1, 'Spin 4 (5 Red), bet 23 pays -1';\nis payout( 4, 24 ), -1, 'Spin 4 (5 Red), bet 24 pays -1';\nis payout( 4, 25 ), -1, 'Spin 4 (5 Red), bet 25 pays -1';\nis payout( 4, 26 ), -1, 'Spin 4 (5 Red), bet 26 pays -1';\nis payout( 4, 27 ), -1, 'Spin 4 (5 Red), bet 27 pays -1';\nis payout( 4, 28 ), -1, 'Spin 4 (5 Red), bet 28 pays -1';\nis payout( 4, 29 ), -1, 'Spin 4 (5 Red), bet 29 pays -1';\nis payout( 4, 30 ), -1, 'Spin 4 (5 Red), bet 30 pays -1';\nis payout( 4, 31 ), -1, 'Spin 4 (5 Red), bet 31 pays -1';\nis payout( 4, 32 ), -1, 'Spin 4 (5 Red), bet 32 pays -1';\nis payout( 4, 33 ), -1, 'Spin 4 (5 Red), bet 33 pays -1';\nis payout( 4, 34 ), -1, 'Spin 4 (5 Red), bet 34 pays -1';\nis payout( 4, 35 ), -1, 'Spin 4 (5 Red), bet 35 pays -1';\nis payout( 4, 36 ), -1, 'Spin 4 (5 Red), bet 36 pays -1';\nis payout( 4, 37 ), 2, 'Spin 4 (5 Red), bet 37 pays 2';\nis payout( 4, 38 ), -1, 'Spin 4 (5 Red), bet 38 pays -1';\nis payout( 4, 39 ), -1, 'Spin 4 (5 Red), bet 39 pays -1';\nis payout( 4, 40 ), -1, 'Spin 4 (5 Red), bet 40 pays -1';\nis payout( 4, 41 ), 2, 'Spin 4 (5 Red), bet 41 pays 2';\nis payout( 4, 42 ), -1, 'Spin 4 (5 Red), bet 42 pays -1';\nis payout( 4, 43 ), 1, 'Spin 4 (5 Red), bet 43 pays 1';\nis payout( 4, 44 ), -1, 'Spin 4 (5 Red), bet 44 pays -1';\nis payout( 4, 45 ), -1, 'Spin 4 (5 Red), bet 45 pays -1';\nis payout( 4, 46 ), 1, 'Spin 4 (5 Red), bet 46 pays 1';\nis payout( 4, 47 ), 1, 'Spin 4 (5 Red), bet 47 pays 1';\nis payout( 4, 48 ), -1, 'Spin 4 (5 Red), bet 48 pays -1';\nis payout( 4, 49 ), -1, 'Spin 4 (5 Red), bet 49 pays -1';\nis payout( 4, 50 ), -1, 'Spin 4 (5 Red), bet 50 pays -1';\nis format_spin( 5 ), '6 Black', 'Spin 5 is 6 Black';\nis payout( 5, 1 ), -1, 'Spin 5 (6 Black), bet 1 pays -1';\nis payout( 5, 2 ), -1, 'Spin 5 (6 Black), bet 2 pays -1';\nis payout( 5, 3 ), -1, 'Spin 5 (6 Black), bet 3 pays -1';\nis payout( 5, 4 ), -1, 'Spin 5 (6 Black), bet 4 pays -1';\nis payout( 5, 5 ), -1, 'Spin 5 (6 Black), bet 5 pays -1';\nis payout( 5, 6 ), 35, 'Spin 5 (6 Black), bet 6 pays 35';\nis payout( 5, 7 ), -1, 'Spin 5 (6 Black), bet 7 pays -1';\nis payout( 5, 8 ), -1, 'Spin 5 (6 Black), bet 8 pays -1';\nis payout( 5, 9 ), -1, 'Spin 5 (6 Black), bet 9 pays -1';\nis payout( 5, 10 ), -1, 'Spin 5 (6 Black), bet 10 pays -1';\nis payout( 5, 11 ), -1, 'Spin 5 (6 Black), bet 11 pays -1';\nis payout( 5, 12 ), -1, 'Spin 5 (6 Black), bet 12 pays -1';\nis payout( 5, 13 ), -1, 'Spin 5 (6 Black), bet 13 pays -1';\nis payout( 5, 14 ), -1, 'Spin 5 (6 Black), bet 14 pays -1';\nis payout( 5, 15 ), -1, 'Spin 5 (6 Black), bet 15 pays -1';\nis payout( 5, 16 ), -1, 'Spin 5 (6 Black), bet 16 pays -1';\nis payout( 5, 17 ), -1, 'Spin 5 (6 Black), bet 17 pays -1';\nis payout( 5, 18 ), -1, 'Spin 5 (6 Black), bet 18 pays -1';\nis payout( 5, 19 ), -1, 'Spin 5 (6 Black), bet 19 pays -1';\nis payout( 5, 20 ), -1, 'Spin 5 (6 Black), bet 20 pays -1';\nis payout( 5, 21 ), -1, 'Spin 5 (6 Black), bet 21 pays -1';\nis payout( 5, 22 ), -1, 'Spin 5 (6 Black), bet 22 pays -1';\nis payout( 5, 23 ), -1, 'Spin 5 (6 Black), bet 23 pays -1';\nis payout( 5, 24 ), -1, 'Spin 5 (6 Black), bet 24 pays -1';\nis payout( 5, 25 ), -1, 'Spin 5 (6 Black), bet 25 pays -1';\nis payout( 5, 26 ), -1, 'Spin 5 (6 Black), bet 26 pays -1';\nis payout( 5, 27 ), -1, 'Spin 5 (6 Black), bet 27 pays -1';\nis payout( 5, 28 ), -1, 'Spin 5 (6 Black), bet 28 pays -1';\nis payout( 5, 29 ), -1, 'Spin 5 (6 Black), bet 29 pays -1';\nis payout( 5, 30 ), -1, 'Spin 5 (6 Black), bet 30 pays -1';\nis payout( 5, 31 ), -1, 'Spin 5 (6 Black), bet 31 pays -1';\nis payout( 5, 32 ), -1, 'Spin 5 (6 Black), bet 32 pays -1';\nis payout( 5, 33 ), -1, 'Spin 5 (6 Black), bet 33 pays -1';\nis payout( 5, 34 ), -1, 'Spin 5 (6 Black), bet 34 pays -1';\nis payout( 5, 35 ), -1, 'Spin 5 (6 Black), bet 35 pays -1';\nis payout( 5, 36 ), -1, 'Spin 5 (6 Black), bet 36 pays -1';\nis payout( 5, 37 ), 2, 'Spin 5 (6 Black), bet 37 pays 2';\nis payout( 5, 38 ), -1, 'Spin 5 (6 Black), bet 38 pays -1';\nis payout( 5, 39 ), -1, 'Spin 5 (6 Black), bet 39 pays -1';\nis payout( 5, 40 ), -1, 'Spin 5 (6 Black), bet 40 pays -1';\nis payout( 5, 41 ), -1, 'Spin 5 (6 Black), bet 41 pays -1';\nis payout( 5, 42 ), 2, 'Spin 5 (6 Black), bet 42 pays 2';\nis payout( 5, 43 ), 1, 'Spin 5 (6 Black), bet 43 pays 1';\nis payout( 5, 44 ), -1, 'Spin 5 (6 Black), bet 44 pays -1';\nis payout( 5, 45 ), 1, 'Spin 5 (6 Black), bet 45 pays 1';\nis payout( 5, 46 ), -1, 'Spin 5 (6 Black), bet 46 pays -1';\nis payout( 5, 47 ), -1, 'Spin 5 (6 Black), bet 47 pays -1';\nis payout( 5, 48 ), 1, 'Spin 5 (6 Black), bet 48 pays 1';\nis payout( 5, 49 ), -1, 'Spin 5 (6 Black), bet 49 pays -1';\nis payout( 5, 50 ), -1, 'Spin 5 (6 Black), bet 50 pays -1';\nis format_spin( 6 ), '7 Red', 'Spin 6 is 7 Red';\nis payout( 6, 1 ), -1, 'Spin 6 (7 Red), bet 1 pays -1';\nis payout( 6, 2 ), -1, 'Spin 6 (7 Red), bet 2 pays -1';\nis payout( 6, 3 ), -1, 'Spin 6 (7 Red), bet 3 pays -1';\nis payout( 6, 4 ), -1, 'Spin 6 (7 Red), bet 4 pays -1';\nis payout( 6, 5 ), -1, 'Spin 6 (7 Red), bet 5 pays -1';\nis payout( 6, 6 ), -1, 'Spin 6 (7 Red), bet 6 pays -1';\nis payout( 6, 7 ), 35, 'Spin 6 (7 Red), bet 7 pays 35';\nis payout( 6, 8 ), -1, 'Spin 6 (7 Red), bet 8 pays -1';\nis payout( 6, 9 ), -1, 'Spin 6 (7 Red), bet 9 pays -1';\nis payout( 6, 10 ), -1, 'Spin 6 (7 Red), bet 10 pays -1';\nis payout( 6, 11 ), -1, 'Spin 6 (7 Red), bet 11 pays -1';\nis payout( 6, 12 ), -1, 'Spin 6 (7 Red), bet 12 pays -1';\nis payout( 6, 13 ), -1, 'Spin 6 (7 Red), bet 13 pays -1';\nis payout( 6, 14 ), -1, 'Spin 6 (7 Red), bet 14 pays -1';\nis payout( 6, 15 ), -1, 'Spin 6 (7 Red), bet 15 pays -1';\nis payout( 6, 16 ), -1, 'Spin 6 (7 Red), bet 16 pays -1';\nis payout( 6, 17 ), -1, 'Spin 6 (7 Red), bet 17 pays -1';\nis payout( 6, 18 ), -1, 'Spin 6 (7 Red), bet 18 pays -1';\nis payout( 6, 19 ), -1, 'Spin 6 (7 Red), bet 19 pays -1';\nis payout( 6, 20 ), -1, 'Spin 6 (7 Red), bet 20 pays -1';\nis payout( 6, 21 ), -1, 'Spin 6 (7 Red), bet 21 pays -1';\nis payout( 6, 22 ), -1, 'Spin 6 (7 Red), bet 22 pays -1';\nis payout( 6, 23 ), -1, 'Spin 6 (7 Red), bet 23 pays -1';\nis payout( 6, 24 ), -1, 'Spin 6 (7 Red), bet 24 pays -1';\nis payout( 6, 25 ), -1, 'Spin 6 (7 Red), bet 25 pays -1';\nis payout( 6, 26 ), -1, 'Spin 6 (7 Red), bet 26 pays -1';\nis payout( 6, 27 ), -1, 'Spin 6 (7 Red), bet 27 pays -1';\nis payout( 6, 28 ), -1, 'Spin 6 (7 Red), bet 28 pays -1';\nis payout( 6, 29 ), -1, 'Spin 6 (7 Red), bet 29 pays -1';\nis payout( 6, 30 ), -1, 'Spin 6 (7 Red), bet 30 pays -1';\nis payout( 6, 31 ), -1, 'Spin 6 (7 Red), bet 31 pays -1';\nis payout( 6, 32 ), -1, 'Spin 6 (7 Red), bet 32 pays -1';\nis payout( 6, 33 ), -1, 'Spin 6 (7 Red), bet 33 pays -1';\nis payout( 6, 34 ), -1, 'Spin 6 (7 Red), bet 34 pays -1';\nis payout( 6, 35 ), -1, 'Spin 6 (7 Red), bet 35 pays -1';\nis payout( 6, 36 ), -1, 'Spin 6 (7 Red), bet 36 pays -1';\nis payout( 6, 37 ), 2, 'Spin 6 (7 Red), bet 37 pays 2';\nis payout( 6, 38 ), -1, 'Spin 6 (7 Red), bet 38 pays -1';\nis payout( 6, 39 ), -1, 'Spin 6 (7 Red), bet 39 pays -1';\nis payout( 6, 40 ), 2, 'Spin 6 (7 Red), bet 40 pays 2';\nis payout( 6, 41 ), -1, 'Spin 6 (7 Red), bet 41 pays -1';\nis payout( 6, 42 ), -1, 'Spin 6 (7 Red), bet 42 pays -1';\nis payout( 6, 43 ), 1, 'Spin 6 (7 Red), bet 43 pays 1';\nis payout( 6, 44 ), -1, 'Spin 6 (7 Red), bet 44 pays -1';\nis payout( 6, 45 ), -1, 'Spin 6 (7 Red), bet 45 pays -1';\nis payout( 6, 46 ), 1, 'Spin 6 (7 Red), bet 46 pays 1';\nis payout( 6, 47 ), 1, 'Spin 6 (7 Red), bet 47 pays 1';\nis payout( 6, 48 ), -1, 'Spin 6 (7 Red), bet 48 pays -1';\nis payout( 6, 49 ), -1, 'Spin 6 (7 Red), bet 49 pays -1';\nis payout( 6, 50 ), -1, 'Spin 6 (7 Red), bet 50 pays -1';\nis format_spin( 7 ), '8 Black', 'Spin 7 is 8 Black';\nis payout( 7, 1 ), -1, 'Spin 7 (8 Black), bet 1 pays -1';\nis payout( 7, 2 ), -1, 'Spin 7 (8 Black), bet 2 pays -1';\nis payout( 7, 3 ), -1, 'Spin 7 (8 Black), bet 3 pays -1';\nis payout( 7, 4 ), -1, 'Spin 7 (8 Black), bet 4 pays -1';\nis payout( 7, 5 ), -1, 'Spin 7 (8 Black), bet 5 pays -1';\nis payout( 7, 6 ), -1, 'Spin 7 (8 Black), bet 6 pays -1';\nis payout( 7, 7 ), -1, 'Spin 7 (8 Black), bet 7 pays -1';\nis payout( 7, 8 ), 35, 'Spin 7 (8 Black), bet 8 pays 35';\nis payout( 7, 9 ), -1, 'Spin 7 (8 Black), bet 9 pays -1';\nis payout( 7, 10 ), -1, 'Spin 7 (8 Black), bet 10 pays -1';\nis payout( 7, 11 ), -1, 'Spin 7 (8 Black), bet 11 pays -1';\nis payout( 7, 12 ), -1, 'Spin 7 (8 Black), bet 12 pays -1';\nis payout( 7, 13 ), -1, 'Spin 7 (8 Black), bet 13 pays -1';\nis payout( 7, 14 ), -1, 'Spin 7 (8 Black), bet 14 pays -1';\nis payout( 7, 15 ), -1, 'Spin 7 (8 Black), bet 15 pays -1';\nis payout( 7, 16 ), -1, 'Spin 7 (8 Black), bet 16 pays -1';\nis payout( 7, 17 ), -1, 'Spin 7 (8 Black), bet 17 pays -1';\nis payout( 7, 18 ), -1, 'Spin 7 (8 Black), bet 18 pays -1';\nis payout( 7, 19 ), -1, 'Spin 7 (8 Black), bet 19 pays -1';\nis payout( 7, 20 ), -1, 'Spin 7 (8 Black), bet 20 pays -1';\nis payout( 7, 21 ), -1, 'Spin 7 (8 Black), bet 21 pays -1';\nis payout( 7, 22 ), -1, 'Spin 7 (8 Black), bet 22 pays -1';\nis payout( 7, 23 ), -1, 'Spin 7 (8 Black), bet 23 pays -1';\nis payout( 7, 24 ), -1, 'Spin 7 (8 Black), bet 24 pays -1';\nis payout( 7, 25 ), -1, 'Spin 7 (8 Black), bet 25 pays -1';\nis payout( 7, 26 ), -1, 'Spin 7 (8 Black), bet 26 pays -1';\nis payout( 7, 27 ), -1, 'Spin 7 (8 Black), bet 27 pays -1';\nis payout( 7, 28 ), -1, 'Spin 7 (8 Black), bet 28 pays -1';\nis payout( 7, 29 ), -1, 'Spin 7 (8 Black), bet 29 pays -1';\nis payout( 7, 30 ), -1, 'Spin 7 (8 Black), bet 30 pays -1';\nis payout( 7, 31 ), -1, 'Spin 7 (8 Black), bet 31 pays -1';\nis payout( 7, 32 ), -1, 'Spin 7 (8 Black), bet 32 pays -1';\nis payout( 7, 33 ), -1, 'Spin 7 (8 Black), bet 33 pays -1';\nis payout( 7, 34 ), -1, 'Spin 7 (8 Black), bet 34 pays -1';\nis payout( 7, 35 ), -1, 'Spin 7 (8 Black), bet 35 pays -1';\nis payout( 7, 36 ), -1, 'Spin 7 (8 Black), bet 36 pays -1';\nis payout( 7, 37 ), 2, 'Spin 7 (8 Black), bet 37 pays 2';\nis payout( 7, 38 ), -1, 'Spin 7 (8 Black), bet 38 pays -1';\nis payout( 7, 39 ), -1, 'Spin 7 (8 Black), bet 39 pays -1';\nis payout( 7, 40 ), -1, 'Spin 7 (8 Black), bet 40 pays -1';\nis payout( 7, 41 ), 2, 'Spin 7 (8 Black), bet 41 pays 2';\nis payout( 7, 42 ), -1, 'Spin 7 (8 Black), bet 42 pays -1';\nis payout( 7, 43 ), 1, 'Spin 7 (8 Black), bet 43 pays 1';\nis payout( 7, 44 ), -1, 'Spin 7 (8 Black), bet 44 pays -1';\nis payout( 7, 45 ), 1, 'Spin 7 (8 Black), bet 45 pays 1';\nis payout( 7, 46 ), -1, 'Spin 7 (8 Black), bet 46 pays -1';\nis payout( 7, 47 ), -1, 'Spin 7 (8 Black), bet 47 pays -1';\nis payout( 7, 48 ), 1, 'Spin 7 (8 Black), bet 48 pays 1';\nis payout( 7, 49 ), -1, 'Spin 7 (8 Black), bet 49 pays -1';\nis payout( 7, 50 ), -1, 'Spin 7 (8 Black), bet 50 pays -1';\nis format_spin( 8 ), '9 Red', 'Spin 8 is 9 Red';\nis payout( 8, 1 ), -1, 'Spin 8 (9 Red), bet 1 pays -1';\nis payout( 8, 2 ), -1, 'Spin 8 (9 Red), bet 2 pays -1';\nis payout( 8, 3 ), -1, 'Spin 8 (9 Red), bet 3 pays -1';\nis payout( 8, 4 ), -1, 'Spin 8 (9 Red), bet 4 pays -1';\nis payout( 8, 5 ), -1, 'Spin 8 (9 Red), bet 5 pays -1';\nis payout( 8, 6 ), -1, 'Spin 8 (9 Red), bet 6 pays -1';\nis payout( 8, 7 ), -1, 'Spin 8 (9 Red), bet 7 pays -1';\nis payout( 8, 8 ), -1, 'Spin 8 (9 Red), bet 8 pays -1';\nis payout( 8, 9 ), 35, 'Spin 8 (9 Red), bet 9 pays 35';\nis payout( 8, 10 ), -1, 'Spin 8 (9 Red), bet 10 pays -1';\nis payout( 8, 11 ), -1, 'Spin 8 (9 Red), bet 11 pays -1';\nis payout( 8, 12 ), -1, 'Spin 8 (9 Red), bet 12 pays -1';\nis payout( 8, 13 ), -1, 'Spin 8 (9 Red), bet 13 pays -1';\nis payout( 8, 14 ), -1, 'Spin 8 (9 Red), bet 14 pays -1';\nis payout( 8, 15 ), -1, 'Spin 8 (9 Red), bet 15 pays -1';\nis payout( 8, 16 ), -1, 'Spin 8 (9 Red), bet 16 pays -1';\nis payout( 8, 17 ), -1, 'Spin 8 (9 Red), bet 17 pays -1';\nis payout( 8, 18 ), -1, 'Spin 8 (9 Red), bet 18 pays -1';\nis payout( 8, 19 ), -1, 'Spin 8 (9 Red), bet 19 pays -1';\nis payout( 8, 20 ), -1, 'Spin 8 (9 Red), bet 20 pays -1';\nis payout( 8, 21 ), -1, 'Spin 8 (9 Red), bet 21 pays -1';\nis payout( 8, 22 ), -1, 'Spin 8 (9 Red), bet 22 pays -1';\nis payout( 8, 23 ), -1, 'Spin 8 (9 Red), bet 23 pays -1';\nis payout( 8, 24 ), -1, 'Spin 8 (9 Red), bet 24 pays -1';\nis payout( 8, 25 ), -1, 'Spin 8 (9 Red), bet 25 pays -1';\nis payout( 8, 26 ), -1, 'Spin 8 (9 Red), bet 26 pays -1';\nis payout( 8, 27 ), -1, 'Spin 8 (9 Red), bet 27 pays -1';\nis payout( 8, 28 ), -1, 'Spin 8 (9 Red), bet 28 pays -1';\nis payout( 8, 29 ), -1, 'Spin 8 (9 Red), bet 29 pays -1';\nis payout( 8, 30 ), -1, 'Spin 8 (9 Red), bet 30 pays -1';\nis payout( 8, 31 ), -1, 'Spin 8 (9 Red), bet 31 pays -1';\nis payout( 8, 32 ), -1, 'Spin 8 (9 Red), bet 32 pays -1';\nis payout( 8, 33 ), -1, 'Spin 8 (9 Red), bet 33 pays -1';\nis payout( 8, 34 ), -1, 'Spin 8 (9 Red), bet 34 pays -1';\nis payout( 8, 35 ), -1, 'Spin 8 (9 Red), bet 35 pays -1';\nis payout( 8, 36 ), -1, 'Spin 8 (9 Red), bet 36 pays -1';\nis payout( 8, 37 ), 2, 'Spin 8 (9 Red), bet 37 pays 2';\nis payout( 8, 38 ), -1, 'Spin 8 (9 Red), bet 38 pays -1';\nis payout( 8, 39 ), -1, 'Spin 8 (9 Red), bet 39 pays -1';\nis payout( 8, 40 ), -1, 'Spin 8 (9 Red), bet 40 pays -1';\nis payout( 8, 41 ), -1, 'Spin 8 (9 Red), bet 41 pays -1';\nis payout( 8, 42 ), 2, 'Spin 8 (9 Red), bet 42 pays 2';\nis payout( 8, 43 ), 1, 'Spin 8 (9 Red), bet 43 pays 1';\nis payout( 8, 44 ), -1, 'Spin 8 (9 Red), bet 44 pays -1';\nis payout( 8, 45 ), -1, 'Spin 8 (9 Red), bet 45 pays -1';\nis payout( 8, 46 ), 1, 'Spin 8 (9 Red), bet 46 pays 1';\nis payout( 8, 47 ), 1, 'Spin 8 (9 Red), bet 47 pays 1';\nis payout( 8, 48 ), -1, 'Spin 8 (9 Red), bet 48 pays -1';\nis payout( 8, 49 ), -1, 'Spin 8 (9 Red), bet 49 pays -1';\nis payout( 8, 50 ), -1, 'Spin 8 (9 Red), bet 50 pays -1';\nis format_spin( 9 ), '10 Black', 'Spin 9 is 10 Black';\nis payout( 9, 1 ), -1, 'Spin 9 (10 Black), bet 1 pays -1';\nis payout( 9, 2 ), -1, 'Spin 9 (10 Black), bet 2 pays -1';\nis payout( 9, 3 ), -1, 'Spin 9 (10 Black), bet 3 pays -1';\nis payout( 9, 4 ), -1, 'Spin 9 (10 Black), bet 4 pays -1';\nis payout( 9, 5 ), -1, 'Spin 9 (10 Black), bet 5 pays -1';\nis payout( 9, 6 ), -1, 'Spin 9 (10 Black), bet 6 pays -1';\nis payout( 9, 7 ), -1, 'Spin 9 (10 Black), bet 7 pays -1';\nis payout( 9, 8 ), -1, 'Spin 9 (10 Black), bet 8 pays -1';\nis payout( 9, 9 ), -1, 'Spin 9 (10 Black), bet 9 pays -1';\nis payout( 9, 10 ), 35, 'Spin 9 (10 Black), bet 10 pays 35';\nis payout( 9, 11 ), -1, 'Spin 9 (10 Black), bet 11 pays -1';\nis payout( 9, 12 ), -1, 'Spin 9 (10 Black), bet 12 pays -1';\nis payout( 9, 13 ), -1, 'Spin 9 (10 Black), bet 13 pays -1';\nis payout( 9, 14 ), -1, 'Spin 9 (10 Black), bet 14 pays -1';\nis payout( 9, 15 ), -1, 'Spin 9 (10 Black), bet 15 pays -1';\nis payout( 9, 16 ), -1, 'Spin 9 (10 Black), bet 16 pays -1';\nis payout( 9, 17 ), -1, 'Spin 9 (10 Black), bet 17 pays -1';\nis payout( 9, 18 ), -1, 'Spin 9 (10 Black), bet 18 pays -1';\nis payout( 9, 19 ), -1, 'Spin 9 (10 Black), bet 19 pays -1';\nis payout( 9, 20 ), -1, 'Spin 9 (10 Black), bet 20 pays -1';\nis payout( 9, 21 ), -1, 'Spin 9 (10 Black), bet 21 pays -1';\nis payout( 9, 22 ), -1, 'Spin 9 (10 Black), bet 22 pays -1';\nis payout( 9, 23 ), -1, 'Spin 9 (10 Black), bet 23 pays -1';\nis payout( 9, 24 ), -1, 'Spin 9 (10 Black), bet 24 pays -1';\nis payout( 9, 25 ), -1, 'Spin 9 (10 Black), bet 25 pays -1';\nis payout( 9, 26 ), -1, 'Spin 9 (10 Black), bet 26 pays -1';\nis payout( 9, 27 ), -1, 'Spin 9 (10 Black), bet 27 pays -1';\nis payout( 9, 28 ), -1, 'Spin 9 (10 Black), bet 28 pays -1';\nis payout( 9, 29 ), -1, 'Spin 9 (10 Black), bet 29 pays -1';\nis payout( 9, 30 ), -1, 'Spin 9 (10 Black), bet 30 pays -1';\nis payout( 9, 31 ), -1, 'Spin 9 (10 Black), bet 31 pays -1';\nis payout( 9, 32 ), -1, 'Spin 9 (10 Black), bet 32 pays -1';\nis payout( 9, 33 ), -1, 'Spin 9 (10 Black), bet 33 pays -1';\nis payout( 9, 34 ), -1, 'Spin 9 (10 Black), bet 34 pays -1';\nis payout( 9, 35 ), -1, 'Spin 9 (10 Black), bet 35 pays -1';\nis payout( 9, 36 ), -1, 'Spin 9 (10 Black), bet 36 pays -1';\nis payout( 9, 37 ), 2, 'Spin 9 (10 Black), bet 37 pays 2';\nis payout( 9, 38 ), -1, 'Spin 9 (10 Black), bet 38 pays -1';\nis payout( 9, 39 ), -1, 'Spin 9 (10 Black), bet 39 pays -1';\nis payout( 9, 40 ), 2, 'Spin 9 (10 Black), bet 40 pays 2';\nis payout( 9, 41 ), -1, 'Spin 9 (10 Black), bet 41 pays -1';\nis payout( 9, 42 ), -1, 'Spin 9 (10 Black), bet 42 pays -1';\nis payout( 9, 43 ), 1, 'Spin 9 (10 Black), bet 43 pays 1';\nis payout( 9, 44 ), -1, 'Spin 9 (10 Black), bet 44 pays -1';\nis payout( 9, 45 ), 1, 'Spin 9 (10 Black), bet 45 pays 1';\nis payout( 9, 46 ), -1, 'Spin 9 (10 Black), bet 46 pays -1';\nis payout( 9, 47 ), -1, 'Spin 9 (10 Black), bet 47 pays -1';\nis payout( 9, 48 ), 1, 'Spin 9 (10 Black), bet 48 pays 1';\nis payout( 9, 49 ), -1, 'Spin 9 (10 Black), bet 49 pays -1';\nis payout( 9, 50 ), -1, 'Spin 9 (10 Black), bet 50 pays -1';\nis format_spin( 10 ), '11 Black', 'Spin 10 is 11 Black';\nis payout( 10, 1 ), -1, 'Spin 10 (11 Black), bet 1 pays -1';\nis payout( 10, 2 ), -1, 'Spin 10 (11 Black), bet 2 pays -1';\nis payout( 10, 3 ), -1, 'Spin 10 (11 Black), bet 3 pays -1';\nis payout( 10, 4 ), -1, 'Spin 10 (11 Black), bet 4 pays -1';\nis payout( 10, 5 ), -1, 'Spin 10 (11 Black), bet 5 pays -1';\nis payout( 10, 6 ), -1, 'Spin 10 (11 Black), bet 6 pays -1';\nis payout( 10, 7 ), -1, 'Spin 10 (11 Black), bet 7 pays -1';\nis payout( 10, 8 ), -1, 'Spin 10 (11 Black), bet 8 pays -1';\nis payout( 10, 9 ), -1, 'Spin 10 (11 Black), bet 9 pays -1';\nis payout( 10, 10 ), -1, 'Spin 10 (11 Black), bet 10 pays -1';\nis payout( 10, 11 ), 35, 'Spin 10 (11 Black), bet 11 pays 35';\nis payout( 10, 12 ), -1, 'Spin 10 (11 Black), bet 12 pays -1';\nis payout( 10, 13 ), -1, 'Spin 10 (11 Black), bet 13 pays -1';\nis payout( 10, 14 ), -1, 'Spin 10 (11 Black), bet 14 pays -1';\nis payout( 10, 15 ), -1, 'Spin 10 (11 Black), bet 15 pays -1';\nis payout( 10, 16 ), -1, 'Spin 10 (11 Black), bet 16 pays -1';\nis payout( 10, 17 ), -1, 'Spin 10 (11 Black), bet 17 pays -1';\nis payout( 10, 18 ), -1, 'Spin 10 (11 Black), bet 18 pays -1';\nis payout( 10, 19 ), -1, 'Spin 10 (11 Black), bet 19 pays -1';\nis payout( 10, 20 ), -1, 'Spin 10 (11 Black), bet 20 pays -1';\nis payout( 10, 21 ), -1, 'Spin 10 (11 Black), bet 21 pays -1';\nis payout( 10, 22 ), -1, 'Spin 10 (11 Black), bet 22 pays -1';\nis payout( 10, 23 ), -1, 'Spin 10 (11 Black), bet 23 pays -1';\nis payout( 10, 24 ), -1, 'Spin 10 (11 Black), bet 24 pays -1';\nis payout( 10, 25 ), -1, 'Spin 10 (11 Black), bet 25 pays -1';\nis payout( 10, 26 ), -1, 'Spin 10 (11 Black), bet 26 pays -1';\nis payout( 10, 27 ), -1, 'Spin 10 (11 Black), bet 27 pays -1';\nis payout( 10, 28 ), -1, 'Spin 10 (11 Black), bet 28 pays -1';\nis payout( 10, 29 ), -1, 'Spin 10 (11 Black), bet 29 pays -1';\nis payout( 10, 30 ), -1, 'Spin 10 (11 Black), bet 30 pays -1';\nis payout( 10, 31 ), -1, 'Spin 10 (11 Black), bet 31 pays -1';\nis payout( 10, 32 ), -1, 'Spin 10 (11 Black), bet 32 pays -1';\nis payout( 10, 33 ), -1, 'Spin 10 (11 Black), bet 33 pays -1';\nis payout( 10, 34 ), -1, 'Spin 10 (11 Black), bet 34 pays -1';\nis payout( 10, 35 ), -1, 'Spin 10 (11 Black), bet 35 pays -1';\nis payout( 10, 36 ), -1, 'Spin 10 (11 Black), bet 36 pays -1';\nis payout( 10, 37 ), 2, 'Spin 10 (11 Black), bet 37 pays 2';\nis payout( 10, 38 ), -1, 'Spin 10 (11 Black), bet 38 pays -1';\nis payout( 10, 39 ), -1, 'Spin 10 (11 Black), bet 39 pays -1';\nis payout( 10, 40 ), -1, 'Spin 10 (11 Black), bet 40 pays -1';\nis payout( 10, 41 ), 2, 'Spin 10 (11 Black), bet 41 pays 2';\nis payout( 10, 42 ), -1, 'Spin 10 (11 Black), bet 42 pays -1';\nis payout( 10, 43 ), 1, 'Spin 10 (11 Black), bet 43 pays 1';\nis payout( 10, 44 ), -1, 'Spin 10 (11 Black), bet 44 pays -1';\nis payout( 10, 45 ), -1, 'Spin 10 (11 Black), bet 45 pays -1';\nis payout( 10, 46 ), 1, 'Spin 10 (11 Black), bet 46 pays 1';\nis payout( 10, 47 ), -1, 'Spin 10 (11 Black), bet 47 pays -1';\nis payout( 10, 48 ), 1, 'Spin 10 (11 Black), bet 48 pays 1';\nis payout( 10, 49 ), -1, 'Spin 10 (11 Black), bet 49 pays -1';\nis payout( 10, 50 ), -1, 'Spin 10 (11 Black), bet 50 pays -1';\nis format_spin( 11 ), '12 Red', 'Spin 11 is 12 Red';\nis payout( 11, 1 ), -1, 'Spin 11 (12 Red), bet 1 pays -1';\nis payout( 11, 2 ), -1, 'Spin 11 (12 Red), bet 2 pays -1';\nis payout( 11, 3 ), -1, 'Spin 11 (12 Red), bet 3 pays -1';\nis payout( 11, 4 ), -1, 'Spin 11 (12 Red), bet 4 pays -1';\nis payout( 11, 5 ), -1, 'Spin 11 (12 Red), bet 5 pays -1';\nis payout( 11, 6 ), -1, 'Spin 11 (12 Red), bet 6 pays -1';\nis payout( 11, 7 ), -1, 'Spin 11 (12 Red), bet 7 pays -1';\nis payout( 11, 8 ), -1, 'Spin 11 (12 Red), bet 8 pays -1';\nis payout( 11, 9 ), -1, 'Spin 11 (12 Red), bet 9 pays -1';\nis payout( 11, 10 ), -1, 'Spin 11 (12 Red), bet 10 pays -1';\nis payout( 11, 11 ), -1, 'Spin 11 (12 Red), bet 11 pays -1';\nis payout( 11, 12 ), 35, 'Spin 11 (12 Red), bet 12 pays 35';\nis payout( 11, 13 ), -1, 'Spin 11 (12 Red), bet 13 pays -1';\nis payout( 11, 14 ), -1, 'Spin 11 (12 Red), bet 14 pays -1';\nis payout( 11, 15 ), -1, 'Spin 11 (12 Red), bet 15 pays -1';\nis payout( 11, 16 ), -1, 'Spin 11 (12 Red), bet 16 pays -1';\nis payout( 11, 17 ), -1, 'Spin 11 (12 Red), bet 17 pays -1';\nis payout( 11, 18 ), -1, 'Spin 11 (12 Red), bet 18 pays -1';\nis payout( 11, 19 ), -1, 'Spin 11 (12 Red), bet 19 pays -1';\nis payout( 11, 20 ), -1, 'Spin 11 (12 Red), bet 20 pays -1';\nis payout( 11, 21 ), -1, 'Spin 11 (12 Red), bet 21 pays -1';\nis payout( 11, 22 ), -1, 'Spin 11 (12 Red), bet 22 pays -1';\nis payout( 11, 23 ), -1, 'Spin 11 (12 Red), bet 23 pays -1';\nis payout( 11, 24 ), -1, 'Spin 11 (12 Red), bet 24 pays -1';\nis payout( 11, 25 ), -1, 'Spin 11 (12 Red), bet 25 pays -1';\nis payout( 11, 26 ), -1, 'Spin 11 (12 Red), bet 26 pays -1';\nis payout( 11, 27 ), -1, 'Spin 11 (12 Red), bet 27 pays -1';\nis payout( 11, 28 ), -1, 'Spin 11 (12 Red), bet 28 pays -1';\nis payout( 11, 29 ), -1, 'Spin 11 (12 Red), bet 29 pays -1';\nis payout( 11, 30 ), -1, 'Spin 11 (12 Red), bet 30 pays -1';\nis payout( 11, 31 ), -1, 'Spin 11 (12 Red), bet 31 pays -1';\nis payout( 11, 32 ), -1, 'Spin 11 (12 Red), bet 32 pays -1';\nis payout( 11, 33 ), -1, 'Spin 11 (12 Red), bet 33 pays -1';\nis payout( 11, 34 ), -1, 'Spin 11 (12 Red), bet 34 pays -1';\nis payout( 11, 35 ), -1, 'Spin 11 (12 Red), bet 35 pays -1';\nis payout( 11, 36 ), -1, 'Spin 11 (12 Red), bet 36 pays -1';\nis payout( 11, 37 ), 2, 'Spin 11 (12 Red), bet 37 pays 2';\nis payout( 11, 38 ), -1, 'Spin 11 (12 Red), bet 38 pays -1';\nis payout( 11, 39 ), -1, 'Spin 11 (12 Red), bet 39 pays -1';\nis payout( 11, 40 ), -1, 'Spin 11 (12 Red), bet 40 pays -1';\nis payout( 11, 41 ), -1, 'Spin 11 (12 Red), bet 41 pays -1';\nis payout( 11, 42 ), 2, 'Spin 11 (12 Red), bet 42 pays 2';\nis payout( 11, 43 ), 1, 'Spin 11 (12 Red), bet 43 pays 1';\nis payout( 11, 44 ), -1, 'Spin 11 (12 Red), bet 44 pays -1';\nis payout( 11, 45 ), 1, 'Spin 11 (12 Red), bet 45 pays 1';\nis payout( 11, 46 ), -1, 'Spin 11 (12 Red), bet 46 pays -1';\nis payout( 11, 47 ), 1, 'Spin 11 (12 Red), bet 47 pays 1';\nis payout( 11, 48 ), -1, 'Spin 11 (12 Red), bet 48 pays -1';\nis payout( 11, 49 ), -1, 'Spin 11 (12 Red), bet 49 pays -1';\nis payout( 11, 50 ), -1, 'Spin 11 (12 Red), bet 50 pays -1';\nis format_spin( 12 ), '13 Black', 'Spin 12 is 13 Black';\nis payout( 12, 1 ), -1, 'Spin 12 (13 Black), bet 1 pays -1';\nis payout( 12, 2 ), -1, 'Spin 12 (13 Black), bet 2 pays -1';\nis payout( 12, 3 ), -1, 'Spin 12 (13 Black), bet 3 pays -1';\nis payout( 12, 4 ), -1, 'Spin 12 (13 Black), bet 4 pays -1';\nis payout( 12, 5 ), -1, 'Spin 12 (13 Black), bet 5 pays -1';\nis payout( 12, 6 ), -1, 'Spin 12 (13 Black), bet 6 pays -1';\nis payout( 12, 7 ), -1, 'Spin 12 (13 Black), bet 7 pays -1';\nis payout( 12, 8 ), -1, 'Spin 12 (13 Black), bet 8 pays -1';\nis payout( 12, 9 ), -1, 'Spin 12 (13 Black), bet 9 pays -1';\nis payout( 12, 10 ), -1, 'Spin 12 (13 Black), bet 10 pays -1';\nis payout( 12, 11 ), -1, 'Spin 12 (13 Black), bet 11 pays -1';\nis payout( 12, 12 ), -1, 'Spin 12 (13 Black), bet 12 pays -1';\nis payout( 12, 13 ), 35, 'Spin 12 (13 Black), bet 13 pays 35';\nis payout( 12, 14 ), -1, 'Spin 12 (13 Black), bet 14 pays -1';\nis payout( 12, 15 ), -1, 'Spin 12 (13 Black), bet 15 pays -1';\nis payout( 12, 16 ), -1, 'Spin 12 (13 Black), bet 16 pays -1';\nis payout( 12, 17 ), -1, 'Spin 12 (13 Black), bet 17 pays -1';\nis payout( 12, 18 ), -1, 'Spin 12 (13 Black), bet 18 pays -1';\nis payout( 12, 19 ), -1, 'Spin 12 (13 Black), bet 19 pays -1';\nis payout( 12, 20 ), -1, 'Spin 12 (13 Black), bet 20 pays -1';\nis payout( 12, 21 ), -1, 'Spin 12 (13 Black), bet 21 pays -1';\nis payout( 12, 22 ), -1, 'Spin 12 (13 Black), bet 22 pays -1';\nis payout( 12, 23 ), -1, 'Spin 12 (13 Black), bet 23 pays -1';\nis payout( 12, 24 ), -1, 'Spin 12 (13 Black), bet 24 pays -1';\nis payout( 12, 25 ), -1, 'Spin 12 (13 Black), bet 25 pays -1';\nis payout( 12, 26 ), -1, 'Spin 12 (13 Black), bet 26 pays -1';\nis payout( 12, 27 ), -1, 'Spin 12 (13 Black), bet 27 pays -1';\nis payout( 12, 28 ), -1, 'Spin 12 (13 Black), bet 28 pays -1';\nis payout( 12, 29 ), -1, 'Spin 12 (13 Black), bet 29 pays -1';\nis payout( 12, 30 ), -1, 'Spin 12 (13 Black), bet 30 pays -1';\nis payout( 12, 31 ), -1, 'Spin 12 (13 Black), bet 31 pays -1';\nis payout( 12, 32 ), -1, 'Spin 12 (13 Black), bet 32 pays -1';\nis payout( 12, 33 ), -1, 'Spin 12 (13 Black), bet 33 pays -1';\nis payout( 12, 34 ), -1, 'Spin 12 (13 Black), bet 34 pays -1';\nis payout( 12, 35 ), -1, 'Spin 12 (13 Black), bet 35 pays -1';\nis payout( 12, 36 ), -1, 'Spin 12 (13 Black), bet 36 pays -1';\nis payout( 12, 37 ), -1, 'Spin 12 (13 Black), bet 37 pays -1';\nis payout( 12, 38 ), 2, 'Spin 12 (13 Black), bet 38 pays 2';\nis payout( 12, 39 ), -1, 'Spin 12 (13 Black), bet 39 pays -1';\nis payout( 12, 40 ), 2, 'Spin 12 (13 Black), bet 40 pays 2';\nis payout( 12, 41 ), -1, 'Spin 12 (13 Black), bet 41 pays -1';\nis payout( 12, 42 ), -1, 'Spin 12 (13 Black), bet 42 pays -1';\nis payout( 12, 43 ), 1, 'Spin 12 (13 Black), bet 43 pays 1';\nis payout( 12, 44 ), -1, 'Spin 12 (13 Black), bet 44 pays -1';\nis payout( 12, 45 ), -1, 'Spin 12 (13 Black), bet 45 pays -1';\nis payout( 12, 46 ), 1, 'Spin 12 (13 Black), bet 46 pays 1';\nis payout( 12, 47 ), -1, 'Spin 12 (13 Black), bet 47 pays -1';\nis payout( 12, 48 ), 1, 'Spin 12 (13 Black), bet 48 pays 1';\nis payout( 12, 49 ), -1, 'Spin 12 (13 Black), bet 49 pays -1';\nis payout( 12, 50 ), -1, 'Spin 12 (13 Black), bet 50 pays -1';\nis format_spin( 13 ), '14 Red', 'Spin 13 is 14 Red';\nis payout( 13, 1 ), -1, 'Spin 13 (14 Red), bet 1 pays -1';\nis payout( 13, 2 ), -1, 'Spin 13 (14 Red), bet 2 pays -1';\nis payout( 13, 3 ), -1, 'Spin 13 (14 Red), bet 3 pays -1';\nis payout( 13, 4 ), -1, 'Spin 13 (14 Red), bet 4 pays -1';\nis payout( 13, 5 ), -1, 'Spin 13 (14 Red), bet 5 pays -1';\nis payout( 13, 6 ), -1, 'Spin 13 (14 Red), bet 6 pays -1';\nis payout( 13, 7 ), -1, 'Spin 13 (14 Red), bet 7 pays -1';\nis payout( 13, 8 ), -1, 'Spin 13 (14 Red), bet 8 pays -1';\nis payout( 13, 9 ), -1, 'Spin 13 (14 Red), bet 9 pays -1';\nis payout( 13, 10 ), -1, 'Spin 13 (14 Red), bet 10 pays -1';\nis payout( 13, 11 ), -1, 'Spin 13 (14 Red), bet 11 pays -1';\nis payout( 13, 12 ), -1, 'Spin 13 (14 Red), bet 12 pays -1';\nis payout( 13, 13 ), -1, 'Spin 13 (14 Red), bet 13 pays -1';\nis payout( 13, 14 ), 35, 'Spin 13 (14 Red), bet 14 pays 35';\nis payout( 13, 15 ), -1, 'Spin 13 (14 Red), bet 15 pays -1';\nis payout( 13, 16 ), -1, 'Spin 13 (14 Red), bet 16 pays -1';\nis payout( 13, 17 ), -1, 'Spin 13 (14 Red), bet 17 pays -1';\nis payout( 13, 18 ), -1, 'Spin 13 (14 Red), bet 18 pays -1';\nis payout( 13, 19 ), -1, 'Spin 13 (14 Red), bet 19 pays -1';\nis payout( 13, 20 ), -1, 'Spin 13 (14 Red), bet 20 pays -1';\nis payout( 13, 21 ), -1, 'Spin 13 (14 Red), bet 21 pays -1';\nis payout( 13, 22 ), -1, 'Spin 13 (14 Red), bet 22 pays -1';\nis payout( 13, 23 ), -1, 'Spin 13 (14 Red), bet 23 pays -1';\nis payout( 13, 24 ), -1, 'Spin 13 (14 Red), bet 24 pays -1';\nis payout( 13, 25 ), -1, 'Spin 13 (14 Red), bet 25 pays -1';\nis payout( 13, 26 ), -1, 'Spin 13 (14 Red), bet 26 pays -1';\nis payout( 13, 27 ), -1, 'Spin 13 (14 Red), bet 27 pays -1';\nis payout( 13, 28 ), -1, 'Spin 13 (14 Red), bet 28 pays -1';\nis payout( 13, 29 ), -1, 'Spin 13 (14 Red), bet 29 pays -1';\nis payout( 13, 30 ), -1, 'Spin 13 (14 Red), bet 30 pays -1';\nis payout( 13, 31 ), -1, 'Spin 13 (14 Red), bet 31 pays -1';\nis payout( 13, 32 ), -1, 'Spin 13 (14 Red), bet 32 pays -1';\nis payout( 13, 33 ), -1, 'Spin 13 (14 Red), bet 33 pays -1';\nis payout( 13, 34 ), -1, 'Spin 13 (14 Red), bet 34 pays -1';\nis payout( 13, 35 ), -1, 'Spin 13 (14 Red), bet 35 pays -1';\nis payout( 13, 36 ), -1, 'Spin 13 (14 Red), bet 36 pays -1';\nis payout( 13, 37 ), -1, 'Spin 13 (14 Red), bet 37 pays -1';\nis payout( 13, 38 ), 2, 'Spin 13 (14 Red), bet 38 pays 2';\nis payout( 13, 39 ), -1, 'Spin 13 (14 Red), bet 39 pays -1';\nis payout( 13, 40 ), -1, 'Spin 13 (14 Red), bet 40 pays -1';\nis payout( 13, 41 ), 2, 'Spin 13 (14 Red), bet 41 pays 2';\nis payout( 13, 42 ), -1, 'Spin 13 (14 Red), bet 42 pays -1';\nis payout( 13, 43 ), 1, 'Spin 13 (14 Red), bet 43 pays 1';\nis payout( 13, 44 ), -1, 'Spin 13 (14 Red), bet 44 pays -1';\nis payout( 13, 45 ), 1, 'Spin 13 (14 Red), bet 45 pays 1';\nis payout( 13, 46 ), -1, 'Spin 13 (14 Red), bet 46 pays -1';\nis payout( 13, 47 ), 1, 'Spin 13 (14 Red), bet 47 pays 1';\nis payout( 13, 48 ), -1, 'Spin 13 (14 Red), bet 48 pays -1';\nis payout( 13, 49 ), -1, 'Spin 13 (14 Red), bet 49 pays -1';\nis payout( 13, 50 ), -1, 'Spin 13 (14 Red), bet 50 pays -1';\nis format_spin( 14 ), '15 Black', 'Spin 14 is 15 Black';\nis payout( 14, 1 ), -1, 'Spin 14 (15 Black), bet 1 pays -1';\nis payout( 14, 2 ), -1, 'Spin 14 (15 Black), bet 2 pays -1';\nis payout( 14, 3 ), -1, 'Spin 14 (15 Black), bet 3 pays -1';\nis payout( 14, 4 ), -1, 'Spin 14 (15 Black), bet 4 pays -1';\nis payout( 14, 5 ), -1, 'Spin 14 (15 Black), bet 5 pays -1';\nis payout( 14, 6 ), -1, 'Spin 14 (15 Black), bet 6 pays -1';\nis payout( 14, 7 ), -1, 'Spin 14 (15 Black), bet 7 pays -1';\nis payout( 14, 8 ), -1, 'Spin 14 (15 Black), bet 8 pays -1';\nis payout( 14, 9 ), -1, 'Spin 14 (15 Black), bet 9 pays -1';\nis payout( 14, 10 ), -1, 'Spin 14 (15 Black), bet 10 pays -1';\nis payout( 14, 11 ), -1, 'Spin 14 (15 Black), bet 11 pays -1';\nis payout( 14, 12 ), -1, 'Spin 14 (15 Black), bet 12 pays -1';\nis payout( 14, 13 ), -1, 'Spin 14 (15 Black), bet 13 pays -1';\nis payout( 14, 14 ), -1, 'Spin 14 (15 Black), bet 14 pays -1';\nis payout( 14, 15 ), 35, 'Spin 14 (15 Black), bet 15 pays 35';\nis payout( 14, 16 ), -1, 'Spin 14 (15 Black), bet 16 pays -1';\nis payout( 14, 17 ), -1, 'Spin 14 (15 Black), bet 17 pays -1';\nis payout( 14, 18 ), -1, 'Spin 14 (15 Black), bet 18 pays -1';\nis payout( 14, 19 ), -1, 'Spin 14 (15 Black), bet 19 pays -1';\nis payout( 14, 20 ), -1, 'Spin 14 (15 Black), bet 20 pays -1';\nis payout( 14, 21 ), -1, 'Spin 14 (15 Black), bet 21 pays -1';\nis payout( 14, 22 ), -1, 'Spin 14 (15 Black), bet 22 pays -1';\nis payout( 14, 23 ), -1, 'Spin 14 (15 Black), bet 23 pays -1';\nis payout( 14, 24 ), -1, 'Spin 14 (15 Black), bet 24 pays -1';\nis payout( 14, 25 ), -1, 'Spin 14 (15 Black), bet 25 pays -1';\nis payout( 14, 26 ), -1, 'Spin 14 (15 Black), bet 26 pays -1';\nis payout( 14, 27 ), -1, 'Spin 14 (15 Black), bet 27 pays -1';\nis payout( 14, 28 ), -1, 'Spin 14 (15 Black), bet 28 pays -1';\nis payout( 14, 29 ), -1, 'Spin 14 (15 Black), bet 29 pays -1';\nis payout( 14, 30 ), -1, 'Spin 14 (15 Black), bet 30 pays -1';\nis payout( 14, 31 ), -1, 'Spin 14 (15 Black), bet 31 pays -1';\nis payout( 14, 32 ), -1, 'Spin 14 (15 Black), bet 32 pays -1';\nis payout( 14, 33 ), -1, 'Spin 14 (15 Black), bet 33 pays -1';\nis payout( 14, 34 ), -1, 'Spin 14 (15 Black), bet 34 pays -1';\nis payout( 14, 35 ), -1, 'Spin 14 (15 Black), bet 35 pays -1';\nis payout( 14, 36 ), -1, 'Spin 14 (15 Black), bet 36 pays -1';\nis payout( 14, 37 ), -1, 'Spin 14 (15 Black), bet 37 pays -1';\nis payout( 14, 38 ), 2, 'Spin 14 (15 Black), bet 38 pays 2';\nis payout( 14, 39 ), -1, 'Spin 14 (15 Black), bet 39 pays -1';\nis payout( 14, 40 ), -1, 'Spin 14 (15 Black), bet 40 pays -1';\nis payout( 14, 41 ), -1, 'Spin 14 (15 Black), bet 41 pays -1';\nis payout( 14, 42 ), 2, 'Spin 14 (15 Black), bet 42 pays 2';\nis payout( 14, 43 ), 1, 'Spin 14 (15 Black), bet 43 pays 1';\nis payout( 14, 44 ), -1, 'Spin 14 (15 Black), bet 44 pays -1';\nis payout( 14, 45 ), -1, 'Spin 14 (15 Black), bet 45 pays -1';\nis payout( 14, 46 ), 1, 'Spin 14 (15 Black), bet 46 pays 1';\nis payout( 14, 47 ), -1, 'Spin 14 (15 Black), bet 47 pays -1';\nis payout( 14, 48 ), 1, 'Spin 14 (15 Black), bet 48 pays 1';\nis payout( 14, 49 ), -1, 'Spin 14 (15 Black), bet 49 pays -1';\nis payout( 14, 50 ), -1, 'Spin 14 (15 Black), bet 50 pays -1';\nis format_spin( 15 ), '16 Red', 'Spin 15 is 16 Red';\nis payout( 15, 1 ), -1, 'Spin 15 (16 Red), bet 1 pays -1';\nis payout( 15, 2 ), -1, 'Spin 15 (16 Red), bet 2 pays -1';\nis payout( 15, 3 ), -1, 'Spin 15 (16 Red), bet 3 pays -1';\nis payout( 15, 4 ), -1, 'Spin 15 (16 Red), bet 4 pays -1';\nis payout( 15, 5 ), -1, 'Spin 15 (16 Red), bet 5 pays -1';\nis payout( 15, 6 ), -1, 'Spin 15 (16 Red), bet 6 pays -1';\nis payout( 15, 7 ), -1, 'Spin 15 (16 Red), bet 7 pays -1';\nis payout( 15, 8 ), -1, 'Spin 15 (16 Red), bet 8 pays -1';\nis payout( 15, 9 ), -1, 'Spin 15 (16 Red), bet 9 pays -1';\nis payout( 15, 10 ), -1, 'Spin 15 (16 Red), bet 10 pays -1';\nis payout( 15, 11 ), -1, 'Spin 15 (16 Red), bet 11 pays -1';\nis payout( 15, 12 ), -1, 'Spin 15 (16 Red), bet 12 pays -1';\nis payout( 15, 13 ), -1, 'Spin 15 (16 Red), bet 13 pays -1';\nis payout( 15, 14 ), -1, 'Spin 15 (16 Red), bet 14 pays -1';\nis payout( 15, 15 ), -1, 'Spin 15 (16 Red), bet 15 pays -1';\nis payout( 15, 16 ), 35, 'Spin 15 (16 Red), bet 16 pays 35';\nis payout( 15, 17 ), -1, 'Spin 15 (16 Red), bet 17 pays -1';\nis payout( 15, 18 ), -1, 'Spin 15 (16 Red), bet 18 pays -1';\nis payout( 15, 19 ), -1, 'Spin 15 (16 Red), bet 19 pays -1';\nis payout( 15, 20 ), -1, 'Spin 15 (16 Red), bet 20 pays -1';\nis payout( 15, 21 ), -1, 'Spin 15 (16 Red), bet 21 pays -1';\nis payout( 15, 22 ), -1, 'Spin 15 (16 Red), bet 22 pays -1';\nis payout( 15, 23 ), -1, 'Spin 15 (16 Red), bet 23 pays -1';\nis payout( 15, 24 ), -1, 'Spin 15 (16 Red), bet 24 pays -1';\nis payout( 15, 25 ), -1, 'Spin 15 (16 Red), bet 25 pays -1';\nis payout( 15, 26 ), -1, 'Spin 15 (16 Red), bet 26 pays -1';\nis payout( 15, 27 ), -1, 'Spin 15 (16 Red), bet 27 pays -1';\nis payout( 15, 28 ), -1, 'Spin 15 (16 Red), bet 28 pays -1';\nis payout( 15, 29 ), -1, 'Spin 15 (16 Red), bet 29 pays -1';\nis payout( 15, 30 ), -1, 'Spin 15 (16 Red), bet 30 pays -1';\nis payout( 15, 31 ), -1, 'Spin 15 (16 Red), bet 31 pays -1';\nis payout( 15, 32 ), -1, 'Spin 15 (16 Red), bet 32 pays -1';\nis payout( 15, 33 ), -1, 'Spin 15 (16 Red), bet 33 pays -1';\nis payout( 15, 34 ), -1, 'Spin 15 (16 Red), bet 34 pays -1';\nis payout( 15, 35 ), -1, 'Spin 15 (16 Red), bet 35 pays -1';\nis payout( 15, 36 ), -1, 'Spin 15 (16 Red), bet 36 pays -1';\nis payout( 15, 37 ), -1, 'Spin 15 (16 Red), bet 37 pays -1';\nis payout( 15, 38 ), 2, 'Spin 15 (16 Red), bet 38 pays 2';\nis payout( 15, 39 ), -1, 'Spin 15 (16 Red), bet 39 pays -1';\nis payout( 15, 40 ), 2, 'Spin 15 (16 Red), bet 40 pays 2';\nis payout( 15, 41 ), -1, 'Spin 15 (16 Red), bet 41 pays -1';\nis payout( 15, 42 ), -1, 'Spin 15 (16 Red), bet 42 pays -1';\nis payout( 15, 43 ), 1, 'Spin 15 (16 Red), bet 43 pays 1';\nis payout( 15, 44 ), -1, 'Spin 15 (16 Red), bet 44 pays -1';\nis payout( 15, 45 ), 1, 'Spin 15 (16 Red), bet 45 pays 1';\nis payout( 15, 46 ), -1, 'Spin 15 (16 Red), bet 46 pays -1';\nis payout( 15, 47 ), 1, 'Spin 15 (16 Red), bet 47 pays 1';\nis payout( 15, 48 ), -1, 'Spin 15 (16 Red), bet 48 pays -1';\nis payout( 15, 49 ), -1, 'Spin 15 (16 Red), bet 49 pays -1';\nis payout( 15, 50 ), -1, 'Spin 15 (16 Red), bet 50 pays -1';\nis format_spin( 16 ), '17 Black', 'Spin 16 is 17 Black';\nis payout( 16, 1 ), -1, 'Spin 16 (17 Black), bet 1 pays -1';\nis payout( 16, 2 ), -1, 'Spin 16 (17 Black), bet 2 pays -1';\nis payout( 16, 3 ), -1, 'Spin 16 (17 Black), bet 3 pays -1';\nis payout( 16, 4 ), -1, 'Spin 16 (17 Black), bet 4 pays -1';\nis payout( 16, 5 ), -1, 'Spin 16 (17 Black), bet 5 pays -1';\nis payout( 16, 6 ), -1, 'Spin 16 (17 Black), bet 6 pays -1';\nis payout( 16, 7 ), -1, 'Spin 16 (17 Black), bet 7 pays -1';\nis payout( 16, 8 ), -1, 'Spin 16 (17 Black), bet 8 pays -1';\nis payout( 16, 9 ), -1, 'Spin 16 (17 Black), bet 9 pays -1';\nis payout( 16, 10 ), -1, 'Spin 16 (17 Black), bet 10 pays -1';\nis payout( 16, 11 ), -1, 'Spin 16 (17 Black), bet 11 pays -1';\nis payout( 16, 12 ), -1, 'Spin 16 (17 Black), bet 12 pays -1';\nis payout( 16, 13 ), -1, 'Spin 16 (17 Black), bet 13 pays -1';\nis payout( 16, 14 ), -1, 'Spin 16 (17 Black), bet 14 pays -1';\nis payout( 16, 15 ), -1, 'Spin 16 (17 Black), bet 15 pays -1';\nis payout( 16, 16 ), -1, 'Spin 16 (17 Black), bet 16 pays -1';\nis payout( 16, 17 ), 35, 'Spin 16 (17 Black), bet 17 pays 35';\nis payout( 16, 18 ), -1, 'Spin 16 (17 Black), bet 18 pays -1';\nis payout( 16, 19 ), -1, 'Spin 16 (17 Black), bet 19 pays -1';\nis payout( 16, 20 ), -1, 'Spin 16 (17 Black), bet 20 pays -1';\nis payout( 16, 21 ), -1, 'Spin 16 (17 Black), bet 21 pays -1';\nis payout( 16, 22 ), -1, 'Spin 16 (17 Black), bet 22 pays -1';\nis payout( 16, 23 ), -1, 'Spin 16 (17 Black), bet 23 pays -1';\nis payout( 16, 24 ), -1, 'Spin 16 (17 Black), bet 24 pays -1';\nis payout( 16, 25 ), -1, 'Spin 16 (17 Black), bet 25 pays -1';\nis payout( 16, 26 ), -1, 'Spin 16 (17 Black), bet 26 pays -1';\nis payout( 16, 27 ), -1, 'Spin 16 (17 Black), bet 27 pays -1';\nis payout( 16, 28 ), -1, 'Spin 16 (17 Black), bet 28 pays -1';\nis payout( 16, 29 ), -1, 'Spin 16 (17 Black), bet 29 pays -1';\nis payout( 16, 30 ), -1, 'Spin 16 (17 Black), bet 30 pays -1';\nis payout( 16, 31 ), -1, 'Spin 16 (17 Black), bet 31 pays -1';\nis payout( 16, 32 ), -1, 'Spin 16 (17 Black), bet 32 pays -1';\nis payout( 16, 33 ), -1, 'Spin 16 (17 Black), bet 33 pays -1';\nis payout( 16, 34 ), -1, 'Spin 16 (17 Black), bet 34 pays -1';\nis payout( 16, 35 ), -1, 'Spin 16 (17 Black), bet 35 pays -1';\nis payout( 16, 36 ), -1, 'Spin 16 (17 Black), bet 36 pays -1';\nis payout( 16, 37 ), -1, 'Spin 16 (17 Black), bet 37 pays -1';\nis payout( 16, 38 ), 2, 'Spin 16 (17 Black), bet 38 pays 2';\nis payout( 16, 39 ), -1, 'Spin 16 (17 Black), bet 39 pays -1';\nis payout( 16, 40 ), -1, 'Spin 16 (17 Black), bet 40 pays -1';\nis payout( 16, 41 ), 2, 'Spin 16 (17 Black), bet 41 pays 2';\nis payout( 16, 42 ), -1, 'Spin 16 (17 Black), bet 42 pays -1';\nis payout( 16, 43 ), 1, 'Spin 16 (17 Black), bet 43 pays 1';\nis payout( 16, 44 ), -1, 'Spin 16 (17 Black), bet 44 pays -1';\nis payout( 16, 45 ), -1, 'Spin 16 (17 Black), bet 45 pays -1';\nis payout( 16, 46 ), 1, 'Spin 16 (17 Black), bet 46 pays 1';\nis payout( 16, 47 ), -1, 'Spin 16 (17 Black), bet 47 pays -1';\nis payout( 16, 48 ), 1, 'Spin 16 (17 Black), bet 48 pays 1';\nis payout( 16, 49 ), -1, 'Spin 16 (17 Black), bet 49 pays -1';\nis payout( 16, 50 ), -1, 'Spin 16 (17 Black), bet 50 pays -1';\nis format_spin( 17 ), '18 Red', 'Spin 17 is 18 Red';\nis payout( 17, 1 ), -1, 'Spin 17 (18 Red), bet 1 pays -1';\nis payout( 17, 2 ), -1, 'Spin 17 (18 Red), bet 2 pays -1';\nis payout( 17, 3 ), -1, 'Spin 17 (18 Red), bet 3 pays -1';\nis payout( 17, 4 ), -1, 'Spin 17 (18 Red), bet 4 pays -1';\nis payout( 17, 5 ), -1, 'Spin 17 (18 Red), bet 5 pays -1';\nis payout( 17, 6 ), -1, 'Spin 17 (18 Red), bet 6 pays -1';\nis payout( 17, 7 ), -1, 'Spin 17 (18 Red), bet 7 pays -1';\nis payout( 17, 8 ), -1, 'Spin 17 (18 Red), bet 8 pays -1';\nis payout( 17, 9 ), -1, 'Spin 17 (18 Red), bet 9 pays -1';\nis payout( 17, 10 ), -1, 'Spin 17 (18 Red), bet 10 pays -1';\nis payout( 17, 11 ), -1, 'Spin 17 (18 Red), bet 11 pays -1';\nis payout( 17, 12 ), -1, 'Spin 17 (18 Red), bet 12 pays -1';\nis payout( 17, 13 ), -1, 'Spin 17 (18 Red), bet 13 pays -1';\nis payout( 17, 14 ), -1, 'Spin 17 (18 Red), bet 14 pays -1';\nis payout( 17, 15 ), -1, 'Spin 17 (18 Red), bet 15 pays -1';\nis payout( 17, 16 ), -1, 'Spin 17 (18 Red), bet 16 pays -1';\nis payout( 17, 17 ), -1, 'Spin 17 (18 Red), bet 17 pays -1';\nis payout( 17, 18 ), 35, 'Spin 17 (18 Red), bet 18 pays 35';\nis payout( 17, 19 ), -1, 'Spin 17 (18 Red), bet 19 pays -1';\nis payout( 17, 20 ), -1, 'Spin 17 (18 Red), bet 20 pays -1';\nis payout( 17, 21 ), -1, 'Spin 17 (18 Red), bet 21 pays -1';\nis payout( 17, 22 ), -1, 'Spin 17 (18 Red), bet 22 pays -1';\nis payout( 17, 23 ), -1, 'Spin 17 (18 Red), bet 23 pays -1';\nis payout( 17, 24 ), -1, 'Spin 17 (18 Red), bet 24 pays -1';\nis payout( 17, 25 ), -1, 'Spin 17 (18 Red), bet 25 pays -1';\nis payout( 17, 26 ), -1, 'Spin 17 (18 Red), bet 26 pays -1';\nis payout( 17, 27 ), -1, 'Spin 17 (18 Red), bet 27 pays -1';\nis payout( 17, 28 ), -1, 'Spin 17 (18 Red), bet 28 pays -1';\nis payout( 17, 29 ), -1, 'Spin 17 (18 Red), bet 29 pays -1';\nis payout( 17, 30 ), -1, 'Spin 17 (18 Red), bet 30 pays -1';\nis payout( 17, 31 ), -1, 'Spin 17 (18 Red), bet 31 pays -1';\nis payout( 17, 32 ), -1, 'Spin 17 (18 Red), bet 32 pays -1';\nis payout( 17, 33 ), -1, 'Spin 17 (18 Red), bet 33 pays -1';\nis payout( 17, 34 ), -1, 'Spin 17 (18 Red), bet 34 pays -1';\nis payout( 17, 35 ), -1, 'Spin 17 (18 Red), bet 35 pays -1';\nis payout( 17, 36 ), -1, 'Spin 17 (18 Red), bet 36 pays -1';\nis payout( 17, 37 ), -1, 'Spin 17 (18 Red), bet 37 pays -1';\nis payout( 17, 38 ), 2, 'Spin 17 (18 Red), bet 38 pays 2';\nis payout( 17, 39 ), -1, 'Spin 17 (18 Red), bet 39 pays -1';\nis payout( 17, 40 ), -1, 'Spin 17 (18 Red), bet 40 pays -1';\nis payout( 17, 41 ), -1, 'Spin 17 (18 Red), bet 41 pays -1';\nis payout( 17, 42 ), 2, 'Spin 17 (18 Red), bet 42 pays 2';\nis payout( 17, 43 ), 1, 'Spin 17 (18 Red), bet 43 pays 1';\nis payout( 17, 44 ), -1, 'Spin 17 (18 Red), bet 44 pays -1';\nis payout( 17, 45 ), 1, 'Spin 17 (18 Red), bet 45 pays 1';\nis payout( 17, 46 ), -1, 'Spin 17 (18 Red), bet 46 pays -1';\nis payout( 17, 47 ), 1, 'Spin 17 (18 Red), bet 47 pays 1';\nis payout( 17, 48 ), -1, 'Spin 17 (18 Red), bet 48 pays -1';\nis payout( 17, 49 ), -1, 'Spin 17 (18 Red), bet 49 pays -1';\nis payout( 17, 50 ), -1, 'Spin 17 (18 Red), bet 50 pays -1';\nis format_spin( 18 ), '19 Red', 'Spin 18 is 19 Red';\nis payout( 18, 1 ), -1, 'Spin 18 (19 Red), bet 1 pays -1';\nis payout( 18, 2 ), -1, 'Spin 18 (19 Red), bet 2 pays -1';\nis payout( 18, 3 ), -1, 'Spin 18 (19 Red), bet 3 pays -1';\nis payout( 18, 4 ), -1, 'Spin 18 (19 Red), bet 4 pays -1';\nis payout( 18, 5 ), -1, 'Spin 18 (19 Red), bet 5 pays -1';\nis payout( 18, 6 ), -1, 'Spin 18 (19 Red), bet 6 pays -1';\nis payout( 18, 7 ), -1, 'Spin 18 (19 Red), bet 7 pays -1';\nis payout( 18, 8 ), -1, 'Spin 18 (19 Red), bet 8 pays -1';\nis payout( 18, 9 ), -1, 'Spin 18 (19 Red), bet 9 pays -1';\nis payout( 18, 10 ), -1, 'Spin 18 (19 Red), bet 10 pays -1';\nis payout( 18, 11 ), -1, 'Spin 18 (19 Red), bet 11 pays -1';\nis payout( 18, 12 ), -1, 'Spin 18 (19 Red), bet 12 pays -1';\nis payout( 18, 13 ), -1, 'Spin 18 (19 Red), bet 13 pays -1';\nis payout( 18, 14 ), -1, 'Spin 18 (19 Red), bet 14 pays -1';\nis payout( 18, 15 ), -1, 'Spin 18 (19 Red), bet 15 pays -1';\nis payout( 18, 16 ), -1, 'Spin 18 (19 Red), bet 16 pays -1';\nis payout( 18, 17 ), -1, 'Spin 18 (19 Red), bet 17 pays -1';\nis payout( 18, 18 ), -1, 'Spin 18 (19 Red), bet 18 pays -1';\nis payout( 18, 19 ), 35, 'Spin 18 (19 Red), bet 19 pays 35';\nis payout( 18, 20 ), -1, 'Spin 18 (19 Red), bet 20 pays -1';\nis payout( 18, 21 ), -1, 'Spin 18 (19 Red), bet 21 pays -1';\nis payout( 18, 22 ), -1, 'Spin 18 (19 Red), bet 22 pays -1';\nis payout( 18, 23 ), -1, 'Spin 18 (19 Red), bet 23 pays -1';\nis payout( 18, 24 ), -1, 'Spin 18 (19 Red), bet 24 pays -1';\nis payout( 18, 25 ), -1, 'Spin 18 (19 Red), bet 25 pays -1';\nis payout( 18, 26 ), -1, 'Spin 18 (19 Red), bet 26 pays -1';\nis payout( 18, 27 ), -1, 'Spin 18 (19 Red), bet 27 pays -1';\nis payout( 18, 28 ), -1, 'Spin 18 (19 Red), bet 28 pays -1';\nis payout( 18, 29 ), -1, 'Spin 18 (19 Red), bet 29 pays -1';\nis payout( 18, 30 ), -1, 'Spin 18 (19 Red), bet 30 pays -1';\nis payout( 18, 31 ), -1, 'Spin 18 (19 Red), bet 31 pays -1';\nis payout( 18, 32 ), -1, 'Spin 18 (19 Red), bet 32 pays -1';\nis payout( 18, 33 ), -1, 'Spin 18 (19 Red), bet 33 pays -1';\nis payout( 18, 34 ), -1, 'Spin 18 (19 Red), bet 34 pays -1';\nis payout( 18, 35 ), -1, 'Spin 18 (19 Red), bet 35 pays -1';\nis payout( 18, 36 ), -1, 'Spin 18 (19 Red), bet 36 pays -1';\nis payout( 18, 37 ), -1, 'Spin 18 (19 Red), bet 37 pays -1';\nis payout( 18, 38 ), 2, 'Spin 18 (19 Red), bet 38 pays 2';\nis payout( 18, 39 ), -1, 'Spin 18 (19 Red), bet 39 pays -1';\nis payout( 18, 40 ), 2, 'Spin 18 (19 Red), bet 40 pays 2';\nis payout( 18, 41 ), -1, 'Spin 18 (19 Red), bet 41 pays -1';\nis payout( 18, 42 ), -1, 'Spin 18 (19 Red), bet 42 pays -1';\nis payout( 18, 43 ), -1, 'Spin 18 (19 Red), bet 43 pays -1';\nis payout( 18, 44 ), 1, 'Spin 18 (19 Red), bet 44 pays 1';\nis payout( 18, 45 ), -1, 'Spin 18 (19 Red), bet 45 pays -1';\nis payout( 18, 46 ), 1, 'Spin 18 (19 Red), bet 46 pays 1';\nis payout( 18, 47 ), 1, 'Spin 18 (19 Red), bet 47 pays 1';\nis payout( 18, 48 ), -1, 'Spin 18 (19 Red), bet 48 pays -1';\nis payout( 18, 49 ), -1, 'Spin 18 (19 Red), bet 49 pays -1';\nis payout( 18, 50 ), -1, 'Spin 18 (19 Red), bet 50 pays -1';\nis format_spin( 19 ), '20 Black', 'Spin 19 is 20 Black';\nis payout( 19, 1 ), -1, 'Spin 19 (20 Black), bet 1 pays -1';\nis payout( 19, 2 ), -1, 'Spin 19 (20 Black), bet 2 pays -1';\nis payout( 19, 3 ), -1, 'Spin 19 (20 Black), bet 3 pays -1';\nis payout( 19, 4 ), -1, 'Spin 19 (20 Black), bet 4 pays -1';\nis payout( 19, 5 ), -1, 'Spin 19 (20 Black), bet 5 pays -1';\nis payout( 19, 6 ), -1, 'Spin 19 (20 Black), bet 6 pays -1';\nis payout( 19, 7 ), -1, 'Spin 19 (20 Black), bet 7 pays -1';\nis payout( 19, 8 ), -1, 'Spin 19 (20 Black), bet 8 pays -1';\nis payout( 19, 9 ), -1, 'Spin 19 (20 Black), bet 9 pays -1';\nis payout( 19, 10 ), -1, 'Spin 19 (20 Black), bet 10 pays -1';\nis payout( 19, 11 ), -1, 'Spin 19 (20 Black), bet 11 pays -1';\nis payout( 19, 12 ), -1, 'Spin 19 (20 Black), bet 12 pays -1';\nis payout( 19, 13 ), -1, 'Spin 19 (20 Black), bet 13 pays -1';\nis payout( 19, 14 ), -1, 'Spin 19 (20 Black), bet 14 pays -1';\nis payout( 19, 15 ), -1, 'Spin 19 (20 Black), bet 15 pays -1';\nis payout( 19, 16 ), -1, 'Spin 19 (20 Black), bet 16 pays -1';\nis payout( 19, 17 ), -1, 'Spin 19 (20 Black), bet 17 pays -1';\nis payout( 19, 18 ), -1, 'Spin 19 (20 Black), bet 18 pays -1';\nis payout( 19, 19 ), -1, 'Spin 19 (20 Black), bet 19 pays -1';\nis payout( 19, 20 ), 35, 'Spin 19 (20 Black), bet 20 pays 35';\nis payout( 19, 21 ), -1, 'Spin 19 (20 Black), bet 21 pays -1';\nis payout( 19, 22 ), -1, 'Spin 19 (20 Black), bet 22 pays -1';\nis payout( 19, 23 ), -1, 'Spin 19 (20 Black), bet 23 pays -1';\nis payout( 19, 24 ), -1, 'Spin 19 (20 Black), bet 24 pays -1';\nis payout( 19, 25 ), -1, 'Spin 19 (20 Black), bet 25 pays -1';\nis payout( 19, 26 ), -1, 'Spin 19 (20 Black), bet 26 pays -1';\nis payout( 19, 27 ), -1, 'Spin 19 (20 Black), bet 27 pays -1';\nis payout( 19, 28 ), -1, 'Spin 19 (20 Black), bet 28 pays -1';\nis payout( 19, 29 ), -1, 'Spin 19 (20 Black), bet 29 pays -1';\nis payout( 19, 30 ), -1, 'Spin 19 (20 Black), bet 30 pays -1';\nis payout( 19, 31 ), -1, 'Spin 19 (20 Black), bet 31 pays -1';\nis payout( 19, 32 ), -1, 'Spin 19 (20 Black), bet 32 pays -1';\nis payout( 19, 33 ), -1, 'Spin 19 (20 Black), bet 33 pays -1';\nis payout( 19, 34 ), -1, 'Spin 19 (20 Black), bet 34 pays -1';\nis payout( 19, 35 ), -1, 'Spin 19 (20 Black), bet 35 pays -1';\nis payout( 19, 36 ), -1, 'Spin 19 (20 Black), bet 36 pays -1';\nis payout( 19, 37 ), -1, 'Spin 19 (20 Black), bet 37 pays -1';\nis payout( 19, 38 ), 2, 'Spin 19 (20 Black), bet 38 pays 2';\nis payout( 19, 39 ), -1, 'Spin 19 (20 Black), bet 39 pays -1';\nis payout( 19, 40 ), -1, 'Spin 19 (20 Black), bet 40 pays -1';\nis payout( 19, 41 ), 2, 'Spin 19 (20 Black), bet 41 pays 2';\nis payout( 19, 42 ), -1, 'Spin 19 (20 Black), bet 42 pays -1';\nis payout( 19, 43 ), -1, 'Spin 19 (20 Black), bet 43 pays -1';\nis payout( 19, 44 ), 1, 'Spin 19 (20 Black), bet 44 pays 1';\nis payout( 19, 45 ), 1, 'Spin 19 (20 Black), bet 45 pays 1';\nis payout( 19, 46 ), -1, 'Spin 19 (20 Black), bet 46 pays -1';\nis payout( 19, 47 ), -1, 'Spin 19 (20 Black), bet 47 pays -1';\nis payout( 19, 48 ), 1, 'Spin 19 (20 Black), bet 48 pays 1';\nis payout( 19, 49 ), -1, 'Spin 19 (20 Black), bet 49 pays -1';\nis payout( 19, 50 ), -1, 'Spin 19 (20 Black), bet 50 pays -1';\nis format_spin( 20 ), '21 Red', 'Spin 20 is 21 Red';\nis payout( 20, 1 ), -1, 'Spin 20 (21 Red), bet 1 pays -1';\nis payout( 20, 2 ), -1, 'Spin 20 (21 Red), bet 2 pays -1';\nis payout( 20, 3 ), -1, 'Spin 20 (21 Red), bet 3 pays -1';\nis payout( 20, 4 ), -1, 'Spin 20 (21 Red), bet 4 pays -1';\nis payout( 20, 5 ), -1, 'Spin 20 (21 Red), bet 5 pays -1';\nis payout( 20, 6 ), -1, 'Spin 20 (21 Red), bet 6 pays -1';\nis payout( 20, 7 ), -1, 'Spin 20 (21 Red), bet 7 pays -1';\nis payout( 20, 8 ), -1, 'Spin 20 (21 Red), bet 8 pays -1';\nis payout( 20, 9 ), -1, 'Spin 20 (21 Red), bet 9 pays -1';\nis payout( 20, 10 ), -1, 'Spin 20 (21 Red), bet 10 pays -1';\nis payout( 20, 11 ), -1, 'Spin 20 (21 Red), bet 11 pays -1';\nis payout( 20, 12 ), -1, 'Spin 20 (21 Red), bet 12 pays -1';\nis payout( 20, 13 ), -1, 'Spin 20 (21 Red), bet 13 pays -1';\nis payout( 20, 14 ), -1, 'Spin 20 (21 Red), bet 14 pays -1';\nis payout( 20, 15 ), -1, 'Spin 20 (21 Red), bet 15 pays -1';\nis payout( 20, 16 ), -1, 'Spin 20 (21 Red), bet 16 pays -1';\nis payout( 20, 17 ), -1, 'Spin 20 (21 Red), bet 17 pays -1';\nis payout( 20, 18 ), -1, 'Spin 20 (21 Red), bet 18 pays -1';\nis payout( 20, 19 ), -1, 'Spin 20 (21 Red), bet 19 pays -1';\nis payout( 20, 20 ), -1, 'Spin 20 (21 Red), bet 20 pays -1';\nis payout( 20, 21 ), 35, 'Spin 20 (21 Red), bet 21 pays 35';\nis payout( 20, 22 ), -1, 'Spin 20 (21 Red), bet 22 pays -1';\nis payout( 20, 23 ), -1, 'Spin 20 (21 Red), bet 23 pays -1';\nis payout( 20, 24 ), -1, 'Spin 20 (21 Red), bet 24 pays -1';\nis payout( 20, 25 ), -1, 'Spin 20 (21 Red), bet 25 pays -1';\nis payout( 20, 26 ), -1, 'Spin 20 (21 Red), bet 26 pays -1';\nis payout( 20, 27 ), -1, 'Spin 20 (21 Red), bet 27 pays -1';\nis payout( 20, 28 ), -1, 'Spin 20 (21 Red), bet 28 pays -1';\nis payout( 20, 29 ), -1, 'Spin 20 (21 Red), bet 29 pays -1';\nis payout( 20, 30 ), -1, 'Spin 20 (21 Red), bet 30 pays -1';\nis payout( 20, 31 ), -1, 'Spin 20 (21 Red), bet 31 pays -1';\nis payout( 20, 32 ), -1, 'Spin 20 (21 Red), bet 32 pays -1';\nis payout( 20, 33 ), -1, 'Spin 20 (21 Red), bet 33 pays -1';\nis payout( 20, 34 ), -1, 'Spin 20 (21 Red), bet 34 pays -1';\nis payout( 20, 35 ), -1, 'Spin 20 (21 Red), bet 35 pays -1';\nis payout( 20, 36 ), -1, 'Spin 20 (21 Red), bet 36 pays -1';\nis payout( 20, 37 ), -1, 'Spin 20 (21 Red), bet 37 pays -1';\nis payout( 20, 38 ), 2, 'Spin 20 (21 Red), bet 38 pays 2';\nis payout( 20, 39 ), -1, 'Spin 20 (21 Red), bet 39 pays -1';\nis payout( 20, 40 ), -1, 'Spin 20 (21 Red), bet 40 pays -1';\nis payout( 20, 41 ), -1, 'Spin 20 (21 Red), bet 41 pays -1';\nis payout( 20, 42 ), 2, 'Spin 20 (21 Red), bet 42 pays 2';\nis payout( 20, 43 ), -1, 'Spin 20 (21 Red), bet 43 pays -1';\nis payout( 20, 44 ), 1, 'Spin 20 (21 Red), bet 44 pays 1';\nis payout( 20, 45 ), -1, 'Spin 20 (21 Red), bet 45 pays -1';\nis payout( 20, 46 ), 1, 'Spin 20 (21 Red), bet 46 pays 1';\nis payout( 20, 47 ), 1, 'Spin 20 (21 Red), bet 47 pays 1';\nis payout( 20, 48 ), -1, 'Spin 20 (21 Red), bet 48 pays -1';\nis payout( 20, 49 ), -1, 'Spin 20 (21 Red), bet 49 pays -1';\nis payout( 20, 50 ), -1, 'Spin 20 (21 Red), bet 50 pays -1';\nis format_spin( 21 ), '22 Black', 'Spin 21 is 22 Black';\nis payout( 21, 1 ), -1, 'Spin 21 (22 Black), bet 1 pays -1';\nis payout( 21, 2 ), -1, 'Spin 21 (22 Black), bet 2 pays -1';\nis payout( 21, 3 ), -1, 'Spin 21 (22 Black), bet 3 pays -1';\nis payout( 21, 4 ), -1, 'Spin 21 (22 Black), bet 4 pays -1';\nis payout( 21, 5 ), -1, 'Spin 21 (22 Black), bet 5 pays -1';\nis payout( 21, 6 ), -1, 'Spin 21 (22 Black), bet 6 pays -1';\nis payout( 21, 7 ), -1, 'Spin 21 (22 Black), bet 7 pays -1';\nis payout( 21, 8 ), -1, 'Spin 21 (22 Black), bet 8 pays -1';\nis payout( 21, 9 ), -1, 'Spin 21 (22 Black), bet 9 pays -1';\nis payout( 21, 10 ), -1, 'Spin 21 (22 Black), bet 10 pays -1';\nis payout( 21, 11 ), -1, 'Spin 21 (22 Black), bet 11 pays -1';\nis payout( 21, 12 ), -1, 'Spin 21 (22 Black), bet 12 pays -1';\nis payout( 21, 13 ), -1, 'Spin 21 (22 Black), bet 13 pays -1';\nis payout( 21, 14 ), -1, 'Spin 21 (22 Black), bet 14 pays -1';\nis payout( 21, 15 ), -1, 'Spin 21 (22 Black), bet 15 pays -1';\nis payout( 21, 16 ), -1, 'Spin 21 (22 Black), bet 16 pays -1';\nis payout( 21, 17 ), -1, 'Spin 21 (22 Black), bet 17 pays -1';\nis payout( 21, 18 ), -1, 'Spin 21 (22 Black), bet 18 pays -1';\nis payout( 21, 19 ), -1, 'Spin 21 (22 Black), bet 19 pays -1';\nis payout( 21, 20 ), -1, 'Spin 21 (22 Black), bet 20 pays -1';\nis payout( 21, 21 ), -1, 'Spin 21 (22 Black), bet 21 pays -1';\nis payout( 21, 22 ), 35, 'Spin 21 (22 Black), bet 22 pays 35';\nis payout( 21, 23 ), -1, 'Spin 21 (22 Black), bet 23 pays -1';\nis payout( 21, 24 ), -1, 'Spin 21 (22 Black), bet 24 pays -1';\nis payout( 21, 25 ), -1, 'Spin 21 (22 Black), bet 25 pays -1';\nis payout( 21, 26 ), -1, 'Spin 21 (22 Black), bet 26 pays -1';\nis payout( 21, 27 ), -1, 'Spin 21 (22 Black), bet 27 pays -1';\nis payout( 21, 28 ), -1, 'Spin 21 (22 Black), bet 28 pays -1';\nis payout( 21, 29 ), -1, 'Spin 21 (22 Black), bet 29 pays -1';\nis payout( 21, 30 ), -1, 'Spin 21 (22 Black), bet 30 pays -1';\nis payout( 21, 31 ), -1, 'Spin 21 (22 Black), bet 31 pays -1';\nis payout( 21, 32 ), -1, 'Spin 21 (22 Black), bet 32 pays -1';\nis payout( 21, 33 ), -1, 'Spin 21 (22 Black), bet 33 pays -1';\nis payout( 21, 34 ), -1, 'Spin 21 (22 Black), bet 34 pays -1';\nis payout( 21, 35 ), -1, 'Spin 21 (22 Black), bet 35 pays -1';\nis payout( 21, 36 ), -1, 'Spin 21 (22 Black), bet 36 pays -1';\nis payout( 21, 37 ), -1, 'Spin 21 (22 Black), bet 37 pays -1';\nis payout( 21, 38 ), 2, 'Spin 21 (22 Black), bet 38 pays 2';\nis payout( 21, 39 ), -1, 'Spin 21 (22 Black), bet 39 pays -1';\nis payout( 21, 40 ), 2, 'Spin 21 (22 Black), bet 40 pays 2';\nis payout( 21, 41 ), -1, 'Spin 21 (22 Black), bet 41 pays -1';\nis payout( 21, 42 ), -1, 'Spin 21 (22 Black), bet 42 pays -1';\nis payout( 21, 43 ), -1, 'Spin 21 (22 Black), bet 43 pays -1';\nis payout( 21, 44 ), 1, 'Spin 21 (22 Black), bet 44 pays 1';\nis payout( 21, 45 ), 1, 'Spin 21 (22 Black), bet 45 pays 1';\nis payout( 21, 46 ), -1, 'Spin 21 (22 Black), bet 46 pays -1';\nis payout( 21, 47 ), -1, 'Spin 21 (22 Black), bet 47 pays -1';\nis payout( 21, 48 ), 1, 'Spin 21 (22 Black), bet 48 pays 1';\nis payout( 21, 49 ), -1, 'Spin 21 (22 Black), bet 49 pays -1';\nis payout( 21, 50 ), -1, 'Spin 21 (22 Black), bet 50 pays -1';\nis format_spin( 22 ), '23 Red', 'Spin 22 is 23 Red';\nis payout( 22, 1 ), -1, 'Spin 22 (23 Red), bet 1 pays -1';\nis payout( 22, 2 ), -1, 'Spin 22 (23 Red), bet 2 pays -1';\nis payout( 22, 3 ), -1, 'Spin 22 (23 Red), bet 3 pays -1';\nis payout( 22, 4 ), -1, 'Spin 22 (23 Red), bet 4 pays -1';\nis payout( 22, 5 ), -1, 'Spin 22 (23 Red), bet 5 pays -1';\nis payout( 22, 6 ), -1, 'Spin 22 (23 Red), bet 6 pays -1';\nis payout( 22, 7 ), -1, 'Spin 22 (23 Red), bet 7 pays -1';\nis payout( 22, 8 ), -1, 'Spin 22 (23 Red), bet 8 pays -1';\nis payout( 22, 9 ), -1, 'Spin 22 (23 Red), bet 9 pays -1';\nis payout( 22, 10 ), -1, 'Spin 22 (23 Red), bet 10 pays -1';\nis payout( 22, 11 ), -1, 'Spin 22 (23 Red), bet 11 pays -1';\nis payout( 22, 12 ), -1, 'Spin 22 (23 Red), bet 12 pays -1';\nis payout( 22, 13 ), -1, 'Spin 22 (23 Red), bet 13 pays -1';\nis payout( 22, 14 ), -1, 'Spin 22 (23 Red), bet 14 pays -1';\nis payout( 22, 15 ), -1, 'Spin 22 (23 Red), bet 15 pays -1';\nis payout( 22, 16 ), -1, 'Spin 22 (23 Red), bet 16 pays -1';\nis payout( 22, 17 ), -1, 'Spin 22 (23 Red), bet 17 pays -1';\nis payout( 22, 18 ), -1, 'Spin 22 (23 Red), bet 18 pays -1';\nis payout( 22, 19 ), -1, 'Spin 22 (23 Red), bet 19 pays -1';\nis payout( 22, 20 ), -1, 'Spin 22 (23 Red), bet 20 pays -1';\nis payout( 22, 21 ), -1, 'Spin 22 (23 Red), bet 21 pays -1';\nis payout( 22, 22 ), -1, 'Spin 22 (23 Red), bet 22 pays -1';\nis payout( 22, 23 ), 35, 'Spin 22 (23 Red), bet 23 pays 35';\nis payout( 22, 24 ), -1, 'Spin 22 (23 Red), bet 24 pays -1';\nis payout( 22, 25 ), -1, 'Spin 22 (23 Red), bet 25 pays -1';\nis payout( 22, 26 ), -1, 'Spin 22 (23 Red), bet 26 pays -1';\nis payout( 22, 27 ), -1, 'Spin 22 (23 Red), bet 27 pays -1';\nis payout( 22, 28 ), -1, 'Spin 22 (23 Red), bet 28 pays -1';\nis payout( 22, 29 ), -1, 'Spin 22 (23 Red), bet 29 pays -1';\nis payout( 22, 30 ), -1, 'Spin 22 (23 Red), bet 30 pays -1';\nis payout( 22, 31 ), -1, 'Spin 22 (23 Red), bet 31 pays -1';\nis payout( 22, 32 ), -1, 'Spin 22 (23 Red), bet 32 pays -1';\nis payout( 22, 33 ), -1, 'Spin 22 (23 Red), bet 33 pays -1';\nis payout( 22, 34 ), -1, 'Spin 22 (23 Red), bet 34 pays -1';\nis payout( 22, 35 ), -1, 'Spin 22 (23 Red), bet 35 pays -1';\nis payout( 22, 36 ), -1, 'Spin 22 (23 Red), bet 36 pays -1';\nis payout( 22, 37 ), -1, 'Spin 22 (23 Red), bet 37 pays -1';\nis payout( 22, 38 ), 2, 'Spin 22 (23 Red), bet 38 pays 2';\nis payout( 22, 39 ), -1, 'Spin 22 (23 Red), bet 39 pays -1';\nis payout( 22, 40 ), -1, 'Spin 22 (23 Red), bet 40 pays -1';\nis payout( 22, 41 ), 2, 'Spin 22 (23 Red), bet 41 pays 2';\nis payout( 22, 42 ), -1, 'Spin 22 (23 Red), bet 42 pays -1';\nis payout( 22, 43 ), -1, 'Spin 22 (23 Red), bet 43 pays -1';\nis payout( 22, 44 ), 1, 'Spin 22 (23 Red), bet 44 pays 1';\nis payout( 22, 45 ), -1, 'Spin 22 (23 Red), bet 45 pays -1';\nis payout( 22, 46 ), 1, 'Spin 22 (23 Red), bet 46 pays 1';\nis payout( 22, 47 ), 1, 'Spin 22 (23 Red), bet 47 pays 1';\nis payout( 22, 48 ), -1, 'Spin 22 (23 Red), bet 48 pays -1';\nis payout( 22, 49 ), -1, 'Spin 22 (23 Red), bet 49 pays -1';\nis payout( 22, 50 ), -1, 'Spin 22 (23 Red), bet 50 pays -1';\nis format_spin( 23 ), '24 Black', 'Spin 23 is 24 Black';\nis payout( 23, 1 ), -1, 'Spin 23 (24 Black), bet 1 pays -1';\nis payout( 23, 2 ), -1, 'Spin 23 (24 Black), bet 2 pays -1';\nis payout( 23, 3 ), -1, 'Spin 23 (24 Black), bet 3 pays -1';\nis payout( 23, 4 ), -1, 'Spin 23 (24 Black), bet 4 pays -1';\nis payout( 23, 5 ), -1, 'Spin 23 (24 Black), bet 5 pays -1';\nis payout( 23, 6 ), -1, 'Spin 23 (24 Black), bet 6 pays -1';\nis payout( 23, 7 ), -1, 'Spin 23 (24 Black), bet 7 pays -1';\nis payout( 23, 8 ), -1, 'Spin 23 (24 Black), bet 8 pays -1';\nis payout( 23, 9 ), -1, 'Spin 23 (24 Black), bet 9 pays -1';\nis payout( 23, 10 ), -1, 'Spin 23 (24 Black), bet 10 pays -1';\nis payout( 23, 11 ), -1, 'Spin 23 (24 Black), bet 11 pays -1';\nis payout( 23, 12 ), -1, 'Spin 23 (24 Black), bet 12 pays -1';\nis payout( 23, 13 ), -1, 'Spin 23 (24 Black), bet 13 pays -1';\nis payout( 23, 14 ), -1, 'Spin 23 (24 Black), bet 14 pays -1';\nis payout( 23, 15 ), -1, 'Spin 23 (24 Black), bet 15 pays -1';\nis payout( 23, 16 ), -1, 'Spin 23 (24 Black), bet 16 pays -1';\nis payout( 23, 17 ), -1, 'Spin 23 (24 Black), bet 17 pays -1';\nis payout( 23, 18 ), -1, 'Spin 23 (24 Black), bet 18 pays -1';\nis payout( 23, 19 ), -1, 'Spin 23 (24 Black), bet 19 pays -1';\nis payout( 23, 20 ), -1, 'Spin 23 (24 Black), bet 20 pays -1';\nis payout( 23, 21 ), -1, 'Spin 23 (24 Black), bet 21 pays -1';\nis payout( 23, 22 ), -1, 'Spin 23 (24 Black), bet 22 pays -1';\nis payout( 23, 23 ), -1, 'Spin 23 (24 Black), bet 23 pays -1';\nis payout( 23, 24 ), 35, 'Spin 23 (24 Black), bet 24 pays 35';\nis payout( 23, 25 ), -1, 'Spin 23 (24 Black), bet 25 pays -1';\nis payout( 23, 26 ), -1, 'Spin 23 (24 Black), bet 26 pays -1';\nis payout( 23, 27 ), -1, 'Spin 23 (24 Black), bet 27 pays -1';\nis payout( 23, 28 ), -1, 'Spin 23 (24 Black), bet 28 pays -1';\nis payout( 23, 29 ), -1, 'Spin 23 (24 Black), bet 29 pays -1';\nis payout( 23, 30 ), -1, 'Spin 23 (24 Black), bet 30 pays -1';\nis payout( 23, 31 ), -1, 'Spin 23 (24 Black), bet 31 pays -1';\nis payout( 23, 32 ), -1, 'Spin 23 (24 Black), bet 32 pays -1';\nis payout( 23, 33 ), -1, 'Spin 23 (24 Black), bet 33 pays -1';\nis payout( 23, 34 ), -1, 'Spin 23 (24 Black), bet 34 pays -1';\nis payout( 23, 35 ), -1, 'Spin 23 (24 Black), bet 35 pays -1';\nis payout( 23, 36 ), -1, 'Spin 23 (24 Black), bet 36 pays -1';\nis payout( 23, 37 ), -1, 'Spin 23 (24 Black), bet 37 pays -1';\nis payout( 23, 38 ), 2, 'Spin 23 (24 Black), bet 38 pays 2';\nis payout( 23, 39 ), -1, 'Spin 23 (24 Black), bet 39 pays -1';\nis payout( 23, 40 ), -1, 'Spin 23 (24 Black), bet 40 pays -1';\nis payout( 23, 41 ), -1, 'Spin 23 (24 Black), bet 41 pays -1';\nis payout( 23, 42 ), 2, 'Spin 23 (24 Black), bet 42 pays 2';\nis payout( 23, 43 ), -1, 'Spin 23 (24 Black), bet 43 pays -1';\nis payout( 23, 44 ), 1, 'Spin 23 (24 Black), bet 44 pays 1';\nis payout( 23, 45 ), 1, 'Spin 23 (24 Black), bet 45 pays 1';\nis payout( 23, 46 ), -1, 'Spin 23 (24 Black), bet 46 pays -1';\nis payout( 23, 47 ), -1, 'Spin 23 (24 Black), bet 47 pays -1';\nis payout( 23, 48 ), 1, 'Spin 23 (24 Black), bet 48 pays 1';\nis payout( 23, 49 ), -1, 'Spin 23 (24 Black), bet 49 pays -1';\nis payout( 23, 50 ), -1, 'Spin 23 (24 Black), bet 50 pays -1';\nis format_spin( 24 ), '25 Red', 'Spin 24 is 25 Red';\nis payout( 24, 1 ), -1, 'Spin 24 (25 Red), bet 1 pays -1';\nis payout( 24, 2 ), -1, 'Spin 24 (25 Red), bet 2 pays -1';\nis payout( 24, 3 ), -1, 'Spin 24 (25 Red), bet 3 pays -1';\nis payout( 24, 4 ), -1, 'Spin 24 (25 Red), bet 4 pays -1';\nis payout( 24, 5 ), -1, 'Spin 24 (25 Red), bet 5 pays -1';\nis payout( 24, 6 ), -1, 'Spin 24 (25 Red), bet 6 pays -1';\nis payout( 24, 7 ), -1, 'Spin 24 (25 Red), bet 7 pays -1';\nis payout( 24, 8 ), -1, 'Spin 24 (25 Red), bet 8 pays -1';\nis payout( 24, 9 ), -1, 'Spin 24 (25 Red), bet 9 pays -1';\nis payout( 24, 10 ), -1, 'Spin 24 (25 Red), bet 10 pays -1';\nis payout( 24, 11 ), -1, 'Spin 24 (25 Red), bet 11 pays -1';\nis payout( 24, 12 ), -1, 'Spin 24 (25 Red), bet 12 pays -1';\nis payout( 24, 13 ), -1, 'Spin 24 (25 Red), bet 13 pays -1';\nis payout( 24, 14 ), -1, 'Spin 24 (25 Red), bet 14 pays -1';\nis payout( 24, 15 ), -1, 'Spin 24 (25 Red), bet 15 pays -1';\nis payout( 24, 16 ), -1, 'Spin 24 (25 Red), bet 16 pays -1';\nis payout( 24, 17 ), -1, 'Spin 24 (25 Red), bet 17 pays -1';\nis payout( 24, 18 ), -1, 'Spin 24 (25 Red), bet 18 pays -1';\nis payout( 24, 19 ), -1, 'Spin 24 (25 Red), bet 19 pays -1';\nis payout( 24, 20 ), -1, 'Spin 24 (25 Red), bet 20 pays -1';\nis payout( 24, 21 ), -1, 'Spin 24 (25 Red), bet 21 pays -1';\nis payout( 24, 22 ), -1, 'Spin 24 (25 Red), bet 22 pays -1';\nis payout( 24, 23 ), -1, 'Spin 24 (25 Red), bet 23 pays -1';\nis payout( 24, 24 ), -1, 'Spin 24 (25 Red), bet 24 pays -1';\nis payout( 24, 25 ), 35, 'Spin 24 (25 Red), bet 25 pays 35';\nis payout( 24, 26 ), -1, 'Spin 24 (25 Red), bet 26 pays -1';\nis payout( 24, 27 ), -1, 'Spin 24 (25 Red), bet 27 pays -1';\nis payout( 24, 28 ), -1, 'Spin 24 (25 Red), bet 28 pays -1';\nis payout( 24, 29 ), -1, 'Spin 24 (25 Red), bet 29 pays -1';\nis payout( 24, 30 ), -1, 'Spin 24 (25 Red), bet 30 pays -1';\nis payout( 24, 31 ), -1, 'Spin 24 (25 Red), bet 31 pays -1';\nis payout( 24, 32 ), -1, 'Spin 24 (25 Red), bet 32 pays -1';\nis payout( 24, 33 ), -1, 'Spin 24 (25 Red), bet 33 pays -1';\nis payout( 24, 34 ), -1, 'Spin 24 (25 Red), bet 34 pays -1';\nis payout( 24, 35 ), -1, 'Spin 24 (25 Red), bet 35 pays -1';\nis payout( 24, 36 ), -1, 'Spin 24 (25 Red), bet 36 pays -1';\nis payout( 24, 37 ), -1, 'Spin 24 (25 Red), bet 37 pays -1';\nis payout( 24, 38 ), -1, 'Spin 24 (25 Red), bet 38 pays -1';\nis payout( 24, 39 ), 2, 'Spin 24 (25 Red), bet 39 pays 2';\nis payout( 24, 40 ), 2, 'Spin 24 (25 Red), bet 40 pays 2';\nis payout( 24, 41 ), -1, 'Spin 24 (25 Red), bet 41 pays -1';\nis payout( 24, 42 ), -1, 'Spin 24 (25 Red), bet 42 pays -1';\nis payout( 24, 43 ), -1, 'Spin 24 (25 Red), bet 43 pays -1';\nis payout( 24, 44 ), 1, 'Spin 24 (25 Red), bet 44 pays 1';\nis payout( 24, 45 ), -1, 'Spin 24 (25 Red), bet 45 pays -1';\nis payout( 24, 46 ), 1, 'Spin 24 (25 Red), bet 46 pays 1';\nis payout( 24, 47 ), 1, 'Spin 24 (25 Red), bet 47 pays 1';\nis payout( 24, 48 ), -1, 'Spin 24 (25 Red), bet 48 pays -1';\nis payout( 24, 49 ), -1, 'Spin 24 (25 Red), bet 49 pays -1';\nis payout( 24, 50 ), -1, 'Spin 24 (25 Red), bet 50 pays -1';\nis format_spin( 25 ), '26 Black', 'Spin 25 is 26 Black';\nis payout( 25, 1 ), -1, 'Spin 25 (26 Black), bet 1 pays -1';\nis payout( 25, 2 ), -1, 'Spin 25 (26 Black), bet 2 pays -1';\nis payout( 25, 3 ), -1, 'Spin 25 (26 Black), bet 3 pays -1';\nis payout( 25, 4 ), -1, 'Spin 25 (26 Black), bet 4 pays -1';\nis payout( 25, 5 ), -1, 'Spin 25 (26 Black), bet 5 pays -1';\nis payout( 25, 6 ), -1, 'Spin 25 (26 Black), bet 6 pays -1';\nis payout( 25, 7 ), -1, 'Spin 25 (26 Black), bet 7 pays -1';\nis payout( 25, 8 ), -1, 'Spin 25 (26 Black), bet 8 pays -1';\nis payout( 25, 9 ), -1, 'Spin 25 (26 Black), bet 9 pays -1';\nis payout( 25, 10 ), -1, 'Spin 25 (26 Black), bet 10 pays -1';\nis payout( 25, 11 ), -1, 'Spin 25 (26 Black), bet 11 pays -1';\nis payout( 25, 12 ), -1, 'Spin 25 (26 Black), bet 12 pays -1';\nis payout( 25, 13 ), -1, 'Spin 25 (26 Black), bet 13 pays -1';\nis payout( 25, 14 ), -1, 'Spin 25 (26 Black), bet 14 pays -1';\nis payout( 25, 15 ), -1, 'Spin 25 (26 Black), bet 15 pays -1';\nis payout( 25, 16 ), -1, 'Spin 25 (26 Black), bet 16 pays -1';\nis payout( 25, 17 ), -1, 'Spin 25 (26 Black), bet 17 pays -1';\nis payout( 25, 18 ), -1, 'Spin 25 (26 Black), bet 18 pays -1';\nis payout( 25, 19 ), -1, 'Spin 25 (26 Black), bet 19 pays -1';\nis payout( 25, 20 ), -1, 'Spin 25 (26 Black), bet 20 pays -1';\nis payout( 25, 21 ), -1, 'Spin 25 (26 Black), bet 21 pays -1';\nis payout( 25, 22 ), -1, 'Spin 25 (26 Black), bet 22 pays -1';\nis payout( 25, 23 ), -1, 'Spin 25 (26 Black), bet 23 pays -1';\nis payout( 25, 24 ), -1, 'Spin 25 (26 Black), bet 24 pays -1';\nis payout( 25, 25 ), -1, 'Spin 25 (26 Black), bet 25 pays -1';\nis payout( 25, 26 ), 35, 'Spin 25 (26 Black), bet 26 pays 35';\nis payout( 25, 27 ), -1, 'Spin 25 (26 Black), bet 27 pays -1';\nis payout( 25, 28 ), -1, 'Spin 25 (26 Black), bet 28 pays -1';\nis payout( 25, 29 ), -1, 'Spin 25 (26 Black), bet 29 pays -1';\nis payout( 25, 30 ), -1, 'Spin 25 (26 Black), bet 30 pays -1';\nis payout( 25, 31 ), -1, 'Spin 25 (26 Black), bet 31 pays -1';\nis payout( 25, 32 ), -1, 'Spin 25 (26 Black), bet 32 pays -1';\nis payout( 25, 33 ), -1, 'Spin 25 (26 Black), bet 33 pays -1';\nis payout( 25, 34 ), -1, 'Spin 25 (26 Black), bet 34 pays -1';\nis payout( 25, 35 ), -1, 'Spin 25 (26 Black), bet 35 pays -1';\nis payout( 25, 36 ), -1, 'Spin 25 (26 Black), bet 36 pays -1';\nis payout( 25, 37 ), -1, 'Spin 25 (26 Black), bet 37 pays -1';\nis payout( 25, 38 ), -1, 'Spin 25 (26 Black), bet 38 pays -1';\nis payout( 25, 39 ), 2, 'Spin 25 (26 Black), bet 39 pays 2';\nis payout( 25, 40 ), -1, 'Spin 25 (26 Black), bet 40 pays -1';\nis payout( 25, 41 ), 2, 'Spin 25 (26 Black), bet 41 pays 2';\nis payout( 25, 42 ), -1, 'Spin 25 (26 Black), bet 42 pays -1';\nis payout( 25, 43 ), -1, 'Spin 25 (26 Black), bet 43 pays -1';\nis payout( 25, 44 ), 1, 'Spin 25 (26 Black), bet 44 pays 1';\nis payout( 25, 45 ), 1, 'Spin 25 (26 Black), bet 45 pays 1';\nis payout( 25, 46 ), -1, 'Spin 25 (26 Black), bet 46 pays -1';\nis payout( 25, 47 ), -1, 'Spin 25 (26 Black), bet 47 pays -1';\nis payout( 25, 48 ), 1, 'Spin 25 (26 Black), bet 48 pays 1';\nis payout( 25, 49 ), -1, 'Spin 25 (26 Black), bet 49 pays -1';\nis payout( 25, 50 ), -1, 'Spin 25 (26 Black), bet 50 pays -1';\nis format_spin( 26 ), '27 Red', 'Spin 26 is 27 Red';\nis payout( 26, 1 ), -1, 'Spin 26 (27 Red), bet 1 pays -1';\nis payout( 26, 2 ), -1, 'Spin 26 (27 Red), bet 2 pays -1';\nis payout( 26, 3 ), -1, 'Spin 26 (27 Red), bet 3 pays -1';\nis payout( 26, 4 ), -1, 'Spin 26 (27 Red), bet 4 pays -1';\nis payout( 26, 5 ), -1, 'Spin 26 (27 Red), bet 5 pays -1';\nis payout( 26, 6 ), -1, 'Spin 26 (27 Red), bet 6 pays -1';\nis payout( 26, 7 ), -1, 'Spin 26 (27 Red), bet 7 pays -1';\nis payout( 26, 8 ), -1, 'Spin 26 (27 Red), bet 8 pays -1';\nis payout( 26, 9 ), -1, 'Spin 26 (27 Red), bet 9 pays -1';\nis payout( 26, 10 ), -1, 'Spin 26 (27 Red), bet 10 pays -1';\nis payout( 26, 11 ), -1, 'Spin 26 (27 Red), bet 11 pays -1';\nis payout( 26, 12 ), -1, 'Spin 26 (27 Red), bet 12 pays -1';\nis payout( 26, 13 ), -1, 'Spin 26 (27 Red), bet 13 pays -1';\nis payout( 26, 14 ), -1, 'Spin 26 (27 Red), bet 14 pays -1';\nis payout( 26, 15 ), -1, 'Spin 26 (27 Red), bet 15 pays -1';\nis payout( 26, 16 ), -1, 'Spin 26 (27 Red), bet 16 pays -1';\nis payout( 26, 17 ), -1, 'Spin 26 (27 Red), bet 17 pays -1';\nis payout( 26, 18 ), -1, 'Spin 26 (27 Red), bet 18 pays -1';\nis payout( 26, 19 ), -1, 'Spin 26 (27 Red), bet 19 pays -1';\nis payout( 26, 20 ), -1, 'Spin 26 (27 Red), bet 20 pays -1';\nis payout( 26, 21 ), -1, 'Spin 26 (27 Red), bet 21 pays -1';\nis payout( 26, 22 ), -1, 'Spin 26 (27 Red), bet 22 pays -1';\nis payout( 26, 23 ), -1, 'Spin 26 (27 Red), bet 23 pays -1';\nis payout( 26, 24 ), -1, 'Spin 26 (27 Red), bet 24 pays -1';\nis payout( 26, 25 ), -1, 'Spin 26 (27 Red), bet 25 pays -1';\nis payout( 26, 26 ), -1, 'Spin 26 (27 Red), bet 26 pays -1';\nis payout( 26, 27 ), 35, 'Spin 26 (27 Red), bet 27 pays 35';\nis payout( 26, 28 ), -1, 'Spin 26 (27 Red), bet 28 pays -1';\nis payout( 26, 29 ), -1, 'Spin 26 (27 Red), bet 29 pays -1';\nis payout( 26, 30 ), -1, 'Spin 26 (27 Red), bet 30 pays -1';\nis payout( 26, 31 ), -1, 'Spin 26 (27 Red), bet 31 pays -1';\nis payout( 26, 32 ), -1, 'Spin 26 (27 Red), bet 32 pays -1';\nis payout( 26, 33 ), -1, 'Spin 26 (27 Red), bet 33 pays -1';\nis payout( 26, 34 ), -1, 'Spin 26 (27 Red), bet 34 pays -1';\nis payout( 26, 35 ), -1, 'Spin 26 (27 Red), bet 35 pays -1';\nis payout( 26, 36 ), -1, 'Spin 26 (27 Red), bet 36 pays -1';\nis payout( 26, 37 ), -1, 'Spin 26 (27 Red), bet 37 pays -1';\nis payout( 26, 38 ), -1, 'Spin 26 (27 Red), bet 38 pays -1';\nis payout( 26, 39 ), 2, 'Spin 26 (27 Red), bet 39 pays 2';\nis payout( 26, 40 ), -1, 'Spin 26 (27 Red), bet 40 pays -1';\nis payout( 26, 41 ), -1, 'Spin 26 (27 Red), bet 41 pays -1';\nis payout( 26, 42 ), 2, 'Spin 26 (27 Red), bet 42 pays 2';\nis payout( 26, 43 ), -1, 'Spin 26 (27 Red), bet 43 pays -1';\nis payout( 26, 44 ), 1, 'Spin 26 (27 Red), bet 44 pays 1';\nis payout( 26, 45 ), -1, 'Spin 26 (27 Red), bet 45 pays -1';\nis payout( 26, 46 ), 1, 'Spin 26 (27 Red), bet 46 pays 1';\nis payout( 26, 47 ), 1, 'Spin 26 (27 Red), bet 47 pays 1';\nis payout( 26, 48 ), -1, 'Spin 26 (27 Red), bet 48 pays -1';\nis payout( 26, 49 ), -1, 'Spin 26 (27 Red), bet 49 pays -1';\nis payout( 26, 50 ), -1, 'Spin 26 (27 Red), bet 50 pays -1';\nis format_spin( 27 ), '28 Black', 'Spin 27 is 28 Black';\nis payout( 27, 1 ), -1, 'Spin 27 (28 Black), bet 1 pays -1';\nis payout( 27, 2 ), -1, 'Spin 27 (28 Black), bet 2 pays -1';\nis payout( 27, 3 ), -1, 'Spin 27 (28 Black), bet 3 pays -1';\nis payout( 27, 4 ), -1, 'Spin 27 (28 Black), bet 4 pays -1';\nis payout( 27, 5 ), -1, 'Spin 27 (28 Black), bet 5 pays -1';\nis payout( 27, 6 ), -1, 'Spin 27 (28 Black), bet 6 pays -1';\nis payout( 27, 7 ), -1, 'Spin 27 (28 Black), bet 7 pays -1';\nis payout( 27, 8 ), -1, 'Spin 27 (28 Black), bet 8 pays -1';\nis payout( 27, 9 ), -1, 'Spin 27 (28 Black), bet 9 pays -1';\nis payout( 27, 10 ), -1, 'Spin 27 (28 Black), bet 10 pays -1';\nis payout( 27, 11 ), -1, 'Spin 27 (28 Black), bet 11 pays -1';\nis payout( 27, 12 ), -1, 'Spin 27 (28 Black), bet 12 pays -1';\nis payout( 27, 13 ), -1, 'Spin 27 (28 Black), bet 13 pays -1';\nis payout( 27, 14 ), -1, 'Spin 27 (28 Black), bet 14 pays -1';\nis payout( 27, 15 ), -1, 'Spin 27 (28 Black), bet 15 pays -1';\nis payout( 27, 16 ), -1, 'Spin 27 (28 Black), bet 16 pays -1';\nis payout( 27, 17 ), -1, 'Spin 27 (28 Black), bet 17 pays -1';\nis payout( 27, 18 ), -1, 'Spin 27 (28 Black), bet 18 pays -1';\nis payout( 27, 19 ), -1, 'Spin 27 (28 Black), bet 19 pays -1';\nis payout( 27, 20 ), -1, 'Spin 27 (28 Black), bet 20 pays -1';\nis payout( 27, 21 ), -1, 'Spin 27 (28 Black), bet 21 pays -1';\nis payout( 27, 22 ), -1, 'Spin 27 (28 Black), bet 22 pays -1';\nis payout( 27, 23 ), -1, 'Spin 27 (28 Black), bet 23 pays -1';\nis payout( 27, 24 ), -1, 'Spin 27 (28 Black), bet 24 pays -1';\nis payout( 27, 25 ), -1, 'Spin 27 (28 Black), bet 25 pays -1';\nis payout( 27, 26 ), -1, 'Spin 27 (28 Black), bet 26 pays -1';\nis payout( 27, 27 ), -1, 'Spin 27 (28 Black), bet 27 pays -1';\nis payout( 27, 28 ), 35, 'Spin 27 (28 Black), bet 28 pays 35';\nis payout( 27, 29 ), -1, 'Spin 27 (28 Black), bet 29 pays -1';\nis payout( 27, 30 ), -1, 'Spin 27 (28 Black), bet 30 pays -1';\nis payout( 27, 31 ), -1, 'Spin 27 (28 Black), bet 31 pays -1';\nis payout( 27, 32 ), -1, 'Spin 27 (28 Black), bet 32 pays -1';\nis payout( 27, 33 ), -1, 'Spin 27 (28 Black), bet 33 pays -1';\nis payout( 27, 34 ), -1, 'Spin 27 (28 Black), bet 34 pays -1';\nis payout( 27, 35 ), -1, 'Spin 27 (28 Black), bet 35 pays -1';\nis payout( 27, 36 ), -1, 'Spin 27 (28 Black), bet 36 pays -1';\nis payout( 27, 37 ), -1, 'Spin 27 (28 Black), bet 37 pays -1';\nis payout( 27, 38 ), -1, 'Spin 27 (28 Black), bet 38 pays -1';\nis payout( 27, 39 ), 2, 'Spin 27 (28 Black), bet 39 pays 2';\nis payout( 27, 40 ), 2, 'Spin 27 (28 Black), bet 40 pays 2';\nis payout( 27, 41 ), -1, 'Spin 27 (28 Black), bet 41 pays -1';\nis payout( 27, 42 ), -1, 'Spin 27 (28 Black), bet 42 pays -1';\nis payout( 27, 43 ), -1, 'Spin 27 (28 Black), bet 43 pays -1';\nis payout( 27, 44 ), 1, 'Spin 27 (28 Black), bet 44 pays 1';\nis payout( 27, 45 ), 1, 'Spin 27 (28 Black), bet 45 pays 1';\nis payout( 27, 46 ), -1, 'Spin 27 (28 Black), bet 46 pays -1';\nis payout( 27, 47 ), -1, 'Spin 27 (28 Black), bet 47 pays -1';\nis payout( 27, 48 ), 1, 'Spin 27 (28 Black), bet 48 pays 1';\nis payout( 27, 49 ), -1, 'Spin 27 (28 Black), bet 49 pays -1';\nis payout( 27, 50 ), -1, 'Spin 27 (28 Black), bet 50 pays -1';\nis format_spin( 28 ), '29 Black', 'Spin 28 is 29 Black';\nis payout( 28, 1 ), -1, 'Spin 28 (29 Black), bet 1 pays -1';\nis payout( 28, 2 ), -1, 'Spin 28 (29 Black), bet 2 pays -1';\nis payout( 28, 3 ), -1, 'Spin 28 (29 Black), bet 3 pays -1';\nis payout( 28, 4 ), -1, 'Spin 28 (29 Black), bet 4 pays -1';\nis payout( 28, 5 ), -1, 'Spin 28 (29 Black), bet 5 pays -1';\nis payout( 28, 6 ), -1, 'Spin 28 (29 Black), bet 6 pays -1';\nis payout( 28, 7 ), -1, 'Spin 28 (29 Black), bet 7 pays -1';\nis payout( 28, 8 ), -1, 'Spin 28 (29 Black), bet 8 pays -1';\nis payout( 28, 9 ), -1, 'Spin 28 (29 Black), bet 9 pays -1';\nis payout( 28, 10 ), -1, 'Spin 28 (29 Black), bet 10 pays -1';\nis payout( 28, 11 ), -1, 'Spin 28 (29 Black), bet 11 pays -1';\nis payout( 28, 12 ), -1, 'Spin 28 (29 Black), bet 12 pays -1';\nis payout( 28, 13 ), -1, 'Spin 28 (29 Black), bet 13 pays -1';\nis payout( 28, 14 ), -1, 'Spin 28 (29 Black), bet 14 pays -1';\nis payout( 28, 15 ), -1, 'Spin 28 (29 Black), bet 15 pays -1';\nis payout( 28, 16 ), -1, 'Spin 28 (29 Black), bet 16 pays -1';\nis payout( 28, 17 ), -1, 'Spin 28 (29 Black), bet 17 pays -1';\nis payout( 28, 18 ), -1, 'Spin 28 (29 Black), bet 18 pays -1';\nis payout( 28, 19 ), -1, 'Spin 28 (29 Black), bet 19 pays -1';\nis payout( 28, 20 ), -1, 'Spin 28 (29 Black), bet 20 pays -1';\nis payout( 28, 21 ), -1, 'Spin 28 (29 Black), bet 21 pays -1';\nis payout( 28, 22 ), -1, 'Spin 28 (29 Black), bet 22 pays -1';\nis payout( 28, 23 ), -1, 'Spin 28 (29 Black), bet 23 pays -1';\nis payout( 28, 24 ), -1, 'Spin 28 (29 Black), bet 24 pays -1';\nis payout( 28, 25 ), -1, 'Spin 28 (29 Black), bet 25 pays -1';\nis payout( 28, 26 ), -1, 'Spin 28 (29 Black), bet 26 pays -1';\nis payout( 28, 27 ), -1, 'Spin 28 (29 Black), bet 27 pays -1';\nis payout( 28, 28 ), -1, 'Spin 28 (29 Black), bet 28 pays -1';\nis payout( 28, 29 ), 35, 'Spin 28 (29 Black), bet 29 pays 35';\nis payout( 28, 30 ), -1, 'Spin 28 (29 Black), bet 30 pays -1';\nis payout( 28, 31 ), -1, 'Spin 28 (29 Black), bet 31 pays -1';\nis payout( 28, 32 ), -1, 'Spin 28 (29 Black), bet 32 pays -1';\nis payout( 28, 33 ), -1, 'Spin 28 (29 Black), bet 33 pays -1';\nis payout( 28, 34 ), -1, 'Spin 28 (29 Black), bet 34 pays -1';\nis payout( 28, 35 ), -1, 'Spin 28 (29 Black), bet 35 pays -1';\nis payout( 28, 36 ), -1, 'Spin 28 (29 Black), bet 36 pays -1';\nis payout( 28, 37 ), -1, 'Spin 28 (29 Black), bet 37 pays -1';\nis payout( 28, 38 ), -1, 'Spin 28 (29 Black), bet 38 pays -1';\nis payout( 28, 39 ), 2, 'Spin 28 (29 Black), bet 39 pays 2';\nis payout( 28, 40 ), -1, 'Spin 28 (29 Black), bet 40 pays -1';\nis payout( 28, 41 ), 2, 'Spin 28 (29 Black), bet 41 pays 2';\nis payout( 28, 42 ), -1, 'Spin 28 (29 Black), bet 42 pays -1';\nis payout( 28, 43 ), -1, 'Spin 28 (29 Black), bet 43 pays -1';\nis payout( 28, 44 ), 1, 'Spin 28 (29 Black), bet 44 pays 1';\nis payout( 28, 45 ), -1, 'Spin 28 (29 Black), bet 45 pays -1';\nis payout( 28, 46 ), 1, 'Spin 28 (29 Black), bet 46 pays 1';\nis payout( 28, 47 ), -1, 'Spin 28 (29 Black), bet 47 pays -1';\nis payout( 28, 48 ), 1, 'Spin 28 (29 Black), bet 48 pays 1';\nis payout( 28, 49 ), -1, 'Spin 28 (29 Black), bet 49 pays -1';\nis payout( 28, 50 ), -1, 'Spin 28 (29 Black), bet 50 pays -1';\nis format_spin( 29 ), '30 Red', 'Spin 29 is 30 Red';\nis payout( 29, 1 ), -1, 'Spin 29 (30 Red), bet 1 pays -1';\nis payout( 29, 2 ), -1, 'Spin 29 (30 Red), bet 2 pays -1';\nis payout( 29, 3 ), -1, 'Spin 29 (30 Red), bet 3 pays -1';\nis payout( 29, 4 ), -1, 'Spin 29 (30 Red), bet 4 pays -1';\nis payout( 29, 5 ), -1, 'Spin 29 (30 Red), bet 5 pays -1';\nis payout( 29, 6 ), -1, 'Spin 29 (30 Red), bet 6 pays -1';\nis payout( 29, 7 ), -1, 'Spin 29 (30 Red), bet 7 pays -1';\nis payout( 29, 8 ), -1, 'Spin 29 (30 Red), bet 8 pays -1';\nis payout( 29, 9 ), -1, 'Spin 29 (30 Red), bet 9 pays -1';\nis payout( 29, 10 ), -1, 'Spin 29 (30 Red), bet 10 pays -1';\nis payout( 29, 11 ), -1, 'Spin 29 (30 Red), bet 11 pays -1';\nis payout( 29, 12 ), -1, 'Spin 29 (30 Red), bet 12 pays -1';\nis payout( 29, 13 ), -1, 'Spin 29 (30 Red), bet 13 pays -1';\nis payout( 29, 14 ), -1, 'Spin 29 (30 Red), bet 14 pays -1';\nis payout( 29, 15 ), -1, 'Spin 29 (30 Red), bet 15 pays -1';\nis payout( 29, 16 ), -1, 'Spin 29 (30 Red), bet 16 pays -1';\nis payout( 29, 17 ), -1, 'Spin 29 (30 Red), bet 17 pays -1';\nis payout( 29, 18 ), -1, 'Spin 29 (30 Red), bet 18 pays -1';\nis payout( 29, 19 ), -1, 'Spin 29 (30 Red), bet 19 pays -1';\nis payout( 29, 20 ), -1, 'Spin 29 (30 Red), bet 20 pays -1';\nis payout( 29, 21 ), -1, 'Spin 29 (30 Red), bet 21 pays -1';\nis payout( 29, 22 ), -1, 'Spin 29 (30 Red), bet 22 pays -1';\nis payout( 29, 23 ), -1, 'Spin 29 (30 Red), bet 23 pays -1';\nis payout( 29, 24 ), -1, 'Spin 29 (30 Red), bet 24 pays -1';\nis payout( 29, 25 ), -1, 'Spin 29 (30 Red), bet 25 pays -1';\nis payout( 29, 26 ), -1, 'Spin 29 (30 Red), bet 26 pays -1';\nis payout( 29, 27 ), -1, 'Spin 29 (30 Red), bet 27 pays -1';\nis payout( 29, 28 ), -1, 'Spin 29 (30 Red), bet 28 pays -1';\nis payout( 29, 29 ), -1, 'Spin 29 (30 Red), bet 29 pays -1';\nis payout( 29, 30 ), 35, 'Spin 29 (30 Red), bet 30 pays 35';\nis payout( 29, 31 ), -1, 'Spin 29 (30 Red), bet 31 pays -1';\nis payout( 29, 32 ), -1, 'Spin 29 (30 Red), bet 32 pays -1';\nis payout( 29, 33 ), -1, 'Spin 29 (30 Red), bet 33 pays -1';\nis payout( 29, 34 ), -1, 'Spin 29 (30 Red), bet 34 pays -1';\nis payout( 29, 35 ), -1, 'Spin 29 (30 Red), bet 35 pays -1';\nis payout( 29, 36 ), -1, 'Spin 29 (30 Red), bet 36 pays -1';\nis payout( 29, 37 ), -1, 'Spin 29 (30 Red), bet 37 pays -1';\nis payout( 29, 38 ), -1, 'Spin 29 (30 Red), bet 38 pays -1';\nis payout( 29, 39 ), 2, 'Spin 29 (30 Red), bet 39 pays 2';\nis payout( 29, 40 ), -1, 'Spin 29 (30 Red), bet 40 pays -1';\nis payout( 29, 41 ), -1, 'Spin 29 (30 Red), bet 41 pays -1';\nis payout( 29, 42 ), 2, 'Spin 29 (30 Red), bet 42 pays 2';\nis payout( 29, 43 ), -1, 'Spin 29 (30 Red), bet 43 pays -1';\nis payout( 29, 44 ), 1, 'Spin 29 (30 Red), bet 44 pays 1';\nis payout( 29, 45 ), 1, 'Spin 29 (30 Red), bet 45 pays 1';\nis payout( 29, 46 ), -1, 'Spin 29 (30 Red), bet 46 pays -1';\nis payout( 29, 47 ), 1, 'Spin 29 (30 Red), bet 47 pays 1';\nis payout( 29, 48 ), -1, 'Spin 29 (30 Red), bet 48 pays -1';\nis payout( 29, 49 ), -1, 'Spin 29 (30 Red), bet 49 pays -1';\nis payout( 29, 50 ), -1, 'Spin 29 (30 Red), bet 50 pays -1';\nis format_spin( 30 ), '31 Black', 'Spin 30 is 31 Black';\nis payout( 30, 1 ), -1, 'Spin 30 (31 Black), bet 1 pays -1';\nis payout( 30, 2 ), -1, 'Spin 30 (31 Black), bet 2 pays -1';\nis payout( 30, 3 ), -1, 'Spin 30 (31 Black), bet 3 pays -1';\nis payout( 30, 4 ), -1, 'Spin 30 (31 Black), bet 4 pays -1';\nis payout( 30, 5 ), -1, 'Spin 30 (31 Black), bet 5 pays -1';\nis payout( 30, 6 ), -1, 'Spin 30 (31 Black), bet 6 pays -1';\nis payout( 30, 7 ), -1, 'Spin 30 (31 Black), bet 7 pays -1';\nis payout( 30, 8 ), -1, 'Spin 30 (31 Black), bet 8 pays -1';\nis payout( 30, 9 ), -1, 'Spin 30 (31 Black), bet 9 pays -1';\nis payout( 30, 10 ), -1, 'Spin 30 (31 Black), bet 10 pays -1';\nis payout( 30, 11 ), -1, 'Spin 30 (31 Black), bet 11 pays -1';\nis payout( 30, 12 ), -1, 'Spin 30 (31 Black), bet 12 pays -1';\nis payout( 30, 13 ), -1, 'Spin 30 (31 Black), bet 13 pays -1';\nis payout( 30, 14 ), -1, 'Spin 30 (31 Black), bet 14 pays -1';\nis payout( 30, 15 ), -1, 'Spin 30 (31 Black), bet 15 pays -1';\nis payout( 30, 16 ), -1, 'Spin 30 (31 Black), bet 16 pays -1';\nis payout( 30, 17 ), -1, 'Spin 30 (31 Black), bet 17 pays -1';\nis payout( 30, 18 ), -1, 'Spin 30 (31 Black), bet 18 pays -1';\nis payout( 30, 19 ), -1, 'Spin 30 (31 Black), bet 19 pays -1';\nis payout( 30, 20 ), -1, 'Spin 30 (31 Black), bet 20 pays -1';\nis payout( 30, 21 ), -1, 'Spin 30 (31 Black), bet 21 pays -1';\nis payout( 30, 22 ), -1, 'Spin 30 (31 Black), bet 22 pays -1';\nis payout( 30, 23 ), -1, 'Spin 30 (31 Black), bet 23 pays -1';\nis payout( 30, 24 ), -1, 'Spin 30 (31 Black), bet 24 pays -1';\nis payout( 30, 25 ), -1, 'Spin 30 (31 Black), bet 25 pays -1';\nis payout( 30, 26 ), -1, 'Spin 30 (31 Black), bet 26 pays -1';\nis payout( 30, 27 ), -1, 'Spin 30 (31 Black), bet 27 pays -1';\nis payout( 30, 28 ), -1, 'Spin 30 (31 Black), bet 28 pays -1';\nis payout( 30, 29 ), -1, 'Spin 30 (31 Black), bet 29 pays -1';\nis payout( 30, 30 ), -1, 'Spin 30 (31 Black), bet 30 pays -1';\nis payout( 30, 31 ), 35, 'Spin 30 (31 Black), bet 31 pays 35';\nis payout( 30, 32 ), -1, 'Spin 30 (31 Black), bet 32 pays -1';\nis payout( 30, 33 ), -1, 'Spin 30 (31 Black), bet 33 pays -1';\nis payout( 30, 34 ), -1, 'Spin 30 (31 Black), bet 34 pays -1';\nis payout( 30, 35 ), -1, 'Spin 30 (31 Black), bet 35 pays -1';\nis payout( 30, 36 ), -1, 'Spin 30 (31 Black), bet 36 pays -1';\nis payout( 30, 37 ), -1, 'Spin 30 (31 Black), bet 37 pays -1';\nis payout( 30, 38 ), -1, 'Spin 30 (31 Black), bet 38 pays -1';\nis payout( 30, 39 ), 2, 'Spin 30 (31 Black), bet 39 pays 2';\nis payout( 30, 40 ), 2, 'Spin 30 (31 Black), bet 40 pays 2';\nis payout( 30, 41 ), -1, 'Spin 30 (31 Black), bet 41 pays -1';\nis payout( 30, 42 ), -1, 'Spin 30 (31 Black), bet 42 pays -1';\nis payout( 30, 43 ), -1, 'Spin 30 (31 Black), bet 43 pays -1';\nis payout( 30, 44 ), 1, 'Spin 30 (31 Black), bet 44 pays 1';\nis payout( 30, 45 ), -1, 'Spin 30 (31 Black), bet 45 pays -1';\nis payout( 30, 46 ), 1, 'Spin 30 (31 Black), bet 46 pays 1';\nis payout( 30, 47 ), -1, 'Spin 30 (31 Black), bet 47 pays -1';\nis payout( 30, 48 ), 1, 'Spin 30 (31 Black), bet 48 pays 1';\nis payout( 30, 49 ), -1, 'Spin 30 (31 Black), bet 49 pays -1';\nis payout( 30, 50 ), -1, 'Spin 30 (31 Black), bet 50 pays -1';\nis format_spin( 31 ), '32 Red', 'Spin 31 is 32 Red';\nis payout( 31, 1 ), -1, 'Spin 31 (32 Red), bet 1 pays -1';\nis payout( 31, 2 ), -1, 'Spin 31 (32 Red), bet 2 pays -1';\nis payout( 31, 3 ), -1, 'Spin 31 (32 Red), bet 3 pays -1';\nis payout( 31, 4 ), -1, 'Spin 31 (32 Red), bet 4 pays -1';\nis payout( 31, 5 ), -1, 'Spin 31 (32 Red), bet 5 pays -1';\nis payout( 31, 6 ), -1, 'Spin 31 (32 Red), bet 6 pays -1';\nis payout( 31, 7 ), -1, 'Spin 31 (32 Red), bet 7 pays -1';\nis payout( 31, 8 ), -1, 'Spin 31 (32 Red), bet 8 pays -1';\nis payout( 31, 9 ), -1, 'Spin 31 (32 Red), bet 9 pays -1';\nis payout( 31, 10 ), -1, 'Spin 31 (32 Red), bet 10 pays -1';\nis payout( 31, 11 ), -1, 'Spin 31 (32 Red), bet 11 pays -1';\nis payout( 31, 12 ), -1, 'Spin 31 (32 Red), bet 12 pays -1';\nis payout( 31, 13 ), -1, 'Spin 31 (32 Red), bet 13 pays -1';\nis payout( 31, 14 ), -1, 'Spin 31 (32 Red), bet 14 pays -1';\nis payout( 31, 15 ), -1, 'Spin 31 (32 Red), bet 15 pays -1';\nis payout( 31, 16 ), -1, 'Spin 31 (32 Red), bet 16 pays -1';\nis payout( 31, 17 ), -1, 'Spin 31 (32 Red), bet 17 pays -1';\nis payout( 31, 18 ), -1, 'Spin 31 (32 Red), bet 18 pays -1';\nis payout( 31, 19 ), -1, 'Spin 31 (32 Red), bet 19 pays -1';\nis payout( 31, 20 ), -1, 'Spin 31 (32 Red), bet 20 pays -1';\nis payout( 31, 21 ), -1, 'Spin 31 (32 Red), bet 21 pays -1';\nis payout( 31, 22 ), -1, 'Spin 31 (32 Red), bet 22 pays -1';\nis payout( 31, 23 ), -1, 'Spin 31 (32 Red), bet 23 pays -1';\nis payout( 31, 24 ), -1, 'Spin 31 (32 Red), bet 24 pays -1';\nis payout( 31, 25 ), -1, 'Spin 31 (32 Red), bet 25 pays -1';\nis payout( 31, 26 ), -1, 'Spin 31 (32 Red), bet 26 pays -1';\nis payout( 31, 27 ), -1, 'Spin 31 (32 Red), bet 27 pays -1';\nis payout( 31, 28 ), -1, 'Spin 31 (32 Red), bet 28 pays -1';\nis payout( 31, 29 ), -1, 'Spin 31 (32 Red), bet 29 pays -1';\nis payout( 31, 30 ), -1, 'Spin 31 (32 Red), bet 30 pays -1';\nis payout( 31, 31 ), -1, 'Spin 31 (32 Red), bet 31 pays -1';\nis payout( 31, 32 ), 35, 'Spin 31 (32 Red), bet 32 pays 35';\nis payout( 31, 33 ), -1, 'Spin 31 (32 Red), bet 33 pays -1';\nis payout( 31, 34 ), -1, 'Spin 31 (32 Red), bet 34 pays -1';\nis payout( 31, 35 ), -1, 'Spin 31 (32 Red), bet 35 pays -1';\nis payout( 31, 36 ), -1, 'Spin 31 (32 Red), bet 36 pays -1';\nis payout( 31, 37 ), -1, 'Spin 31 (32 Red), bet 37 pays -1';\nis payout( 31, 38 ), -1, 'Spin 31 (32 Red), bet 38 pays -1';\nis payout( 31, 39 ), 2, 'Spin 31 (32 Red), bet 39 pays 2';\nis payout( 31, 40 ), -1, 'Spin 31 (32 Red), bet 40 pays -1';\nis payout( 31, 41 ), 2, 'Spin 31 (32 Red), bet 41 pays 2';\nis payout( 31, 42 ), -1, 'Spin 31 (32 Red), bet 42 pays -1';\nis payout( 31, 43 ), -1, 'Spin 31 (32 Red), bet 43 pays -1';\nis payout( 31, 44 ), 1, 'Spin 31 (32 Red), bet 44 pays 1';\nis payout( 31, 45 ), 1, 'Spin 31 (32 Red), bet 45 pays 1';\nis payout( 31, 46 ), -1, 'Spin 31 (32 Red), bet 46 pays -1';\nis payout( 31, 47 ), 1, 'Spin 31 (32 Red), bet 47 pays 1';\nis payout( 31, 48 ), -1, 'Spin 31 (32 Red), bet 48 pays -1';\nis payout( 31, 49 ), -1, 'Spin 31 (32 Red), bet 49 pays -1';\nis payout( 31, 50 ), -1, 'Spin 31 (32 Red), bet 50 pays -1';\nis format_spin( 32 ), '33 Black', 'Spin 32 is 33 Black';\nis payout( 32, 1 ), -1, 'Spin 32 (33 Black), bet 1 pays -1';\nis payout( 32, 2 ), -1, 'Spin 32 (33 Black), bet 2 pays -1';\nis payout( 32, 3 ), -1, 'Spin 32 (33 Black), bet 3 pays -1';\nis payout( 32, 4 ), -1, 'Spin 32 (33 Black), bet 4 pays -1';\nis payout( 32, 5 ), -1, 'Spin 32 (33 Black), bet 5 pays -1';\nis payout( 32, 6 ), -1, 'Spin 32 (33 Black), bet 6 pays -1';\nis payout( 32, 7 ), -1, 'Spin 32 (33 Black), bet 7 pays -1';\nis payout( 32, 8 ), -1, 'Spin 32 (33 Black), bet 8 pays -1';\nis payout( 32, 9 ), -1, 'Spin 32 (33 Black), bet 9 pays -1';\nis payout( 32, 10 ), -1, 'Spin 32 (33 Black), bet 10 pays -1';\nis payout( 32, 11 ), -1, 'Spin 32 (33 Black), bet 11 pays -1';\nis payout( 32, 12 ), -1, 'Spin 32 (33 Black), bet 12 pays -1';\nis payout( 32, 13 ), -1, 'Spin 32 (33 Black), bet 13 pays -1';\nis payout( 32, 14 ), -1, 'Spin 32 (33 Black), bet 14 pays -1';\nis payout( 32, 15 ), -1, 'Spin 32 (33 Black), bet 15 pays -1';\nis payout( 32, 16 ), -1, 'Spin 32 (33 Black), bet 16 pays -1';\nis payout( 32, 17 ), -1, 'Spin 32 (33 Black), bet 17 pays -1';\nis payout( 32, 18 ), -1, 'Spin 32 (33 Black), bet 18 pays -1';\nis payout( 32, 19 ), -1, 'Spin 32 (33 Black), bet 19 pays -1';\nis payout( 32, 20 ), -1, 'Spin 32 (33 Black), bet 20 pays -1';\nis payout( 32, 21 ), -1, 'Spin 32 (33 Black), bet 21 pays -1';\nis payout( 32, 22 ), -1, 'Spin 32 (33 Black), bet 22 pays -1';\nis payout( 32, 23 ), -1, 'Spin 32 (33 Black), bet 23 pays -1';\nis payout( 32, 24 ), -1, 'Spin 32 (33 Black), bet 24 pays -1';\nis payout( 32, 25 ), -1, 'Spin 32 (33 Black), bet 25 pays -1';\nis payout( 32, 26 ), -1, 'Spin 32 (33 Black), bet 26 pays -1';\nis payout( 32, 27 ), -1, 'Spin 32 (33 Black), bet 27 pays -1';\nis payout( 32, 28 ), -1, 'Spin 32 (33 Black), bet 28 pays -1';\nis payout( 32, 29 ), -1, 'Spin 32 (33 Black), bet 29 pays -1';\nis payout( 32, 30 ), -1, 'Spin 32 (33 Black), bet 30 pays -1';\nis payout( 32, 31 ), -1, 'Spin 32 (33 Black), bet 31 pays -1';\nis payout( 32, 32 ), -1, 'Spin 32 (33 Black), bet 32 pays -1';\nis payout( 32, 33 ), 35, 'Spin 32 (33 Black), bet 33 pays 35';\nis payout( 32, 34 ), -1, 'Spin 32 (33 Black), bet 34 pays -1';\nis payout( 32, 35 ), -1, 'Spin 32 (33 Black), bet 35 pays -1';\nis payout( 32, 36 ), -1, 'Spin 32 (33 Black), bet 36 pays -1';\nis payout( 32, 37 ), -1, 'Spin 32 (33 Black), bet 37 pays -1';\nis payout( 32, 38 ), -1, 'Spin 32 (33 Black), bet 38 pays -1';\nis payout( 32, 39 ), 2, 'Spin 32 (33 Black), bet 39 pays 2';\nis payout( 32, 40 ), -1, 'Spin 32 (33 Black), bet 40 pays -1';\nis payout( 32, 41 ), -1, 'Spin 32 (33 Black), bet 41 pays -1';\nis payout( 32, 42 ), 2, 'Spin 32 (33 Black), bet 42 pays 2';\nis payout( 32, 43 ), -1, 'Spin 32 (33 Black), bet 43 pays -1';\nis payout( 32, 44 ), 1, 'Spin 32 (33 Black), bet 44 pays 1';\nis payout( 32, 45 ), -1, 'Spin 32 (33 Black), bet 45 pays -1';\nis payout( 32, 46 ), 1, 'Spin 32 (33 Black), bet 46 pays 1';\nis payout( 32, 47 ), -1, 'Spin 32 (33 Black), bet 47 pays -1';\nis payout( 32, 48 ), 1, 'Spin 32 (33 Black), bet 48 pays 1';\nis payout( 32, 49 ), -1, 'Spin 32 (33 Black), bet 49 pays -1';\nis payout( 32, 50 ), -1, 'Spin 32 (33 Black), bet 50 pays -1';\nis format_spin( 33 ), '34 Red', 'Spin 33 is 34 Red';\nis payout( 33, 1 ), -1, 'Spin 33 (34 Red), bet 1 pays -1';\nis payout( 33, 2 ), -1, 'Spin 33 (34 Red), bet 2 pays -1';\nis payout( 33, 3 ), -1, 'Spin 33 (34 Red), bet 3 pays -1';\nis payout( 33, 4 ), -1, 'Spin 33 (34 Red), bet 4 pays -1';\nis payout( 33, 5 ), -1, 'Spin 33 (34 Red), bet 5 pays -1';\nis payout( 33, 6 ), -1, 'Spin 33 (34 Red), bet 6 pays -1';\nis payout( 33, 7 ), -1, 'Spin 33 (34 Red), bet 7 pays -1';\nis payout( 33, 8 ), -1, 'Spin 33 (34 Red), bet 8 pays -1';\nis payout( 33, 9 ), -1, 'Spin 33 (34 Red), bet 9 pays -1';\nis payout( 33, 10 ), -1, 'Spin 33 (34 Red), bet 10 pays -1';\nis payout( 33, 11 ), -1, 'Spin 33 (34 Red), bet 11 pays -1';\nis payout( 33, 12 ), -1, 'Spin 33 (34 Red), bet 12 pays -1';\nis payout( 33, 13 ), -1, 'Spin 33 (34 Red), bet 13 pays -1';\nis payout( 33, 14 ), -1, 'Spin 33 (34 Red), bet 14 pays -1';\nis payout( 33, 15 ), -1, 'Spin 33 (34 Red), bet 15 pays -1';\nis payout( 33, 16 ), -1, 'Spin 33 (34 Red), bet 16 pays -1';\nis payout( 33, 17 ), -1, 'Spin 33 (34 Red), bet 17 pays -1';\nis payout( 33, 18 ), -1, 'Spin 33 (34 Red), bet 18 pays -1';\nis payout( 33, 19 ), -1, 'Spin 33 (34 Red), bet 19 pays -1';\nis payout( 33, 20 ), -1, 'Spin 33 (34 Red), bet 20 pays -1';\nis payout( 33, 21 ), -1, 'Spin 33 (34 Red), bet 21 pays -1';\nis payout( 33, 22 ), -1, 'Spin 33 (34 Red), bet 22 pays -1';\nis payout( 33, 23 ), -1, 'Spin 33 (34 Red), bet 23 pays -1';\nis payout( 33, 24 ), -1, 'Spin 33 (34 Red), bet 24 pays -1';\nis payout( 33, 25 ), -1, 'Spin 33 (34 Red), bet 25 pays -1';\nis payout( 33, 26 ), -1, 'Spin 33 (34 Red), bet 26 pays -1';\nis payout( 33, 27 ), -1, 'Spin 33 (34 Red), bet 27 pays -1';\nis payout( 33, 28 ), -1, 'Spin 33 (34 Red), bet 28 pays -1';\nis payout( 33, 29 ), -1, 'Spin 33 (34 Red), bet 29 pays -1';\nis payout( 33, 30 ), -1, 'Spin 33 (34 Red), bet 30 pays -1';\nis payout( 33, 31 ), -1, 'Spin 33 (34 Red), bet 31 pays -1';\nis payout( 33, 32 ), -1, 'Spin 33 (34 Red), bet 32 pays -1';\nis payout( 33, 33 ), -1, 'Spin 33 (34 Red), bet 33 pays -1';\nis payout( 33, 34 ), 35, 'Spin 33 (34 Red), bet 34 pays 35';\nis payout( 33, 35 ), -1, 'Spin 33 (34 Red), bet 35 pays -1';\nis payout( 33, 36 ), -1, 'Spin 33 (34 Red), bet 36 pays -1';\nis payout( 33, 37 ), -1, 'Spin 33 (34 Red), bet 37 pays -1';\nis payout( 33, 38 ), -1, 'Spin 33 (34 Red), bet 38 pays -1';\nis payout( 33, 39 ), 2, 'Spin 33 (34 Red), bet 39 pays 2';\nis payout( 33, 40 ), 2, 'Spin 33 (34 Red), bet 40 pays 2';\nis payout( 33, 41 ), -1, 'Spin 33 (34 Red), bet 41 pays -1';\nis payout( 33, 42 ), -1, 'Spin 33 (34 Red), bet 42 pays -1';\nis payout( 33, 43 ), -1, 'Spin 33 (34 Red), bet 43 pays -1';\nis payout( 33, 44 ), 1, 'Spin 33 (34 Red), bet 44 pays 1';\nis payout( 33, 45 ), 1, 'Spin 33 (34 Red), bet 45 pays 1';\nis payout( 33, 46 ), -1, 'Spin 33 (34 Red), bet 46 pays -1';\nis payout( 33, 47 ), 1, 'Spin 33 (34 Red), bet 47 pays 1';\nis payout( 33, 48 ), -1, 'Spin 33 (34 Red), bet 48 pays -1';\nis payout( 33, 49 ), -1, 'Spin 33 (34 Red), bet 49 pays -1';\nis payout( 33, 50 ), -1, 'Spin 33 (34 Red), bet 50 pays -1';\nis format_spin( 34 ), '35 Black', 'Spin 34 is 35 Black';\nis payout( 34, 1 ), -1, 'Spin 34 (35 Black), bet 1 pays -1';\nis payout( 34, 2 ), -1, 'Spin 34 (35 Black), bet 2 pays -1';\nis payout( 34, 3 ), -1, 'Spin 34 (35 Black), bet 3 pays -1';\nis payout( 34, 4 ), -1, 'Spin 34 (35 Black), bet 4 pays -1';\nis payout( 34, 5 ), -1, 'Spin 34 (35 Black), bet 5 pays -1';\nis payout( 34, 6 ), -1, 'Spin 34 (35 Black), bet 6 pays -1';\nis payout( 34, 7 ), -1, 'Spin 34 (35 Black), bet 7 pays -1';\nis payout( 34, 8 ), -1, 'Spin 34 (35 Black), bet 8 pays -1';\nis payout( 34, 9 ), -1, 'Spin 34 (35 Black), bet 9 pays -1';\nis payout( 34, 10 ), -1, 'Spin 34 (35 Black), bet 10 pays -1';\nis payout( 34, 11 ), -1, 'Spin 34 (35 Black), bet 11 pays -1';\nis payout( 34, 12 ), -1, 'Spin 34 (35 Black), bet 12 pays -1';\nis payout( 34, 13 ), -1, 'Spin 34 (35 Black), bet 13 pays -1';\nis payout( 34, 14 ), -1, 'Spin 34 (35 Black), bet 14 pays -1';\nis payout( 34, 15 ), -1, 'Spin 34 (35 Black), bet 15 pays -1';\nis payout( 34, 16 ), -1, 'Spin 34 (35 Black), bet 16 pays -1';\nis payout( 34, 17 ), -1, 'Spin 34 (35 Black), bet 17 pays -1';\nis payout( 34, 18 ), -1, 'Spin 34 (35 Black), bet 18 pays -1';\nis payout( 34, 19 ), -1, 'Spin 34 (35 Black), bet 19 pays -1';\nis payout( 34, 20 ), -1, 'Spin 34 (35 Black), bet 20 pays -1';\nis payout( 34, 21 ), -1, 'Spin 34 (35 Black), bet 21 pays -1';\nis payout( 34, 22 ), -1, 'Spin 34 (35 Black), bet 22 pays -1';\nis payout( 34, 23 ), -1, 'Spin 34 (35 Black), bet 23 pays -1';\nis payout( 34, 24 ), -1, 'Spin 34 (35 Black), bet 24 pays -1';\nis payout( 34, 25 ), -1, 'Spin 34 (35 Black), bet 25 pays -1';\nis payout( 34, 26 ), -1, 'Spin 34 (35 Black), bet 26 pays -1';\nis payout( 34, 27 ), -1, 'Spin 34 (35 Black), bet 27 pays -1';\nis payout( 34, 28 ), -1, 'Spin 34 (35 Black), bet 28 pays -1';\nis payout( 34, 29 ), -1, 'Spin 34 (35 Black), bet 29 pays -1';\nis payout( 34, 30 ), -1, 'Spin 34 (35 Black), bet 30 pays -1';\nis payout( 34, 31 ), -1, 'Spin 34 (35 Black), bet 31 pays -1';\nis payout( 34, 32 ), -1, 'Spin 34 (35 Black), bet 32 pays -1';\nis payout( 34, 33 ), -1, 'Spin 34 (35 Black), bet 33 pays -1';\nis payout( 34, 34 ), -1, 'Spin 34 (35 Black), bet 34 pays -1';\nis payout( 34, 35 ), 35, 'Spin 34 (35 Black), bet 35 pays 35';\nis payout( 34, 36 ), -1, 'Spin 34 (35 Black), bet 36 pays -1';\nis payout( 34, 37 ), -1, 'Spin 34 (35 Black), bet 37 pays -1';\nis payout( 34, 38 ), -1, 'Spin 34 (35 Black), bet 38 pays -1';\nis payout( 34, 39 ), 2, 'Spin 34 (35 Black), bet 39 pays 2';\nis payout( 34, 40 ), -1, 'Spin 34 (35 Black), bet 40 pays -1';\nis payout( 34, 41 ), 2, 'Spin 34 (35 Black), bet 41 pays 2';\nis payout( 34, 42 ), -1, 'Spin 34 (35 Black), bet 42 pays -1';\nis payout( 34, 43 ), -1, 'Spin 34 (35 Black), bet 43 pays -1';\nis payout( 34, 44 ), 1, 'Spin 34 (35 Black), bet 44 pays 1';\nis payout( 34, 45 ), -1, 'Spin 34 (35 Black), bet 45 pays -1';\nis payout( 34, 46 ), 1, 'Spin 34 (35 Black), bet 46 pays 1';\nis payout( 34, 47 ), -1, 'Spin 34 (35 Black), bet 47 pays -1';\nis payout( 34, 48 ), 1, 'Spin 34 (35 Black), bet 48 pays 1';\nis payout( 34, 49 ), -1, 'Spin 34 (35 Black), bet 49 pays -1';\nis payout( 34, 50 ), -1, 'Spin 34 (35 Black), bet 50 pays -1';\nis format_spin( 35 ), '36 Red', 'Spin 35 is 36 Red';\nis payout( 35, 1 ), -1, 'Spin 35 (36 Red), bet 1 pays -1';\nis payout( 35, 2 ), -1, 'Spin 35 (36 Red), bet 2 pays -1';\nis payout( 35, 3 ), -1, 'Spin 35 (36 Red), bet 3 pays -1';\nis payout( 35, 4 ), -1, 'Spin 35 (36 Red), bet 4 pays -1';\nis payout( 35, 5 ), -1, 'Spin 35 (36 Red), bet 5 pays -1';\nis payout( 35, 6 ), -1, 'Spin 35 (36 Red), bet 6 pays -1';\nis payout( 35, 7 ), -1, 'Spin 35 (36 Red), bet 7 pays -1';\nis payout( 35, 8 ), -1, 'Spin 35 (36 Red), bet 8 pays -1';\nis payout( 35, 9 ), -1, 'Spin 35 (36 Red), bet 9 pays -1';\nis payout( 35, 10 ), -1, 'Spin 35 (36 Red), bet 10 pays -1';\nis payout( 35, 11 ), -1, 'Spin 35 (36 Red), bet 11 pays -1';\nis payout( 35, 12 ), -1, 'Spin 35 (36 Red), bet 12 pays -1';\nis payout( 35, 13 ), -1, 'Spin 35 (36 Red), bet 13 pays -1';\nis payout( 35, 14 ), -1, 'Spin 35 (36 Red), bet 14 pays -1';\nis payout( 35, 15 ), -1, 'Spin 35 (36 Red), bet 15 pays -1';\nis payout( 35, 16 ), -1, 'Spin 35 (36 Red), bet 16 pays -1';\nis payout( 35, 17 ), -1, 'Spin 35 (36 Red), bet 17 pays -1';\nis payout( 35, 18 ), -1, 'Spin 35 (36 Red), bet 18 pays -1';\nis payout( 35, 19 ), -1, 'Spin 35 (36 Red), bet 19 pays -1';\nis payout( 35, 20 ), -1, 'Spin 35 (36 Red), bet 20 pays -1';\nis payout( 35, 21 ), -1, 'Spin 35 (36 Red), bet 21 pays -1';\nis payout( 35, 22 ), -1, 'Spin 35 (36 Red), bet 22 pays -1';\nis payout( 35, 23 ), -1, 'Spin 35 (36 Red), bet 23 pays -1';\nis payout( 35, 24 ), -1, 'Spin 35 (36 Red), bet 24 pays -1';\nis payout( 35, 25 ), -1, 'Spin 35 (36 Red), bet 25 pays -1';\nis payout( 35, 26 ), -1, 'Spin 35 (36 Red), bet 26 pays -1';\nis payout( 35, 27 ), -1, 'Spin 35 (36 Red), bet 27 pays -1';\nis payout( 35, 28 ), -1, 'Spin 35 (36 Red), bet 28 pays -1';\nis payout( 35, 29 ), -1, 'Spin 35 (36 Red), bet 29 pays -1';\nis payout( 35, 30 ), -1, 'Spin 35 (36 Red), bet 30 pays -1';\nis payout( 35, 31 ), -1, 'Spin 35 (36 Red), bet 31 pays -1';\nis payout( 35, 32 ), -1, 'Spin 35 (36 Red), bet 32 pays -1';\nis payout( 35, 33 ), -1, 'Spin 35 (36 Red), bet 33 pays -1';\nis payout( 35, 34 ), -1, 'Spin 35 (36 Red), bet 34 pays -1';\nis payout( 35, 35 ), -1, 'Spin 35 (36 Red), bet 35 pays -1';\nis payout( 35, 36 ), 35, 'Spin 35 (36 Red), bet 36 pays 35';\nis payout( 35, 37 ), -1, 'Spin 35 (36 Red), bet 37 pays -1';\nis payout( 35, 38 ), -1, 'Spin 35 (36 Red), bet 38 pays -1';\nis payout( 35, 39 ), 2, 'Spin 35 (36 Red), bet 39 pays 2';\nis payout( 35, 40 ), -1, 'Spin 35 (36 Red), bet 40 pays -1';\nis payout( 35, 41 ), -1, 'Spin 35 (36 Red), bet 41 pays -1';\nis payout( 35, 42 ), 2, 'Spin 35 (36 Red), bet 42 pays 2';\nis payout( 35, 43 ), -1, 'Spin 35 (36 Red), bet 43 pays -1';\nis payout( 35, 44 ), 1, 'Spin 35 (36 Red), bet 44 pays 1';\nis payout( 35, 45 ), 1, 'Spin 35 (36 Red), bet 45 pays 1';\nis payout( 35, 46 ), -1, 'Spin 35 (36 Red), bet 46 pays -1';\nis payout( 35, 47 ), 1, 'Spin 35 (36 Red), bet 47 pays 1';\nis payout( 35, 48 ), -1, 'Spin 35 (36 Red), bet 48 pays -1';\nis payout( 35, 49 ), -1, 'Spin 35 (36 Red), bet 49 pays -1';\nis payout( 35, 50 ), -1, 'Spin 35 (36 Red), bet 50 pays -1';\nis format_spin( 36 ), '0', 'Spin 36 is 0';\nis payout( 36, 1 ), -1, 'Spin 36 (0), bet 1 pays -1';\nis payout( 36, 2 ), -1, 'Spin 36 (0), bet 2 pays -1';\nis payout( 36, 3 ), -1, 'Spin 36 (0), bet 3 pays -1';\nis payout( 36, 4 ), -1, 'Spin 36 (0), bet 4 pays -1';\nis payout( 36, 5 ), -1, 'Spin 36 (0), bet 5 pays -1';\nis payout( 36, 6 ), -1, 'Spin 36 (0), bet 6 pays -1';\nis payout( 36, 7 ), -1, 'Spin 36 (0), bet 7 pays -1';\nis payout( 36, 8 ), -1, 'Spin 36 (0), bet 8 pays -1';\nis payout( 36, 9 ), -1, 'Spin 36 (0), bet 9 pays -1';\nis payout( 36, 10 ), -1, 'Spin 36 (0), bet 10 pays -1';\nis payout( 36, 11 ), -1, 'Spin 36 (0), bet 11 pays -1';\nis payout( 36, 12 ), -1, 'Spin 36 (0), bet 12 pays -1';\nis payout( 36, 13 ), -1, 'Spin 36 (0), bet 13 pays -1';\nis payout( 36, 14 ), -1, 'Spin 36 (0), bet 14 pays -1';\nis payout( 36, 15 ), -1, 'Spin 36 (0), bet 15 pays -1';\nis payout( 36, 16 ), -1, 'Spin 36 (0), bet 16 pays -1';\nis payout( 36, 17 ), -1, 'Spin 36 (0), bet 17 pays -1';\nis payout( 36, 18 ), -1, 'Spin 36 (0), bet 18 pays -1';\nis payout( 36, 19 ), -1, 'Spin 36 (0), bet 19 pays -1';\nis payout( 36, 20 ), -1, 'Spin 36 (0), bet 20 pays -1';\nis payout( 36, 21 ), -1, 'Spin 36 (0), bet 21 pays -1';\nis payout( 36, 22 ), -1, 'Spin 36 (0), bet 22 pays -1';\nis payout( 36, 23 ), -1, 'Spin 36 (0), bet 23 pays -1';\nis payout( 36, 24 ), -1, 'Spin 36 (0), bet 24 pays -1';\nis payout( 36, 25 ), -1, 'Spin 36 (0), bet 25 pays -1';\nis payout( 36, 26 ), -1, 'Spin 36 (0), bet 26 pays -1';\nis payout( 36, 27 ), -1, 'Spin 36 (0), bet 27 pays -1';\nis payout( 36, 28 ), -1, 'Spin 36 (0), bet 28 pays -1';\nis payout( 36, 29 ), -1, 'Spin 36 (0), bet 29 pays -1';\nis payout( 36, 30 ), -1, 'Spin 36 (0), bet 30 pays -1';\nis payout( 36, 31 ), -1, 'Spin 36 (0), bet 31 pays -1';\nis payout( 36, 32 ), -1, 'Spin 36 (0), bet 32 pays -1';\nis payout( 36, 33 ), -1, 'Spin 36 (0), bet 33 pays -1';\nis payout( 36, 34 ), -1, 'Spin 36 (0), bet 34 pays -1';\nis payout( 36, 35 ), -1, 'Spin 36 (0), bet 35 pays -1';\nis payout( 36, 36 ), -1, 'Spin 36 (0), bet 36 pays -1';\nis payout( 36, 37 ), -1, 'Spin 36 (0), bet 37 pays -1';\nis payout( 36, 38 ), -1, 'Spin 36 (0), bet 38 pays -1';\nis payout( 36, 39 ), -1, 'Spin 36 (0), bet 39 pays -1';\nis payout( 36, 40 ), -1, 'Spin 36 (0), bet 40 pays -1';\nis payout( 36, 41 ), -1, 'Spin 36 (0), bet 41 pays -1';\nis payout( 36, 42 ), -1, 'Spin 36 (0), bet 42 pays -1';\nis payout( 36, 43 ), -1, 'Spin 36 (0), bet 43 pays -1';\nis payout( 36, 44 ), -1, 'Spin 36 (0), bet 44 pays -1';\nis payout( 36, 45 ), -1, 'Spin 36 (0), bet 45 pays -1';\nis payout( 36, 46 ), -1, 'Spin 36 (0), bet 46 pays -1';\nis payout( 36, 47 ), -1, 'Spin 36 (0), bet 47 pays -1';\nis payout( 36, 48 ), -1, 'Spin 36 (0), bet 48 pays -1';\nis payout( 36, 49 ), 35, 'Spin 36 (0), bet 49 pays 35';\nis payout( 36, 50 ), -1, 'Spin 36 (0), bet 50 pays -1';\nis format_spin( 37 ), '00', 'Spin 37 is 00';\nis payout( 37, 1 ), -1, 'Spin 37 (00), bet 1 pays -1';\nis payout( 37, 2 ), -1, 'Spin 37 (00), bet 2 pays -1';\nis payout( 37, 3 ), -1, 'Spin 37 (00), bet 3 pays -1';\nis payout( 37, 4 ), -1, 'Spin 37 (00), bet 4 pays -1';\nis payout( 37, 5 ), -1, 'Spin 37 (00), bet 5 pays -1';\nis payout( 37, 6 ), -1, 'Spin 37 (00), bet 6 pays -1';\nis payout( 37, 7 ), -1, 'Spin 37 (00), bet 7 pays -1';\nis payout( 37, 8 ), -1, 'Spin 37 (00), bet 8 pays -1';\nis payout( 37, 9 ), -1, 'Spin 37 (00), bet 9 pays -1';\nis payout( 37, 10 ), -1, 'Spin 37 (00), bet 10 pays -1';\nis payout( 37, 11 ), -1, 'Spin 37 (00), bet 11 pays -1';\nis payout( 37, 12 ), -1, 'Spin 37 (00), bet 12 pays -1';\nis payout( 37, 13 ), -1, 'Spin 37 (00), bet 13 pays -1';\nis payout( 37, 14 ), -1, 'Spin 37 (00), bet 14 pays -1';\nis payout( 37, 15 ), -1, 'Spin 37 (00), bet 15 pays -1';\nis payout( 37, 16 ), -1, 'Spin 37 (00), bet 16 pays -1';\nis payout( 37, 17 ), -1, 'Spin 37 (00), bet 17 pays -1';\nis payout( 37, 18 ), -1, 'Spin 37 (00), bet 18 pays -1';\nis payout( 37, 19 ), -1, 'Spin 37 (00), bet 19 pays -1';\nis payout( 37, 20 ), -1, 'Spin 37 (00), bet 20 pays -1';\nis payout( 37, 21 ), -1, 'Spin 37 (00), bet 21 pays -1';\nis payout( 37, 22 ), -1, 'Spin 37 (00), bet 22 pays -1';\nis payout( 37, 23 ), -1, 'Spin 37 (00), bet 23 pays -1';\nis payout( 37, 24 ), -1, 'Spin 37 (00), bet 24 pays -1';\nis payout( 37, 25 ), -1, 'Spin 37 (00), bet 25 pays -1';\nis payout( 37, 26 ), -1, 'Spin 37 (00), bet 26 pays -1';\nis payout( 37, 27 ), -1, 'Spin 37 (00), bet 27 pays -1';\nis payout( 37, 28 ), -1, 'Spin 37 (00), bet 28 pays -1';\nis payout( 37, 29 ), -1, 'Spin 37 (00), bet 29 pays -1';\nis payout( 37, 30 ), -1, 'Spin 37 (00), bet 30 pays -1';\nis payout( 37, 31 ), -1, 'Spin 37 (00), bet 31 pays -1';\nis payout( 37, 32 ), -1, 'Spin 37 (00), bet 32 pays -1';\nis payout( 37, 33 ), -1, 'Spin 37 (00), bet 33 pays -1';\nis payout( 37, 34 ), -1, 'Spin 37 (00), bet 34 pays -1';\nis payout( 37, 35 ), -1, 'Spin 37 (00), bet 35 pays -1';\nis payout( 37, 36 ), -1, 'Spin 37 (00), bet 36 pays -1';\nis payout( 37, 37 ), -1, 'Spin 37 (00), bet 37 pays -1';\nis payout( 37, 38 ), -1, 'Spin 37 (00), bet 38 pays -1';\nis payout( 37, 39 ), -1, 'Spin 37 (00), bet 39 pays -1';\nis payout( 37, 40 ), -1, 'Spin 37 (00), bet 40 pays -1';\nis payout( 37, 41 ), -1, 'Spin 37 (00), bet 41 pays -1';\nis payout( 37, 42 ), -1, 'Spin 37 (00), bet 42 pays -1';\nis payout( 37, 43 ), -1, 'Spin 37 (00), bet 43 pays -1';\nis payout( 37, 44 ), -1, 'Spin 37 (00), bet 44 pays -1';\nis payout( 37, 45 ), -1, 'Spin 37 (00), bet 45 pays -1';\nis payout( 37, 46 ), -1, 'Spin 37 (00), bet 46 pays -1';\nis payout( 37, 47 ), -1, 'Spin 37 (00), bet 47 pays -1';\nis payout( 37, 48 ), -1, 'Spin 37 (00), bet 48 pays -1';\nis payout( 37, 49 ), -1, 'Spin 37 (00), bet 49 pays -1';\nis payout( 37, 50 ), 35, 'Spin 37 (00), bet 50 pays 35';\n\ndone_testing;\n\n1;\n\n# ex: set textwidth=72 :\n"
  },
  {
    "path": "75_Roulette/perl/roulette.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse POSIX qw{ strftime };   # Time formatting\nuse Term::ReadLine;         # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\n# A main() function is not usual in Perl scripts. I have installed one\n# here to make the script into a \"modulino.\" The next line executes\n# main() if and only if caller() returns false. It will do this if we\n# were loaded by another Perl script but not otherwise. This was done so\n# I could test the payout and spin formatting logic.\nmain() unless caller;\n\nsub main {\n\n    print <<'EOD';\n                                ROULETTE\n               Creative Computing  Morristown, New Jersey\n\n\n\n\nWelcome to the roulette table.\n\nEOD\n\n    if ( get_yes_no( 'Do you want instructions' ) ) {\n        print <<'EOD';\n\nThis is the betting layout\n  (*=red)\n\n 1*    2     3*\n 4     5*    6\n 7*    8     9*\n10    11    12*\n---------------\n13    14*   15\n16*   17    18*\n19*   20    21*\n22    23*   24\n---------------\n25*   26    27*\n28    29    30*\n31    32*   33\n34*   35    36*\n---------------\n    00    0\n\nTypes of bets:\n\nThe numbers 1 to 36 signify a straight bet\non that number.\nThese pay off 35:1\n\nThe 2:1 bets are:\n 37) 1-12     40) first column\n 38) 13-24    41) second column\n 39) 25-36    42) third column\n\nThe even money bets are:\n 43) 1-18     46) odd\n 44) 19-36    47) red\n 45) even     48) black\n\n 49) 0 and 50) 00 pay off 35:1\n Note: 0 and 00 do not count under any\n       bets except their own.\n\nWhen I ask for each bet, type the number\nand the amount, separated by a comma.\nFor example: to bet $500 on black, type 48,500\nwhen I ask for a bet.\n\nThe minimum bet is $5, the maximum is $500.\n\nEOD\n}\n\n    my $P = 1000;\n    my $D = 100000.;\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        my $Y = get_input( 'How many bets? ',\n            sub { m/ \\A [0-9]+ \\z /smx && $ARG > 0 && $ARG <= 50 },\n            \"Please enter a positive integer no greater than 50\\n\",\n        );\n        my @B;\n        my @T;\n        foreach my $C ( 1 .. $Y ) {\n            my ( $X, $Z ) = split qr< , >smx, get_input(\n                \"Number $C: \",\n                sub { m/ \\A ( [0-9]+ ) , ( [0-9]+ ) \\z /smx\n                    && $1 > 0 && $1 <= 50 && $2 >= 5 && $2 <= 500 },\n                \"Please enter two comma-separated positive numbers\\n\",\n            );\n            if ( $B[$X] ) {\n                say 'You made that bet once already, dum-dum.';\n                redo;\n            }\n            $B[$X] = $Z;    # BASIC does $B[$C] = $Z\n            $T[$C] = $X;\n        }\n\n        print <<'EOD';\n\n    Spinning ...\n\nEOD\n        my $S = int rand 38;    # Zero-based, versus 1-based in BASIC\n\n        say format_spin( $S );\n\n        say '';\n\n        foreach my $C ( 1 .. $Y ) {\n            my $X = $T[$C];\n            my $payout = payout( $S, $X ) * $B[$X];\n            $D -= $payout;\n            $P += $payout;\n            if ( $payout > 0 ) {\n                say \"You win $payout dollars on bet $C\";\n            } else {\n                $payout = -$payout;\n                say \"You lose $payout dollars on bet $C\";\n            }\n        }\n        say \"Totals\\tMe\\tYou\";\n        say \"\\t$D\\t$P\";\n        say '';\n\n\n        last unless get_yes_no( 'Again' );\n    }\n\n    say '';\n\n    if ( $P > 0 ) {\n        my $B = get_input(\n            'To whom shall I make out the check? ',\n        );\n        my $check_number = 1000 + int rand 9000;\n        my $todays_date = strftime( '%B %d, %Y', localtime );\n        print <<\"EOD\";\n\n------------------------------------------------------------ Check number $check_number\n\n                                        $todays_date\n\nPay to the order of ------ $B -----  \\$$P\n\n          The Memory Bank of New York\n\n                                        The Computer\n                                        ---------X-----\n\n-------------------------------------------------------------------------------\n\nCome back soon!\nEOD\n    } else {\n        print <<'EOD';\nThanks for your money.\nI'll use it to buy a solid gold roulette wheel\nEOD\n    }\n}\n\n{\n    # Define the kind of each possible spin. 0 is '0' or '00', 1 is\n    # black, and 2 is red. We assign the values in a BEGIN block because\n    # execution never actually reaches this point in the script.\n    my @kind;\n    BEGIN {\n        @kind = ( 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1,\n            2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 0,\n            0 );\n    }\n\n    # Convert the spin (0-37) to its name on the wheel.\n    sub format_spin {\n        my ( $number ) = @_;\n        state $format = [\n            sub { '0' x ( $_[0] - 35 ) },\n            sub { sprintf '%s Black', $_[0] + 1 },\n            sub { sprintf '%s Red', $_[0] + 1 },\n        ];\n        return $format->[$kind[$number]]( $number );\n    }\n\n    # Compute the payout given the spin (0-37) and the bet (1-50).\n    sub payout {\n        my ( $number, $bet ) = @_;\n        # We compute the payout on '0' and '00' directly, since under\n        # our rules they are only eligible for the 35-to-1 bet.\n        $kind[$number]\n            or return $number == $bet - 49 + 36 ? 35 : -1;\n        --$bet; # #bet is 1-based coming in\n        # Dispatch table for computing the payout for spins 0-36.\n        state $payout = [\n            ( sub { $_[0] == $_[1] ? 35 : -1 } ) x 36,\n            ( sub { int( $_[0] / 12 ) == $_[1] - 36 ? 2 : -1 } ) x 3,\n            ( sub { $_[0] % 3 == $_[1] - 39 ? 2 : -1 } ) x 3,\n            ( sub { int( $_[0] / 18 ) == $_[1] - 42 ? 1 : -1 } ) x 2,\n            ( sub { $_[0] % 2 == 45 - $_[1] ? 1 : -1 } ) x 2,\n            ( sub { $kind[$_[0]] == 48 - $_[1] ? 1 : -1 } ) x 2,\n            ( sub { -1 } ) x 2, # Bet on '0' or '00' loses\n        ];\n        return $payout->[$bet]->( $number, $bet );\n    }\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n__END__\n\n=head1 TITLE\n\nroulette - Play the game 'Roulette' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n roulette.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of roulette, which is the 75th\nentry in Basic Computer Games.\n\nThe main internal changes are converting the roulette slot numbering to\n0-based and replacing most of the payout logic with a dispatch table.\nThese changes were tested for correctness against the original BASIC.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "75_Roulette/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "75_Roulette/python/roulette.py",
    "content": "import random\nfrom datetime import date\nfrom typing import List, Tuple\n\nglobal RED_NUMBERS\nRED_NUMBERS = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]\n\n\ndef print_instructions() -> None:\n    print(\n        \"\"\"\nTHIS IS THE BETTING LAYOUT\n  (*=RED)\n\n 1*    2     3*\n 4     5*    6\n 7*    8     9*\n10    11    12*\n---------------\n13    14*   15\n16*   17    18*\n19*   20    21*\n22    23*   24\n---------------\n25*   26    27*\n28    29    30*\n31    32*   33\n34*   35    36*\n---------------\n    00    0\n\nTYPES OF BETS\n\nTHE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\nON THAT NUMBER.\nTHESE PAY OFF 35:1\n\nTHE 2:1 BETS ARE:\n37) 1-12     40) FIRST COLUMN\n38) 13-24    41) SECOND COLUMN\n39) 25-36    42) THIRD COLUMN\n\nTHE EVEN MONEY BETS ARE:\n43) 1-18     46) ODD\n44) 19-36    47) RED\n45) EVEN     48) BLACK\n\n 49)0 AND 50)00 PAY OFF 35:1\nNOTE: 0 AND 00 DO NOT COUNT UNDER ANY\n   BETS EXCEPT THEIR OWN.\n\nWHEN I ASK FOR EACH BET, TYPE THE NUMBER\nAND THE AMOUNT, SEPARATED BY A COMMA.\nFOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\nWHEN I ASK FOR A BET.\n\nTHE MINIMUM BET IS $5, THE MAXIMUM IS $500.\n\n    \"\"\"\n    )\n\n\ndef query_bets() -> Tuple[List[int], List[int]]:\n    \"\"\"Queries the user to input their bets\"\"\"\n    bet_count = -1\n    while bet_count <= 0:\n        try:\n            bet_count = int(input(\"HOW MANY BETS? \"))\n        except Exception:\n            ...\n\n    bet_ids = [-1] * bet_count\n    bet_values = [0] * bet_count\n\n    for i in range(bet_count):\n        while bet_ids[i] == -1:\n            try:\n                in_string = input(f\"NUMBER {str(i + 1)}? \").split(\",\")\n                id_, val = int(in_string[0]), int(in_string[1])\n\n                # check other bet_IDs\n                for j in range(i):\n                    if id_ != -1 and bet_ids[j] == id_:\n                        id_ = -1\n                        print(\"YOU ALREADY MADE THAT BET ONCE, DUM-DUM\")\n                        break\n\n                if id_ > 0 and id_ <= 50 and val >= 5 and val <= 500:\n                    bet_ids[i] = id_\n                    bet_values[i] = val\n            except Exception:\n                pass\n    return bet_ids, bet_values\n\n\ndef bet_results(bet_ids: List[int], bet_values: List[int], result) -> int:\n    \"\"\"Computes the results, prints them, and returns the total net winnings\"\"\"\n    total_winnings = 0\n\n    def get_modifier(id_: int, num: int) -> int:\n        if (\n            (id_ == 37 and num <= 12)\n            or (id_ == 38 and num > 12 and num <= 24)\n            or (id_ == 39 and num > 24 and num < 37)\n            or (id_ == 40 and num < 37 and num % 3 == 1)\n            or (id_ == 41 and num < 37 and num % 3 == 2)\n            or (id_ == 42 and num < 37 and num % 3 == 0)\n        ):\n            return 2\n        elif (\n            (id_ == 43 and num <= 18)\n            or (id_ == 44 and num > 18 and num <= 36)\n            or (id_ == 45 and num % 2 == 0)\n            or (id_ == 46 and num % 2 == 1)\n            or (id_ == 47 and num in RED_NUMBERS)\n            or (id_ == 48 and num not in RED_NUMBERS)\n        ):\n            return 1\n        elif id_ < 37 and id_ == num:\n            return 35\n        else:\n            return -1\n\n    for i in range(len(bet_ids)):\n        winnings = bet_values[i] * get_modifier(bet_ids[i], result)\n        total_winnings += winnings\n\n        if winnings >= 0:\n            print(f\"YOU WIN {str(winnings)} DOLLARS ON BET {str(i + 1)}\")\n        else:\n            print(f\"YOU LOSE {str(winnings * -1)} DOLLARS ON BET {str(i + 1)}\")\n\n    return winnings\n\n\ndef print_check(amount: int) -> None:\n    \"\"\"Print a check of a given amount\"\"\"\n    name = input(\"TO WHOM SHALL I MAKE THE CHECK? \")\n\n    print(\"-\" * 72)\n    print()\n    print(\" \" * 40 + \"CHECK NO. \" + str(random.randint(0, 100)))\n    print(\" \" * 40 + str(date.today()))\n    print()\n    print(f\"PAY TO THE ORDER OF -----{name}----- ${amount}\")\n    print()\n    print(\" \" * 40 + \"THE MEMORY BANK OF NEW YORK\")\n    print(\" \" * 40 + \"THE COMPUTER\")\n    print(\" \" * 40 + \"----------X-----\")\n    print(\"-\" * 72)\n\n\ndef main() -> None:\n    player_balance = 1000\n    host_balance = 100000\n\n    print(\" \" * 32 + \"ROULETTE\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n    if string_to_bool(input(\"DO YOU WANT INSTRUCTIONS? \")):\n        print_instructions()\n\n    while True:\n        bet_ids, bet_values = query_bets()\n\n        print(\"SPINNING\")\n        print()\n        print()\n\n        val = random.randint(0, 38)\n        if val == 38:\n            print(\"0\")\n        elif val == 37:\n            print(\"00\")\n        elif val in RED_NUMBERS:\n            print(f\"{val} RED\")\n        else:\n            print(f\"{val} BLACK\")\n\n        print()\n        total_winnings = bet_results(bet_ids, bet_values, val)\n        player_balance += total_winnings\n        host_balance -= total_winnings\n\n        print()\n        print(\"TOTALS:\\tME\\t\\tYOU\")\n        print(\"\\t\\t\" + str(host_balance) + \"\\t\" + str(player_balance))\n\n        if player_balance <= 0:\n            print(\"OOPS! YOU JUST SPENT YOUR LAST DOLLAR!\")\n            break\n        elif host_balance <= 0:\n            print(\"YOU BROKE THE HOUSE!\")\n            player_balance = 101000\n            break\n        if not string_to_bool(input(\"PLAY AGAIN? \")):\n            break\n\n    if player_balance <= 0:\n        print(\"THANKS FOR YOUR MONEY\")\n        print(\"I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\")\n    else:\n        print_check(player_balance)\n    print(\"COME BACK SOON!\")\n\n\ndef string_to_bool(string: str) -> bool:\n    \"\"\"Converts a string to a bool\"\"\"\n    return string.lower() in {\"y\", \"true\", \"t\", \"yes\"}\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "75_Roulette/roulette.bas",
    "content": "10 PRINT TAB(32);\"ROULETTE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n40 PRINT \"ENTER THE CURRENT DATE (AS IN 'JANUARY 23, 1979') -\";\n50 INPUT D$,E$\n1000 REM-ROULETTE\n1010 REM-DAVID JOSLIN\n1020 PRINT \"WELCOME TO THE ROULETTE TABLE\"\n1030 PRINT\n1040 PRINT \"DO YOU WANT INSTRUCTIONS\";\n1050 INPUT Y$\n1060 IF LEFT$(Y$,1)=\"N\" THEN 1550\n1070 PRINT\n1080 PRINT \"THIS IS THE BETTING LAYOUT\"\n1090 PRINT \"  (*=RED)\"\n1100 PRINT\n1110 PRINT \" 1*    2     3*\"\n1120 PRINT \" 4     5*    6 \"\n1130 PRINT \" 7*    8     9*\"\n1140 PRINT \"10    11    12*\"\n1150 PRINT \"---------------\"\n1160 PRINT \"13    14*   15 \"\n1170 PRINT \"16*   17    18*\"\n1180 PRINT \"19*   20    21*\"\n1190 PRINT \"22    23*   24 \"\n1200 PRINT \"---------------\"\n1210 PRINT \"25*   26    27*\"\n1220 PRINT \"28    29    30*\"\n1230 PRINT \"31    32*   33 \"\n1240 PRINT \"34*   35    36*\"\n1250 PRINT \"---------------\"\n1260 PRINT \"    00    0    \"\n1270 PRINT\n1280 PRINT \"TYPES OF BETS\"\n1290 PRINT\n1300 PRINT \"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\"\n1310 PRINT \"ON THAT NUMBER.\"\n1320 PRINT \"THESE PAY OFF 35:1\"\n1330 PRINT\n1340 PRINT \"THE 2:1 BETS ARE:\"\n1350 PRINT \" 37) 1-12     40) FIRST COLUMN\"\n1360 PRINT \" 38) 13-24    41) SECOND COLUMN\"\n1370 PRINT \" 39) 25-36    42) THIRD COLUMN\"\n1380 PRINT\n1390 PRINT \"THE EVEN MONEY BETS ARE:\"\n1400 PRINT \" 43) 1-18     46) ODD\"\n1410 PRINT \" 44) 19-36    47) RED\"\n1420 PRINT \" 45) EVEN     48) BLACK\"\n1430 PRINT\n1440 PRINT \" 49)0 AND 50)00 PAY OFF 35:1\"\n1450 PRINT \" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\"\n1460 PRINT \"       BETS EXCEPT THEIR OWN.\"\n1470 PRINT\n1480 PRINT \"WHEN I ASK FOR EACH BET, TYPE THE NUMBER\"\n1490 PRINT \"AND THE AMOUNT, SEPARATED BY A COMMA.\"\n1500 PRINT \"FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\"\n1510 PRINT \"WHEN I ASK FOR A BET.\"\n1520 PRINT\n1530 PRINT \"THE MINIMUM BET IS $5, THE MAXIMUM IS $500.\"\n1540 PRINT\n1550 REM-PROGRAM BEGINS HERE\n1560 REM-TYPE OF BET(NUMBER) ODDS\n1570 REM  DON'T NEED TO DIMENSION STRINGS\n1580 DIM B(100),C(100),T(100),X(38)\n1590 DIM A(50)\n1600 FOR I=1 TO 38: X(I)=0: NEXT I: REM  MAT X=ZER\n1610 P=1000\n1620 D=100000.\n1630 PRINT \"HOW MANY BETS\";\n1640 INPUT Y\n1650 IF Y<1 OR Y<>INT(Y) THEN 1630\n1660 FOR I=1 TO 50: A(I)=0: NEXT I: REM  MAT A=ZER\n1670 FOR C=1 TO Y\n1680 PRINT \"NUMBER\";C;\n1690 INPUT X,Z\n1700 B(C)=Z\n1710 T(C)=X\n1720 IF X<1 OR X>50 OR X<>INT(X) THEN 1680\n1730 IF Z<1 OR Z<>INT(Z) THEN 1680\n1740 IF Z<5 OR Z>500 THEN 1680\n1750 IF A(X)=0 THEN 1780\n1760 PRINT \"YOU MADE THAT BET ONCE ALREADY,DUM-DUM\"\n1770 GOTO 1680\n1780 A(X)=1\n1790 NEXT C\n1800 PRINT \"SPINNING\"\n1810 PRINT\n1820 PRINT\n1830 S=INT(RND(1)*100)\n1840 IF S=0 OR S>38 THEN 1830\n1850 X(S)=X(S)+1\n1860 IF S<37 THEN 1920\n1870 IF S=37 THEN 1900\n1880 PRINT \"00\"\n1890 GOTO 2020\n1900 PRINT \"0\"\n1910 GOTO 2020\n1920 RESTORE\n1930 FOR I1=1 TO 18\n1940 READ R\n1950 IF R=S THEN 2000\n1960 NEXT I1\n1970 A$=\"BLACK\"\n1980 PRINT S;A$\n1990 GOTO 2020\n2000 A$=\"RED\"\n2010 GOTO 1980\n2020 PRINT\n2030 FOR C=1 TO Y\n2040 IF T(C)<37 THEN 2710\n2050 ON T(C)-36 GOTO 2090,2190,2220,2250,2300,2350,2400,2470,2500\n2060 ON T(C)-45 GOTO 2530,2560,2630\n2070 GOTO 2710\n2080 STOP\n2090 REM  1-12(37) 2:1\n2100 IF S <= 12 THEN 2150\n2110 PRINT \"YOU LOSE\";B(C);\"DOLLARS ON BET\";C\n2120 D=D+B(C)\n2130 P=P-B(C)\n2140 GOTO 2180\n2150 PRINT \"YOU WIN\";B(C)*2;\"DOLLARS ON BET\"C\n2160 D=D-B(C)*2\n2170 P=P+B(C)*2\n2180 GOTO 2810\n2190 REM  13-24(38) 2:1\n2200 IF S>12 AND S<25 THEN 2150\n2210 GOTO 2110\n2220 REM  25-36(39) 2:1\n2230 IF S>24 AND S<37 THEN 2150\n2240 GOTO 2110\n2250 REM  FIRST COLUMN(40) 2:1\n2260 FOR I=1 TO 34 STEP 3\n2270 IF S=I THEN 2150\n2280 NEXT I\n2290 GOTO 2110\n2300 REM  SECOND COLUMN(41) 2:1\n2310 FOR I=2 TO 35 STEP 3\n2320 IF S=I THEN 2150\n2330 NEXT I\n2340 GOTO 2110\n2350 REM  THIRD COLUMN(42) 2:1\n2360 FOR I=3 TO 36 STEP 3\n2370 IF S=I THEN 2150\n2380 NEXT I\n2390 GOTO 2110\n2400 REM  1-18(43) 1:1\n2410 IF S<19 THEN 2430\n2420 GOTO 2110\n2430 PRINT \"YOU WIN\";B(C);\"DOLLARS ON BET\";C\n2440 D=D-B(C)\n2450 P=P+B(C)\n2460 GOTO 2810\n2470 REM  19-36(44) 1:1\n2480 IF S<37 AND S>18 THEN 2430\n2490 GOTO 2110\n2500 REM  EVEN(45) 1:1\n2510 IF S/2=INT(S/2) AND S<37 THEN 2430\n2520 GOTO 2110\n2530 REM  ODD(46) 1:1\n2540 IF S/2<>INT(S/2) AND S<37 THEN 2430\n2550 GOTO 2110\n2560 REM  RED(47) 1:1\n2570 RESTORE\n2580 FOR I=1 TO 18\n2590 READ R\n2600 IF S=R THEN 2430\n2610 NEXT I\n2620 GOTO 2110\n2630 REM  BLACK(48) 1:1\n2640 RESTORE\n2650 FOR I=1 TO 18\n2660 READ R\n2670 IF S=R THEN 2110\n2680 NEXT I\n2690 IF S>36 THEN 2110\n2700 GOTO 2430\n2710 REM--1TO36,0,00(1-36,49,50)35:1\n2720 IF T(C)<49 THEN 2760\n2730 IF T(C)=49 AND S=37 THEN 2780\n2740 IF T(C)=50 AND S=38 THEN 2780\n2750 GOTO 2110\n2760 IF T(C)=S THEN 2780\n2770 GOTO 2110\n2780 PRINT \"YOU WIN\";B(C)*35;\"DOLLARS ON BET\";C\n2790 D=D-B(C)*35\n2800 P=P+B(C)*35\n2810 NEXT C\n2820 PRINT\n2830 PRINT \"TOTALS:\",\"ME\",\"YOU\"\n2840 PRINT \" \",D,P\n2850 IF P>0 THEN 2880\n2860 PRINT \"OOPS! YOU JUST SPENT YOUR LAST DOLLAR!\"\n2870 GOTO 3190\n2880 IF D>0 THEN 2920\n2890 PRINT \"YOU BROKE THE HOUSE!\"\n2900 P=101000.\n2910 GOTO 2960\n2920 PRINT \"AGAIN\";\n2930 INPUT Y$\n2940 IF LEFT$(Y$,1)=\"Y\" THEN 1630\n2950 DATA 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36\n2960 IF P<1 THEN 3190\n2970 PRINT \"TO WHOM SHALL I MAKE THE CHECK\";\n2980 INPUT B$\n2990 PRINT\n3000 FOR I=1 TO 72: PRINT \"-\";: NEXT I: REM PRINT 72 DASHES\n3010 PRINT TAB(50);\"CHECK NO. \";INT(RND(1)*100)\n3020 PRINT\n3030 GOSUB 3230\n3040 PRINT TAB(40);M$\n3050 PRINT\n3060 PRINT\n3070 PRINT \"PAY TO THE ORDER OF-----\";B$;\"-----$ \";\n3080 PRINT P\n3090 PRINT\n3100 PRINT\n3110 PRINT TAB(10),\"THE MEMORY BANK OF NEW YORK\"\n3120 PRINT\n3130 PRINT TAB(40),\"THE COMPUTER\"\n3140 PRINT TAB(40)\"----------X-----\"\n3150 PRINT\n3160 FOR I=1 TO 62: PRINT \"-\";: NEXT I\n3170 PRINT \"COME BACK SOON!\"\n3180 GOTO 3210\n3190 PRINT \"THANKS FOR YOUR MONEY.\"\n3200 PRINT \"I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\"\n3210 PRINT\n3220 GOTO 3420\n3230 REM\n3240 REM     THIS ROUTINE RETURNS THE CURRENT DATE IN M$\n3250 REM     IF YOU HAVE SYSTEM FUNCTIONS TO HANDLE THIS\n3260 REM     THEY CAN BE USED HERE.  HOWEVER IN THIS\n3270 REM     PROGRAM, WE JUST INPUT THE DATE AT THE START\n3280 REM     THE GAME\n3290 REM\n3300 REM     THE DATE IS RETURNED IN VARIABLE M$\n3310 M$=D$+\", \"+E$\n3320 RETURN\n3420 END\n"
  },
  {
    "path": "75_Roulette/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "75_Roulette/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmorristown = \"0.1.4\"\nrand = \"0.8.5\"\n"
  },
  {
    "path": "75_Roulette/rust/src/main.rs",
    "content": "mod util;\n\nuse morristown::{Instructions, PromptMultiOption};\nuse rand::Rng;\nuse util::INSTRUCTIONS;\n\nfn main() {\n    morristown::print_intro(\"ROULETTE\");\n\n    let date = morristown::prompt_multi_string(\n        \"ENTER CURRENT DATE (AS IN 'JANUARY 23, 1978)\",\n        \",\",\n        Some(PromptMultiOption::UnitAmount(2)),\n    );\n\n    Instructions::new_multiline(\n        true,\n        false,\n        \"DO YOU WANT INSTRUCTIONS?\",\n        INSTRUCTIONS.to_vec(),\n    )\n    .print();\n\n    let mut house: usize = 100000;\n    let mut player: usize = 1000;\n\n    loop {\n        let bet_count = morristown::prompt_number_range::<u8>(\"HOW MANY BETS?\", 1..=10);\n        let mut bets: Vec<Vec<usize>> = Vec::new();\n\n        for i in 1..=bet_count {\n            loop {\n                let msg = format!(\"NUMBER {}?\", i);\n                let bet_input = morristown::prompt_multi_number::<usize>(\n                    msg.as_str(),\n                    \",\",\n                    Some(PromptMultiOption::UnitAmount(2)),\n                    None,\n                );\n                let (bet_num, wager) = (bet_input[0], bet_input[1]);\n\n                if let Some(_) = bets.iter().find(|bet| bet[0] == bet_num) {\n                    println!(\"YOU MADE THAT BET ONCE ALREADY, DUM-DUM\");\n                } else if bet_num > 0 && bet_num <= 50 && wager >= 5 && wager <= 500 {\n                    bets.push(bet_input);\n                    player -= wager;\n                    house += wager;\n                    break;\n                } else if wager > player {\n                    println!(\"NOT ENOUGH MONEY\")\n                } else {\n                    println!(\"INVALID BET. TRY AGAIN\");\n                }\n            }\n        }\n\n        println!(\"\\nSPINNING\");\n        std::thread::sleep(std::time::Duration::from_secs(1));\n        let spin: u8 = rand::thread_rng().gen_range(1..=38);\n\n        let color = if util::REDS.contains(&spin) {\n            \"RED\"\n        } else {\n            \"BLACK\"\n        };\n\n        println!(\"\\n{} {}\\n\", spin, color);\n\n        for (i, bet) in bets.iter().enumerate() {\n            let (bet_num, wager) = (bet[0] as u8, bet[1]);\n            let (win, payoff) = util::process_bet(bet_num, spin);\n\n            let msg = if win {\n                let pay = wager * payoff as usize;\n                player += wager + pay;\n                house -= pay;\n                \"WIN\"\n            } else {\n                \"LOSE\"\n            };\n\n            println!(\"YOU {msg} {wager} DOLLARS ON BET {}\", i + 1);\n        }\n\n        println!(\"\\nTOTALS:\\t\\tME\\t\\tYOU\");\n        println!(\"\\t\\t{house}\\t\\t{player}\");\n\n        if player <= 0 {\n            println!(\"OOPS! YOU JUST SPENT YOUR LAST DOLLAR\");\n            println!(\"THANKS FOR YOUR MONEY\");\n            println!(\"I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\");\n            break;\n        }\n\n        if house <= 0 {\n            println!(\"YOU BROKE THE HOUSE!\");\n            util::print_check(player, date);\n            break;\n        }\n\n        if !morristown::prompt_bool(\"AGAIN?\", false) {\n            util::print_check(player, date);\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "75_Roulette/rust/src/util.rs",
    "content": "use std::ops::RangeInclusive;\n\nuse rand::{thread_rng, Rng};\n\npub const INSTRUCTIONS: [&str; 38] = [\n    \"\\nTHIS IS THE BETTING LAYOUT\",\n    \"\\n(*=RED)\\n\",\n    \"1*\\t2\\t3*\",\n    \"4\\t5*\\t6\",\n    \"7*\\t8\\t9*\",\n    \"10\\t11\\t12*\",\n    \"--------------------\",\n    \"13\\t14*\\t15\",\n    \"16*\\t17\\t18*\",\n    \"19*\\t20\\t21*\",\n    \"22\\t23*\\t24\",\n    \"--------------------\",\n    \"25*\\t26\\t27*\",\n    \"28\\t29\\t30*\",\n    \"31\\t32*\\t33\",\n    \"34*\\t35\\t36*\",\n    \"--------------------\",\n    \"     00      0\\n\",\n    \"TYPES OF BETS\\n\",\n    \"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\",\n    \"ON THAT NUMBER\",\n    \"THESE PAY OFF 35:1\\n\",\n    \"THE 2:1 BETS ARE:\",\n    \"37) 1-12\\t40) FIRST COLUMN\",\n    \"38) 13-24\\t41) SECOND COLUMN\",\n    \"39) 25-36\\t42) THIRD COLUMN\\n\",\n    \"THE EVEN MONEY BETS ARE:\",\n    \"43) 1-18\\t46) ODD\",\n    \"44) 19-36\\t47) RED\",\n    \"45) EVEN\\t48) BLACK\\n\",\n    \"\\n49)0 AND 50)00 PAY OFF 35:1\",\n    \"NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\",\n    \"\\tBETS EXCEPT THEIR OWN\\n\",\n    \"WHEN I ASK FOR EACH BET,TYPE THE NUMBER\",\n    \"AND THE AMOUNT,SEPARATED BY A COMMA\",\n    \"FOR EXAMPLE:TO BET $500 ON BLACK,TYPE 48,500\",\n    \"WHEN I ASK FOR A BET\\n\",\n    \"MINIMUM BET IS $5,MAXIMUM IS $500\\n\",\n];\n\npub const REDS: [u8; 18] = [\n    1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36,\n];\n\npub fn process_bet(bet_num: u8, spin: u8) -> (bool, u8) {\n    match bet_num {\n        1..=36 => (bet_num == spin, 35),\n        37 => (is_within_range(1..=12, spin), 2),\n        38 => (is_within_range(13..=24, spin), 2),\n        39 => (is_within_range(25..=36, spin), 2),\n        40 => (spin % 3 == 1, 2),\n        41 => (spin % 3 == 2, 2),\n        42 => (spin % 3 == 0, 2),\n        43 => (is_within_range(1..=18, spin), 1),\n        44 => (is_within_range(19..=36, spin), 1),\n        45 => (spin % 2 == 0, 1),\n        46 => (spin % 2 == 1, 1),\n        47 => (REDS.contains(&spin), 1),\n        48 => (!REDS.contains(&spin), 1),\n        _ => {\n            println!(\"##INVALID BET##\");\n            return (false, 0);\n        }\n    }\n}\n\nfn is_within_range(r: RangeInclusive<u8>, n: u8) -> bool {\n    r.contains(&n)\n}\n\npub fn print_check(money: usize, date: Vec<String>) {\n    let name = morristown::prompt_string(\"TO WHOM SHALL I MAKE THE CHECK?\");\n    let check_no = thread_rng().gen_range(1..=100);\n\n    let dashes = 60;\n\n    println!(\"\\n{}\", \"-\".repeat(dashes));\n    println!(\"CHECK NO.  {}\\n\", check_no);\n    println!(\"{}{}, {}\\n\\n\", \"\\t\".repeat(4), date[0], date[1]);\n    println!(\"PAY TO THE ORDER OF-----{name}-----$  {money}\\n\\n\");\n    println!(\"\\t\\tTHE MEMORY BANK OF VIRGINIA\\n\");\n    println!(\"\\t\\t\\t\\tTHE COMPUTER\");\n    println!(\"\\t\\t\\t      ----------X-----\\t\");\n    println!(\"{}\", \"-\".repeat(dashes));\n    println!(\"COME BACK SOON!\\n\")\n}\n"
  },
  {
    "path": "75_Roulette/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "75_Roulette/vbnet/Roulette.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Roulette\", \"Roulette.vbproj\", \"{B2D2B22C-D332-4153-8ACF-E8136283FBC7}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "75_Roulette/vbnet/Roulette.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Roulette</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "76_Russian_Roulette/README.md",
    "content": "### Russian Roulette\n\nIn this game, you are given by the computer a revolver loaded with one bullet and five empty chambers. You spin the chamber and pull the trigger by inputting a “1,” or, if you want to quit, input a “2.” You win if you play ten times and are still alive.\n\nTom Adametx wrote this program while a student at Curtis Jr. High School in Sudbury, Massachusetts.\n\n⚠️ This game includes EXPLICT references to suicide, and should not be included in most distributions, especially considering the extreme simplicity of the program.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=141)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=153)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "76_Russian_Roulette/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace RussianRoulette\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            PrintTitle();\n\n            var includeRevolver = true;\n            while (true)\n            {\n                PrintInstructions(includeRevolver);\n                switch (PlayGame())\n                {\n                    case GameResult.Win:\n                        includeRevolver = true;\n                        break;\n                    case GameResult.Chicken:\n                    case GameResult.Dead:\n                        includeRevolver = false;\n                        break;\n                }\n            }\n        }\n\n        private static void PrintTitle()\n        {\n            Console.WriteLine(\"           Russian Roulette\");\n            Console.WriteLine(\"Creative Computing  Morristown, New Jersey\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"This is a game of >>>>>>>>>>Russian Roulette.\");\n        }\n\n        private static void PrintInstructions(bool includeRevolver)\n        {\n            Console.WriteLine();\n            if (includeRevolver)\n            {\n                Console.WriteLine(\"Here is a revolver.\");\n            }\n            else\n            {\n                Console.WriteLine();\n                Console.WriteLine();\n                Console.WriteLine(\"...Next Victim...\");\n            }\n            Console.WriteLine(\"Type '1' to spin chamber and pull trigger.\");\n            Console.WriteLine(\"Type '2' to give up.\");\n        }\n\n        private static GameResult PlayGame()\n        {\n            var rnd = new Random();\n            var round = 0;\n            while (true)\n            {\n                round++;\n                Console.Write(\"Go: \");\n                var input = Console.ReadKey().KeyChar;\n                Console.WriteLine();\n                if (input != '2')\n                {\n                    // Random.Next will retun a value that is the same or greater than the minimum and\n                    // less than the maximum.\n                    // A revolver has 6 rounds.\n                    if (rnd.Next(1, 7) == 6)\n                    {\n                        Console.WriteLine(\"     Bang!!!!!   You're dead!\");\n                        Console.WriteLine(\"Condolences will be sent to your relatives.\");\n                        return GameResult.Dead;\n                    }\n                    else\n                    {\n                        if (round > 10)\n                        {\n                            Console.WriteLine(\"You win!!!!!\");\n                            Console.WriteLine(\"Let someone else blow their brains out.\");\n                            return GameResult.Win;\n                        }\n                        else\n                        {\n                            Console.WriteLine(\"- CLICK -\");\n                            Console.WriteLine();\n                        }\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(\"     CHICKEN!!!!!\");\n                    return GameResult.Chicken;\n                }\n            }\n        }\n\n        private enum GameResult\n        {\n            Win,\n            Chicken,\n            Dead\n        }\n    }\n}\n"
  },
  {
    "path": "76_Russian_Roulette/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "76_Russian_Roulette/csharp/RussianRoulette.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "76_Russian_Roulette/csharp/RussianRoulette.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31019.35\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"RussianRoulette\", \"RussianRoulette.csproj\", \"{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {97F5B1B0-A80A-4C1F-9F76-8D68B4A49E82}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "76_Russian_Roulette/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "76_Russian_Roulette/java/src/RussianRoulette.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Russian Roulette Paper\n * <p>\n * Based on the Basic game of Russian Roulette here\n * https://github.com/coding-horror/basic-computer-games/blob/main/76%20Russian%20Roulette/russianroulette.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\npublic class RussianRoulette {\n\n    public static final int BULLETS_IN_CHAMBER = 10;\n    public static final double CHANCE_OF_GETTING_SHOT = .833333d;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        INIT,\n        GAME_START,\n        FIRE_BULLET,\n        NEXT_VICTIM\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    int bulletsShot;\n\n    public RussianRoulette() {\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.INIT;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case INIT:\n                    intro();\n                    gameState = GAME_STATE.GAME_START;\n\n                    break;\n\n                case GAME_START:\n                    bulletsShot = 0;\n                    System.out.println();\n                    System.out.println(\"HERE IS A REVOLVER.\");\n                    System.out.println(\"TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\");\n                    System.out.println(\"TYPE '2' TO GIVE UP.\");\n                    gameState = GAME_STATE.FIRE_BULLET;\n                    break;\n\n                case FIRE_BULLET:\n\n                    int choice = displayTextAndGetNumber(\"GO \");\n\n                    // Anything but selecting give up = have a shot\n                    if (choice != 2) {\n                        bulletsShot++;\n                        if (Math.random() > CHANCE_OF_GETTING_SHOT) {\n                            System.out.println(\"     BANG!!!!!   YOU'RE DEAD!\");\n                            System.out.println(\"CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\");\n                            gameState = GAME_STATE.NEXT_VICTIM;\n                        } else if (bulletsShot > BULLETS_IN_CHAMBER) {\n                            System.out.println(\"YOU WIN!!!!!\");\n                            System.out.println(\"LET SOMEONE ELSE BLOW HIS BRAINS OUT.\");\n                            gameState = GAME_STATE.GAME_START;\n                        } else {\n                            // Phew player survived this round\n                            System.out.println(\"- CLICK -\");\n                        }\n                    } else {\n                        // Player gave up\n                        System.out.println(\"     CHICKEN!!!!!\");\n                        gameState = GAME_STATE.NEXT_VICTIM;\n\n                    }\n                    break;\n\n                case NEXT_VICTIM:\n                    System.out.println(\"...NEXT VICTIM...\");\n                    gameState = GAME_STATE.GAME_START;\n            }\n            // Infinite loop - based on original basic version\n        } while (true);\n    }\n\n    private void intro() {\n        System.out.println(addSpaces(28) + \"RUSSIAN ROULETTE\");\n        System.out.println(addSpaces(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\");\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.nextLine();\n    }\n\n    /**\n     * Return a string of x spaces\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String addSpaces(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    public static void main(String[] args) {\n\n        RussianRoulette russianRoulette = new RussianRoulette();\n        russianRoulette.play();\n    }\n}\n"
  },
  {
    "path": "76_Russian_Roulette/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "76_Russian_Roulette/javascript/russianroulette.html",
    "content": "<html>\n<head>\n<title>RUSSIAN ROULETTE</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"russianroulette.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "76_Russian_Roulette/javascript/russianroulette.js",
    "content": "// RUSSIAN ROULETTE\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(28) + \"RUSSIAN ROULETTE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\\n\");\n    restart = true;\n    while (1) {\n        if (restart) {\n            restart = false;\n            print(\"\\n\");\n            print(\"HERE IS A REVOLVER.\\n\");\n        }\n        print(\"TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\\n\");\n        print(\"TYPE '2' TO GIVE UP.\\n\");\n        print(\"GO\");\n        n = 0;\n        while (1) {\n            i = parseInt(await input());\n            if (i == 2) {\n                print(\"     CHICKEN!!!!!\\n\");\n                break;\n            }\n            n++;\n            if (Math.random() > 0.833333) {\n                print(\"     BANG!!!!!   YOU'RE DEAD!\\n\");\n                print(\"CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\\n\");\n                break;\n            }\n            if (n > 10) {\n                print(\"YOU WIN!!!!!\\n\");\n                print(\"LET SOMEONE ELSE BLOW HIS BRAINS OUT.\\n\");\n                restart = true;\n                break;\n            }\n            print(\"- CLICK -\\n\");\n            print(\"\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"...NEXT VICTIM...\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "76_Russian_Roulette/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "76_Russian_Roulette/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "76_Russian_Roulette/lua/russianroulette.lua",
    "content": "print [[\n                    RUSSIAN ROULETTE\n        CREATIVE COMPUTING  MORRISTOWN, NEW JERSY\nThis is a game of >>>>>>>>>>Russian Roulette\nHere is a Revolver\n\n]]\n\nlocal function parse_input()\n    local incorrect_input = true\n    local input = nil\n    while incorrect_input do\n        input = io.read(1)\n        if input == \"1\" or input == \"2\" then incorrect_input = false end\n    end\n    return input\nend\n\nlocal function russian_roulette()\n    local NUMBER_OF_ROUNDS = 9\n\n    while true do\n        local dead = false\n        local n = 0\n        print(\"Type '1' to Spin chamber and pull trigger\")\n        print(\"Type '2' to Give up\")\n        print(\"Go\")\n\n        while not dead do\n            local choice = parse_input()\n            if choice == \"2\" then break end\n\n            if math.random() > 0.833333333333334 then\n                dead = true\n            else\n                print(\"CLICK\")\n                n = n + 1\n            end\n\n            if n > NUMBER_OF_ROUNDS then break end\n        end\n\n        if dead then\n            print(\"BANG!!!!!   You're Dead!\")\n            print(\"Condolences will be sent to your relatives.\\n\\n\\n\")\n            print(\"...Next victim...\")\n        elseif n > NUMBER_OF_ROUNDS then\n            print(\"You win!!!!!\")\n            print(\"Let someone else blow his brain out.\\n\")\n        else\n            print(\"     Chicken!!!!!\\n\\n\\n\")\n            print(\"...Next victim....\")\n        end\n    end\nend\n\nrussian_roulette()\n\n"
  },
  {
    "path": "76_Russian_Roulette/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "76_Russian_Roulette/perl/russianroulette.pl",
    "content": "#!/usr/bin/perl\n#use strict;\n# Automatic converted by bas2perl.pl\n\nprint ' 'x28 . \"RUSSIAN ROULETTE\\n\";\nprint ' 'x15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\\n\";\nLine10:\nprint \"\\n\"; print \"HERE IS A REVOLVER.\\n\";\nLine20:\nprint \"TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\\n\";\nprint \"TYPE '2' TO GIVE UP.\\n\";\nprint \"GO\";\n$N=0;\nLine30:\nprint \"? \"; chomp($I = <STDIN>);\nif ($I ne 2) { goto Line35; }\nprint \" CHICKEN!!!!!\\n\";\ngoto Line72;\nLine35:\n$N=$N+1;\nif (rand(1)>.833333) { goto Line70; }\nif ($N>10) { goto Line80; }\nprint \"- CLICK -\\n\";\nprint \"\\n\"; goto Line30;\nLine70:\nprint \" BANG!!!!! YOU'RE DEAD!\\n\";\nprint \"CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\\n\";\nLine72:\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nprint \"...NEXT VICTIM...\\n\"; goto Line20;\nLine80:\nprint \"YOU WIN!!!!!\\n\";\nprint \"LET SOMEONE ELSE BLOW HIS BRAINS OUT.\\n\";\ngoto Line10;\nexit;\n"
  },
  {
    "path": "76_Russian_Roulette/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "76_Russian_Roulette/python/russianroulette.py",
    "content": "\"\"\"\nRussian Roulette\n\nFrom Basic Computer Games (1978)\n\n   In this game, you are given by the computer a\n  revolver loaded with one bullet and five empty\n  chambers. You spin the chamber and pull the trigger\n  by inputting a \"1\", or, if you want to quit, input\n  a \"2\". You win if you play ten times and are still\n  alive.\n   Tom Adametx wrote this program while a student at\n  Curtis Jr. High School in Sudbury, Massachusetts.\n\"\"\"\n\n\nfrom random import random\n\nNUMBER_OF_ROUNDS = 9\n\n\ndef initial_message() -> None:\n    print(\" \" * 28 + \"Russian Roulette\")\n    print(\" \" * 15 + \"Creative Computing  Morristown, New Jersey\\n\\n\\n\")\n    print(\"This is a game of >>>>>>>>>>Russian Roulette.\\n\")\n    print(\"Here is a Revolver.\")\n\n\ndef parse_input() -> int:\n    while True:\n        try:\n            return int(input(\"? \"))\n        except ValueError:\n            print(\"Number expected...\")\n\n\ndef main() -> None:\n    initial_message()\n    while True:\n        dead = False\n        n = 0\n        print(\"Type '1' to Spin chamber and pull trigger\")\n        print(\"Type '2' to Give up\")\n        print(\"Go\")\n        while not dead:\n            i = parse_input()\n\n            if i == 2:\n                break\n\n            if random() > 0.8333333333333334:\n                dead = True\n            else:\n                print(\"- CLICK -\\n\")\n                n += 1\n\n            if n > NUMBER_OF_ROUNDS:\n                break\n        if dead:\n            print(\"BANG!!!!!   You're Dead!\")\n            print(\"Condolences will be sent to your relatives.\\n\\n\\n\")\n            print(\"...Next victim...\")\n        elif n > NUMBER_OF_ROUNDS:\n            print(\"You win!!!!!\")\n            print(\"Let someone else blow his brain out.\\n\")\n        else:\n            print(\"     Chicken!!!!!\\n\\n\\n\")\n            print(\"...Next victim....\")\n\n\nif __name__ == \"__main__\":\n    main()\n\n########################################################\n# Porting Notes\n#\n#    Altough the description says that accepts \"1\" or \"2\",\n#   the original game accepts any number as input, and\n#   if it's different of \"2\" the program considers\n#   as if the user had passed \"1\". That feature was\n#   kept in this port.\n#    Also, in the original game you must \"pull the trigger\"\n#   11 times instead of 10 in orden to win,\n#   given that N=0 at the beginning and the condition to\n#   win is \"IF N > 10 THEN  80\". That was fixed in this\n#   port, asking the user to pull the trigger only ten\n#   times, tough the number of round can be set changing\n#   the constant NUMBER_OF_ROUNDS.\n#\n########################################################\n"
  },
  {
    "path": "76_Russian_Roulette/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "76_Russian_Roulette/ruby/russianroulette.rb",
    "content": "puts <<~INSTRUCTIONS\n                            RUSSIAN ROULETTE\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nTHIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\n\nHERE IS A REVOLVER.\n\nINSTRUCTIONS\n\nNUMBER_OF_ROUNDS = 9\n\ndef parse_input\n    correct_input = false\n\n    while not correct_input\n        puts \" ?\"\n        inp = gets.chomp\n        if inp == \"1\" or inp == \"2\"\n            correct_input = true\n        end\n    end\n\n    inp\nend\n\nwhile true\n\n    dead = false\n    n = 0\n\n    puts \"TYPE \\'1\\' TO SPIN CHAMBER AND PULL TRIGGER\"\n    puts \"TYPE \\'2\\' TO GIVE UP\"\n    puts \"GO\"\n\n    while not dead\n\n        inp = parse_input\n\n        if inp == \"2\"\n            break\n        end\n\n        if rand > 0.8333333333333334\n            dead = true\n        else\n            puts \"- CLICK -\"\n            n += 1\n        end\n\n        if n > NUMBER_OF_ROUNDS\n            break\n        end\n\n    end\n\n    if dead\n        puts \"BANG!!!!!   You're Dead!\"\n        puts \"Condolences will be sent to your relatives.\\n\\n\\n\"\n        puts \"...Next victim...\"\n    else\n        if n > NUMBER_OF_ROUNDS\n            puts \"You win!!!!!\"\n            puts \"Let someone else blow his brain out.\\n\"\n        else\n            puts \"     Chicken!!!!!\\n\\n\\n\"\n            puts \"...Next victim....\"\n        end\n    end\n\nend\n"
  },
  {
    "path": "76_Russian_Roulette/russianroulette.bas",
    "content": "1 PRINT TAB(28);\"RUSSIAN ROULETTE\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n5 PRINT \"THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\"\n10 PRINT:PRINT \"HERE IS A REVOLVER.\"\n20 PRINT \"TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\"\n22 PRINT \"TYPE '2' TO GIVE UP.\"\n23 PRINT \"GO\";\n25 N=0\n30 INPUT I\n31 IF I<>2 THEN 35\n32 PRINT \"     CHICKEN!!!!!\"\n33 GOTO 72\n35 N=N+1\n40 IF RND(1)>.833333 THEN 70\n45 IF N>10 THEN 80\n50 PRINT \"- CLICK -\"\n60 PRINT: GOTO 30\n70 PRINT \"     BANG!!!!!   YOU'RE DEAD!\"\n71 PRINT \"CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\"\n72 PRINT:PRINT:PRINT\n75 PRINT \"...NEXT VICTIM...\":GOTO 20\n80 PRINT \"YOU WIN!!!!!\"\n85 PRINT \"LET SOMEONE ELSE BLOW HIS BRAINS OUT.\"\n90 GOTO 10\n99 END\n"
  },
  {
    "path": "76_Russian_Roulette/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "76_Russian_Roulette/rust/src/main.rs",
    "content": "use std::time::Duration;\n\nuse rand::Rng;\n\nfn main() {\n    println!(\"\\n\\t\\tRUSSIAN ROULETTE\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\");\n    println!(\"\\nTHIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\\n\");\n    println!(\"HERE IS A REVOLVER.\");\n\n    loop {\n        println!(\"TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER\");\n        println!(\"TYPE '2' TO GIVE UP.\");\n        println!(\"GO\");\n\n        let mut tries = 0;\n\n        loop {\n            let mut pull_trigger = true;\n\n            loop {\n                println!(\"?\");\n                let mut input = String::new();\n\n                std::io::stdin()\n                    .read_line(&mut input)\n                    .expect(\"Error reading line!\");\n\n                match input.trim() {\n                    \"1\" => break,\n                    \"2\" => {\n                        pull_trigger = false;\n                        break;\n                    }\n                    _ => println!(\"Invalid input.\"),\n                }\n            }\n\n            if pull_trigger {\n                std::thread::sleep(Duration::from_secs(1));\n\n                match rand::thread_rng().gen_range(0..6) {\n                    0 => {\n                        println!(\"\\tBANG!!!!!   YOU'RE DEAD!\");\n                        println!(\"CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\");\n                        println!(\"\\n\\n...NEXT VICTIM...\");\n                        break;\n                    }\n                    _ => {\n                        println!(\"- CLICK -\");\n                        tries += 1;\n                    }\n                }\n\n                if tries >= 10 {\n                    println!(\"YOU WIN!!!!!\");\n                    println!(\"LET SOMEONE ELSE BLOW HIS BRAINS OUT.\\n\");\n                    break;\n                }\n            } else {\n                println!(\"\\tCHICKEN!!!!!\");\n                println!(\"\\n\\n...NEXT VICTIM...\");\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "76_Russian_Roulette/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "76_Russian_Roulette/vbnet/RussianRoulette.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"RussianRoulette\", \"RussianRoulette.vbproj\", \"{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "76_Russian_Roulette/vbnet/RussianRoulette.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>RussianRoulette</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "77_Salvo/README.md",
    "content": "### Salvo\n\nThe rules are _not_ explained by the program, so read carefully this description by Larry Siegel, the program author.\n\nSALVO is played on a 10x10 grid or board using an x,y coordinate system. The player has 4 ships:\n- battleship (5 squares)\n- cruiser (3 squares)\n- two destroyers (2 squares each)\n\nThe ships may be placed horizontally, vertically, or diagonally and must not overlap. The ships do not move during the game.\n\nAs long as any square of a battleship still survives, the player is allowed three shots, for a cruiser 2 shots, and for each destroyer 1 shot. Thus, at the beginning of the game the player has 3+2+1+1=7 shots. The players enters all of his shots and the computer tells what was hit. A shot is entered by its grid coordinates, x,y. The winner is the one who sinks all of the opponents ships.\n\nImportant note: Your ships are located and the computer’s ships are located on 2 _separate_ 10x10 boards.\n\nAuthor of the program is Lawrence Siegel of Shaker Heights, Ohio.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=142)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=157)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\nThe program does no validation of ship positions; your ship coordinates may be scattered around the board in any way you like.  (Computer ships will not do this, but they may be placed diagonally in such a way that they cross each other.)  Scattering your ships in this way probably defeats whatever all that spaghetti-code logic the computer is using to pick its moves, which is based on the assumption of contiguous ships.\n\nMoreover: as per the analysis in\n\nhttps://forums.raspberrypi.com/viewtopic.php?p=1997950#p1997950\n\nsee also the earlier post\n\nhttps://forums.raspberrypi.com/viewtopic.php?p=1994961#p1994961\n\nin the same thread, there is a typo in later published versions of the SALVO Basic source code compared to the original edition of 101 Basic Computer Games.\n\nThis typo is interesting because it causes the program to play by a much weaker strategy while exhibiting no other obvious side effects. I would recommend changing the line 3970 in the Basic program back to the original\n\n`3970 K(R,S)=K(R,S)+E(U)-2*INT(H(U)+.5)`\n\nand to change the JavaScript program accordingly.  (And note that some ports — looking at you, Python — do not implement the original strategy at all, but merely pick random unshot locations for every shot.)\n\n"
  },
  {
    "path": "77_Salvo/csharp/Coordinate.cs",
    "content": "namespace Salvo;\n\ninternal record struct Coordinate(int Value)\n{\n    public const int MinValue = 1;\n    public const int MaxValue = 10;\n\n    public static IEnumerable<Coordinate> Range => Enumerable.Range(1, 10).Select(v => new Coordinate(v));\n\n    public bool IsInRange => Value is >= MinValue and <= MaxValue;\n\n    public static Coordinate Create(float value) => new((int)value);\n\n    public static bool TryCreateValid(float value, out Coordinate coordinate)\n    {\n        coordinate = default;\n        if (value != (int)value) { return false; }\n\n        var result = Create(value);\n\n        if (result.IsInRange)\n        {\n            coordinate = result;\n            return true;\n        }\n\n        return false;\n    }\n\n    public Coordinate BringIntoRange(IRandom random)\n        => Value switch\n        {\n            < MinValue => new(MinValue + (int)random.NextFloat(2.5F)),\n            > MaxValue => new(MaxValue - (int)random.NextFloat(2.5F)),\n            _ => this\n        };\n\n    public static implicit operator Coordinate(float value) => Create(value);\n    public static implicit operator int(Coordinate coordinate) => coordinate.Value;\n\n    public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset);\n    public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value;\n\n    public override string ToString() => $\" {Value} \";\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Extensions/IOExtensions.cs",
    "content": "namespace Games.Common.IO;\n\ninternal static class IOExtensions\n{\n    internal static Position ReadPosition(this IReadWrite io) => Position.Create(io.Read2Numbers(\"\"));\n\n    internal static Position ReadValidPosition(this IReadWrite io)\n    {\n        while (true)\n        {\n            if (Position.TryCreateValid(io.Read2Numbers(\"\"), out var position)) \n            { \n                return position; \n            }\n            io.Write(Streams.Illegal);\n        }\n    }\n\n    internal static IEnumerable<Position> ReadPositions(this IReadWrite io, string shipName, int shipSize)\n    {\n        io.WriteLine(shipName);\n        for (var i = 0; i < shipSize; i++)\n        {\n             yield return io.ReadPosition();\n        }\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Extensions/RandomExtensions.cs",
    "content": "namespace Games.Common.Randomness;\n\ninternal static class RandomExtensions\n{\n    internal static (Position, Offset) NextShipPosition(this IRandom random)\n    {\n        var startX = random.NextCoordinate();\n        var startY = random.NextCoordinate();\n        var deltaY = random.NextOffset();\n        var deltaX = random.NextOffset();\n        return (new(startX, startY), new(deltaX, deltaY));\n    }\n\n    private static Coordinate NextCoordinate(this IRandom random)\n        => random.Next(Coordinate.MinValue, Coordinate.MaxValue + 1);\n\n    private static int NextOffset(this IRandom random) => random.Next(-1, 2);\n\n    internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom random, int shipSize)\n    {\n        while (true)\n        {\n            var (start, delta) = random.NextShipPosition();\n            var shipSizeLessOne = shipSize - 1;\n            var end = start + delta * shipSizeLessOne;\n            if (delta != 0 && end.IsInRange) \n            {\n                return (start, delta);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Fleet.cs",
    "content": "using System.Collections.Immutable;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Salvo;\n\ninternal class Fleet\n{\n    private readonly List<Ship> _ships;\n\n    internal Fleet(IReadWrite io)\n    {\n        io.WriteLine(Prompts.Coordinates);\n        _ships = new()\n        {\n            new Battleship(io),\n            new Cruiser(io),\n            new Destroyer(\"A\", io),\n            new Destroyer(\"B\", io)\n        };\n    }\n\n    internal Fleet(IRandom random)\n    {\n        _ships = new();\n        while (true)\n        {\n            _ships.Add(new Battleship(random));\n            if (TryPositionShip(() => new Cruiser(random)) &&\n                TryPositionShip(() => new Destroyer(\"A\", random)) &&\n                TryPositionShip(() => new Destroyer(\"B\", random)))\n            {\n                return;\n            } \n            _ships.Clear();\n        }\n\n        bool TryPositionShip(Func<Ship> shipFactory)\n        {\n            var shipGenerationAttempts = 0;\n            while (true)\n            {\n                var ship = shipFactory.Invoke();\n                shipGenerationAttempts++;\n                if (shipGenerationAttempts > 25) { return false; }\n                if (_ships.Min(ship.DistanceTo) >= 3.59)\n                {\n                    _ships.Add(ship);\n                    return true; \n                }\n            }\n        }\n    }\n\n    internal IEnumerable<Ship> Ships => _ships.AsEnumerable();\n\n    internal void ReceiveShots(IEnumerable<Position> shots, Action<Ship> reportHit)\n    {\n        foreach (var position in shots)\n        {\n            var ship = _ships.FirstOrDefault(s => s.IsHit(position));\n            if (ship == null) { continue; }\n            if (ship.IsDestroyed) { _ships.Remove(ship); }\n            reportHit(ship);\n        }\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Game.cs",
    "content": "namespace Salvo;\n\ninternal class Game \n{\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    public Game(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    internal void Play()\n    {\n        _io.Write(Streams.Title);\n\n        var turnHandler = new TurnHandler(_io, _random);\n        _io.WriteLine();\n\n        Winner? winner;\n        do \n        {\n            winner = turnHandler.PlayTurn();\n        } while (winner == null);\n\n        _io.Write(winner == Winner.Computer ? Streams.IWon : Streams.YouWon);\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Offset.cs",
    "content": "namespace Salvo;\n\ninternal record struct Offset(int X, int Y)\n{\n    public static readonly Offset Zero = 0;\n\n    public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale);\n\n    public static implicit operator Offset(int value) => new(value, value);\n\n    public static IEnumerable<Offset> Units\n    {\n        get\n        {\n            for (int x = -1; x <= 1; x++)\n            {\n                for (int y = -1; y <= 1; y++)\n                {\n                    var offset = new Offset(x, y);\n                    if (offset != Zero) { yield return offset; }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Position.cs",
    "content": "namespace Salvo;\n\ninternal record struct Position(Coordinate X, Coordinate Y)\n{\n    public bool IsInRange => X.IsInRange && Y.IsInRange;\n    public bool IsOnDiagonal => X == Y;\n\n    public static Position Create((float X, float Y) coordinates) => new(coordinates.X, coordinates.Y);\n\n    public static bool TryCreateValid((float X, float Y) coordinates, out Position position)\n    {\n        if (Coordinate.TryCreateValid(coordinates.X, out var x) && Coordinate.TryCreateValid(coordinates.Y, out var y))\n        {\n            position = new(x, y);\n            return true;\n        }\n\n        position = default;\n        return false;\n    }\n\n    public static IEnumerable<Position> All\n        => Coordinate.Range.SelectMany(x => Coordinate.Range.Select(y => new Position(x, y)));\n\n    public IEnumerable<Position> Neighbours\n    {\n        get\n        {\n            foreach (var offset in Offset.Units)\n            {\n                var neighbour = this + offset;\n                if (neighbour.IsInRange) { yield return neighbour; }\n            }\n        }\n    }\n\n    internal float DistanceTo(Position other)\n    {\n        var (deltaX, deltaY) = (X - other.X, Y - other.Y);\n        return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);\n    }\n\n    internal Position BringIntoRange(IRandom random)\n        => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random));\n\n    public static Position operator +(Position position, Offset offset) \n        => new(position.X + offset.X, position.Y + offset.Y);\n\n    public static implicit operator Position(int value) => new(value, value);\n\n    public override string ToString() => $\"{X}{Y}\";\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Program.cs",
    "content": "global using System;\nglobal using Games.Common.IO;\nglobal using Games.Common.Randomness;\nglobal using Salvo;\nglobal using Salvo.Ships;\nglobal using static Salvo.Resources.Resource;\n\n//new Game(new ConsoleIO(), new RandomNumberGenerator()).Play();\nnew Game(new ConsoleIO(), new DataRandom()).Play();\n"
  },
  {
    "path": "77_Salvo/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/Coordinates.txt",
    "content": "Enter coordinates for...\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt",
    "content": "I have more shots than blank squares.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/IHaveShots.txt",
    "content": "I have {0} shots.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/IHit.txt",
    "content": "I hit your {0}\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/IWon.txt",
    "content": "I have won.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/Illegal.txt",
    "content": "Illegal, enter again.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/Resource.cs",
    "content": "using System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Salvo.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Title => GetStream();\n        public static Stream YouHaveMoreShotsThanSquares => GetStream();\n        public static Stream YouWon => GetStream();\n        public static Stream IHaveMoreShotsThanSquares => GetStream();\n        public static Stream IWon => GetStream();\n        public static Stream Illegal => GetStream();\n    }\n\n    internal static class Strings\n    {\n        public static string WhereAreYourShips => GetString();\n        public static string YouHaveShots(int number) => Format(number);\n        public static string IHaveShots(int number) => Format(number);\n        public static string YouHit(string shipName) => Format(shipName);\n        public static string IHit(string shipName) => Format(shipName);\n        public static string ShotBefore(int turnNumber) => Format(turnNumber);\n        public static string Turn(int number) => Format(number);\n    }\n\n    internal static class Prompts\n    {\n        public static string Coordinates => GetString();\n        public static string Start => GetString();\n        public static string SeeShots => GetString();\n    }\n\n    private static string Format<T>(T value, [CallerMemberName] string? name = null) \n        => string.Format(GetString(name), value);\n\n    private static string GetString([CallerMemberName] string? name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string? name = null) =>\n        Assembly.GetExecutingAssembly().GetManifestResourceStream($\"{typeof(Resource).Namespace}.{name}.txt\")\n            ?? throw new Exception($\"Could not find embedded resource stream '{name}'.\");\n}"
  },
  {
    "path": "77_Salvo/csharp/Resources/SeeShots.txt",
    "content": "Do you want to see my shots"
  },
  {
    "path": "77_Salvo/csharp/Resources/ShotBefore.txt",
    "content": "You shot there before on turn {0}\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/Start.txt",
    "content": "Do you want to start"
  },
  {
    "path": "77_Salvo/csharp/Resources/Title.txt",
    "content": "                                Salvo\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/Turn.txt",
    "content": "\nTurn {0}\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/WhereAreYourShips.txt",
    "content": "Where are your ships?"
  },
  {
    "path": "77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt",
    "content": "You have more shots than there are blank squares.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/YouHaveShots.txt",
    "content": "You have {0} shots.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/YouHit.txt",
    "content": "You hit my {0}.\n"
  },
  {
    "path": "77_Salvo/csharp/Resources/YouWon.txt",
    "content": "You have won.\n"
  },
  {
    "path": "77_Salvo/csharp/Salvo.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>11</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "77_Salvo/csharp/Salvo.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Salvo\", \"Salvo.csproj\", \"{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "77_Salvo/csharp/Ships/Battleship.cs",
    "content": "namespace Salvo.Ships;\n\ninternal sealed class Battleship : Ship\n{\n    internal Battleship(IReadWrite io) \n        : base(io) \n    { \n    }\n\n    internal Battleship(IRandom random)\n        : base(random)\n    {\n    }\n\n    internal override int Shots => 3;\n    internal override int Size => 5;\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Ships/Cruiser.cs",
    "content": "namespace Salvo.Ships;\n\ninternal sealed class Cruiser : Ship\n{\n    internal Cruiser(IReadWrite io) \n        : base(io) \n    { \n    }\n    \n    internal Cruiser(IRandom random)\n        : base(random)\n    {\n    }\n\n    internal override int Shots => 2;\n    internal override int Size => 3;\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Ships/Destroyer.cs",
    "content": "namespace Salvo.Ships;\n\ninternal sealed class Destroyer : Ship\n{\n    internal Destroyer(string nameIndex, IReadWrite io)\n        : base(io, $\"<{nameIndex}>\")\n    {\n    }\n\n    internal Destroyer(string nameIndex, IRandom random)\n        : base(random, $\"<{nameIndex}>\")\n    {\n    }\n\n    internal override int Shots => 1;\n    internal override int Size => 2;\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Ships/Ship.cs",
    "content": "namespace Salvo.Ships;\n\ninternal abstract class Ship\n{\n    private readonly List<Position> _positions = new();\n\n    protected Ship(IReadWrite io, string? nameSuffix = null)\n    {\n        Name = GetType().Name + nameSuffix;\n        _positions = io.ReadPositions(Name, Size).ToList();\n    }\n\n    protected Ship(IRandom random, string? nameSuffix = null)\n    {\n        Name = GetType().Name + nameSuffix;\n\n        var (start, delta) = random.GetRandomShipPositionInRange(Size);\n        for (var i = 0; i < Size; i++)\n        {\n            _positions.Add(start + delta * i);\n        }\n    }\n\n    internal string Name { get; }\n    internal abstract int Shots { get; }\n    internal abstract int Size { get; }\n    internal bool IsDamaged => _positions.Count > 0 && _positions.Count < Size;\n    internal bool IsDestroyed => _positions.Count == 0;\n\n    internal bool IsHit(Position position) => _positions.Remove(position);\n\n    internal float DistanceTo(Ship other)\n        => _positions.SelectMany(a => other._positions.Select(b => a.DistanceTo(b))).Min();\n\n    public override string ToString() \n        => string.Join(Environment.NewLine, _positions.Select(p => p.ToString()).Prepend(Name));\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Targetting/ComputerShotSelector.cs",
    "content": "namespace Salvo.Targetting;\n\ninternal class ComputerShotSelector : ShotSelector\n{\n    private readonly KnownHitsShotSelectionStrategy _knownHitsStrategy;\n    private readonly SearchPatternShotSelectionStrategy _searchPatternStrategy;\n    private readonly IReadWrite _io;\n    private readonly bool _showShots;\n\n    internal ComputerShotSelector(Fleet source, IRandom random, IReadWrite io) \n        : base(source)\n    {\n        _knownHitsStrategy = new KnownHitsShotSelectionStrategy(this);\n        _searchPatternStrategy = new SearchPatternShotSelectionStrategy(this, random);\n        _io = io;\n        _showShots = io.ReadString(Prompts.SeeShots).Equals(\"yes\", StringComparison.InvariantCultureIgnoreCase);\n    }\n\n    protected override IEnumerable<Position> GetShots()\n    {\n        var shots = GetSelectionStrategy().GetShots(NumberOfShots).ToArray();\n        if (_showShots)\n        {\n            _io.WriteLine(string.Join(Environment.NewLine, shots));\n        }\n        return shots;\n    }\n\n    internal void RecordHit(Ship ship, int turn) => _knownHitsStrategy.RecordHit(ship, turn);\n\n    private ShotSelectionStrategy GetSelectionStrategy()\n        => _knownHitsStrategy.KnowsOfDamagedShips ? _knownHitsStrategy : _searchPatternStrategy;\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Targetting/HumanShotSelector.cs",
    "content": "namespace Salvo.Targetting;\n\ninternal class HumanShotSelector : ShotSelector\n{\n    private readonly IReadWrite _io;\n\n    internal HumanShotSelector(Fleet source, IReadWrite io) \n        : base(source)\n    {\n        _io = io;\n    }\n\n    protected override IEnumerable<Position> GetShots()\n    {\n        var shots = new Position[NumberOfShots];\n        \n        for (var i = 0; i < shots.Length; i++)\n        {\n            while (true)\n            {\n                var position = _io.ReadValidPosition();\n                if (WasSelectedPreviously(position, out var turnTargeted)) \n                { \n                    _io.WriteLine($\"YOU SHOT THERE BEFORE ON TURN {turnTargeted}\");\n                    continue;\n                }\n                shots[i] = position;\n                break;\n            }\n        }\n\n        return shots;\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs",
    "content": "namespace Salvo.Targetting;\n\ninternal class KnownHitsShotSelectionStrategy : ShotSelectionStrategy\n{\n    private readonly List<(int Turn, Ship Ship)> _damagedShips = new();\n\n    internal KnownHitsShotSelectionStrategy(ShotSelector shotSelector)\n        : base(shotSelector)\n    {\n    }\n\n    internal bool KnowsOfDamagedShips => _damagedShips.Any();\n\n    internal override IEnumerable<Position> GetShots(int numberOfShots)\n    {\n        var tempGrid = Position.All.ToDictionary(x => x, _ => 0);\n        var shots = Enumerable.Range(1, numberOfShots).Select(x => new Position(x, x)).ToArray();\n\n        foreach (var (hitTurn, ship) in _damagedShips)\n        {\n            foreach (var position in Position.All)\n            {\n                if (WasSelectedPreviously(position))\n                {  \n                    tempGrid[position]=-10000000;\n                    continue;\n                }\n\n                foreach (var neighbour in position.Neighbours)    \n                {\n                    if (WasSelectedPreviously(neighbour, out var turn) && turn == hitTurn)\n                    {\n                        tempGrid[position] += hitTurn + 10 - position.Y * ship.Shots;\n                    }\n                }\n            }\n        }\n\n        foreach (var position in Position.All)\n        {\n            var Q9=0;\n            for (var i = 0; i < numberOfShots; i++)\n            {\n                if (tempGrid[shots[i]] < tempGrid[shots[Q9]]) \n                { \n                    Q9 = i;\n                }\n            }\n            if (position.X <= numberOfShots && position.IsOnDiagonal) { continue; }\n            if (tempGrid[position]<tempGrid[shots[Q9]]) { continue; }\n            if (!shots.Contains(position))\n            {\n                shots[Q9] = position;\n            }\n        }\n\n        return shots;\n    } \n\n    internal void RecordHit(Ship ship, int turn)\n    {\n        if (ship.IsDestroyed) \n        {\n            _damagedShips.RemoveAll(x => x.Ship == ship);\n        }\n        else\n        {\n            _damagedShips.Add((turn, ship));\n        }\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Targetting/SearchPattern.cs",
    "content": "using System.Collections.Immutable;\n\nnamespace Salvo.Targetting;\n\ninternal class SearchPattern\n{\n    private static readonly ImmutableArray<Offset> _offsets =\n        ImmutableArray.Create<Offset>(new(1, 1), new(-1, 1), new(1, -3), new(1, 1), new(0, 2), new(-1, 1));\n\n    private int _nextIndex;\n\n    internal bool TryGetOffset(out Offset offset)\n    {\n        offset = default;\n        if (_nextIndex >= _offsets.Length) { return false; }\n        \n        offset = _offsets[_nextIndex++];\n        return true;\n    }\n\n    internal void Reset() => _nextIndex = 0;\n}"
  },
  {
    "path": "77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs",
    "content": "namespace Salvo.Targetting;\n\ninternal class SearchPatternShotSelectionStrategy : ShotSelectionStrategy\n{\n    private const int MaxSearchPatternAttempts = 100;\n    private readonly IRandom _random;\n    private readonly SearchPattern _searchPattern = new();\n    private readonly List<Position> _shots = new();\n\n    internal SearchPatternShotSelectionStrategy(ShotSelector shotSelector, IRandom random) \n        : base(shotSelector)\n    {\n        _random = random;\n    }\n\n    internal override IEnumerable<Position> GetShots(int numberOfShots)\n    {\n        _shots.Clear();\n        while(_shots.Count < numberOfShots)\n        {\n            var (seed, _) = _random.NextShipPosition();\n            SearchFrom(numberOfShots, seed);\n        }\n        return _shots;\n    }\n\n    private void SearchFrom(int numberOfShots, Position candidateShot)\n    {\n        var attemptsLeft = MaxSearchPatternAttempts;\n        while (true)\n        {\n            _searchPattern.Reset();\n            if (attemptsLeft-- == 0) { return; }\n            candidateShot = candidateShot.BringIntoRange(_random);\n            if (FindValidShots(numberOfShots, ref candidateShot)) { return; }\n        }\n    }\n\n    private bool FindValidShots(int numberOfShots, ref Position candidateShot)\n    {\n        while (true)\n        {\n            if (IsValidShot(candidateShot))\n            {\n                _shots.Add(candidateShot);\n                if (_shots.Count == numberOfShots) { return true; }\n            }\n            if (!_searchPattern.TryGetOffset(out var offset)) { return false; }\n            candidateShot += offset;\n        }\n    }\n\n    private bool IsValidShot(Position candidate)\n        => candidate.IsInRange && !WasSelectedPreviously(candidate) && !_shots.Contains(candidate);\n}"
  },
  {
    "path": "77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs",
    "content": "namespace Salvo.Targetting;\n\ninternal abstract class ShotSelectionStrategy\n{\n    private readonly ShotSelector _shotSelector;\n    protected ShotSelectionStrategy(ShotSelector shotSelector)\n    {\n        _shotSelector = shotSelector;\n    }\n\n    internal abstract IEnumerable<Position> GetShots(int numberOfShots);\n\n    protected bool WasSelectedPreviously(Position position) => _shotSelector.WasSelectedPreviously(position);\n\n    protected bool WasSelectedPreviously(Position position, out int turn)\n        => _shotSelector.WasSelectedPreviously(position, out turn);\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Targetting/ShotSelector.cs",
    "content": "namespace Salvo.Targetting;\n\ninternal abstract class ShotSelector\n{\n    private readonly Fleet _source;\n    private readonly Dictionary<Position, int> _previousShots = new();\n\n    internal ShotSelector(Fleet source)\n    {\n        _source = source;\n    }\n\n    internal int NumberOfShots => _source.Ships.Sum(s => s.Shots);\n    internal bool CanTargetAllRemainingSquares => NumberOfShots >= 100 - _previousShots.Count;\n\n    internal bool WasSelectedPreviously(Position position) => _previousShots.ContainsKey(position);\n\n    internal bool WasSelectedPreviously(Position position, out int turn)\n        => _previousShots.TryGetValue(position, out turn);\n\n    internal IEnumerable<Position> GetShots(int turnNumber)\n    {\n        foreach (var shot in GetShots())\n        {\n            _previousShots.Add(shot, turnNumber);\n            yield return shot;\n        }\n    }\n\n    protected abstract IEnumerable<Position> GetShots();\n}\n"
  },
  {
    "path": "77_Salvo/csharp/TurnHandler.cs",
    "content": "using Salvo.Targetting;\n\nnamespace Salvo;\n\ninternal class TurnHandler\n{\n    private readonly IReadWrite _io;\n    private readonly Fleet _humanFleet;\n    private readonly Fleet _computerFleet;\n    private readonly bool _humanStarts;\n    private readonly HumanShotSelector _humanShotSelector;\n    private readonly ComputerShotSelector _computerShotSelector;\n    private readonly Func<Winner?> _turnAction;\n    private int _turnNumber;\n\n    public TurnHandler(IReadWrite io, IRandom random)\n    {\n        _io = io;\n        _computerFleet = new Fleet(random);\n        _humanFleet = new Fleet(io);\n        _turnAction = AskWhoStarts()\n            ? () => PlayHumanTurn() ?? PlayComputerTurn()\n            : () => PlayComputerTurn() ?? PlayHumanTurn();\n        _humanShotSelector = new HumanShotSelector(_humanFleet, io);\n        _computerShotSelector = new ComputerShotSelector(_computerFleet, random, io);\n    }\n\n    public Winner? PlayTurn()\n    {\n        _io.Write(Strings.Turn(++_turnNumber));\n        return _turnAction.Invoke();\n    }\n\n    private bool AskWhoStarts()\n    {\n        while (true)\n        {\n            var startResponse = _io.ReadString(Prompts.Start);\n            if (startResponse.Equals(Strings.WhereAreYourShips, StringComparison.InvariantCultureIgnoreCase))\n            {\n                foreach (var ship in _computerFleet.Ships)\n                {\n                    _io.WriteLine(ship);\n                }\n            }\n            else\n            {\n                return startResponse.Equals(\"yes\", StringComparison.InvariantCultureIgnoreCase);\n            }\n        }\n    }\n\n    private Winner? PlayComputerTurn()\n    {\n        var numberOfShots = _computerShotSelector.NumberOfShots;\n        _io.Write(Strings.IHaveShots(numberOfShots));\n        if (numberOfShots == 0) { return Winner.Human; }\n        if (_computerShotSelector.CanTargetAllRemainingSquares)\n        {\n            _io.Write(Streams.IHaveMoreShotsThanSquares);\n            return Winner.Computer;\n        }\n\n        _humanFleet.ReceiveShots(\n            _computerShotSelector.GetShots(_turnNumber),\n            ship =>\n            { \n                _io.Write(Strings.IHit(ship.Name));\n                _computerShotSelector.RecordHit(ship, _turnNumber);\n            });\n\n        return null;\n    }\n\n    private Winner? PlayHumanTurn()\n    {\n        var numberOfShots = _humanShotSelector.NumberOfShots;\n        _io.Write(Strings.YouHaveShots(numberOfShots));\n        if (numberOfShots == 0) { return Winner.Computer; }\n        if (_humanShotSelector.CanTargetAllRemainingSquares) \n        { \n            _io.WriteLine(Streams.YouHaveMoreShotsThanSquares);\n            return Winner.Human;\n        }\n        \n        _computerFleet.ReceiveShots(\n            _humanShotSelector.GetShots(_turnNumber), \n            ship => _io.Write(Strings.YouHit(ship.Name)));\n        \n        return null;\n    }\n}\n"
  },
  {
    "path": "77_Salvo/csharp/Winner.cs",
    "content": "namespace Salvo;\n\ninternal enum Winner\n{\n    Human,\n    Computer\n}\n"
  },
  {
    "path": "77_Salvo/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "77_Salvo/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "77_Salvo/javascript/salvo.html",
    "content": "<html>\n<head>\n<title>SALVO</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"salvo.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "77_Salvo/javascript/salvo.js",
    "content": "// SALVO\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar aa = [];\nvar ba = [];\nvar ca = [];\nvar da = [];\nvar ea = [];\nvar fa = [];\nvar ga = [];\nvar ha = [];\nvar ka = [];\nvar w;\nvar r3;\nvar x;\nvar y;\nvar v;\nvar v2;\n\nfunction sgn(k)\n{\n    if (k < 0)\n        return -1;\n    if (k > 0)\n        return 1;\n    return 0;\n}\n\nfunction fna(k)\n{\n    return (5 - k) * 3 - 2 * Math.floor(k / 4) + sgn(k - 1) - 1;\n}\n\nfunction fnb(k)\n{\n    return k + Math.floor(k / 4) - sgn(k - 1);\n}\n\nfunction generate_random()\n{\n    x = Math.floor(Math.random() * 10 + 1);\n    y = Math.floor(Math.random() * 10 + 1);\n    v = Math.floor(3 * Math.random() - 1);\n    v2 = Math.floor(3 * Math.random() - 1);\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"SALVO\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    z8 = 0;\n    for (w = 1; w <= 12; w++) {\n        ea[w] = -1;\n        ha[w] = -1;\n    }\n    for (x = 1; x <= 10; x++) {\n        ba[x] = [];\n        ka[x] = [];\n        for (y = 1; y <= 10; y++) {\n            ba[x][y] = 0;\n            ka[x][y] = 0;\n        }\n    }\n    for (x = 1; x <= 12; x++) {\n        fa[x] = 0;\n        ga[x] = 0;\n    }\n    for (x = 1; x <= 10; x++) {\n        aa[x] = [];\n        for (y = 1; y <= 10; y++) {\n            aa[x][y] = 0;\n        }\n    }\n    u6 = 0;\n    for (k = 4; k >= 1; k--) {\n        do {\n            generate_random();\n        } while (v + v2 + v * v2 == 0 || y + v * fnb(k) > 10 || y + v * fnb(k) < 1 || x + v2 * fnb(k) > 10 || x + v2 * fnb(k) < 1) ;\n        u6++;\n        if (u6 > 25) {\n            for (x = 1; x <= 10; x++) {\n                aa[x] = [];\n                for (y = 1; y <= 10; y++) {\n                    aa[x][y] = 0;\n                }\n            }\n            u6 = 0;\n            k = 5;\n            continue;\n        }\n        for (z = 0; z <= fnb(k); z++) {\n            fa[z + fna(k)] = x + v2 * z;\n            ga[z + fna(k)] = y + v * z;\n        }\n        u8 = fna(k);\n        if (u8 <= u8 + fnb(k)) {\n            retry = false;\n            for (z2 = u8; z2 <= u8 + fnb(k); z2++) {\n                if (u8 >= 2) {\n                    for (z3 = 1; z3 < u8 - 1; z3++) {\n                        if (Math.sqrt(Math.pow((fa[z3] - fa[z2]), 2)) + Math.pow((ga[z3] - ga[z2]), 2) < 3.59) {\n                            retry = true;\n                            break;\n                        }\n                    }\n                    if (retry)\n                        break;\n                }\n            }\n            if (retry) {\n                k++;\n                continue;\n            }\n        }\n        for (z = 0; z <= fnb(k); z++) {\n            if (k - 1 < 0)\n                sk = -1;\n            else if (k - 1 > 0)\n                sk = 1;\n            else\n                sk = 0;\n            aa[fa[z + u8]][ga[z + u8]] = 0.5 + sk * (k - 1.5);\n        }\n        u6 = 0;\n    }\n    print(\"ENTER COORDINATES FOR...\\n\");\n    print(\"BATTLESHIP\\n\");\n    for (x = 1; x <= 5; x++) {\n        str = await input();\n        y = parseInt(str);\n        z = parseInt(str.substr(str.indexOf(\",\") + 1));\n        ba[y][z] = 3;\n    }\n    print(\"CRUISER\\n\");\n    for (x = 1; x <= 3; x++) {\n        str = await input();\n        y = parseInt(str);\n        z = parseInt(str.substr(str.indexOf(\",\") + 1));\n        ba[y][z] = 2;\n    }\n    print(\"DESTROYER<A>\\n\");\n    for (x = 1; x <= 2; x++) {\n        str = await input();\n        y = parseInt(str);\n        z = parseInt(str.substr(str.indexOf(\",\") + 1));\n        ba[y][z] = 1;\n    }\n    print(\"DESTROYER<B>\\n\");\n    for (x = 1; x <= 2; x++) {\n        str = await input();\n        y = parseInt(str);\n        z = parseInt(str.substr(str.indexOf(\",\") + 1));\n        ba[y][z] = 0.5;\n    }\n    while (1) {\n        print(\"DO YOU WANT TO START\");\n        js = await input();\n        if (js == \"WHERE ARE YOUR SHIPS?\") {\n            print(\"BATTLESHIP\\n\");\n            for (z = 1; z <= 5; z++)\n                print(\" \" + fa[z] + \" \" + ga[z] + \"\\n\");\n            print(\"CRUISER\\n\");\n            print(\" \" + fa[6] + \" \" + ga[6] + \"\\n\");\n            print(\" \" + fa[7] + \" \" + ga[7] + \"\\n\");\n            print(\" \" + fa[8] + \" \" + ga[8] + \"\\n\");\n            print(\"DESTROYER<A>\\n\");\n            print(\" \" + fa[9] + \" \" + ga[9] + \"\\n\");\n            print(\" \" + fa[10] + \" \" + ga[10] + \"\\n\");\n            print(\"DESTROYER<B>\\n\");\n            print(\" \" + fa[11] + \" \" + ga[11] + \"\\n\");\n            print(\" \" + fa[12] + \" \" + ga[12] + \"\\n\");\n        } else {\n            break;\n        }\n    }\n    c = 0;\n    print(\"DO YOU WANT TO SEE MY SHOTS\");\n    ks = await input();\n    print(\"\\n\");\n    if (js != \"YES\")\n        first_time = true;\n    else\n        first_time = false;\n    while (1) {\n        if (first_time) {\n            first_time = false;\n        } else {\n            if (js == \"YES\") {\n                c++;\n                print(\"\\n\");\n                print(\"TURN \" + c + \"\\n\");\n            }\n            a = 0;\n            for (w = 0.5; w <= 3; w += 0.5) {\n            loop1:\n                for (x = 1; x <= 10; x++) {\n                    for (y = 1; y <= 10; y++) {\n                        if (ba[x][y] == w) {\n                            a += Math.floor(w + 0.5);\n                            break loop1;\n                        }\n                    }\n                }\n            }\n            for (w = 1; w <= 7; w++) {\n                ca[w] = 0;\n                da[w] = 0;\n                fa[w] = 0;\n                ga[w] = 0;\n            }\n            p3 = 0;\n            for (x = 1; x <= 10; x++) {\n                for (y = 1; y <= 10; y++) {\n                    if (aa[x][y] <= 10)\n                        p3++;\n                }\n            }\n            print(\"YOU HAVE \" + a + \" SHOTS.\\n\");\n            if (p3 < a) {\n                print(\"YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES.\\n\");\n                print(\"YOU HAVE WON.\\n\");\n                return;\n            }\n            if (a == 0) {\n                print(\"I HAVE WON.\\n\");\n                return;\n            }\n            for (w = 1; w <= a; w++) {\n                while (1) {\n                    str = await input();\n                    x = parseInt(str);\n                    y = parseInt(str.substr(str.indexOf(\",\") + 1));\n                    if (x >= 1 && x <= 10 && y >= 1 && y <= 10) {\n                        if (aa[x][y] > 10) {\n                            print(\"YOU SHOT THERE BEFORE ON TURN \" + (aa[x][y] - 10) + \"\\n\");\n                            continue;\n                        }\n                        break;\n                    }\n                    print(\"ILLEGAL, ENTER AGAIN.\\n\");\n                }\n                ca[w] = x;\n                da[w] = y;\n            }\n            for (w = 1; w <= a; w++) {\n                if (aa[ca[w]][da[w]] == 3) {\n                    print(\"YOU HIT MY BATTLESHIP.\\n\");\n                } else if (aa[ca[w]][da[w]] == 2) {\n                    print(\"YOU HIT MY CRUISER.\\n\");\n                } else if (aa[ca[w]][da[w]] == 1) {\n                    print(\"YOU HIT MY DESTROYER<A>.\\n\");\n                } else if (aa[ca[w]][da[w]] == 0.5) {\n                    print(\"YOU HIT MY DESTROYER<B>.\\n\");\n                }\n                aa[ca[w]][da[w]] = 10 + c;\n            }\n        }\n        a = 0;\n        if (js != \"YES\") {\n            c++;\n            print(\"\\n\");\n            print(\"TURN \" + c + \"\\n\");\n        }\n        a = 0;\n        for (w = 0.5; w <= 3; w += 0.5) {\n        loop2:\n            for (x = 1; x <= 10; x++) {\n                for (y = 1; y <= 10; y++) {\n                    if (ba[x][y] == w) {\n                        a += Math.floor(w + 0.5);\n                        break loop2;\n                    }\n                }\n            }\n        }\n        p3 = 0;\n        for (x = 1; x <= 10; x++) {\n            for (y = 1; y <= 10; y++) {\n                if (aa[x][y] <= 10)\n                    p3++;\n            }\n        }\n        print(\"I HAVE \" + a + \" SHOTS.\\n\");\n        if (p3 < a) {\n            print(\"I HAVE MORE SHOTS THAN BLANK SQUARES.\\n\");\n            print(\"I HAVE WON.\\n\");\n            return;\n        }\n        if (a == 0) {\n            print(\"YOU HAVE WON.\\n\");\n            return;\n        }\n        for (w = 1; w <= 12; w++) {\n            if (ha[w] > 0)\n                break;\n        }\n        if (w <= 12) {\n            for (r = 1; r <= 10; r++) {\n                ka[r] = [];\n                for (s = 1; s <= 10; s++)\n                    ka[r][s] = 0;\n            }\n            for (u = 1; u <= 12; u++) {\n                if (ea[u] >= 10)\n                    continue;\n                for (r = 1; r <= 10; r++) {\n                    for (s = 1; s <= 10; s++) {\n                        if (ba[r][s] >= 10) {\n                            ka[r][s] = -10000000;\n                        } else {\n                            for (m = sgn(1 - r); m <= sgn(10 - r); m++) {\n                                for (n = sgn(1 - s); n <= sgn(10 - s); n++) {\n                                    if (n + m + n * m != 0 && ba[r + m][s + n] == ea[u])\n                                        ka[r][s] += ea[u] - s * Math.floor(ha[u] + 0.5);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            for (r = 1; r <= a; r++) {\n                fa[r] = r;\n                ga[r] = r;\n            }\n            for (r = 1; r <= 10; r++) {\n                for (s = 1; s <= 10; s++) {\n                    q9 = 1;\n                    for (m = 1; m <= a; m++) {\n                        if (ka[fa[m]][ga[m]] < ka[fa[q9]][ga[q9]])\n                            q9 = m;\n                    }\n                    if ((r > a || r != s) && ka[r][s] >= ka[fa[q9]][ga[q9]]) {\n                        for (m = 1; m <= a; m++) {\n                            if (fa[m] != r) {\n                                fa[q9] = r;\n                                ga[q9] = s;\n                                break;\n                            }\n                            if (ga[m] == s)\n                                break;\n                        }\n                    }\n                }\n            }\n        } else {\n            // RANDOM\n            w = 0;\n            r3 = 0;\n            generate_random();\n            r2 = 0;\n            while (1) {\n                r3++;\n                if (r3 > 100) {\n                    generate_random();\n                    r2 = 0;\n                    r3 = 1;\n                }\n                if (x > 10) {\n                    x = 10 - Math.floor(Math.random() * 2.5);\n                } else if (x <= 0) {\n                    x = 1 + Math.floor(Math.random() * 2.5);\n                }\n                if (y > 10) {\n                    y = 10 - Math.floor(Math.random() * 2.5);\n                } else if (y <= 0) {\n                    y = 1 + Math.floor(Math.random() * 2.5);\n                }\n                while (1) {\n                    valid = true;\n                    if (x < 1 || x > 10 || y < 1 || y > 10 || ba[x][y] > 10) {\n                        valid = false;\n                    } else {\n                        for (q9 = 1; q9 <= w; q9++) {\n                            if (fa[q9] == x && ga[q9] == y) {\n                                valid = false;\n                                break;\n                            }\n                        }\n                        if (q9 > w)\n                            w++;\n                    }\n                    if (valid) {\n                        fa[w] = x;\n                        ga[w] = y;\n                        if (w == a) {\n                            finish = true;\n                            break;\n                        }\n                    }\n                    if (r2 == 6) {\n                        r2 = 0;\n                        finish = false;\n                        break;\n                    }\n                    x1 = [1,-1, 1,1,0,-1][r2];\n                    y1 = [1, 1,-3,1,2, 1][r2];\n                    r2++;\n                    x += x1;\n                    y += y1;\n                }\n                if (finish)\n                    break;\n            }\n        }\n        if (ks == \"YES\") {\n            for (z5 = 1; z5 <= a; z5++)\n                print(\" \" + fa[z5] + \" \" + ga[z5] + \"\\n\");\n        }\n        for (w = 1; w <= a; w++) {\n            hit = false;\n            if (ba[fa[w]][ga[w]] == 3) {\n                print(\"I HIT YOUR BATTLESHIP.\\n\");\n                hit = true;\n            } else if (ba[fa[w]][ga[w]] == 2) {\n                print(\"I HIT YOUR CRUISER.\\n\");\n                hit = true;\n            } else if (ba[fa[w]][ga[w]] == 1) {\n                print(\"I HIT YOUR DESTROYER<A>.\\n\");\n                hit = true;\n            } else if (ba[fa[w]][ga[w]] == 0.5) {\n                print(\"I HIT YOUR DESTROYER<B>.\\n\");\n                hit = true;\n            }\n            if (hit) {\n                for (q = 1; q <= 12; q++) {\n                    if (ea[q] != -1)\n                        continue;\n                    ea[q] = 10 + c;\n                    ha[q] = ba[fa[w]][ga[w]];\n                    m3 = 0;\n                    for (m2 = 1; m2 <= 12; m2++) {\n                        if (ha[m2] == ha[q])\n                            m3++;\n                    }\n                    if (m3 == Math.floor(ha[q] + 0.5) + 1 + Math.floor(Math.floor(ha[q] + 0.5) / 3)) {\n                        for (m2 = 1; m2 <= 12; m2++) {\n                            if (ha[m2] == ha[q]) {\n                                ea[m2] = -1;\n                                ha[m2] = -1;\n                            }\n                        }\n                    }\n                    break;\n                }\n                if (q > 12) {\n                    print(\"PROGRAM ABORT:\\n\");\n                    for (q = 1; q <= 12; q++) {\n                        print(\"ea[\" + q + \"] = \" + ea[q] + \"\\n\");\n                        print(\"ha[\" + q + \"] = \" + ha[q] + \"\\n\");\n                    }\n                    return;\n                }\n            }\n            ba[fa[w]][ga[w]] = 10 + c;\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "77_Salvo/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "77_Salvo/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "77_Salvo/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "77_Salvo/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "77_Salvo/python/salvo.py",
    "content": "import random\nimport re\nfrom typing import List, Optional, Tuple\n\nBoardType = List[List[Optional[int]]]\nCoordinateType = Tuple[int, int]\n\nBOARD_WIDTH = 10\nBOARD_HEIGHT = 10\n\n\n# data structure keeping track of information\n# about the ships in the game. for each ship,\n# the following information is provided:\n#\n#   name - string representation of the ship\n#   length - number of \"parts\" on the ship that\n#            can be shot\n#   shots - number of shots the ship counts for\nSHIPS = [\n    (\"BATTLESHIP\", 5, 3),\n    (\"CRUISER\", 3, 2),\n    (\"DESTROYER<A>\", 2, 1),\n    (\"DESTROYER<B>\", 2, 1),\n]\n\nVALID_MOVES = [\n    [-1, 0],  # North\n    [-1, 1],  # North East\n    [0, 1],  # East\n    [1, 1],  # South East\n    [1, 0],  # South\n    [1, -1],  # South West\n    [0, -1],  # West\n    [-1, -1],  # North West\n]\n\nCOORD_REGEX = \"[ \\t]{0,}(-?[0-9]{1,3})[ \\t]{0,},[ \\t]{0,}(-?[0-9]{1,2})\"\n\n\n# array of BOARD_HEIGHT arrays, BOARD_WIDTH in length,\n# representing the human player and computer\nplayer_board: BoardType = []\ncomputer_board: BoardType = []\n\n# array representing the coordinates\n# for each ship for player and computer\n# array is in the same order as SHIPS\ncomputer_ship_coords: List[List[CoordinateType]] = []\n\n\n####################################\n#\n# SHOTS\n#\n# The number of shots computer/player\n# has is determined by the shot \"worth\"\n# of each ship the computer/player\n# possesses. As long as the ship has one\n# part not hit (i.e., ship was not\n# sunk), the player gets all the shots\n# from that ship.\n\n# flag indicating if computer's shots are\n# printed out during computer's turn\nprint_computer_shots = False\n\n# keep track of the number\n# of available computer shots\n# inital shots are 7\nnum_computer_shots = 7\n\n# keep track of the number\n# of available player shots\n# initial shots are 7\nnum_player_shots = 7\n\n#\n# SHOTS\n#\n####################################\n\n# flag indicating whose turn it currently is\nCOMPUTER = False\nPLAYER = True\nactive_turn = COMPUTER\n\n####################\n#\n# game functions\n#\n####################\n\n# random number functions\n#\n# seed the random number generator\nrandom.seed()\n\n\n# random_x_y\n#\n\n\ndef random_x_y() -> CoordinateType:\n    \"\"\"Generate a valid x,y coordinate on the board\"\"\"\n\n    x = random.randrange(1, BOARD_WIDTH + 1)\n    y = random.randrange(1, BOARD_HEIGHT + 1)\n    return (x, y)\n\n\ndef input_coord() -> CoordinateType:\n    \"\"\"\n    Ask user for single (x,y) coordinate\n\n    validate the coordinates are within the bounds\n    of the board width and height. mimic the behavior\n    of the original program which exited with error\n    messages if coordinates where outside of array bounds.\n    if input is not numeric, print error out to user and\n    let them try again.\n    \"\"\"\n    match = None\n    while not match:\n        coords = input(\"? \")\n        match = re.match(COORD_REGEX, coords)\n        if not match:\n            print(\"!NUMBER EXPECTED - RETRY INPUT LINE\")\n    x = int(match.group(1))\n    y = int(match.group(2))\n\n    if x > BOARD_HEIGHT or y > BOARD_WIDTH:\n        print(\"!OUT OF ARRAY BOUNDS IN LINE 1540\")\n        exit()\n\n    if x <= 0 or y <= 0:\n        print(\"!NEGATIVE ARRAY DIM IN LINE 1540\")\n        exit()\n\n    return x, y\n\n\ndef generate_ship_coordinates(ship: int) -> List[CoordinateType]:\n    \"\"\"\n    given a ship from the SHIPS array, generate\n    the coordinates of the ship. the starting point\n    of the ship's first coordinate is generated randomly.\n    once the starting coordinates are determined, the\n    possible directions of the ship, accounting for the\n    edges of the board, are determined. once possible\n    directions are found, a direction is randomly\n    determined and the remaining coordinates are\n    generated by adding or substraction from the starting\n    coordinates as determined by direction.\n\n    arguments:\n      ship - index into the SHIPS array\n\n    returns:\n      array of sets of coordinates (x,y)\n    \"\"\"\n    # randomly generate starting x,y coordinates\n    start_x, start_y = random_x_y()\n\n    # using starting coordinates and the ship type,\n    # generate a vector of possible directions the ship\n    # could be placed. directions are numbered 0-7 along\n    # points of the compass (N, NE, E, SE, S, SW, W, NW)\n    # clockwise. a vector of valid directions where the\n    # ship does not go off the board is determined\n    ship_len = SHIPS[ship][1] - 1\n    dirs = [False for _ in range(8)]\n    dirs[0] = (start_x - ship_len) >= 1\n    dirs[2] = (start_y + ship_len) <= BOARD_WIDTH\n    dirs[1] = dirs[0] and dirs[2]\n    dirs[4] = (start_x + ship_len) <= BOARD_HEIGHT\n    dirs[3] = dirs[2] and dirs[4]\n    dirs[6] = (start_y - ship_len) >= 1\n    dirs[5] = dirs[4] and dirs[6]\n    dirs[7] = dirs[6] and dirs[0]\n    directions = [p for p in range(len(dirs)) if dirs[p]]\n\n    # using the vector of valid directions, pick a\n    # random direction to place the ship\n    dir_idx = random.randrange(len(directions))\n    direction = directions[dir_idx]\n\n    # using the starting x,y, direction and ship\n    # type, return the coordinates of each point\n    # of the ship. VALID_MOVES is a staic array\n    # of coordinate offsets to walk from starting\n    # coordinate to the end coordinate in the\n    # chosen direction\n    ship_len = SHIPS[ship][1] - 1\n    d_x = VALID_MOVES[direction][0]\n    d_y = VALID_MOVES[direction][1]\n\n    coords = [(start_x, start_y)]\n    x_coord = start_x\n    y_coord = start_y\n    for _ in range(ship_len):\n        x_coord = x_coord + d_x\n        y_coord = y_coord + d_y\n        coords.append((x_coord, y_coord))\n    return coords\n\n\ndef create_blank_board() -> BoardType:\n    \"\"\"Create a blank game board\"\"\"\n    return [[None for _y in range(BOARD_WIDTH)] for _x in range(BOARD_HEIGHT)]\n\n\ndef print_board(board: BoardType) -> None:\n    \"\"\"Print out the game board for testing purposes\"\"\"\n    # print board header (column numbers)\n    print(\"  \", end=\"\")\n    for z in range(BOARD_WIDTH):\n        print(f\"{z+1:3}\", end=\"\")\n    print()\n\n    for x in range(len(board)):\n        print(f\"{x+1:2}\", end=\"\")\n        for y in range(len(board[x])):\n            if board[x][y] is None:\n                print(f\"{' ':3}\", end=\"\")\n            else:\n                print(f\"{board[x][y]:3}\", end=\"\")\n        print()\n\n\ndef place_ship(board: BoardType, coords: List[CoordinateType], ship: int) -> None:\n    \"\"\"\n    Place a ship on a given board.\n\n    updates\n    the board's row,column value at the given\n    coordinates to indicate where a ship is\n    on the board.\n\n    inputs: board - array of BOARD_HEIGHT by BOARD_WIDTH\n            coords - array of sets of (x,y) coordinates of each\n                     part of the given ship\n            ship - integer representing the type of ship (given in SHIPS)\n    \"\"\"\n    for coord in coords:\n        board[coord[0] - 1][coord[1] - 1] = ship\n\n\ndef generate_board() -> Tuple[BoardType, List[List[CoordinateType]]]:\n    \"\"\"\n    NOTE: A little quirk that exists here and in the orginal\n          game: Ships are allowed to cross each other!\n          For example: 2 destroyers, length 2, one at\n          [(1,1),(2,2)] and other at [(2,1),(1,2)]\n    \"\"\"\n    board = create_blank_board()\n\n    ship_coords = []\n    for ship in range(len(SHIPS)):\n        placed = False\n        coords = []\n        while not placed:\n            coords = generate_ship_coordinates(ship)\n            clear = all(board[coord[0] - 1][coord[1] - 1] is None for coord in coords)\n            if clear:\n                placed = True\n        place_ship(board, coords, ship)\n        ship_coords.append(coords)\n    return board, ship_coords\n\n\ndef execute_shot(\n    turn: bool, board: BoardType, x: int, y: int, current_turn: int\n) -> int:\n    \"\"\"\n    given a board and x, y coordinates,\n    execute a shot. returns True if the shot\n    is valid, False if not\n    \"\"\"\n    square = board[x - 1][y - 1]\n    ship_hit = -1\n    if square is not None and square >= 0 and square < len(SHIPS):\n        ship_hit = square\n    board[x - 1][y - 1] = 10 + current_turn\n    return ship_hit\n\n\ndef calculate_shots(board: BoardType) -> int:\n    \"\"\"Examine each board and determine how many shots remaining\"\"\"\n    ships_found = [0 for _ in range(len(SHIPS))]\n    for x in range(BOARD_HEIGHT):\n        for y in range(BOARD_WIDTH):\n            square = board[x - 1][y - 1]\n            if square is not None and square >= 0 and square < len(SHIPS):\n                ships_found[square] = 1\n    return sum(\n        SHIPS[ship][2]\n        for ship in range(len(ships_found))\n        if ships_found[ship] == 1\n    )\n\n\ndef initialize_game() -> None:\n    # initialize the global player and computer boards\n    global player_board\n    player_board = create_blank_board()\n\n    # generate the ships for the computer's board\n    global computer_board\n    global computer_ship_coords\n    computer_board, computer_ship_coords = generate_board()\n\n    # print out the title 'screen'\n    print(\"{:>38}\".format(\"SALVO\"))\n    print(\"{:>57s}\".format(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"))\n    print()\n    print(\"{:>52s}\".format(\"ORIGINAL BY LAWRENCE SIEGEL, 1973\"))\n    print(\"{:>56s}\".format(\"PYTHON 3 PORT BY TODD KAISER, MARCH 2021\"))\n    print(\"\\n\")\n\n    # ask the player for ship coordinates\n    print(\"ENTER COORDINATES FOR...\")\n    ship_coords = []\n    for ship in SHIPS:\n        print(ship[0])\n        list = []\n        for _ in range(ship[1]):\n            x, y = input_coord()\n            list.append((x, y))\n        ship_coords.append(list)\n\n    # add ships to the user's board\n    for ship_index in range(len(SHIPS)):\n        place_ship(player_board, ship_coords[ship_index], ship_index)\n\n    # see if the player wants the computer's ship\n    # locations printed out and if the player wants to\n    # start\n    input_loop = True\n    player_start = \"YES\"\n    while input_loop:\n        player_start = input(\"DO YOU WANT TO START? \")\n        if player_start == \"WHERE ARE YOUR SHIPS?\":\n            for ship_index in range(len(SHIPS)):\n                print(SHIPS[ship_index][0])\n                coords = computer_ship_coords[ship_index]\n                for coord in coords:\n                    x = coord[0]\n                    y = coord[1]\n                    print(f\"{x:2}\", f\"{y:2}\")\n        else:\n            input_loop = False\n\n    # ask the player if they want the computer's shots\n    # printed out each turn\n    global print_computer_shots\n    see_computer_shots = input(\"DO YOU WANT TO SEE MY SHOTS? \")\n    if see_computer_shots.lower() == \"yes\":\n        print_computer_shots = True\n\n    global first_turn\n    if player_start.lower() != \"yes\":\n        first_turn = COMPUTER\n\n    # calculate the initial number of shots for each\n    global num_computer_shots, num_player_shots\n    num_player_shots = calculate_shots(player_board)\n    num_computer_shots = calculate_shots(computer_board)\n\n\n####################################\n#\n# Turn Control\n#\n# define functions for executing the turns for\n# the player and the computer. By defining this as\n# functions, we can easily start the game with\n# either computer or player and alternate back and\n# forth, replicating the gotos in the original game\n\n\n# initialize the first_turn function to the player's turn\nfirst_turn = PLAYER\n\n\ndef execute_turn(turn: bool, current_turn: int) -> int:\n    global num_computer_shots, num_player_shots\n\n    # print out the number of shots the current player has\n    board = None\n    num_shots = 0\n    if turn == COMPUTER:\n        print(f\"I HAVE {num_computer_shots} SHOTS.\")\n        board = player_board\n        num_shots = num_computer_shots\n    else:\n        print(f\"YOU HAVE {num_player_shots} SHOTS.\")\n        board = computer_board\n        num_shots = num_player_shots\n\n    shots = []\n    for _shot in range(num_shots):\n        valid_shot = False\n        x = -1\n        y = -1\n\n        # loop until we have a valid shot. for the\n        # computer, we randomly pick a shot. for the\n        # player we request shots\n        while not valid_shot:\n            x, y = random_x_y() if turn == COMPUTER else input_coord()\n            square = board[x - 1][y - 1]\n            if square is not None and square > 10:\n                if turn == PLAYER:\n                    print(\"YOU SHOT THERE BEFORE ON TURN\", square - 10)\n                continue\n            shots.append((x, y))\n            valid_shot = True\n\n    hits = []\n    for shot in shots:\n        hit = execute_shot(turn, board, shot[0], shot[1], current_turn)\n        if hit >= 0:\n            hits.append(hit)\n        if turn == COMPUTER and print_computer_shots:\n            print(shot[0], shot[1])\n\n    for hit in hits:\n        if turn == COMPUTER:\n            print(\"I HIT YOUR\", SHIPS[hit][0])\n        else:\n            print(\"YOU HIT MY\", SHIPS[hit][0])\n\n    if turn == COMPUTER:\n        num_player_shots = calculate_shots(board)\n        return num_player_shots\n    else:\n        num_computer_shots = calculate_shots(board)\n        return num_computer_shots\n\n\n#\n# Turn Control\n#\n######################################\n\n\ndef main() -> None:\n    current_turn = 0\n    initialize_game()\n\n    # execute turns until someone wins or we run\n    # out of squares to shoot\n    game_over = False\n    while not game_over:\n        current_turn += 1\n\n        print(\"\\n\")\n        print(\"TURN\", current_turn)\n\n        if (\n            execute_turn(first_turn, current_turn) == 0\n            or execute_turn(not first_turn, current_turn) == 0\n        ):\n            game_over = True\n            continue\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "77_Salvo/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "77_Salvo/salvo.bas",
    "content": "1000 PRINT TAB(33);\"SALVO\"\n1010 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n1020 PRINT:PRINT:PRINT\n1030 REM\n1040 DIM A(10,10),B(10,10),C(7),D(7),E(12),F(12),G(12),H(12),K(10,10)\n1050 Z8=0\n1060 FOR W=1 TO 12\n1070 E(W)=-1\n1080 H(W)=-1\n1090 NEXT W\n1100 FOR X=1 TO 10\n1110 FOR Y=1 TO 10\n1120 B(X,Y)=0\n1130 NEXT Y\n1140 NEXT X\n1150 FOR X=1 TO 12\n1160 F(X)=0\n1170 G(X)=0\n1180 NEXT X\n1190 FOR X=1 TO 10\n1200 FOR Y=1 TO 10\n1210 A(X,Y)=0\n1220 NEXT Y\n1230 NEXT X\n1240 FOR K=4 TO 1 STEP -1\n1250 U6=0\n1260 GOSUB 2910\n1270 DEF FNA(K)=(5-K)*3-2*INT(K/4)+SGN(K-1)-1\n1280 DEF FNB(K)=K+INT(K/4)-SGN(K-1)\n1290 IF V+V2+V*V2=0 THEN 1260\n1300 IF Y+V*FNB(K)>10 THEN 1260\n1310 IF Y+V*FNB(K)<1 THEN 1260\n1320 IF X+V2*FNB(K)>10 THEN 1260\n1330 IF X+V2*FNB(K)<1 THEN 1260\n1340 U6=U6+1\n1350 IF U6>25 THEN 1190\n1360 FOR Z=0 TO FNB(K)\n1370 F(Z+FNA(K))=X+V2*Z\n1380 G(Z+FNA(K))=Y+V*Z\n1390 NEXT Z\n1400 U8=FNA(K)\n1405 IF U8>U8+FNB(K) THEN 1460\n1410 FOR Z2= U8 TO U8+FNB(K)\n1415 IF U8<2 THEN 1450\n1420 FOR Z3=1 TO U8-1\n1430 IF SQR((F(Z3)-F(Z2))^2 + (G(Z3)-G(Z2))^2) < 3.59 THEN 1260\n1440 NEXT Z3\n1450 NEXT Z2\n1460 FOR Z=0 TO FNB(K)\n1470 A(F(Z+U8),G(Z+U8))=.5+SGN(K-1)*(K-1.5)\n1480 NEXT Z\n1490 NEXT K\n1500 PRINT \"ENTER COORDINATES FOR...\"\n1510 PRINT \"BATTLESHIP\"\n1520 FOR X=1 TO 5\n1530 INPUT Y,Z\n1540 B(Y,Z)=3\n1550 NEXT X\n1560 PRINT \"CRUISER\"\n1570 FOR X=1 TO 3\n1580 INPUT Y,Z\n1590 B(Y,Z)=2\n1600 NEXT X\n1610 PRINT \"DESTROYER<A>\"\n1620 FOR X=1 TO 2\n1630 INPUT Y,Z\n1640 B(Y,Z)=1\n1650 NEXT X\n1660 PRINT \"DESTROYER<B>\"\n1670 FOR X=1 TO 2\n1680 INPUT Y,Z\n1690 B(Y,Z)=.5\n1700 NEXT X\n1710 PRINT \"DO YOU WANT TO START\";\n1720 INPUT J$\n1730 IF J$<>\"WHERE ARE YOUR SHIPS?\" THEN 1890\n1740 PRINT \"BATTLESHIP\"\n1750 FOR Z=1 TO 5\n1760 PRINT F(Z);G(Z)\n1770 NEXT Z\n1780 PRINT \"CRUISER\"\n1790 PRINT F(6);G(6)\n1800 PRINT F(7);G(7)\n1810 PRINT F(8);G(8)\n1820 PRINT \"DESTROYER<A>\"\n1830 PRINT F(9);G(9)\n1840 PRINT F(10);G(10)\n1850 PRINT \"DESTROYER<B>\"\n1860 PRINT F(11);G(11)\n1870 PRINT F(12);G(12)\n1880 GOTO 1710\n1890 C=0\n1900 PRINT \"DO YOU WANT TO SEE MY SHOTS\";\n1910 INPUT K$\n1920 PRINT\n1930 IF J$<>\"YES\" THEN 2620\n1940 REM*******************START\n1950 IF J$<>\"YES\" THEN 1990\n1960 C=C+1\n1970 PRINT\n1980 PRINT \"TURN\";C\n1990 A=0\n2000 FOR W=.5 TO 3 STEP .5\n2010 FOR X=1 TO 10\n2020 FOR Y=1 TO 10\n2030 IF B(X,Y)=W THEN 2070\n2040 NEXT Y\n2050 NEXT X\n2060 GOTO 2080\n2070 A=A+INT(W+.5)\n2080 NEXT W\n2090 FOR W=1 TO 7\n2100 C(W)=0\n2110 D(W)=0\n2120 F(W)=0\n2130 G(W)=0\n2140 NEXT W\n2150 P3=0\n2160 FOR X=1 TO 10\n2170 FOR Y=1 TO 10\n2180 IF A(X,Y)>10 THEN 2200\n2190 P3=P3+1\n2200 NEXT Y\n2210 NEXT X\n2220 PRINT \"YOU HAVE\";A;\"SHOTS.\"\n2230 IF P3>=A THEN 2260\n2240 PRINT \"YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES.\"\n2250 GOTO 2890\n2260 IF A<>0 THEN 2290\n2270 PRINT \"I HAVE WON.\"\n2280 STOP\n2290 FOR W=1 TO A\n2300 INPUT X,Y\n2310 IF X<>INT(X) THEN 2370\n2320 IF X>10 THEN 2370\n2330 IF X<1 THEN 2370\n2340 IF Y<>INT(Y) THEN 2370\n2350 IF Y>10 THEN 2370\n2360 IF Y>=1 THEN 2390\n2370 PRINT \"ILLEGAL, ENTER AGAIN.\"\n2380 GOTO 2300\n2390 IF A(X,Y)>10 THEN 2440\n2400 C(W)=X\n2410 D(W)=Y\n2420 NEXT W\n2430 GOTO 2460\n2440 PRINT \"YOU SHOT THERE BEFORE ON TURN\";A(X,Y)-10\n2450 GOTO 2300\n2460 FOR W=1 TO A\n2470 IF A(C(W),D(W))=3 THEN 2540\n2480 IF A(C(W),D(W))=2 THEN 2560\n2490 IF A(C(W),D(W))=1 THEN 2580\n2500 IF A(C(W),D(W))=.5 THEN 2600\n2510 A(C(W),D(W))=10+C\n2520 NEXT W\n2530 GOTO 2620\n2540 PRINT \"YOU HIT MY BATTLESHIP.\"\n2550 GOTO 2510\n2560 PRINT \"YOU HIT MY CRUISER.\"\n2570 GOTO 2510\n2580 PRINT \"YOU HIT MY DESTROYER<A>.\"\n2590 GOTO 2510\n2600 PRINT \"YOU HIT MY DESTROYER<B>.\"\n2610 GOTO 2510\n2620 A=0\n2630 IF J$=\"YES\" THEN 2670\n2640 C=C+1\n2650 PRINT\n2660 PRINT \"TURN\";C\n2670 A=0\n2680 FOR W=.5 TO 3 STEP .5\n2690 FOR X=1 TO 10\n2700 FOR Y=1 TO 10\n2710 IF A(X,Y)=W THEN 2750\n2720 NEXT Y\n2730 NEXT X\n2740 GOTO 2760\n2750 A=A+INT(W+.5)\n2760 NEXT W\n2770 P3=0\n2780 FOR X=1 TO 10\n2790 FOR Y=1 TO 10\n2800 IF A(X,Y)>10 THEN 2820\n2810 P3=P3+1\n2820 NEXT Y\n2830 NEXT X\n2840 PRINT \"I HAVE\";A;\"SHOTS.\"\n2850 IF P3>A THEN 2880\n2860 PRINT \"I HAVE MORE SHOTS THAN BLANK SQUARES.\"\n2870 GOTO 2270\n2880 IF A<>0 THEN 2960\n2890 PRINT \"YOU HAVE WON.\"\n2900 STOP\n2910 X=INT(RND(1)*10+1)\n2920 Y=INT(RND(1)*10+1)\n2930 V=INT(3*RND(1)-1)\n2940 V2=INT(3*RND(1)-1)\n2950 RETURN\n2960 FOR W=1 TO 12\n2970 IF H(W)>0 THEN 3800\n2980 NEXT W\n2990 REM*******************RANDOM\n3000 W=0\n3010 R3=0\n3020 GOSUB 2910\n3030 RESTORE\n3040 R2=0\n3050 R3=R3+1\n3060 IF R3>100 THEN 3010\n3070 IF X>10 THEN 3110\n3080 IF X>0 THEN 3120\n3090 X=1+INT(RND(1)*2.5)\n3100 GOTO 3120\n3110 X=10-INT(RND(1)*2.5)\n3120 IF Y>10 THEN 3160\n3130 IF Y>0 THEN 3270\n3140 Y=1+INT(RND(1)*2.5)\n3150 GOTO 3270\n3160 Y=10-INT(RND(1)*2.5)\n3170 GOTO 3270\n3180 F(W)=X\n3190 G(W)=Y\n3200 IF W=A THEN 3380\n3210 IF R2=6 THEN 3030\n3220 READ X1,Y1\n3230 R2=R2+1\n3240 DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1\n3250 X=X+X1\n3260 Y=Y+Y1\n3270 IF X>10 THEN 3210\n3280 IF X<1 THEN 3210\n3290 IF Y>10 THEN 3210\n3300 IF Y<1 THEN 3210\n3310 IF B(X,Y)>10 THEN 3210\n3320 FOR Q9=1 TO W\n3330 IF F(Q9)<>X THEN 3350\n3340 IF G(Q9)=Y THEN 3210\n3350 NEXT Q9\n3360 W=W+1\n3370 GOTO 3180\n3380 IF K$<>\"YES\" THEN 3420\n3390 FOR Z5=1 TO A\n3400 PRINT F(Z5);G(Z5)\n3410 NEXT Z5\n3420 FOR W=1 TO A\n3430 IF B(F(W),G(W))=3 THEN 3500\n3440 IF B(F(W),G(W))=2 THEN 3520\n3450 IF B(F(W),G(W))=1 THEN 3560\n3460 IF B(F(W),G(W))=.5 THEN 3540\n3470 B(F(W),G(W))=10+C\n3480 NEXT W\n3490 GOTO 1950\n3500 PRINT \"I HIT YOUR BATTLESHIP\"\n3510 GOTO 3570\n3520 PRINT \"I HIT YOUR CRUISER\"\n3530 GOTO 3570\n3540 PRINT \"I HIT YOUR DESTROYER<B>\"\n3550 GOTO 3570\n3560 PRINT \"I HIT YOUR DESTROYER<A>\"\n3570 FOR Q=1 TO 12\n3580 IF E(Q)<>-1 THEN 3730\n3590 E(Q)=10+C\n3600 H(Q)=B(F(W),G(W))\n3610 M3=0\n3620 FOR M2=1 TO 12\n3630 IF H(M2)<>H(Q) THEN 3650\n3640 M3=M3+1\n3650 NEXT M2\n3660 IF M3<>INT(H(Q)+.5)+1+INT(INT(H(Q)+.5)/3) THEN 3470\n3670 FOR M2=1 TO 12\n3680 IF H(M2)<>H(Q) THEN 3710\n3690 E(M2)=-1\n3700 H(M2)=-1\n3710 NEXT M2\n3720 GOTO 3470\n3730 NEXT Q\n3740 PRINT \"PROGRAM ABORT:\"\n3750 FOR Q=1 TO 12\n3760 PRINT \"E(\";Q;\") =\";E(Q)\n3770 PRINT \"H(\";Q;\") =\";H(Q)\n3780 NEXT Q\n3790 STOP\n3800 REM************************USINGEARRAY\n3810 FOR R=1 TO 10\n3820 FOR S=1 TO 10\n3830 K(R,S)=0\n3840 NEXT S\n3850 NEXT R\n3860 FOR U=1 TO 12\n3870 IF E(U)<10 THEN 4020\n3880 FOR R=1 TO 10\n3890 FOR S=1 TO 10\n3900 IF B(R,S)<10 THEN 3930\n3910 K(R,S)=-10000000\n3920 GOTO 4000\n3930 FOR M=SGN(1-R) TO SGN(10-R)\n3940 FOR N=SGN(1-S) TO SGN(10-S)\n3950 IF N+M+N*M=0 THEN 3980\n3960 IF B(R+M,S+N)<>E(U) THEN 3980\n3970 K(R,S)=K(R,S)+E(U)-S*INT(H(U)+.5)\n3980 NEXT N\n3990 NEXT M\n4000 NEXT S\n4010 NEXT R\n4020 NEXT U\n4030 FOR R=1 TO A\n4040 F(R)=R\n4050 G(R)=R\n4060 NEXT R\n4070 FOR R=1 TO 10\n4080 FOR S=1 TO 10\n4090 Q9=1\n4100 FOR M=1 TO A\n4110 IF K(F(M),G(M))>=K(F(Q9),G(Q9)) THEN 4130\n4120 Q9=M\n4130 NEXT M\n4131 IF R>A THEN 4140\n4132 IF R=S THEN 4210\n4140 IF K(R,S)<K(F(Q9),G(Q9)) THEN 4210\n4150 FOR M=1 TO A\n4160 IF F(M)<>R THEN 4190\n4170 IF G(M)=S THEN 4210\n4180 NEXT M\n4190 F(Q9)=R\n4200 G(Q9)=S\n4210 NEXT S\n4220 NEXT R\n4230 GOTO 3380\n4240 END\n"
  },
  {
    "path": "77_Salvo/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "77_Salvo/vbnet/Salvo.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Salvo\", \"Salvo.vbproj\", \"{849885BF-24BD-4FEB-A224-A9502742D4B0}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{849885BF-24BD-4FEB-A224-A9502742D4B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{849885BF-24BD-4FEB-A224-A9502742D4B0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{849885BF-24BD-4FEB-A224-A9502742D4B0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{849885BF-24BD-4FEB-A224-A9502742D4B0}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "77_Salvo/vbnet/Salvo.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Salvo</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "78_Sine_Wave/README.md",
    "content": "### Sine Wave\n\nDid you ever go to a computer show and see a bunch of CRT terminals just sitting there waiting forlornly for someone to give a demo on them. It was one of those moments when I was at DEC that I decided there should be a little bit of background activity. And why not plot with words instead of the usual X’s? Thus SINE WAVE was born and lives on in dozens of different versions. At least those CRTs don’t look so lifeless anymore.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=146)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=161)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "78_Sine_Wave/csharp/Program.cs",
    "content": "﻿using System;\n\nConsole.WriteLine(Tab(30) + \"Sine Wave\");\nConsole.WriteLine(Tab(15) + \"Creative Computing Morristown, New Jersey\\n\\n\\n\\n\\n\");\n\nbool isCreative = true;\nfor (double t = 0.0; t <= 40.0; t += 0.25)\n{\n    int a = (int)(26 + 25 * Math.Sin(t));\n    string word = isCreative ? \"Creative\" : \"Computing\";\n    Console.WriteLine($\"{Tab(a)}{word}\");\n    isCreative = !isCreative;\n}\n\nstatic string Tab(int n) => new string(' ', n);\n"
  },
  {
    "path": "78_Sine_Wave/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "78_Sine_Wave/csharp/SineWave.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "78_Sine_Wave/csharp/SineWave.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31005.135\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SineWave\", \"SineWave.csproj\", \"{730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {32A37343-2955-4124-8765-9143F6C529DC}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "78_Sine_Wave/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "78_Sine_Wave/java/src/SineWave.java",
    "content": "/**\n * Sine Wave\n *\n * Based on the Sine Wave program here\n * https://github.com/coding-horror/basic-computer-games/blob/main/78%20Sine%20Wave/sinewave.bas\n *\n * Note:  The idea was to create a version of the 1970's Basic program in Java, without introducing\n *        new features - no additional text, error checking, etc has been added.\n */\npublic class SineWave {\n\n    public static void main(String[] args) {\n        System.out.println(\"\"\"\n           SINE WAVE\n           CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n           \"\"\");\n        var isCreative = true;\n        for(var t = 0d; t<40; t += .25) {\n            //Indent output\n            var indentations = 26 + (int) (25 * Math.sin(t));\n            System.out.print(\" \".repeat(indentations));\n            //Change output every iteration\n            var word = isCreative ? \"CREATIVE\" : \"COMPUTING\";\n            System.out.println(word);\n            isCreative = !isCreative ;\n        }\n    }\n}\n"
  },
  {
    "path": "78_Sine_Wave/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "78_Sine_Wave/javascript/sinewave.mjs",
    "content": "#!/usr/bin/env node\n\nimport { println, tab } from '../../00_Common/javascript/common.mjs';\n\nprintln(tab(30), \"SINE WAVE\");\nprintln(tab(15), \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\nprintln(\"\\n\".repeat(4));\n\n// REMARKABLE PROGRAM BY DAVID AHL\n// Transliterated to Javascript by Les Orchard <me@lmorchard.com>\n\nlet toggleWord = true;\n\nfor (let step = 0; step < 40; step += 0.25) {\n  let indent = Math.floor(26 + 25 * Math.sin(step));\n  println(tab(indent), toggleWord ? \"CREATIVE\" : \"COMPUTING\");\n  toggleWord = !toggleWord;\n}\n"
  },
  {
    "path": "78_Sine_Wave/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "78_Sine_Wave/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "78_Sine_Wave/lua/sinewave.lua",
    "content": "require(\"math\")\nrequire(\"string\")\n\nprint(\"\\n                         Sine Wave\")\nprint(\"           Creative Computing Morriston, New Jersy\")\nprint(\"\\n\\n\\n\\n\")\n\n-- Original BASIC version by David Ahl\n-- Ported to lua by BeeverFeever(github), 2022\n\nlocal toggleWord = true\n\nfor t = 0, 40, 0.25 do\n    local gap = math.floor(26 + 25 * math.sin(t))\n    if toggleWord == true then\n        -- string.rep used to add the gat at the front of the printed out words\n        print(string.rep(\" \", math.floor(gap)) .. \"Creative\")\n    elseif toggleWord == false then\n        print(string.rep(\" \", math.floor(gap)) .. \"Computing\")\n    end\nend\n"
  },
  {
    "path": "78_Sine_Wave/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "78_Sine_Wave/perl/sinewave.pl",
    "content": "#!/usr/bin/perl\nuse strict;\nuse warnings;\n\nprint ' ' x 30 .\"SINE WAVE\\n\";\nprint ' ' x 15 .\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\\n\\n\";\n\nmy $B=0;\n\nfor (my $T=0; $T<40; $T+=.25) {\n\tmy $A=int(26+25*sin($T));\n\tprint ' ' x $A;\n\tif ($B==0) { print \"CREATIVE\\n\"; }\n\tif ($B==1) { print \"COMPUTING\\n\"; }\n\t$B= !$B; #Toggle\n\t}\n"
  },
  {
    "path": "78_Sine_Wave/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "78_Sine_Wave/python/sinewave.py",
    "content": "########################################################\r\n#\r\n# Sine Wave\r\n#\r\n# From: BASIC Computer Games (1978)\r\n#       Edited by David H. Ahl\r\n#\r\n# \"Did you ever go to a computer show and see a bunch of\r\n#  CRT terminals just sitting there waiting forlornly\r\n#  for someone to give a demo on them.  It was one of\r\n#  those moments when I was at DEC that I decided there\r\n#  should be a little bit of background activity.  And\r\n#  why not plot with words instead of the usual X's?\r\n#  Thus SINE WAVE was born and lives on in dozens of\r\n#  different versions.  At least those CRTs don't look\r\n#  so lifeless anymore.\"\r\n#\r\n# Original BASIC version by David Ahl\r\n#\r\n# Python port by Jeff Jetton, 2019\r\n#\r\n########################################################\r\n\r\nimport math\r\nimport time\r\n\r\n\r\ndef main() -> None:\r\n    # Constants\r\n    STRINGS = (\"Creative\", \"Computing\")  # Text to display\r\n    MAX_LINES = 160\r\n    STEP_SIZE = 0.25  # Number of radians to increase at each\r\n    # line. Controls speed of horizontal\r\n    # printing movement.\r\n    CENTER = 26  # Controls left edge of \"middle\" string\r\n    DELAY = 0.05  # Amount of seconds to wait between lines\r\n\r\n    # Display \"intro\" text\r\n    print(\"\\n                        Sine Wave\")\r\n    print(\"         Creative Computing  Morristown, New Jersey\")\r\n    print(\"\\n\\n\\n\\n\")\r\n    # \"REMarkable program by David Ahl\"\r\n\r\n    string_index = 0\r\n    radians: float = 0\r\n    width = CENTER - 1\r\n\r\n    # \"Start long loop\"\r\n    for _line_num in range(MAX_LINES):\r\n\r\n        # Get string to display on this line\r\n        curr_string = STRINGS[string_index]\r\n\r\n        # Calculate how far over to print the text\r\n        sine = math.sin(radians)\r\n        padding = int(CENTER + width * sine)\r\n        print(curr_string.rjust(padding + len(curr_string)))\r\n\r\n        # Increase radians and increment our tuple index\r\n        radians += STEP_SIZE\r\n        string_index += 1\r\n        if string_index >= len(STRINGS):\r\n            string_index = 0\r\n\r\n        # Make sure the text doesn't fly by too fast...\r\n        time.sleep(DELAY)\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n\r\n########################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   The original BASIC version hardcoded two words in\r\n#   the body of the code and then used a sentinel flag\r\n#   (flipping between 0 and 1) with IF statements to\r\n#   determine the word to display next.\r\n#\r\n#   Here, the words have been moved to a Python tuple,\r\n#   which is iterated over without any assumptions about\r\n#   how long it is.  The STRINGS tuple can therefore be\r\n#   modified to have to program print out any sequence\r\n#   of any number of lines of text.\r\n#\r\n#   Since a modern computer running Python will print\r\n#   to the screen much more quickly than a '70s-era\r\n#   computer running BASIC would, a delay component\r\n#   has been introduced in this version to make the\r\n#   output more historically accurate.\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   Ask the user for desired number of lines (perhaps\r\n#   with an \"infinite\" option) and/or step size.\r\n#\r\n#   Let the user input the text strings to display,\r\n#   rather than having it pre-defined in a constant.\r\n#   Calculate an appropriate CENTER based on length of\r\n#   longest string.\r\n#\r\n#   Try changing STINGS so that it only includes a\r\n#   single string, just like this:\r\n#\r\n#       STRINGS = ('Howdy!')\r\n#\r\n#   What happens? Why? How would you fix it?\r\n#\r\n########################################################\r\n"
  },
  {
    "path": "78_Sine_Wave/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "78_Sine_Wave/ruby/sinewave.rb",
    "content": "def intro\n  puts \"                              SINE WAVE\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\\n\\n\\n\"\nend\n\ndef main\n  intro\n  (0..40).step(0.25).each do |t|\n    a = (26 + 25 * Math.sin(t)).to_i\n    text = (t % 0.5) == 0 ? \"CREATIVE\" : \"COMPUTING\"\n    puts \" \" * a + text\n  end\nend\n\nmain\n"
  },
  {
    "path": "78_Sine_Wave/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "78_Sine_Wave/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "78_Sine_Wave/rust/src/main.rs",
    "content": "fn main() {\n    let mut ticker:f64 = 0.0;\n    let mut spaces ;\n    \n    //pring welcome message\n    welcome();\n\n    //drawing loop\n    loop {\n        //print however many spaces\n        spaces = (26.0 + 25.0*ticker.sin()).round() as i32;\n        for _i in 0..=spaces{\n            print!(\" \"); //print a space\n        }\n\n        //print Creative or Computing\n        if (ticker.round() as i32) % 2 == 0 {\n            println!(\"CREATIVE\");\n        } else {\n            println!(\"COMPUTING\");\n        } \n\n        //increment ticker\n        ticker += 0.25;\n    }\n\n}\n\n/**\n * prints welcome message\n */\nfn welcome() {\n    println!(\"\n                             SINE WAVE\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n    \");\n}"
  },
  {
    "path": "78_Sine_Wave/sinewave.bas",
    "content": "10 PRINT TAB(30);\"SINE WAVE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT: PRINT: PRINT\n40 REMARKABLE PROGRAM BY DAVID AHL\n50 B=0\n100 REM  START LONG LOOP\n110 FOR T=0 TO 40 STEP .25\n120 A=INT(26+25*SIN(T))\n130 PRINT TAB(A);\n140 IF B=1 THEN 180\n150 PRINT \"CREATIVE\"\n160 B=1\n170 GOTO 200\n180 PRINT \"COMPUTING\"\n190 B=0\n200 NEXT T\n999 END\n"
  },
  {
    "path": "78_Sine_Wave/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "78_Sine_Wave/vbnet/SineWave.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"SineWave\", \"SineWave.vbproj\", \"{204DD0CD-1DA5-4B4B-992F-1C3ED089A147}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "78_Sine_Wave/vbnet/SineWave.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>SineWave</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "79_Slalom/README.md",
    "content": "### Slalom\n\nThis game simulates a slalom run down a course with one to 25 gates. The user picks the number of gates and has some control over his speed down the course.\n\nIf you’re not a skier, here’s your golden opportunity to try it with minimal risk. If you are a skier, here’s something to do while your leg is in a cast.\n\nSLALOM was written by J. Panek while a student at Dartmouth College.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=147)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=162)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- In the original version, the data pointer doesn't reset after a race is completed. This causes subsequent races to error at some future point at line 540, `READ Q'.\n\n- It also doesn't restore the data pointer after executing the MAX command to see the gate speeds, meaning that if you use this command, it effectively skips those gates, and the speeds shown are completely incorrect.\n\n#### Porting Notes\n"
  },
  {
    "path": "79_Slalom/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "79_Slalom/csharp/Slalom.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "79_Slalom/csharp/Slalom.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Slalom\", \"Slalom.csproj\", \"{6D0607CF-B01C-4E17-A4DE-D15514AE5F84}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "79_Slalom/csharp/program.cs",
    "content": "using System.Text;\n\nnamespace Slalom\n{\n    class Slalom\n    {\n        private int[] GateMaxSpeed = { 14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20,\n                                       18,26,25,33,31,22 };\n\n        private int GoldMedals = 0;\n        private int SilverMedals = 0;\n        private int BronzeMedals = 0;\n        private void DisplayIntro()\n        {\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"SLALOM\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine(\"\");\n        }\n\n        private void DisplayInstructions()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"*** Slalom: This is the 1976 Winter Olympic Giant Slalom.  You are\");\n            Console.WriteLine(\"            the American team's only hope of a gold medal.\");\n            Console.WriteLine();\n            Console.WriteLine(\"     0 -- Type this if you want to see how long you've taken.\");\n            Console.WriteLine(\"     1 -- Type this if you want to speed up a lot.\");\n            Console.WriteLine(\"     2 -- Type this if you want to speed up a little.\");\n            Console.WriteLine(\"     3 -- Type this if you want to speed up a teensy.\");\n            Console.WriteLine(\"     4 -- Type this if you want to keep going the same speed.\");\n            Console.WriteLine(\"     5 -- Type this if you want to check a teensy.\");\n            Console.WriteLine(\"     6 -- Type this if you want to check a litte.\");\n            Console.WriteLine(\"     7 -- Type this if you want to check a lot.\");\n            Console.WriteLine(\"     8 -- Type this if you want to cheat and try to skip a gate.\");\n            Console.WriteLine();\n            Console.WriteLine(\" The place to use these options is when the computer asks:\");\n            Console.WriteLine();\n            Console.WriteLine(\"Option?\");\n            Console.WriteLine();\n            Console.WriteLine(\"               Good Luck!\");\n            Console.WriteLine();\n        }\n\n        private bool PromptYesNo(string Prompt)\n        {\n            bool Success = false;\n\n            while (!Success)\n            {\n                Console.Write(Prompt);\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (LineInput.Equals(\"yes\"))\n                    return true;\n                else if (LineInput.Equals(\"no\"))\n                    return false;\n                else\n                    Console.WriteLine(\"Please type 'YES' or 'NO'\");\n            }\n\n            return false;\n        }\n\n        private int PromptForGates()\n        {\n            bool Success = false;\n            int NumberOfGates = 0;\n\n            while (!Success)\n            {\n                Console.Write(\"How many gates does this course have (1 to 25) \");\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (int.TryParse(LineInput, out NumberOfGates))\n                {\n                    if (NumberOfGates >= 1 && NumberOfGates <= 25)\n                    {\n                        Success = true;\n                    }\n                    else if (NumberOfGates < 1)\n                    {\n                        Console.WriteLine(\"Try again,\");\n                    }\n                    else // greater than 25\n                    {\n                        Console.WriteLine(\"25 is the limit.\");\n                        NumberOfGates = 25;\n                        Success = true;\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(\"Try again,\");\n                }\n            }\n\n            return NumberOfGates;\n        }\n\n        private int PromptForRate()\n        {\n            bool Success = false;\n            int Rating = 0;\n\n            while (!Success)\n            {\n                Console.Write(\"Rate yourself as a skier, (1=worst, 3=best) \");\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (int.TryParse(LineInput, out Rating))\n                {\n                    if (Rating >= 1 && Rating <= 3)\n                    {\n                        Success = true;\n                    }\n                    else\n                    {\n                        Console.WriteLine(\"The bounds are 1-3\");\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(\"The bounds are 1-3\");\n                }\n            }\n\n            return Rating;\n        }\n\n        private int PromptForOption()\n        {\n            bool Success = false;\n            int Option = 0;\n\n            while (!Success)\n            {\n                Console.Write(\"Option? \");\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (int.TryParse(LineInput, out Option))\n                {\n                    if (Option >= 0 && Option <= 8)\n                    {\n                        Success = true;\n                    }\n                    else if (Option > 8)\n                    {\n                        Console.WriteLine(\"What?\");\n                    }\n                }\n                else\n                {\n                    Console.WriteLine(\"What?\");\n                }\n            }\n\n            return Option;\n        }\n\n        private string PromptForCommand()\n        {\n            bool Success = false;\n            string Result = \"\";\n\n            Console.WriteLine();\n            Console.WriteLine(\"Type \\\"INS\\\" for intructions\");\n            Console.WriteLine(\"Type \\\"MAX\\\" for approximate maximum speeds\");\n            Console.WriteLine(\"Type \\\"RUN\\\" for the beginning of the race\");\n\n            while (!Success)\n            {\n\n                Console.Write(\"Command--? \");\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (LineInput.Equals(\"ins\") || LineInput.Equals(\"max\") || LineInput.Equals(\"run\"))\n                {\n                    Result = LineInput;\n                    Success = true;\n                }\n                else\n                {\n                    Console.WriteLine();\n                    Console.WriteLine();\n                    Console.WriteLine(\"\\\"{0}\\\" is an illegal command--retry\", LineInput);\n                }\n            }\n\n            return Result;\n        }\n\n        private bool ExceedGateSpeed(double MaxGateSpeed, double MPH, double Time)\n        {\n            Random rand = new Random();\n\n            Console.WriteLine(\"{0:N0} M.P.H.\", MPH);\n            if (MPH > MaxGateSpeed)\n            {\n                Console.Write(\"You went over the maximum speed \");\n                if (rand.NextDouble() < ((MPH - (double)MaxGateSpeed) * 0.1) + 0.2)\n                {\n                    Console.WriteLine(\"and made it!\");\n                }\n                else\n                {\n                    if (rand.NextDouble() < 0.5)\n                    {\n                        Console.WriteLine(\"snagged a flag!\");\n                    }\n                    else\n                    {\n                        Console.WriteLine(\"wiped out!\");\n                    }\n\n                    Console.WriteLine(\"You took {0:N2} seconds\", rand.NextDouble() + Time);\n\n                    return false;\n                }\n            }\n            else if (MPH > (MaxGateSpeed - 1))\n            {\n                Console.WriteLine(\"Close one!\");\n            }\n\n            return true;\n        }\n        private void DoARun(int NumberOfGates, int Rating)\n        {\n            Random rand = new Random();\n            double MPH = 0;\n            double Time = 0;\n            int Option = 0;\n            double MaxGateSpeed = 0; // Q\n            double PreviousMPH = 0;\n            double Medals = 0;\n\n            Console.WriteLine(\"The starter counts down...5...4...3...2...1...GO!\");\n\n            MPH = rand.NextDouble() * (18-9)+9;\n\n            Console.WriteLine();\n            Console.WriteLine(\"You're off!\");\n\n            for (int GateNumber = 1; GateNumber <= NumberOfGates; GateNumber++)\n            {\n                MaxGateSpeed = GateMaxSpeed[GateNumber-1];\n\n                Console.WriteLine();\n                Console.WriteLine(\"Here comes Gate # {0}:\", GateNumber);\n                Console.WriteLine(\"{0:N0} M.P.H.\", MPH);\n\n                PreviousMPH = MPH;\n\n                Option = PromptForOption();\n                while (Option == 0)\n                {\n                    Console.WriteLine(\"You've taken {0:N2} seconds.\", Time);\n                    Option = PromptForOption();\n                }\n\n                switch (Option)\n                {\n                    case 1:\n                        MPH = MPH + (rand.NextDouble() * (10-5)+5);\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 2:\n                        MPH = MPH + (rand.NextDouble() * (5-3)+3);\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 3:\n                        MPH = MPH + (rand.NextDouble() * (4-1)+1);\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 4:\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 5:\n                        MPH = MPH - (rand.NextDouble() * (4-1)+1);\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 6:\n                        MPH = MPH - (rand.NextDouble() * (5-3)+3);\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 7:\n                        MPH = MPH - (rand.NextDouble() * (10-5)+5);\n                        if (ExceedGateSpeed(MaxGateSpeed, MPH, Time))\n                            break;\n                        else\n                            return;\n                    case 8:  // Cheat!\n                        Console.WriteLine(\"***Cheat\");\n                        if (rand.NextDouble() < 0.7)\n                        {\n                            Console.WriteLine(\"An official caught you!\");\n                            Console.WriteLine(\"You took {0:N2} seconds.\", Time);\n\n                            return;\n                        }\n                        else\n                        {\n                            Console.WriteLine(\"You made it!\");\n                            Time = Time + 1.5;\n                        }\n                        break;\n                }\n\n                if (MPH < 7)\n                {\n                    Console.WriteLine(\"Let's be realistic, OK?  Let's go back and try again...\");\n                    MPH = PreviousMPH;\n                }\n                else\n                {\n                    Time = Time + (MaxGateSpeed - MPH + 1);\n                    if (MPH > MaxGateSpeed)\n                    {\n                        Time = Time + 0.5;\n\n                    }\n                }\n            }\n\n            Console.WriteLine();\n            Console.WriteLine(\"You took {0:N2} seconds.\", Time);\n\n            Medals = Time;\n            Medals = Medals / NumberOfGates;\n\n            if (Medals < (1.5 - (Rating * 0.1)))\n            {\n                Console.WriteLine(\"You won a gold medal!\");\n                GoldMedals++;\n            }\n            else if (Medals < (2.9 - (Rating * 0.1)))\n            {\n                Console.WriteLine(\"You won a silver medal!\");\n                SilverMedals++;\n            }\n            else if (Medals < (4.4 - (Rating * 0.01)))\n            {\n                Console.WriteLine(\"You won a bronze medal!\");\n                BronzeMedals++;\n            }\n        }\n\n        private void PlayOneRound()\n        {\n            int NumberOfGates = 0;\n            string Command = \"first\";\n            bool KeepPlaying = false;\n            int Rating = 0;\n\n            Console.WriteLine(\"\");\n\n            NumberOfGates = PromptForGates();\n\n            while (!Command.Equals(\"\"))\n            {\n                Command = PromptForCommand();\n\n                // Display instructions\n                if (Command.Equals(\"ins\"))\n                {\n                    DisplayInstructions();\n                }\n                else if (Command.Equals(\"max\"))\n                {\n                    Console.WriteLine(\"Gate Max\");\n                    Console.WriteLine(\" #  M.P.H.\");\n                    Console.WriteLine(\"----------\");\n                    for (int i = 0; i < NumberOfGates; i++)\n                    {\n                        Console.WriteLine(\" {0}     {1}\", i+1, GateMaxSpeed[i]);\n                    }\n                }\n                else // do a run!\n                {\n                    Rating = PromptForRate();\n\n                    do\n                    {\n                        DoARun(NumberOfGates, Rating);\n\n                        KeepPlaying = PromptYesNo(\"Do you want to race again? \");\n                    }\n                    while (KeepPlaying);\n\n                    Console.WriteLine(\"Thanks for the race\");\n\n                    if (GoldMedals > 0)\n                        Console.WriteLine(\"Gold Medals: {0}\", GoldMedals);\n                    if (SilverMedals > 0)\n                        Console.WriteLine(\"Silver Medals: {0}\", SilverMedals);\n                    if (BronzeMedals > 0)\n                        Console.WriteLine(\"Bronze Medals: {0}\", BronzeMedals);\n\n                    return;\n                }\n            }\n        }\n\n        public void PlayTheGame()\n        {\n            DisplayIntro();\n\n            PlayOneRound();\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Slalom().PlayTheGame();\n\n        }\n    }\n}\n"
  },
  {
    "path": "79_Slalom/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "79_Slalom/java/Slalom.java",
    "content": "import java.util.Arrays;\r\nimport java.util.InputMismatchException;\r\nimport java.util.Random;\r\nimport java.util.Scanner;\r\n\r\n/**\r\n * Slalom\r\n * <p>\r\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\r\n *\r\n * There is a bug in the original version where the data pointer doesn't reset after a race is completed. This causes subsequent races to error at\r\n * some future point on line \"540    READ Q\"\r\n */\r\npublic class Slalom {\r\n\r\n    private static final int MAX_NUM_GATES = 25;\r\n    private static final int[] MAX_SPEED = {\r\n            14, 18, 26, 29, 18,\r\n            25, 28, 32, 29, 20,\r\n            29, 29, 25, 21, 26,\r\n            29, 20, 21, 20, 18,\r\n            26, 25, 33, 31, 22\r\n    };\r\n\r\n    public static void main(String[] args) {\r\n        var random = new Random();\r\n\r\n        printIntro();\r\n        Scanner scanner = new Scanner(System.in);\r\n\r\n        int numGates = readNumberOfGatesChoice(scanner);\r\n\r\n        printMenu();\r\n        MenuChoice menuChoice;\r\n        do {\r\n            menuChoice = readMenuOption(scanner);\r\n            switch (menuChoice) {\r\n                case INS:\r\n                    printInstructions();\r\n                    break;\r\n                case MAX:\r\n                    printApproxMaxSpeeds(numGates);\r\n                    break;\r\n                case RUN:\r\n                    run(numGates, scanner, random);\r\n                    break;\r\n            }\r\n        } while (menuChoice != MenuChoice.RUN);\r\n    }\r\n\r\n    private static void run(int numGates, Scanner scan, Random random) {\r\n        int rating = readSkierRating(scan);\r\n        boolean gameInProgress = true;\r\n        var medals = new Medals(0, 0, 0);\r\n\r\n        while (gameInProgress) {\r\n            System.out.println(\"THE STARTER COUNTS DOWN...5...4...3...2...1...GO!\");\r\n            System.out.println(\"YOU'RE OFF!\");\r\n\r\n            int speed = random.nextInt(18 - 9) + 9;\r\n\r\n            float totalTimeTaken = 0;\r\n            try {\r\n                totalTimeTaken = runThroughGates(numGates, scan, random, speed);\r\n                System.out.printf(\"%nYOU TOOK %.2f SECONDS.%n\", totalTimeTaken + random.nextFloat());\r\n\r\n                medals = evaluateAndUpdateMedals(totalTimeTaken, numGates, rating, medals);\r\n            } catch (WipedOutOrSnaggedAFlag | DisqualifiedException e) {\r\n                //end of this race! Print time taken and stop\r\n                System.out.printf(\"%nYOU TOOK %.2f SECONDS.%n\", totalTimeTaken + random.nextFloat());\r\n            }\r\n\r\n            gameInProgress = readRaceAgainChoice(scan);\r\n        }\r\n\r\n        System.out.println(\"THANKS FOR THE RACE\");\r\n        if (medals.getGold() >= 1) System.out.printf(\"GOLD MEDALS: %d%n\", medals.getGold());\r\n        if (medals.getSilver() >= 1) System.out.printf(\"SILVER MEDALS: %d%n\", medals.getSilver());\r\n        if (medals.getBronze() >= 1) System.out.printf(\"BRONZE MEDALS: %d%n\", medals.getBronze());\r\n    }\r\n\r\n    private static Medals evaluateAndUpdateMedals(float totalTimeTaken, int numGates, int rating,\r\n                                                  Medals medals) {\r\n        var m = totalTimeTaken;\r\n        m = m / numGates;\r\n        int goldMedals = medals.getGold();\r\n        int silverMedals = medals.getSilver();\r\n        int bronzeMedals = medals.getBronze();\r\n        if (m < 1.5 - (rating * 0.1)) {\r\n            System.out.println(\"YOU WON A GOLD MEDAL!\");\r\n            goldMedals++;\r\n        } else if (m < 2.9 - rating * 0.1) {\r\n            System.out.println(\"YOU WON A SILVER MEDAL\");\r\n            silverMedals++;\r\n        } else if (m < 4.4 - rating * 0.01) {\r\n            System.out.println(\"YOU WON A BRONZE MEDAL\");\r\n            bronzeMedals++;\r\n        }\r\n        return new Medals(goldMedals, silverMedals, bronzeMedals);\r\n    }\r\n\r\n    /**\r\n     * @return the total time taken through all the gates.\r\n     */\r\n    private static float runThroughGates(int numGates, Scanner scan, Random random, int speed) throws DisqualifiedException, WipedOutOrSnaggedAFlag {\r\n        float totalTimeTaken = 0.0f;\r\n        for (int i = 0; i < numGates; i++) {\r\n            var gateNum = i + 1;\r\n            boolean stillInRace = true;\r\n            boolean gateCompleted = false;\r\n            while (!gateCompleted) {\r\n                System.out.printf(\"%nHERE COMES GATE # %d:%n\", gateNum);\r\n                printSpeed(speed);\r\n\r\n                var tmpSpeed = speed;\r\n\r\n                int chosenOption = readOption(scan);\r\n                switch (chosenOption) {\r\n                    case 0:\r\n                        //how long\r\n                        printHowLong(totalTimeTaken, random);\r\n                        break;\r\n                    case 1:\r\n                        //speed up a lot\r\n                        speed = speed + random.nextInt(10 - 5) + 5;\r\n                        break;\r\n                    case 2:\r\n                        //speed up a little\r\n                        speed = speed + random.nextInt(5 - 3) + 3;\r\n                        break;\r\n                    case 3:\r\n                        //speed up a teensy\r\n                        speed = speed + random.nextInt(4 - 1) + 1;\r\n                        break;\r\n                    case 4:\r\n                        //keep going at the same speed\r\n                        break;\r\n                    case 5:\r\n                        //check a teensy\r\n                        speed = speed - random.nextInt(4 - 1) + 1;\r\n                        break;\r\n                    case 6:\r\n                        //check a little\r\n                        speed = speed - random.nextInt(5 - 3) + 3;\r\n                        break;\r\n                    case 7:\r\n                        //check a lot\r\n                        speed = speed - random.nextInt(10 - 5) + 5;\r\n                        break;\r\n                    case 8:\r\n                        //cheat\r\n                        System.out.println(\"***CHEAT\");\r\n                        if (random.nextFloat() < 0.7) {\r\n                            System.out.println(\"AN OFFICIAL CAUGHT YOU!\");\r\n                            stillInRace = false;\r\n                        } else {\r\n                            System.out.println(\"YOU MADE IT!\u0007\");\r\n                            totalTimeTaken = totalTimeTaken + 1.5f;\r\n                        }\r\n                        break;\r\n                }\r\n\r\n                if (stillInRace) {\r\n                    printSpeed(speed);\r\n                    stillInRace = checkAndProcessIfOverMaxSpeed(random, speed, MAX_SPEED[i]);\r\n                    if (!stillInRace) throw new WipedOutOrSnaggedAFlag();\r\n                } else {\r\n                    throw new DisqualifiedException();//we've been dis-qualified\r\n                }\r\n\r\n                if (speed < 7) {\r\n                    System.out.println(\"LET'S BE REALISTIC, OK?  LET'S GO BACK AND TRY AGAIN...\");\r\n                    speed = tmpSpeed;\r\n                    gateCompleted = false;\r\n                } else {\r\n                    totalTimeTaken = totalTimeTaken + (MAX_SPEED[i] - speed + 1);\r\n                    if (speed > MAX_SPEED[i]) {\r\n                        totalTimeTaken = totalTimeTaken + 0.5f;\r\n                    }\r\n                    gateCompleted = true;\r\n                }\r\n            }\r\n\r\n        }\r\n        return totalTimeTaken;\r\n    }\r\n\r\n    private static boolean checkAndProcessIfOverMaxSpeed(Random random, int speed, int maxSpeed) {\r\n        boolean stillInRace = true;\r\n        if (speed > maxSpeed) {\r\n            if (random.nextFloat() >= (speed - maxSpeed) * 0.1 + 0.2) {\r\n                System.out.println(\"YOU WENT OVER THE MAXIMUM SPEED AND MADE IT!\");\r\n            } else {\r\n                System.out.print(\"YOU WENT OVER THE MAXIMUM SPEED AND \");\r\n                if (random.nextBoolean()) {\r\n                    System.out.println(\"WIPED OUT!\");\r\n                } else {\r\n                    System.out.println(\"SNAGGED A FLAG!\");\r\n                }\r\n                stillInRace = false;\r\n            }\r\n        } else if (speed > maxSpeed - 1) {\r\n            System.out.println(\"CLOSE ONE!\");\r\n        }\r\n        return stillInRace;\r\n    }\r\n\r\n    private static boolean readRaceAgainChoice(Scanner scan) {\r\n        System.out.print(\"\\nDO YOU WANT TO RACE AGAIN? \");\r\n        String raceAgain = \"\";\r\n        final String YES = \"YES\";\r\n        final String NO = \"NO\";\r\n        while (!YES.equals(raceAgain) && !NO.equals(raceAgain)) {\r\n            raceAgain = scan.nextLine();\r\n            if (!(YES.equals(raceAgain) || NO.equals(raceAgain))) {\r\n                System.out.println(\"PLEASE TYPE 'YES' OR 'NO'\");\r\n            }\r\n        }\r\n        return raceAgain.equals(YES);\r\n    }\r\n\r\n    private static void printSpeed(int speed) {\r\n        System.out.printf(\"%3d M.P.H.%n\", speed);\r\n    }\r\n\r\n    private static void printHowLong(float t, Random random) {\r\n        System.out.printf(\"YOU'VE TAKEN %.2f SECONDS.%n\", t + random.nextFloat());\r\n    }\r\n\r\n    private static int readOption(Scanner scan) {\r\n        Integer option = null;\r\n\r\n        while (option == null) {\r\n            System.out.print(\"OPTION? \");\r\n            try {\r\n                option = scan.nextInt();\r\n            } catch (InputMismatchException ex) {\r\n                System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\\n\");\r\n            }\r\n            scan.nextLine();\r\n            if (option != null && (option > 8 || option < 0)) {\r\n                System.out.println(\"WHAT?\");\r\n                option = null;\r\n            }\r\n        }\r\n        return option;\r\n    }\r\n\r\n    private static int readSkierRating(Scanner scan) {\r\n        int rating = 0;\r\n\r\n        while (rating < 1 || rating > 3) {\r\n            System.out.print(\"RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)? \");\r\n            try {\r\n                rating = scan.nextInt();\r\n                if (rating < 1 || rating > 3) {\r\n                    System.out.println(\"THE BOUNDS ARE 1-3\");\r\n                }\r\n            } catch (InputMismatchException ex) {\r\n                System.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\\n\");\r\n            }\r\n            scan.nextLine();\r\n        }\r\n        return rating;\r\n    }\r\n\r\n    private static void printApproxMaxSpeeds(int numGates) {\r\n        System.out.println(\"GATE MAX\");\r\n        System.out.println(\" #  M.P.H.\");\r\n        System.out.println(\"---------\");\r\n        for (int i = 0; i < numGates; i++) {\r\n            System.out.println((i+1) + \"  \" + MAX_SPEED[i]);\r\n        }\r\n    }\r\n\r\n    private static void printInstructions() {\r\n        System.out.println(\"\\n*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM.  YOU ARE\");\r\n        System.out.println(\"            THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL.\");\r\n        System.out.println();\r\n        System.out.println(\"     0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN.\");\r\n        System.out.println(\"     1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT.\");\r\n        System.out.println(\"     2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE.\");\r\n        System.out.println(\"     3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY.\");\r\n        System.out.println(\"     4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED.\");\r\n        System.out.println(\"     5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY.\");\r\n        System.out.println(\"     6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE.\");\r\n        System.out.println(\"     7 -- TYPE THIS IF YOU WANT TO CHECK A LOT.\");\r\n        System.out.println(\"     8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE.\");\r\n        System.out.println();\r\n        System.out.println(\" THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:\");\r\n        System.out.println();\r\n        System.out.println(\"OPTION?\");\r\n        System.out.println();\r\n        System.out.println(\"                GOOD LUCK!\");\r\n    }\r\n\r\n    private static MenuChoice readMenuOption(Scanner scan) {\r\n        System.out.print(\"COMMAND--? \");\r\n        MenuChoice menuChoice = null;\r\n\r\n        while (menuChoice == null) {\r\n            String choice = scan.next();\r\n            if (Arrays.stream(MenuChoice.values()).anyMatch(a -> a.name().equals(choice))) {\r\n                menuChoice = MenuChoice.valueOf(choice);\r\n            } else {\r\n                System.out.print(\"\\\"\"+ choice + \"\\\" IS AN ILLEGAL COMMAND--RETRY? \");\r\n            }\r\n            scan.nextLine();\r\n        }\r\n        return menuChoice;\r\n    }\r\n\r\n    private static void printMenu() {\r\n        System.out.println(\"TYPE INS FOR INSTRUCTIONS\");\r\n        System.out.println(\"TYPE MAX FOR APPROXIMATE MAXIMUM SPEEDS\");\r\n        System.out.println(\"TYPE RUN FOR THE BEGINNING OF THE RACE\");\r\n    }\r\n\r\n    private static int readNumberOfGatesChoice(Scanner scan) {\r\n        int numGates = 0;\r\n        while (numGates < 1) {\r\n            System.out.print(\"HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)? \");\r\n            numGates = scan.nextInt();\r\n            if (numGates > MAX_NUM_GATES) {\r\n                System.out.println(MAX_NUM_GATES + \" IS THE LIMIT.\");\r\n                numGates = MAX_NUM_GATES;\r\n            }\r\n        }\r\n        return numGates;\r\n    }\r\n\r\n    private static void printIntro() {\r\n        System.out.println(\"                                SLALOM\");\r\n        System.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\r\n        System.out.println(\"\\n\\n\");\r\n    }\r\n\r\n    private enum MenuChoice {\r\n        INS, MAX, RUN\r\n    }\r\n\r\n    private static class DisqualifiedException extends Exception {\r\n    }\r\n\r\n    private static class WipedOutOrSnaggedAFlag extends Exception {\r\n    }\r\n\r\n    private static class Medals {\r\n        private int gold = 0;\r\n        private int silver = 0;\r\n        private int bronze = 0;\r\n\r\n        public Medals(int gold, int silver, int bronze) {\r\n            this.gold = gold;\r\n            this.silver = silver;\r\n            this.bronze = bronze;\r\n        }\r\n\r\n        public int getGold() {\r\n            return gold;\r\n        }\r\n\r\n        public int getSilver() {\r\n            return silver;\r\n        }\r\n\r\n        public int getBronze() {\r\n            return bronze;\r\n        }\r\n    }\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "79_Slalom/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "79_Slalom/javascript/slalom.html",
    "content": "<html>\n<head>\n<title>SLALOM</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"slalom.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "79_Slalom/javascript/slalom.js",
    "content": "// SLALOM\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar speed = [,14,18,26,29,18,\n             25,28,32,29,20,\n             29,29,25,21,26,\n             29,20,21,20,18,\n             26,25,33,31,22];\n\nfunction show_instructions()\n{\n    print(\"\\n\");\n    print(\"*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM.  YOU ARE\\n\");\n    print(\"            THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL.\\n\");\n    print(\"\\n\");\n    print(\"     0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN.\\n\");\n    print(\"     1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT.\\n\");\n    print(\"     2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE.\\n\");\n    print(\"     3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY.\\n\");\n    print(\"     4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED.\\n\");\n    print(\"     5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY.\\n\");\n    print(\"     6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE.\\n\");\n    print(\"     7 -- TYPE THIS IF YOU WANT TO CHECK A LOT.\\n\");\n    print(\"     8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE.\\n\");\n    print(\"\\n\");\n    print(\" THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:\\n\");\n    print(\"\\n\");\n    print(\"OPTION?\\n\");\n    print(\"\\n\");\n    print(\"                GOOD LUCK!\\n\");\n    print(\"\\n\");\n}\n\nfunction show_speeds()\n{\n    print(\"GATE MAX\\n\");\n    print(\" #  M.P.H.\\n\");\n    print(\"----------\\n\");\n    for (var b = 1; b <= v; b++) {\n        print(\" \" + b + \"  \" + speed[b] + \"\\n\");\n    }\n}\n\n// Main program\nasync function main()\n{\n    var gold = 0;\n    var silver = 0;\n    var bronze = 0;\n\n    print(tab(33) + \"SLALOM\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)\");\n        v = parseInt(await input());\n        if (v >= 25) {\n            print(\"25 IS THE LIMIT\\n\");\n            v = 25;\n        } else if (v < 1) {\n            print(\"TRY AGAIN.\\n\");\n        } else {\n            break;\n        }\n    }\n    print(\"\\n\");\n    print(\"TYPE \\\"INS\\\" FOR INSTRUCTIONS\\n\");\n    print(\"TYPE \\\"MAX\\\" FOR APPROXIMATE MAXIMUM SPEEDS\\n\");\n    print(\"TYPE \\\"RUN\\\" FOR THE BEGINNING OF THE RACE\\n\");\n    while (1) {\n        print(\"COMMAND--\");\n        str = await input();\n        if (str == \"INS\") {\n            show_instructions();\n        } else if (str == \"MAX\") {\n            show_speeds();\n        } else if (str == \"RUN\") {\n            break;\n        } else {\n            print(\"\\\"\" + str + \"\\\" IS AN ILLEGAL COMMAND--RETRY\");\n        }\n    }\n    while (1) {\n        print(\"RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)\");\n        a = parseInt(await input());\n        if (a < 1 || a > 3)\n            print(\"THE BOUNDS ARE 1-3\\n\");\n        else\n            break;\n    }\n    while (1) {\n        print(\"THE STARTER COUNTS DOWN...5...4...3...2...1...GO!\");\n        t = 0;\n        s = Math.floor(Math.random(1) * (18 - 9) + 9);\n        print(\"\\n\");\n        print(\"YOU'RE OFF!\\n\");\n        for (o = 1; o <= v; o++) {\n            q = speed[o];\n            print(\"\\n\");\n            print(\"HERE COMES GATE #\" + o + \" :\\n\");\n            print(s + \" M.P.H.\\n\");\n            s1 = s;\n            while (1) {\n                print(\"OPTION\");\n                o1 = parseInt(await input());\n                if (o1 < 0 || o1 > 8)\n                    print(\"WHAT?\\n\");\n                else if (o1 == 0)\n                    print(\"YOU'VE TAKEN \" + (t + Math.random()) + \" SECONDS.\\n\");\n                else\n                    break;\n            }\n            finish = false;\n            switch (o1) {\n                case 1:\n                    s += Math.floor(Math.random() * (10 - 5) + 5);\n                    break;\n                case 2:\n                    s += Math.floor(Math.random() * (5 - 3) + 3);\n                    break;\n                case 3:\n                    s += Math.floor(Math.random() * (4 - 1) + 1);\n                    break;\n                case 4:\n                    break;\n                case 5:\n                    s -= Math.floor(Math.random() * (4 - 1) + 1);\n                    break;\n                case 6:\n                    s -= Math.floor(Math.random() * (5 - 3) + 3);\n                    break;\n                case 7:\n                    s -= Math.floor(Math.random() * (10 - 5) + 5);\n                    break;\n                case 8:\n                    print(\"***CHEAT\\n\");\n                    if (Math.random() >= 0.7) {\n                        print(\"YOU MADE IT!\\n\");\n                        t += 1.5;\n                    } else {\n                        print(\"AN OFFICIAL CAUGHT YOU!\\n\");\n                        print(\"YOU TOOK \" + (t + Math.random()) + \" SECONDS.\\n\");\n                        finish = true;\n                    }\n                    break;\n            }\n            if (!finish) {\n                if (o1 != 4)\n                    print(s + \" M.P.H.\\n\");\n                if (s > q) {\n                    if (Math.random() < ((s - q) * 0.1) + 0.2) {\n                        print(\"YOU WENT OVER THE MAXIMUM SPEED AND \");\n                        if (Math.random() < 0.5) {\n                            print(\"SNAGGED A FLAG!\\n\");\n                        } else {\n                            print(\"WIPED OUT!\\n\");\n                        }\n                        print(\"YOU TOOK \" + (t + Math.random()) + \" SECONDS.\\n\");\n                        finish = true;\n                    } else {\n                        print(\"YOU WENT OVER THE MAXIMUM SPEED AND MADE IT!\\n\");\n                    }\n                } else if (s > q - 1) {\n                    print(\"CLOSE ONE!\\n\");\n                }\n            }\n            if (finish)\n                break;\n            if (s < 7) {\n                print(\"LET'S BE REALISTIC, OK?  LET'S GO BACK AND TRY AGAIN...\\n\");\n                s = s1;\n                o--;\n                continue;\n            }\n            t += q - s + 1;\n            if (s > q) {\n                t += 0.5;\n            }\n        }\n        if (!finish) {\n            print(\"\\n\");\n            print(\"YOU TOOK \" + (t + Math.random()) + \" SECONDS.\\n\");\n            m = t;\n            m /= v;\n            if (m < 1.5 - (a * 0.1)) {\n                print(\"YOU WON A GOLD MEDAL!\\n\");\n                gold++;\n            } else if (m < 2.9 - (a * 0.1)) {\n                print(\"YOU WON A SILVER MEDAL\\n\");\n                silver++;\n            } else if (m < 4.4 - (a * 0.1)) {\n                print(\"YOU WON A BRONZE MEDAL\\n\");\n                bronze++;\n            }\n        }\n        while (1) {\n            print(\"\\n\");\n            print(\"DO YOU WANT TO RACE AGAIN\");\n            str = await input();\n            if (str != \"YES\" && str != \"NO\")\n                print(\"PLEASE TYPE 'YES' OR 'NO'\\n\");\n            else\n                break;\n        }\n        if (str != \"YES\")\n            break;\n    }\n    print(\"THANKS FOR THE RACE\\n\");\n    if (gold >= 1)\n        print(\"GOLD MEDALS: \" + gold + \"\\n\");\n    if (silver >= 1)\n        print(\"SILVER MEDALS: \" + silver + \"\\n\");\n    if (bronze >= 1)\n        print(\"BRONZE MEDALS: \" + bronze + \"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "79_Slalom/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "79_Slalom/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "79_Slalom/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "79_Slalom/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "79_Slalom/python/slalom.py",
    "content": "from random import random\n\nmedals = {\n    \"gold\": 0,\n    \"silver\": 0,\n    \"bronze\": 0,\n}\n\n\ndef ask(question: str) -> str:\n    print(question, end=\"? \")\n    return input().upper()\n\n\ndef ask_int(question: str) -> int:\n    reply = ask(question)\n    return int(reply) if reply.isnumeric() else -1\n\n\ndef pre_run(gates, max_speeds) -> None:\n    print('\\nType \"INS\" for instructions')\n    print('Type \"MAX\" for approximate maximum speeds')\n    print('Type \"RUN\" for the beginning of the race')\n    cmd = ask(\"Command--\")\n    while cmd != \"RUN\":\n        if cmd == \"INS\":\n            print(\"\\n*** Slalom: This is the 1976 Winter Olypic Giant Slalom.  You are\")\n            print(\"            the American team's only hope for a gold medal.\\n\")\n            print(\"     0 -- Type this if you want to see how long you've taken.\")\n            print(\"     1 -- Type this if you want to speed up a lot.\")\n            print(\"     2 -- Type this if you want to speed up a little.\")\n            print(\"     3 -- Type this if you want to speed up a teensy.\")\n            print(\"     4 -- Type this if you want to keep going the same speed.\")\n            print(\"     5 -- Type this if you want to check a teensy.\")\n            print(\"     6 -- Type this if you want to check a little.\")\n            print(\"     7 -- Type this if you want to check a lot.\")\n            print(\"     8 -- Type this if you want to cheat and try to skip a gate.\\n\")\n            print(\" The place to use these options is when the Computer asks:\\n\")\n            print(\"Option?\\n\")\n            print(\"                Good Luck!\\n\")\n            cmd = ask(\"Command--\")\n        elif cmd == \"MAX\":\n            print(\"Gate Max\")\n            print(\" # M.P.H.\")\n            print(\"----------\")\n            for i in range(0, gates):\n                print(f\" {i + 1}  {max_speeds[i]}\")\n            cmd = ask(\"Command--\")\n        else:\n            cmd = ask(f'\"{cmd}\" is an illegal command--Retry')\n\n\ndef run(gates, lvl, max_speeds) -> None:\n    global medals\n    print(\"The starter counts down...5...4...3...2...1...Go!\")\n    time: float = 0\n    speed = int(random() * (18 - 9) + 9)\n    print(\"You're off\")\n    for i in range(0, gates):\n        while True:\n            print(f\"\\nHere comes gate #{i + 1}:\")\n            print(f\" {int(speed)} M.P.H.\")\n            old_speed = speed\n            opt = ask_int(\"Option\")\n            while opt < 1 or opt > 8:\n                if opt == 0:\n                    print(f\"You've taken {int(time)} seconds.\")\n                else:\n                    print(\"What?\")\n                opt = ask_int(\"Option\")\n\n            if opt == 8:\n                print(\"***Cheat\")\n                if random() < 0.7:\n                    print(\"An official caught you!\")\n                    print(f\"You took {int(time + random())} seconds.\")\n                    return\n                else:\n                    print(\"You made it!\")\n                    time += 1.5\n            else:\n                match opt:\n                    case 1:\n                        speed += int(random() * (10 - 5) + 5)\n\n                    case 2:\n                        speed += int(random() * (5 - 3) + 3)\n\n                    case 3:\n                        speed += int(random() * (4 - 1) + 1)\n\n                    case 5:\n                        speed -= int(random() * (4 - 1) + 1)\n\n                    case 6:\n                        speed -= int(random() * (5 - 3) + 3)\n\n                    case 7:\n                        speed -= int(random() * (10 - 5) + 5)\n                print(f\" {speed} M.P.H.\")\n                if speed > max_speeds[i]:\n                    if random() < ((speed - max_speeds[i]) * 0.1) + 0.2:\n                        print(\n                            f\"You went over the maximum speed and {'snagged a flag' if random() < .5 else 'wiped out'}!\"\n                        )\n                        print(f\"You took {int(time + random())} seconds\")\n                        return\n                    else:\n                        print(\"You went over the maximum speed and made it!\")\n                if speed > max_speeds[i] - 1:\n                    print(\"Close one!\")\n            if speed < 7:\n                print(\"Let's be realistic, ok? Let's go back and try again...\")\n                speed = old_speed\n            else:\n                time += max_speeds[i] - speed + 1\n                if speed > max_speeds[i]:\n                    time += 0.5\n                break\n    print(f\"\\nYou took {int(time + random())} seconds.\")\n    avg = time / gates\n    if avg < 1.5 - (lvl * 0.1):\n        print(\"Yout won a gold medal!\")\n        medals[\"gold\"] += 1\n    elif avg < 2.9 - (lvl * 0.1):\n        print(\"You won a silver medal!\")\n        medals[\"silver\"] += 1\n    elif avg < 4.4 - (lvl * 0.01):\n        print(\"You won a bronze medal!\")\n        medals[\"bronze\"] += 1\n\n\ndef main() -> None:\n    print(\"Slalom\".rjust(39))\n    print(\"Creative Computing Morristown, New Jersey\\n\\n\\n\".rjust(57))\n\n    max_speeds = [\n        14,\n        18,\n        26,\n        29,\n        18,\n        25,\n        28,\n        32,\n        29,\n        20,\n        29,\n        29,\n        25,\n        21,\n        26,\n        29,\n        20,\n        21,\n        20,\n        18,\n        26,\n        25,\n        33,\n        31,\n        22,\n    ]\n\n    while True:\n        gates = ask_int(\"How many gates does this course have (1 to 25)\")\n        if gates < 1:\n            print(\"Try again,\")\n        else:\n            if gates > 25:\n                print(\"25 is the limit.\")\n            break\n\n    pre_run(gates, max_speeds)\n\n    while True:\n        lvl = ask_int(\"Rate yourself as a skier, (1=Worst, 3=Best)\")\n        if lvl < 1 or lvl > 3:\n            print(\"The bounds are 1-3.\")\n        else:\n            break\n\n    while True:\n        run(gates, lvl, max_speeds)\n        while True:\n            answer = ask(\"Do you want to play again?\")\n            if answer in [\"YES\", \"NO\"]:\n                break\n            else:\n                print('Please type \"YES\" or \"NO\"')\n        if answer == \"NO\":\n            break\n\n    print(\"Thanks for the race\")\n    if medals[\"gold\"] > 0:\n        print(f\"Gold medals: {medals['gold']}\")\n    if medals[\"silver\"] > 0:\n        print(f\"Silver medals: {medals['silver']}\")\n    if medals[\"bronze\"] > 0:\n        print(f\"Bronze medals: {medals['bronze']}\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "79_Slalom/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "79_Slalom/slalom.bas",
    "content": "10 PRINT TAB(33);\"SLALOM\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n310 PRINT \"HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)\";\n320 INPUT V\n330 IF V>25 THEN 360\n340 IF V<1 THEN 390\n350 GOTO 1440\n360 PRINT \"25 IS THE LIMIT.\"\n370 LET V=25\n380 GOTO 1440\n390 PRINT \"TRY AGAIN,\"\n400 GOTO 310\n410 PRINT \"RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)\";\n420 INPUT A\n430 IF A<1 THEN 460\n440 IF A>3 THEN 460\n450 GOTO 480\n460 PRINT \"THE BOUNDS ARE 1-3\"\n470 GOTO 410\n480 PRINT\"THE STARTER COUNTS DOWN...5...4...3...2...1...GO!\";\n490 REM\n500 LET T=0\n510 LET S=INT(RND(1)*(18-9)+9)\n520 PRINT\n525 PRINT \"YOU'RE OFF!\"\n530 FOR O=1 TO V\n540    READ Q\n550    PRINT\n555    PRINT \"HERE COMES GATE #\";STR$(O);\":\"\n560    PRINT S;\"M.P.H.\"\n570    LET S1=S\n580    PRINT \"OPTION\";\n590    INPUT O1\n600    IF O1=0 THEN 970\n610   IF O1>8 THEN 1420\n620    IF O1<1 THEN 1420\n630    GOSUB 990\n640    IF S<7 THEN 1390\n650    LET T=T+(Q-S+1)\n660    IF S>Q THEN 1630\n670 NEXT O\n680 PRINT:PRINT \"YOU TOOK\";(T+RND(1));\"SECONDS.\"\n690 LET M=T\n700 LET M=M/V\n710 IF M<1.5-(A*.1) THEN 1650\n720 IF M<2.9-(A*.1) THEN 1680\n730 IF M<4.4-(A*.01) THEN 1710\n740 PRINT:PRINT \"DO YOU WANT TO RACE AGAIN\";\n750 INPUT B$\n760 REM\n770 IF B$=\"NO\" THEN 1740\n780 IF B$=\"YES\" THEN 480\n790 PRINT \"PLEASE TYPE 'YES' OR 'NO'\"\n800 GOTO 740\n810 STOP\n820 PRINT\n825 PRINT \"*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM.  YOU ARE\"\n830 PRINT \"            THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL.\"\n840 PRINT\n845 PRINT \"     0 -- TYPE THIS IF YOU WANT TO SEE HOW LONG YOU'VE TAKEN.\"\n850 PRINT \"     1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT.\"\n860 PRINT \"     2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE.\"\n870 PRINT \"     3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY.\"\n880 PRINT \"     4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED.\"\n890 PRINT \"     5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY.\"\n900 PRINT \"     6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE.\"\n910 PRINT \"     7 -- TYPE THIS IF YOU WANT TO CHECK A LOT.\"\n920 PRINT \"     8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE.\"\n930 PRINT\n935 PRINT \" THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:\"\n940 PRINT\n945 PRINT \"OPTION?\"\n950 PRINT\n955 PRINT \"                GOOD LUCK!\"\n957 PRINT\n960 GOTO 1470\n970 PRINT \"YOU'VE TAKEN\";(T+RND(1));\"SECONDS.\"\n980 GOTO 580\n990 ON O1 GOTO 1130,1010,1170,1080,1190,1100,1150,1210\n1000 STOP\n1010 LET S=S+INT(RND(1)*(5-3)+3)\n1020 PRINT S;\"M.P.H.\"\n1030 IF S>Q THEN 1290\n1040 IF S>Q-1 THEN 1060\n1050 RETURN\n1060 PRINT \"CLOSE ONE!\"\n1070 RETURN\n1080 PRINT S;\"M.P.H.\"\n1090 GOTO 1030\n1100 LET S=S-INT(RND(1)*(5-3)+3)\n1110 PRINT S;\"M.P.H.\"\n1120 GOTO 1030\n1130 LET S=S+INT(RND(1)*(10-5)+5)\n1140 GOTO 1080\n1150 LET S=S-INT(RND(1)*(10-5)+5)\n1160 GOTO 1110\n1170 LET S=S+INT(RND(1)*(4-1)+1)\n1180 GOTO 1110\n1190 LET S=S-INT(RND(1)*(4-1)+1)\n1200 GOTO 1110\n1210 PRINT \"***CHEAT\"\n1220 IF RND(1)<.7 THEN 1260\n1230 PRINT \"YOU MADE IT!\u0007\"\n1240 LET T=T+1.5\n1250 RETURN\n1260 PRINT \"AN OFFICIAL CAUGHT YOU!\"\n1270 PRINT \"YOU TOOK\";(T+RND(1));\"SECONDS.\"\n1280 GOTO 740\n1290 IF RND(1)<((S-Q)*.1)+.2 THEN 1320\n1300 PRINT \"YOU WENT OVER THE NAXIMUM SPEED AND MADE IT!\"\n1310 RETURN\n1320 PRINT \"YOU WENT OVER THE MAXIMUM SPEED AND \";\n1330 IF RND(1)<.5 THEN 1370\n1340 PRINT \"WIPED OUT!\"\n1350 PRINT \"YOU TOOK\";(T+RND(1));\"SECONDS\"\n1360 GOTO 740\n1370 PRINT \"SNAGGED A FLAG!\"\n1380 GOTO 1350\n1390 PRINT \"LET'S BE REALISTIC, OK?  LET'S GO BACK AND TRY AGAIN...\"\n1400 LET S=S1\n1410 GOTO 550\n1420 PRINT \"WHAT?\"\n1430 GOTO 580\n1440 PRINT\n1445 PRINT \"TYPE \";CHR$(34);\"INS\";CHR$(34);\" FOR INSTRUCTIONS\"\n1450 PRINT \"TYPE \";CHR$(34);\"MAX\";CHR$(34);\" FOR APPROXIMATE MAXIMUM SPEEDS\"\n1460 PRINT \"TYPE \";CHR$(34);\"RUN\";CHR$(34);\" FOR THE BEGINNING OF THE RACE\"\n1470 PRINT \"COMMAND--\";\n1480 INPUT A$\n1490 REM\n1500 IF A$=\"INS\" THEN 820\n1510 IF A$=\"MAX\" THEN 1550\n1520 IF A$=\"RUN\" THEN 410\n1530 PRINT CHR$(34);A$;CHR$(34);\" IS AN ILLEGAL COMMAND--RETRY\";\n1540 GOTO 1480\n1550 PRINT \"GATE MAX\"\n1560 PRINT \" #  M.P.H.\"\n1570 PRINT\"----------\"\n1580 FOR B=1 TO V\n1590    READ Q\n1600    PRINT B;\"  \";Q\n1610 NEXT B\n1620 GOTO 1470\n1630 LET T=T+.5\n1640 GOTO 670\n1650 PRINT \"YOU WON A GOLD MEDAL!\"\n1660 LET G(1)=G(1)+1\n1670 GOTO 1730\n1680 PRINT \"YOU WON A SILVER MEDAL\"\n1690 LET S(1)=S(1)+1\n1700 GOTO 1730\n1710 PRINT \"YOU WON A BRONZE MEDAL\"\n1720 LET B(1)=B(1)+1\n1730 GOTO 740\n1740 PRINT \"THANKS FOR THE RACE\"\n1750 IF G(1)<1 THEN 1770\n1760 PRINT \"GOLD MEDALS:\";G(1)\n1770 IF S(1)<1 THEN 1790\n1780 PRINT \"SILVER MEDALS:\";S(1)\n1790 IF B(1)<1 THEN 1830\n1800 PRINT \"BRONZE MEDALS:\";B(1)\n1810 DATA 14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20\n1820 DATA 18,26,25,33,31,22\n1830 END\n"
  },
  {
    "path": "79_Slalom/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "79_Slalom/vbnet/Slalom.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Slalom\", \"Slalom.vbproj\", \"{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "79_Slalom/vbnet/Slalom.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Slalom</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "80_Slots/README.md",
    "content": "### Slots\n\nThe slot machine or one-arm bandit is a mechanical device that will absorb coins just about as fast as you can feed it. After inserting a coin, you pull a handle that sets three independent reels spinning. If the reels stop with certain symbols appearing in the pay line, you get a certain payoff. The original slot machine, called the Liberty Bell, was invented in 1895 by Charles Fey in San Francisco. Fey refused to sell or lease the manufacturing rights, so H.S. Mills in Chicago built a similar, but much improved machine called the Operators Bell. This has survived nearly unchanged to today.\n\nOn the Operators Bell and other standard slot machines, there are 20 symbols on each wheel but they are not distributed evenly among the objects (cherries, bar, apples, etc.). Of the 8,000 passible combinations, the expected payoff (to the player) is 7,049 or $89.11 for every $100.00 put in, one of the lowest expected payoffs in all casino games.\n\nIn the program here, the payoff is considerably more liberal; indeed it appears to favor the player by 11% — i.e., an expected payoff of $111 for each $100 bet.\n\nThe program was originally written by Fred Mirabella and Bob Harper.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=149)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=164)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Known Bugs\n\n- The original program does not correctly detect identical draws in the first and third position as a double (instead, it counts as a loss).  This is probably not intended.  Some of the ports fix this, so that any two matches count as a double.\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "80_Slots/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n\nThis C# implementation of slots was done using a [C# script](https://github.com/filipw/dotnet-script).\n\n# Required\n[.NET Core SDK (i.e., .NET 6.0)](https://dotnet.microsoft.com/en-us/download)\n\nInstall dotnet-script.  On the command line run:\n```\ndotnet tool install -g dotnet-script\n```\n\n# Run\n```\ndotnet script .\\slots.csx\n```\n"
  },
  {
    "path": "80_Slots/csharp/Slots.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "80_Slots/csharp/Slots.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Slots\", \"Slots.csproj\", \"{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "80_Slots/csharp/slots.csx",
    "content": "Print(\"SLOTS\");\nPrint(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\nPrint(); Print(); Print();\nPrint(\"YOU ARE IN THE H&M CASINO,IN FRONT OF ONE OF OUR\");\nPrint(\"ONE-ARM BANDITS. BET FROM $1 TO $100.\");\nPrint(\"TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET.\");\n\nvar _standings = 0;\n\nvar play = true;\nwhile(play)\n{\n    Play();\n    play = PlayAgain();\n}\n\nDone();\n\npublic void Play()\n{\n    var bet = GetBet();\n    Print();\n    Ring();\n\n    var random = new Random();\n    var x = GetSlot();\n    var y = GetSlot();\n    var z = GetSlot();\n\n    Print();\n    Print($\"{x.ToString()} {y.ToString()} {z.ToString()}\");\n\n    if(x == y && x == z)\n    {\n        if(z == Slot.BAR)\n        {\n            // BAR BAR BAR\n            Print();\n            Print(\"***JACKPOT***\");\n            Print(\"YOU WON!\");\n            _standings = (100*bet) + bet + _standings;\n        }\n        else\n        {\n            Print();\n            Print(\"**TOP DOLLAR**\");\n            Print(\"YOU WON!\");\n            _standings = (10*bet) + bet + _standings;\n        }\n    }\n    else if(x == y)\n    {\n        if(y == Slot.BAR)\n        {\n            DoubleBar(bet);\n        }\n        else\n        {\n            Double(bet);\n        }\n    }\n    else if(x == z)\n    {\n        if(z == Slot.BAR)\n        {\n            DoubleBar(bet);\n        }\n        else\n        {\n            Lost(bet);\n        }\n    }\n    else if(y == z)\n    {\n        if(z == Slot.BAR)\n        {\n            DoubleBar(bet);\n        }\n        else\n        {\n            Double(bet);\n        }\n    }\n    else\n    {\n        Lost(bet);\n    }\n\n    Print($\"YOUR STANDINGS ARE ${_standings}\");\n}\n\npublic bool PlayAgain()\n{\n    Console.Write(\"AGAIN? (Y) \");\n    var playAgain = Console.ReadKey(true);\n    Print();\n    return playAgain.Key == ConsoleKey.Y || playAgain.Key == ConsoleKey.Enter;\n}\n\npublic void Done()\n{\n    Print();\n    if(_standings < 0)\n    {\n        Print(\"PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\");\n    }\n    else if (_standings == 0)\n    {\n        Print(\"HEY, YOU BROKE EVEN.\");\n    }\n    else\n    {\n        Print(\"COLLECT YOUR WINNINGS FROM THE H&M CASHIER\");\n    }\n}\n\n// Prints the text provided.  Default is a blank line\npublic void Print(string line = \"\")\n{\n    Console.WriteLine(line);\n}\n\npublic int GetBet()\n{\n    Print();\n    Console.Write(\"YOUR BET \");\n    var betInput = ReadLine();\n    int bet;\n    var inputValid = int.TryParse(betInput, out bet);\n    if (!inputValid)\n    {\n        Print(\"NUMBER EXPECTED - RETRY\");\n        return GetBet();\n    }\n\n    if(bet > 100)\n    {\n        Print(\"HOUSE LIMITS ARE $100\");\n        inputValid = false;\n    }\n    else if(bet < 1)\n    {\n        Print(\"MINIMUM BET IS $1\");\n        inputValid = false;\n    }\n\n    return inputValid ? bet : GetBet();\n}\n\npublic enum Slot { BAR, BELL, ORANGE, LEMON, PLUM, CHERRY };\n\npublic Slot GetSlot()\n{\n    var rand = new Random();\n    var num = rand.Next(0, 5);\n    return (Slot)num;\n}\n\npublic void DoubleBar(int bet)\n{\n    Print();\n    Print(\"*DOUBLE BAR*\");\n    Print(\"YOU WON!\");\n    _standings = (5*bet) + bet + _standings;\n}\n\npublic void Double(int bet)\n{\n    Print();\n    Print(\"DOUBLE!!\");\n    Print(\"YOU WON!\");\n    _standings = (2*bet) + bet + _standings;\n}\n\npublic void Lost(int bet)\n{\n    Print();\n    Print(\"YOU LOST.\");\n    _standings = _standings - bet;\n}\n\npublic void Ring()\n{\n    for(int i = 1; i <= 10; i++)\n    {\n        // https://stackoverflow.com/a/321148/1497\n        Console.Beep();\n        // Console.Beep(800, 501 - (i * 50)); // Uncomment for a fancier bell\n    }\n}\n"
  },
  {
    "path": "80_Slots/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "80_Slots/java/src/Slots.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Slots\n * <p>\n * Based on the Basic game of Slots here\n * https://github.com/coding-horror/basic-computer-games/blob/main/80%20Slots/slots.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Slots {\n\n    public static final String[] SLOT_SYMBOLS = {\"BAR\", \"BELL\", \"ORANGE\", \"LEMON\", \"PLUM\", \"CHERRY\"};\n\n    public static final int NUMBER_SYMBOLS = SLOT_SYMBOLS.length;\n\n    // Jackpot symbol (BAR)\n    public static final int BAR_SYMBOL = 0;\n\n    // Indicator that the current spin won nothing\n    public static final int NO_WINNER = -1;\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    private enum GAME_STATE {\n        START_GAME,\n        ONE_SPIN,\n        RESULTS,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // Different types of spin results\n    private enum WINNINGS {\n        JACKPOT(100),\n        TOP_DOLLAR(10),\n        DOUBLE_BAR(5),\n        REGULAR(2),\n        NO_WIN(0);\n\n        private final int multiplier;\n\n        WINNINGS(int mult) {\n            multiplier = mult;\n        }\n\n        // No win returns the negative amount of net\n        // otherwise calculate winnings based on\n        // multiplier\n        public int calculateWinnings(int bet) {\n\n            if (multiplier == 0) {\n                return -bet;\n            } else {\n                // Return original bet plus a multipler\n                // of the win type\n                return (multiplier * bet) + bet;\n            }\n        }\n    }\n\n    private int playerBalance;\n\n    public Slots() {\n\n        kbScanner = new Scanner(System.in);\n        gameState = GAME_STATE.START_GAME;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        int[] slotReel = new int[3];\n\n        do {\n            // Results of a single spin\n            WINNINGS winnings;\n\n            switch (gameState) {\n\n                case START_GAME:\n                    intro();\n                    playerBalance = 0;\n                    gameState = GAME_STATE.ONE_SPIN;\n                    break;\n\n                case ONE_SPIN:\n\n                    int playerBet = displayTextAndGetNumber(\"YOUR BET? \");\n\n                    slotReel[0] = randomSymbol();\n                    slotReel[1] = randomSymbol();\n                    slotReel[2] = randomSymbol();\n\n                    // Store which symbol (if any) matches at least one other reel\n                    int whichSymbolWon = winningSymbol(slotReel[0], slotReel[1], slotReel[2]);\n\n                    // Display the three randomly drawn symbols\n                    StringBuilder output = new StringBuilder();\n                    for (int i = 0; i < 3; i++) {\n                        if (i > 0) {\n                            output.append(\" \");\n                        }\n                        output.append(SLOT_SYMBOLS[slotReel[i]]);\n                    }\n\n                    System.out.println(output);\n\n                    // Calculate results\n\n                    if (whichSymbolWon == NO_WINNER) {\n                        // No symbols match = nothing won\n                        winnings = WINNINGS.NO_WIN;\n                    } else if (slotReel[0] == slotReel[1] && slotReel[0] == slotReel[2]) {\n                        // Top dollar, 3 matching symbols\n                        winnings = WINNINGS.TOP_DOLLAR;\n                        if (slotReel[0] == BAR_SYMBOL) {\n                            // All 3 symbols are BAR. Jackpot!\n                            winnings = WINNINGS.JACKPOT;\n                        }\n                    } else {\n                        // At this point the remaining options are a regular win\n                        // or a double, since the rest (including not winning) have already\n                        // been checked above.\n                        // Assume a regular win\n                        winnings = WINNINGS.REGULAR;\n\n                        // But if it was the BAR symbol that matched, its a double bar\n                        if (slotReel[0] == BAR_SYMBOL) {\n                            winnings = WINNINGS.DOUBLE_BAR;\n                        }\n\n                    }\n\n                    // Update the players balance with the amount won or lost on this spin\n                    playerBalance += winnings.calculateWinnings(playerBet);\n\n                    System.out.println();\n\n                    // Output what happened on this spin\n                    switch (winnings) {\n                        case NO_WIN:\n                            System.out.println(\"YOU LOST.\");\n                            break;\n\n                        case REGULAR:\n                            System.out.println(\"DOUBLE!!\");\n                            System.out.println(\"YOU WON!\");\n                            break;\n\n                        case DOUBLE_BAR:\n                            System.out.println(\"*DOUBLE BAR*\");\n                            System.out.println(\"YOU WON!\");\n                            break;\n\n                        case TOP_DOLLAR:\n                            System.out.println();\n                            System.out.println(\"**TOP DOLLAR**\");\n                            System.out.println(\"YOU WON!\");\n                            break;\n\n                        case JACKPOT:\n                            System.out.println();\n                            System.out.println(\"***JACKPOT***\");\n                            System.out.println(\"YOU WON!\");\n                            break;\n\n                    }\n\n                    System.out.println(\"YOUR STANDINGS ARE $\" + playerBalance);\n\n                    // If player does not elect to play again, show results of session\n                    if (!yesEntered(displayTextAndGetInput(\"AGAIN? \"))) {\n                        gameState = GAME_STATE.RESULTS;\n\n                    }\n                    break;\n\n                case RESULTS:\n                    if (playerBalance == 0) {\n                        System.out.println(\"HEY, YOU BROKE EVEN.\");\n                    } else if (playerBalance > 0) {\n                        System.out.println(\"COLLECT YOUR WINNINGS FROM THE H&M CASHIER.\");\n                    } else {\n                        // Lost\n                        System.out.println(\"PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\");\n                    }\n\n                    gameState = GAME_STATE.GAME_OVER;\n                    break;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(30) + \"SLOTS\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"YOU ARE IN THE H&M CASINO,IN FRONT OF ONE OF OUR\");\n        System.out.println(\"ONE-ARM BANDITS. BET FROM $1 TO $100.\");\n        System.out.println(\"TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET.\");\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to an Integer\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private int displayTextAndGetNumber(String text) {\n        return Integer.parseInt(displayTextAndGetInput(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text));\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n\n    /**\n     * Find the symbol that won this round i.e. the first reel that matched another reel\n     *\n     * @param reel1 reel1 spin result\n     * @param reel2 reel2 spin result\n     * @param reel3 reel3 spin result\n     * @return NO_WINNER if no reels match otherwise an int 0-2 to indicate the reel that matches another\n     */\n    private int winningSymbol(int reel1, int reel2, int reel3) {\n        if (reel1 == reel2) {\n            return 0;\n        } else if (reel1 == reel3) {\n            return 0;\n        } else if (reel2 == reel3) {\n            return 1;\n        } else {\n            return NO_WINNER;\n        }\n    }\n\n    /**\n     * Random symbol for a slot wheel\n     *\n     * @return number between 0-5\n     */\n    private int randomSymbol() {\n        return (int) (Math.random() * NUMBER_SYMBOLS);\n    }\n}\n"
  },
  {
    "path": "80_Slots/java/src/SlotsGame.java",
    "content": "public class SlotsGame {\n    public static void main(String[] args) {\n        Slots slots = new Slots();\n        slots.play();\n    }\n}\n"
  },
  {
    "path": "80_Slots/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "80_Slots/javascript/slots.html",
    "content": "<html>\n<head>\n<title>SLOTS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"slots.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "80_Slots/javascript/slots.js",
    "content": "// SLOTS\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar figures = [, \"BAR\", \"BELL\", \"ORANGE\", \"LEMON\", \"PLUM\", \"CHERRY\"];\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"SLOTS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // Produced by Fred Mirabelle and Bob Harper on Jan 29, 1973\n    // It simulates the slot machine.\n    print(\"YOU ARE IN THE H&M CASINO,IN FRONT ON ONE OF OUR\\n\");\n    print(\"ONE-ARM BANDITS. BET FROM $1 TO $100.\\n\");\n    print(\"TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET.\\n\");\n    p = 0;\n    while (1) {\n        while (1) {\n            print(\"\\n\");\n            print(\"YOUR BET\");\n            m = parseInt(await input());\n            if (m > 100) {\n                print(\"HOUSE LIMITS ARE $100\\n\");\n            } else if (m < 1) {\n                print(\"MINIMUM BET IS $1\\n\");\n            } else {\n                break;\n            }\n        }\n        // Not implemented: GOSUB 1270 ten chimes\n        print(\"\\n\");\n        x = Math.floor(6 * Math.random() + 1);\n        y = Math.floor(6 * Math.random() + 1);\n        z = Math.floor(6 * Math.random() + 1);\n        print(\"\\n\");\n        // Not implemented: GOSUB 1310 seven chimes after figure x and y\n        print(figures[x] + \" \" + figures[y] + \" \" + figures[z] + \"\\n\");\n        lost = false;\n        if (x == y && y == z) {  // Three figure\n            print(\"\\n\");\n            if (z != 1) {\n                print(\"**TOP DOLLAR**\\n\");\n                p += ((10 * m) + m);\n            } else {\n                print(\"***JACKPOT***\\n\");\n                p += ((100 * m) + m);\n            }\n            print(\"YOU WON!\\n\");\n        } else if (x == y || y == z || x == z) {\n            if (x == y)\n                c = x;\n            else\n                c = z;\n            if (c == 1) {\n                print(\"\\n\");\n                print(\"*DOUBLE BAR*\\n\");\n                print(\"YOU WON\\n\");\n                p += ((5 * m) + m);\n            } else if (x != z) {\n                print(\"\\n\");\n                print(\"DOUBLE!!\\n\");\n                print(\"YOU WON!\\n\");\n                p += ((2 * m) + m);\n            } else {\n                lost = true;\n            }\n        } else {\n            lost = true;\n        }\n        if (lost) {\n            print(\"\\n\");\n            print(\"YOU LOST.\\n\");\n            p -= m;\n        }\n        print(\"YOUR STANDINGS ARE $\" + p + \"\\n\");\n        print(\"AGAIN\");\n        str = await input();\n        if (str.substr(0, 1) != \"Y\")\n            break;\n    }\n    print(\"\\n\");\n    if (p < 0) {\n        print(\"PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\\n\");\n    } else if (p == 0) {\n        print(\"HEY, YOU BROKE EVEN.\\n\");\n    } else {\n        print(\"COLLECT YOUR WINNINGS FROM THE H&M CASHIER.\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "80_Slots/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "80_Slots/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "80_Slots/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nThis Perl script is a port of slots, which is the 80th entry in Basic\nComputer Games.\n\nI know nothing about slot machines, and my research into them says to me\nthat the payout tables can be fairly arbitrary. But I have taken the\nliberty of deeming the BASIC program's refusal to pay on LEMON CHERRY\nLEMON a bug, and made that case a double.\n\nMy justification for this is that at the point where the BASIC has\ndetected the double in the first and third reels it has already detected\nthat there is no double in the first and second reels. After the check\nfor a bar (and therefore a double bar) fails it goes back and checks for\na double on the second and third reels. But we know this check will\nfail, since the check for a double on the first and second reels failed.\nSo if a loss was intended at this point, why not just call it a loss?\n\nTo restore the original behavior, comment out the entire line commented\n'# Bug fix?' (about line 75) and uncomment the line with the trailing\ncomment '# Bug?' (about line 83).\n"
  },
  {
    "path": "80_Slots/perl/slots.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse List::Util qw{ shuffle };   # Shuffle an array.\nuse Scalar::Util qw{ looks_like_number };\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nprint <<'EOD';\n                                 SLOTS\n               Creative Computing  Morristown, New Jersey\n\n\n\nYou are in the H&M casino, in front of one of our\none-arm bandits.  Bet from $1 to $100.\nTo pull the arm, punch the return key after making your bet.\nEOD\n\nmy $winnings = 0;  # Winnings\n\nwhile ( 1 ) {   # Iterate indefinitely\n\n    say '';\n\n    my $bet = get_input( 'Your bet? ',\n        sub { m/ \\A [0-9]+ \\z /smx },\n        'Please enter a whole number between 0 and 100',\n    );\n    if ( $bet > 100 ) {\n        say 'The house limit is $100';\n        next;\n    }\n    if ( $bet < 1 ) {\n        say 'The minimum bet is $1';\n        next;\n    }\n\n    say \"\\a\" x 10;\n    my $reel_x = int( 6 * rand() );\n    my $reel_y = int( 6 * rand() );\n    my $reel_z = int( 6 * rand() );\n    foreach my $column ( $reel_x, $reel_y, $reel_z ) {\n        state $symbol = [ qw{ Bar Bell Orange Lemon Plum Cherry } ];\n        print $symbol->[$column], \"\\a\" x 5, ' ';\n    }\n\n    use constant YOU_WON    => 'You won!';\n    use constant YOU_LOST   => 'You lost.';\n\n    say '';\n    if ( $reel_x == $reel_y ) {\n        if ( $reel_y == $reel_z ) {\n            if ( $reel_z ) {\n                say '** TOP DOLLAR **';\n                $winnings += 11 * $bet;\n            } else {\n                say '*** JACKPOT ***';\n                $winnings += 101 * $bet;\n            }\n            say YOU_WON;\n        } elsif ( $reel_y ) {\n            $winnings += double( $bet );\n        } else {\n            $winnings += double_bar( $bet );\n        }\n    } elsif ( $reel_x == $reel_z ) {\n        if ( $reel_z ) {\n            $winnings += double( $bet );        # Bug fix?\n            # NOTE that the below code is what is actually implemented\n            # in the basic, but it is implemented strangely enough (a\n            # GOTO a line that contains a test that, if I understand the\n            # control flow, must fail) that I wonder if it is an error.\n            # I know nothing about slot machines, but research suggests\n            # the payoff table is fairly arbitrary. The code above makes\n            # code above makes the game orthogonal.\n            # $winnings += you_lost( $bet );    # Bug?\n        } else {\n            $winnings += double_bar( $bet );\n        }\n    } elsif ( $reel_y == $reel_z ) {\n        if ( $reel_z ) {\n            $winnings += double( $bet );\n        } else {\n            $winnings += double_bar( $bet );\n        }\n    } else {\n        $winnings += you_lost( $bet );\n    }\n\n    say 'Your standings are $', $winnings;\n\n    last unless get_yes_no( 'Again' );\n\n}\n\nif ( $winnings < 0 ) {\n    say 'Pay up!  Please leave your money on the terminal.';\n} elsif ( $winnings > 0 ) {\n    say 'Collect your winnings from the H&M cashier.';\n} else {\n    say 'Hey, you broke even.';\n}\n\nsub double {\n    my ( $bet ) = @_;\n    say 'DOUBLE!';\n    say YOU_WON;\n    return 3 * $bet;\n}\n\nsub double_bar {\n    my ( $bet ) = @_;\n    say '* DOUBLE BAR *';\n    say YOU_WON;\n    return 6 * $bet;\n}\n\nsub you_lost {\n    my ( $bet ) = @_;\n    say YOU_LOST;\n    return -$bet;\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n__END__\n\n=head1 TITLE\n\nslots - Play the game 'Slots' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n slots.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of C<slots>, which is the 80th entry in Basic\nComputer Games.\n\nI know nothing about slot machines, and my research into them says to me\nthat the payout tables can be fairly arbitrary. But I have taken the\nliberty of deeming the BASIC program's refusal to pay on LEMON CHERRY\nLEMON a bug, and made that case a double.\n\nMy justification for this is that at the point where the BASIC has\ndetected the double in the first and third reels it has already detected\nthat there is no double in the first and second reels. After the check\nfor a bar (and therefore a double bar) fails it goes back and checks for\na double on the second and third reels. But we know this check will\nfail, since the check for a double on the first and second reels failed.\nSo if a loss was intended at this point, why not just call it a loss?\n\nTo restore the original behavior, comment out the entire line commented\nC<'# Bug fix?'> (about line 75) and uncomment the line with the trailing\ncomment C<'# Bug?'> (about line 83).\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "80_Slots/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "80_Slots/python/slots.py",
    "content": "########################################################\n#\n# Slots\n#\n# From Basic Computer Games (1978)\n#\n#    \"The slot machine or one-arm bandit is a mechanical\n#   device that will absorb coins just about as fast as\n#   you can feed it. After inserting a coin, you pull a\n#   handle that sets three indepent reels spining. If the\n#   reels stop with certain symbols appearing in the pay\n#   line, you get a certain payoff. The original slot\n#   machine, called the Liberty bell, was invented in 1895\n#   by Charles Fey in San Francisco. Fey refused to sell\n#   or lease the manufacturing rights, so H.S. Mills in\n#   Chicago built a similar, but much improved, machine\n#   called the Operators Bell. This has survived nearly\n#   unchanged to today.\n#     On the operators Bell and other standard slot\n#   machines, there are 20 symbols on each wheel but they\n#   are not distributed evenly among the objects(cherries,\n#   bar, apples, etc). Of the 8000 possible combinations,\n#   the expected payoff(to the player) is 7049 or $89.11\n#   for every $100.00 put in, one of the lowest expected\n#   payoffs of all casino games.\n#     In the program here, the payoff is considerably more\n#   liberal; indeed it appears to favor the player by 11%\n#   -- i.e., an expected payoff of $111 for each $100 bet.\"\n#     The program was originally written by Fred Mirabelle\n#   and Bob Harper\n#\n########################################################\n\nimport sys\nfrom collections import Counter\nfrom random import choices\nfrom typing import List\n\n\ndef initial_message() -> None:\n    print(\" \" * 30 + \"Slots\")\n    print(\" \" * 15 + \"Creative Computing Morrison, New Jersey\")\n    print(\"\\n\" * 3)\n    print(\"You are in the H&M Casino, in front of one of our\")\n    print(\"one-arm Bandits. Bet from $1 to $100.\")\n    print(\"To pull the arm, punch the return key after making your bet.\")\n\n\ndef input_betting() -> int:\n    print(\"\\n\")\n    b = -1\n    while b < 1 or b > 100:\n        try:\n            b = int(input(\"Your bet:\"))\n        except ValueError:\n            b = -1\n        if b > 100:\n            print(\"House limits are $100\")\n        elif b < 1:\n            print(\"Minium bet is $1\")\n    beeping()\n    return b\n\n\ndef beeping() -> None:\n    # Function to produce a beep sound.\n    # In the original program is the subroutine at line 1270\n    for _ in range(5):\n        sys.stdout.write(\"\\a\")\n        sys.stdout.flush()\n\n\ndef spin_wheels() -> List[str]:\n    possible_fruits = [\"Bar\", \"Bell\", \"Orange\", \"Lemon\", \"Plum\", \"Cherry\"]\n    wheel = choices(possible_fruits, k=3)\n\n    print(*wheel)\n    beeping()\n\n    return wheel\n\n\ndef adjust_profits(wheel: List[str], m: int, profits: int) -> int:\n    # we remove the duplicates\n    s = set(wheel)\n\n    if len(s) == 1:\n        # the three fruits are the same\n        fruit = s.pop()\n\n        if fruit == \"Bar\":\n            print(\"\\n***Jackpot***\")\n            profits = ((100 * m) + m) + profits\n        else:\n            print(\"\\n**Top Dollar**\")\n            profits = ((10 * m) + m) + profits\n\n        print(\"You Won!\")\n    elif len(s) == 2:\n        # two fruits are equal\n        c = Counter(wheel)\n        # we get the fruit that appears two times\n        fruit = sorted(c.items(), key=lambda x: x[1], reverse=True)[0][0]\n\n        if fruit == \"Bar\":\n            print(\"\\n*Double Bar*\")\n            profits = ((5 * m) + m) + profits\n        else:\n            print(\"\\nDouble!!\")\n            profits = ((2 * m) + m) + profits\n\n        print(\"You Won!\")\n    else:\n        # three different fruits\n        print(\"\\nYou Lost.\")\n        profits -= m\n\n    return profits\n\n\ndef final_message(profits: int) -> None:\n    if profits < 0:\n        print(\"Pay up!  Please leave your money on the terminal\")\n    elif profits == 0:\n        print(\"Hey, You broke even.\")\n    else:\n        print(\"Collect your winings from the H&M cashier.\")\n\n\ndef main() -> None:\n    profits = 0\n    keep_betting = True\n\n    initial_message()\n    while keep_betting:\n        m = input_betting()\n        w = spin_wheels()\n        profits = adjust_profits(w, m, profits)\n\n        print(f\"Your standings are ${profits}\")\n        answer = input(\"Again?\")\n\n        try:\n            if answer[0].lower() != \"y\":\n                keep_betting = False\n        except IndexError:\n            keep_betting = False\n\n    final_message(profits)\n\n\nif __name__ == \"__main__\":\n    main()\n\n######################################################################\n#\n# Porting notes\n#\n#   The selections of the fruits(Bar, apples, lemon, etc.) are made\n#   with equal probability, accordingly to random.choices documentation.\n#   It could be added a weights list to the function and therefore\n#   adjust the expected payoff\n#\n######################################################################\n"
  },
  {
    "path": "80_Slots/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "80_Slots/ruby/slots.rb",
    "content": "$pot = 0\n\ndef greeting\n    puts \"SLOTS\".center(80)\n    puts \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".center(80)\n    puts \"\\n\\n\"\n\n    # PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973\n    # IT SIMULATES THE SLOT MACHINE.\n\n    puts \"You are in the H&M Casino, in front of one of our\"\n    puts \"one-arm bandits. You can bet from $1 to $100.\"\n    puts \"To pull the arm, punch the return key after making your bet.\"\n    puts \"\\nBet zero to end the game.\"\nend\n\ndef overLimit\n    puts \"House Limit is $100\"\nend\n\ndef underMinimum\n    puts \"Minimum Bet is $1\"\nend\n\n# bells don't work on my machine. YMMV\n# I'm displaying dashes between the reels\n\ndef tenBells\n    10.times do\n        # beep if you can\n        print \"-\"\n    end\nend\n\ndef fiveBells\n    \"-----\"\nend\n\ndef goodbye\n    puts \"\\n\\n\\n\"\n    # end the game\n    exit\nend\n\ndef payUp\n    puts \"PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\"\nend\n\ndef brokeEven\n    puts \"HEY, YOU BROKE EVEN.\"\nend\n\ndef collectWinnings\n    puts \"COLLECT YOUR WINNINGS FROM THE H&M CASHIER.\"\nend\n\ndef win winType, bet\n    case winType\n        when \"jackpot\"\n            winMessage = \"***JACKPOT***\"\n            winnings = 101\n        when \"topDollar\"\n            winMessage = \"**TOP DOLLAR**\"\n            winnings = 11\n        when \"doubleBar\"\n            winMessage = \"*DOUBLE BAR!!*\"\n            winnings = 6\n        when \"double\"\n            winMessage = \"DOUBLE!!\"\n            winnings = 3\n    end\n    puts \"\\nYou won: \" + winMessage\n    $pot += (winnings * bet)\nend\n\ngreeting\n\n#$pot = 0\nwhile true\n    reelArray = [\"BAR\",\"BELL\",\"ORANGE\",\"LEMON\",\"PLUM\",\"CHERRY\"]\n    print \"\\nYOUR BET? \"\n    # get input, remove leading and trailing whitespace, cast to integer\n    bet = gets.strip.to_i\n\n    if bet == 0 then\n        goodbye\n    elsif bet > 100 then\n        overLimit # error if more than $100\n    elsif bet < 1 then\n        underMinimum # have to bet at least a dollar\n    else\n        # valid bet, continue\n        tenBells # ding\n\n        # assign a random value from the array to each of the three reels\n        reel1 = reelArray[rand(5)]\n        reel2 = reelArray[rand(5)]\n        reel3 = reelArray[rand(5)]\n\n        # print the slot machine reels\n        puts \"\\n\\n\" + reel1 + fiveBells + reel2 + fiveBells + reel3\n\n        # see if we have a match in the first two reels\n        if reel1 == reel2 then\n            if reel2 == reel3 then\n                if reel3 == \"BAR\" then\n                    # all three reels are \"BAR\"\n                    win \"jackpot\", bet\n                 else\n                   # all three reels match but aren't \"BAR\"\n                   win \"topDollar\", bet\n                end\n            elsif reel2 == \"BAR\" then\n                # reels 1 and 2 are both \"BAR\"\n                win \"doubleBar\", bet\n             else\n                # reels 1 and 2 match but aren't \"BAR\"\n                win \"double\", bet\n            end\n        # otherwise see if there's a match in the remaining reels\n        elsif reel1 == reel3 or reel2 == reel3 then\n            if reel3 == \"BAR\" then\n                # two reels match, both \"BAR\"\n                win \"doubleBar\", bet\n            else\n                # two reels match, but not \"BAR\"\n                win \"double\", bet\n            end\n        else\n            # bad news - no matches\n            puts \"\\nYou lost\"\n            # decrement your standings by the bet amount\n            $pot -= bet\n        end\n\n        puts \"Your standings are: \" + $pot.to_s\n        print \"\\nAgain? \" # YES to continue\n        # get input, remove leading and trailing whitespace, make uppercase\n        again = gets.strip.upcase\n        if again != \"Y\" && again != \"YES\" then\n            # that's enough... evaluate the pot and quit\n            if $pot < 0 then\n                payUp\n            elsif $pot == 0 then\n                brokeEven\n            else # yay!\n                collectWinnings\n            end\n            goodbye\n        end\n    end\nend\n"
  },
  {
    "path": "80_Slots/slots.bas",
    "content": "10 PRINT TAB(30);\"SLOTS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 REM PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973\n110 REM IT SIMULATES THE SLOT MACHINE.\n120 PRINT \"YOU ARE IN THE H&M CASINO,IN FRONT OF ONE OF OUR\"\n130 PRINT \"ONE-ARM BANDITS. BET FROM $1 TO $100.\"\n140 PRINT \"TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET.\"\n150 LET P=0\n160 PRINT: PRINT\"YOUR BET\";\n170 INPUT M\n180 IF M>100 THEN 860\n190 IF M<1 THEN 880\n200 M=INT(M)\n210 GOSUB 1270\n220 PRINT\n230 LET X=INT(6*RND(1)+1)\n240 LET Y=INT(6*RND(1)+1)\n250 LET Z=INT(6*RND(1)+1)\n260 PRINT\n270 IF X=1 THEN 910\n280 IF X=2 THEN 930\n290 IF X=3 THEN 950\n300 IF X=4 THEN 970\n310 IF X=5 THEN 990\n320 IF X=6 THEN 1010\n330 IF Y=1 THEN 1030\n340 IF Y=2 THEN 1050\n350 IF Y=3 THEN 1070\n360 IF Y=4 THEN 1090\n370 IF Y=5 THEN 1110\n380 IF Y=6 THEN 1130\n390 IF Z=1 THEN 1150\n400 IF Z=2 THEN 1170\n410 IF Z=3 THEN 1190\n420 IF Z=4 THEN 1210\n430 IF Z=5 THEN 1230\n440 IF Z=6 THEN 1250\n450 IF X=Y THEN 600\n460 IF X=Z THEN 630\n470 IF Y=Z THEN 650\n480 PRINT\n490 PRINT \"YOU LOST.\"\n500 LET P=P-M\n510 PRINT \"YOUR STANDINGS ARE $\"P\n520 PRINT \"AGAIN\";\n530 INPUT A$\n540 IF A$=\"Y\" THEN 160\n550 PRINT\n560 IF P<0 THEN 670\n570 IF P=0 THEN 690\n580 IF P>0 THEN 710\n590 GOTO 1350\n600 IF Y=Z THEN 730\n610 IF Y=1 THEN 820\n620 GOTO 1341\n630 IF Z=1 THEN 820\n640 GOTO 470\n650 IF Z=1 THEN 820\n660 GOTO 1341\n670 PRINT \"PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\"\n680 GOTO 1350\n690 PRINT\"HEY, YOU BROKE EVEN.\"\n700 GOTO 1350\n710 PRINT \"COLLECT YOUR WINNINGS FROM THE H&M CASHIER.\"\n720 GOTO 1350\n730 IF Z=1 THEN 780\n740 PRINT: PRINT\"**TOP DOLLAR**\"\n750 PRINT \"YOU WON!\"\n760 P=(((10*M)+M)+P)\n770 GOTO 510\n780 PRINT:PRINT\"***JACKPOT***\"\n790 PRINT \"YOU WON!\"\n800 P=(((100*M)+M)+P)\n810 GOTO 510\n820 PRINT:PRINT\"*DOUBLE BAR*\"\n830 PRINT\"YOU WON!\"\n840 P=(((5*M)+M)+P)\n850 GOTO 510\n860 PRINT\"HOUSE LIMITS ARE $100\"\n870 GOTO 160\n880 PRINT\"MINIMUM BET IS $1\"\n890 GOTO 160\n900 GOTO 220\n910 PRINT\"BAR\";:GOSUB 1310\n920 GOTO 330\n930 PRINT\"BELL\";:GOSUB 1310\n940 GOTO 330\n950 PRINT\"ORANGE\";:GOSUB 1310\n960 GOTO 330\n970 PRINT\"LEMON\";:GOSUB 1310\n980 GOTO 330\n990 PRINT\"PLUM\";:GOSUB 1310\n1000 GOTO 330\n1010 PRINT\"CHERRY\";:GOSUB 1310\n1020 GOTO 330\n1030 PRINT\" BAR\";:GOSUB 1310\n1040 GOTO 390\n1050 PRINT\" BELL\";:GOSUB 1310\n1060 GOTO 390\n1070 PRINT\" ORANGE\";:GOSUB 1310\n1080 GOTO 390\n1090 PRINT\" LEMON\";:GOSUB 1310\n1100 GOTO 390\n1110 PRINT\" PLUM\";:GOSUB 1310\n1120 GOTO 390\n1130 PRINT\" CHERRY\";:GOSUB 1310\n1140 GOTO 390\n1150 PRINT\" BAR\"\n1160 GOTO 450\n1170 PRINT\" BELL\"\n1180 GOTO 450\n1190 PRINT\" ORANGE\"\n1200 GOTO 450\n1210 PRINT\" LEMON\"\n1220 GOTO 450\n1230 PRINT\" PLUM\"\n1240 GOTO 450\n1250 PRINT\" CHERRY\"\n1260 GOTO 450\n1270 FOR Q4=1 TO 10\n1280 PRINT CHR$(7);\n1290 NEXT Q4\n1300 RETURN\n1310 FOR T8=1 TO 5\n1320 PRINT CHR$(7);\n1330 NEXT T8\n1340 RETURN\n1341 PRINT: PRINT \"DOUBLE!!\"\n1342 PRINT\"YOU WON!\"\n1343 P=(((2*M)+M)+P)\n1344 GOTO 510\n1350 STOP\n9999 END\n"
  },
  {
    "path": "80_Slots/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "80_Slots/vbnet/Slots.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Slots\", \"Slots.vbproj\", \"{F64CB361-215F-4984-B154-304FF663A60C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F64CB361-215F-4984-B154-304FF663A60C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F64CB361-215F-4984-B154-304FF663A60C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F64CB361-215F-4984-B154-304FF663A60C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F64CB361-215F-4984-B154-304FF663A60C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "80_Slots/vbnet/Slots.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Slots</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "81_Splat/README.md",
    "content": "### Splat\n\nSPLAT simulates a parachute jump in which you try to open your parachute at the last possible moment without going splat! You may select your own terminal velocity or let the computer do it for you. You many also select the acceleration due to gravity or, again, let the computer do it in which case you might wind up on any of eight planets (out to Neptune), the moon, or the sun.\n\nThe computer then tells you the height you’re jumping from and asks for the seconds of free fall. It then divides your free fall time into eight intervals and gives you progress reports on your way down. The computer also keeps track of all prior jumps in the array A and lets you know how you compared with previous successful jumps. If you want to recall information from previous runs, then you should store array A in a disk or take file and read it before each run.\n\nJohn Yegge created this program while at the Oak Ridge Associated Universities.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=151)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=166)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "81_Splat/csharp/Program.cs",
    "content": "﻿using System.Collections;\nusing System.Text;\n\nnamespace Splat\n{\n    class Splat\n    {\n        private ArrayList DistanceLog = new ArrayList();\n\n        private string[][] AccelerationData =\n        {\n            new string[] {\"Fine. You're on Mercury. Acceleration={0} ft/sec/sec\", \"12.2\"},\n            new string[] {\"All right.  You're on Venus. Acceleration={0} ft/sec/sec\", \"28.3\"},\n            new string[] {\"Then you're on Earth. Acceleration={0} ft/sec/sec\", \"32.16\"},\n            new string[] {\"Fine. You're on the Moon. Acceleration={0} ft/sec/sec\", \"5.15\"},\n            new string[] {\"All right. You're on Mars. Acceleration={0} ft/sec/sec\", \"12.5\"},\n            new string[] {\"Then you're on Jupiter. Acceleration={0} ft/sec/sec\", \"85.2\"},\n            new string[] {\"Fine. You're on Saturn. Acceleration={0} ft/sec/sec\", \"37.6\"},\n            new string[] {\"All right. You're on Uranus. Acceleration={0} ft/sec/sec\", \"33.8\"},\n            new string[] {\"Then you're on Neptune. Acceleration={0} ft/sec/sec\", \"39.6\"},\n            new string[] {\"Fine. You're on the Sun. Acceleration={0} ft/sec/sec\", \"896\"}\n        };\n\n        private void DisplayIntro()\n        {\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"SPLAT\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"Welcome to 'Splat' -- the game that simulates a parachute\");\n            Console.WriteLine(\"jump.  Try to open your chute at the last possible\");\n            Console.WriteLine(\"moment without going splat.\");\n            Console.WriteLine(\"\");\n        }\n\n        private bool PromptYesNo(string Prompt)\n        {\n            bool Success = false;\n\n            while (!Success)\n            {\n                Console.Write(Prompt);\n                string LineInput = Console.ReadLine().Trim().ToLower();\n\n                if (LineInput.Equals(\"yes\"))\n                    return true;\n                else if (LineInput.Equals(\"no\"))\n                    return false;\n                else\n                    Console.WriteLine(\"Yes or No\");\n            }\n\n            return false;\n        }\n\n        private void WriteRandomBadResult()\n        {\n           string[] BadResults = {\"Requiescat in pace.\",\"May the Angel of Heaven lead you into paradise.\",\n                \"Rest in peace.\",\"Son-of-a-gun.\",\"#$%&&%!$\",\"A kick in the pants is a boost if you're headed right.\",\n                \"Hmmm. Should have picked a shorter time.\",\"Mutter. Mutter. Mutter.\",\"Pushing up daisies.\",\n                \"Easy come, easy go.\"};\n\n            Random rand = new Random();\n\n            Console.WriteLine(BadResults[rand.Next(BadResults.Length)]);\n        }\n\n        private void WriteColumnOutput(double Column1, double Column2)\n        {\n\n            Console.WriteLine(\"{0,-11:N3}    {1,-17:N2}\", Column1, Column2);\n\n        }\n\n        private void WriteColumnOutput(double Column1, string Column2)\n        {\n\n            Console.WriteLine(\"{0,-11:N3}    {1,-17}\", Column1, Column2);\n\n        }\n\n        private void WriteColumnOutput(string Column1, string Column2)\n        {\n\n            Console.WriteLine(\"{0,-11}    {1,-17}\", Column1, Column2);\n\n        }\n\n        private void WriteSuccessfulResults(double Distance)\n        {\n            // Add new result\n            DistanceLog.Add(Distance);\n\n            // Sort by distance\n            DistanceLog.Sort();\n\n            int ArrayLength = DistanceLog.Count;\n\n            // If 1st, 2nd, or 3rd jump then write a special message\n            if (ArrayLength <= 3)\n            {\n                Console.Write(\"Amazing!!! Not bad for your \");\n                if (ArrayLength == 1)\n                    Console.Write(\"1st \");\n                else if (ArrayLength == 2)\n                    Console.Write(\"2nd \");\n                else\n                    Console.Write(\"3rd \");\n                Console.WriteLine(\"successful jump!!!\");\n            }\n            // Otherwise write a message based on where this jump falls in the list\n            else\n            {\n                int JumpPosition = DistanceLog.IndexOf(Distance);\n\n\n                if (ArrayLength - JumpPosition <= .1 * ArrayLength)\n                {\n                    Console.WriteLine(\"Wow! That's some jumping. Of the {0} successful jumps\", ArrayLength);\n                    Console.WriteLine(\"before yours, only {0} opened their chutes lower than\", (ArrayLength - JumpPosition));\n                    Console.WriteLine(\"you did.\");\n                }\n                else if (ArrayLength - JumpPosition <= .25 * ArrayLength)\n                {\n                    Console.WriteLine(\"Pretty good! {0} successful jumps preceded yours and only\", ArrayLength - 1);\n                    Console.WriteLine(\"{0} of them got lower than you did before their chutes\", (ArrayLength - 1 - JumpPosition));\n                    Console.WriteLine(\"opened.\");\n                }\n                else if (ArrayLength - JumpPosition <= .5 * ArrayLength)\n                {\n                    Console.WriteLine(\"Not bad. There have been  {0} successful jumps before yours.\", ArrayLength - 1);\n                    Console.WriteLine(\"You were beaten out by {0} of them.\", (ArrayLength - 1 - JumpPosition));\n                }\n                else if (ArrayLength - JumpPosition <= .75 * ArrayLength)\n                {\n                    Console.WriteLine(\"Conservative aren't you? You ranked only {0} in the\", (ArrayLength - JumpPosition));\n                    Console.WriteLine(\"{0} successful jumps before yours.\", ArrayLength - 1);\n                }\n                else if (ArrayLength - JumpPosition <= .9 * ArrayLength)\n                {\n                    Console.WriteLine(\"Humph! Don't you have any sporting blood? There were\");\n                    Console.WriteLine(\"{0} successful jumps before yours and you came in {1} jumps\", ArrayLength - 1, JumpPosition);\n                    Console.WriteLine(\"better than the worst. Shape up!!!\");\n                }\n                else\n                {\n                    Console.WriteLine(\"Hey! You pulled the rip cord much too soon. {0} successful\", ArrayLength - 1);\n                    Console.WriteLine(\"jumps before yours and you came in number {0}! Get with it!\", (ArrayLength - JumpPosition));\n                }\n            }\n\n        }\n\n        private void PlayOneRound()\n        {\n            bool InputSuccess = false;\n            Random rand = new Random();\n            double Velocity = 0;\n            double TerminalVelocity = 0;\n            double Acceleration = 0;\n            double AccelerationInput = 0;\n            double Altitude = ((9001 * rand.NextDouble()) + 1000);\n            double SecondsTimer = 0;\n            double Distance = 0;\n            bool TerminalVelocityReached = false;\n\n            Console.WriteLine(\"\");\n\n            // Determine the terminal velocity (user or system)\n            if (PromptYesNo(\"Select your own terminal velocity (yes or no)? \"))\n            {\n                // Prompt user to enter the terminal velocity of their choice\n                while (!InputSuccess)\n                {\n                    Console.Write(\"What terminal velocity (mi/hr)? \");\n                    string Input = Console.ReadLine().Trim();\n                    InputSuccess = double.TryParse(Input, out TerminalVelocity);\n                    if (!InputSuccess)\n                        Console.WriteLine(\"*** Please enter a valid number ***\");\n                 }\n            }\n            else\n            {\n                TerminalVelocity = rand.NextDouble() * 1000;\n                Console.WriteLine(\"OK.  Terminal Velocity = {0:N0} mi/hr\", (TerminalVelocity));\n            }\n\n            // Convert Terminal Velocity to ft/sec\n            TerminalVelocity = TerminalVelocity * 5280 / 3600;\n\n            // Not sure what this calculation is\n            Velocity = TerminalVelocity + ((TerminalVelocity * rand.NextDouble()) / 20) - ((TerminalVelocity * rand.NextDouble()) / 20);\n\n            // Determine acceleration due to gravity (user or system)\n            if (PromptYesNo(\"Want to select acceleration due to gravity (yes or no)? \"))\n            {\n                 // Prompt user to enter the acceleration of their choice\n                InputSuccess = false;\n                while (!InputSuccess)\n                {\n                    Console.Write(\"What acceleration (ft/sec/sec)? \");\n                    string Input = Console.ReadLine().Trim();\n                    InputSuccess = double.TryParse(Input, out AccelerationInput);\n                    if (!InputSuccess)\n                        Console.WriteLine(\"*** Please enter a valid number ***\");\n                 }\n            }\n            else\n            {\n                // Choose a random acceleration entry from the data array\n                int Index = rand.Next(0, AccelerationData.Length);\n                Double.TryParse(AccelerationData[Index][1], out AccelerationInput);\n\n                // Display the corresponding planet this acceleration exists on and the value\n                Console.WriteLine(AccelerationData[Index][0], AccelerationInput.ToString());\n            }\n\n            Acceleration = AccelerationInput + ((AccelerationInput * rand.NextDouble()) / 20) - ((AccelerationInput * rand.NextDouble()) / 20);\n\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"    Altitude         = {0:N0} ft\", Altitude);\n            Console.WriteLine(\"    Term. Velocity   = {0:N3} ft/sec +/-5%\", TerminalVelocity);\n            Console.WriteLine(\"    Acceleration     = {0:N2} ft/sec/sec +/-5%\", AccelerationInput);\n            Console.WriteLine(\"Set the timer for your freefall.\");\n\n            // Prompt for how many seconds the fall should be before opening the chute\n            InputSuccess = false;\n            while (!InputSuccess)\n            {\n                Console.Write(\"How many seconds? \");\n                string Input = Console.ReadLine().Trim();\n                InputSuccess = double.TryParse(Input, out SecondsTimer);\n                if (!InputSuccess)\n                    Console.WriteLine(\"*** Please enter a valid number ***\");\n            }\n\n            // Begin the drop!\n            Console.WriteLine(\"Here we go.\");\n            Console.WriteLine(\"\");\n\n            WriteColumnOutput(\"Time (sec)\", \"Dist to Fall (ft)\");\n            WriteColumnOutput(\"==========\", \"=================\");\n\n            // Loop through the number of seconds stepping by 8 intervals\n            for (double i = 0; i < SecondsTimer; i+=(SecondsTimer/8))\n            {\n                if (i > (Velocity / Acceleration))\n                {\n                    // Terminal Velocity achieved.  Only print out the warning once.\n                    if (TerminalVelocityReached == false)\n                        Console.WriteLine(\"Terminal velocity reached at T plus {0:N4} seconds.\", (Velocity / Acceleration));\n\n                    TerminalVelocityReached = true;\n                }\n\n                // Calculate distance dependent upon whether terminal velocity has been reached\n                if (TerminalVelocityReached)\n                {\n                    Distance = Altitude - ((Math.Pow(Velocity,2) / (2 * Acceleration)) + (Velocity * (i - (Velocity / Acceleration))));\n                }\n                else\n                {\n                    Distance = Altitude - ((Acceleration / 2) * Math.Pow(i,2));\n                }\n\n                // Was the ground hit?  If so, then SPLAT!\n                if (Distance <= 0)\n                {\n                    if (TerminalVelocityReached)\n                    {\n                        WriteColumnOutput((Velocity / Acceleration) + ((Altitude - (Math.Pow(Velocity,2) / (2 * Acceleration))) / Velocity).ToString(), \"SPLAT\");\n                    }\n                    else\n                    {\n                        WriteColumnOutput(Math.Sqrt(2 * Altitude / Acceleration), \"SPLAT\");\n                    }\n\n                    WriteRandomBadResult();\n\n                    Console.WriteLine(\"I'll give you another chance.\");\n                    break;\n                }\n                else\n                {\n                    WriteColumnOutput(i, Distance);\n                }\n            }\n\n            // If the number of seconds of drop ended and we are still above ground then success!\n            if (Distance > 0)\n            {\n                // We made it!  Chutes open!\n                Console.WriteLine(\"Chute Open\");\n\n                // Store succesful jump and write out a fun message\n                WriteSuccessfulResults(Distance);\n            }\n\n        }\n\n        public void PlayTheGame()\n        {\n            bool ContinuePlay = false;\n\n            DisplayIntro();\n\n            do\n            {\n                PlayOneRound();\n\n                ContinuePlay = PromptYesNo(\"Do you want to play again? \");\n                if (!ContinuePlay)\n                    ContinuePlay = PromptYesNo(\"Please? \");\n            }\n            while (ContinuePlay);\n\n            Console.WriteLine(\"SSSSSSSSSS.\");\n\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Splat().PlayTheGame();\n\n        }\n    }\n}\n"
  },
  {
    "path": "81_Splat/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "81_Splat/csharp/Splat.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "81_Splat/csharp/Splat.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Splat\", \"Splat.csproj\", \"{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "81_Splat/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "81_Splat/java/src/Splat.java",
    "content": "import java.util.*;\n\n/**\n * SPLAT simulates a parachute jump in which you try to open your parachute at the last possible moment without going\n * splat! You may select your own terminal velocity or let the computer do it for you. You many also select the\n * acceleration due to gravity or, again, let the computer do it in which case you might wind up on any of eight\n * planets (out to Neptune), the moon, or the sun.\n * <p>\n * The computer then tells you the height you’re jumping from and asks for the seconds of free fall. It then divides\n * your free fall time into eight intervals and gives you progress reports on your way down. The computer also keeps\n * track of all prior jumps in the array A and lets you know how you compared with previous successful jumps. If you\n * want to recall information from previous runs, then you should store array A in a disk or take file and read it\n * before each run.\n * <p>\n * John Yegge created this program while at the Oak Ridge Associated Universities.\n * <p>\n * Ported from BASIC by jason plumb (@breedx2)\n * </p>\n */\npublic class Splat {\n    private static final Random random = new Random();\n    private final Scanner scanner = new Scanner(System.in);\n    private final List<Float> pastSuccessfulJumpDistances = new ArrayList<>();\n\n    public static void main(String[] args) {\n        new Splat().run();\n    }\n\n    public void run() {\n        showIntroduction();\n\n        while (true) {\n\n            InitialJumpConditions initial = buildInitialConditions();\n\n            System.out.println();\n            System.out.printf(\"    ALTITUDE         = %d FT\\n\", initial.getAltitude());\n            System.out.printf(\"    TERM. VELOCITY   = %.2f FT/SEC +/-5%%\\n\", initial.getOriginalTerminalVelocity());\n            System.out.printf(\"    ACCELERATION     = %.2f FT/SEC/SEC +/-5%%\\n\", initial.getOriginalAcceleration());\n\n            System.out.println(\"SET THE TIMER FOR YOUR FREEFALL.\");\n            float freefallTime = promptFloat(\"HOW MANY SECONDS \");\n            System.out.println(\"HERE WE GO.\\n\");\n            System.out.println(\"TIME (SEC)  DIST TO FALL (FT)\");\n            System.out.println(\"==========  =================\");\n\n            JumpResult jump = executeJump(initial, freefallTime);\n            showJumpResults(initial, jump);\n\n            if (!playAgain()) {\n                System.out.println(\"SSSSSSSSSS.\");\n                return;\n            }\n        }\n    }\n\n    private void showIntroduction() {\n        System.out.printf(\"%33s%s\\n\", \" \", \"SPLAT\");\n        System.out.printf(\"%15s%s\\n\", \" \", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.print(\"\\n\\n\\n\");\n        System.out.println(\"WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\");\n        System.out.println(\"JUMP.  TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\");\n        System.out.println(\"MOMENT WITHOUT GOING SPLAT.\");\n    }\n\n    private InitialJumpConditions buildInitialConditions() {\n        System.out.print(\"\\n\\n\");\n        float terminalVelocity = promptTerminalVelocity();\n        float acceleration = promptGravitationalAcceleration();\n        return InitialJumpConditions.create(terminalVelocity, acceleration);\n    }\n\n    private float promptTerminalVelocity() {\n        if (askYesNo(\"SELECT YOUR OWN TERMINAL VELOCITY\")) {\n            float terminalVelocity = promptFloat(\"WHAT TERMINAL VELOCITY (MI/HR) \");\n            return mphToFeetPerSec(terminalVelocity);\n        }\n        float terminalVelocity = (int) (1000 * random.nextFloat());\n        System.out.printf(\"OK.  TERMINAL VELOCITY = %.2f MI/HR\\n\", terminalVelocity);\n        return mphToFeetPerSec(terminalVelocity);\n    }\n\n    private float promptFloat(String prompt){\n        while(true){\n            System.out.print(prompt);\n            try {\n                return scanner.nextFloat();\n            } catch (Exception e) {\n                scanner.next(); // clear current input\n            }\n        }\n    }\n\n    private float promptGravitationalAcceleration() {\n        if (askYesNo(\"WANT TO SELECT ACCELERATION DUE TO GRAVITY\")) {\n            return promptFloat(\"WHAT ACCELERATION (FT/SEC/SEC) \");\n        }\n        return chooseRandomAcceleration();\n    }\n\n    private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) {\n        JumpResult jump = new JumpResult(initial.getAltitude());\n        for (float time = 0.0f; time < chuteOpenTime; time += chuteOpenTime / 8) {\n            if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) {\n                jump.setReachedTerminalVelocity();\n                System.out.printf(\"TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\\n\", initial.getTimeOfTerminalAccelerationReached());\n            }\n            float newDistance = computeDistance(initial, time, jump.hasReachedTerminalVelocity());\n            jump.setDistance(newDistance);\n\n            if (jump.isSplat()) {\n                return jump;\n            }\n            System.out.printf(\"%10.2f  %f\\n\", time, jump.getDistance());\n        }\n        return jump;\n    }\n\n    private float computeDistance(InitialJumpConditions initial, float i, boolean hasReachedTerminalVelocity) {\n        final float V = initial.getTerminalVelocity();\n        final float A = initial.getAcceleration();\n        if (hasReachedTerminalVelocity) {\n            return initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A))));\n        }\n        return initial.getAltitude() - ((A / 2) * i * i);\n    }\n\n    private void showJumpResults(InitialJumpConditions initial, JumpResult jump) {\n        if (jump.isSplat()) {\n            showSplatMessage(initial, jump);\n            showCleverSplatMessage();\n            return;\n        }\n        System.out.println(\"CHUTE OPEN\");\n        int worseJumpCount = countWorseHistoricalJumps(jump);\n        int successfulJumpCt = pastSuccessfulJumpDistances.size();\n        pastSuccessfulJumpDistances.add(jump.getDistance());\n\n        if (pastSuccessfulJumpDistances.size() <= 2) {\n            List<String> ordinals = Arrays.asList(\"1ST\", \"2ND\", \"3RD\");\n            System.out.printf(\"AMAZING!!! NOT BAD FOR YOUR %s SUCCESSFUL JUMP!!!\\n\", ordinals.get(successfulJumpCt));\n            return;\n        }\n\n        int betterThanCount = successfulJumpCt - worseJumpCount;\n        if (betterThanCount <= 0.1 * successfulJumpCt) {\n            System.out.printf(\"WOW!  THAT'S SOME JUMPING.  OF THE %d SUCCESSFUL JUMPS\\n\", successfulJumpCt);\n            System.out.printf(\"BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\\n\", betterThanCount);\n            System.out.println(\"YOU DID.\");\n        } else if (betterThanCount <= 0.25 * successfulJumpCt) {\n            System.out.printf(\"PRETTY GOOD!  %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\\n\", successfulJumpCt);\n            System.out.printf(\"%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\\n\", betterThanCount);\n            System.out.println(\"OPENED.\");\n        } else if (betterThanCount <= 0.5 * successfulJumpCt) {\n            System.out.printf(\"NOT BAD.  THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\\n\", successfulJumpCt);\n            System.out.printf(\"YOU WERE BEATEN OUT BY %d OF THEM.\\n\", betterThanCount);\n        } else if (betterThanCount <= 0.75 * successfulJumpCt) {\n            System.out.printf(\"CONSERVATIVE, AREN'T YOU?  YOU RANKED ONLY %d IN THE\\n\", betterThanCount);\n            System.out.printf(\"%d SUCCESSFUL JUMPS BEFORE YOURS.\\n\", successfulJumpCt);\n        } else if (betterThanCount <= -0.9 * successfulJumpCt) {\n            System.out.println(\"HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD?  THERE WERE\");\n            System.out.printf(\"%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\\n\", successfulJumpCt, worseJumpCount);\n            System.out.println(\"BETTER THAN THE WORST.  SHAPE UP!!!\\n\");\n        } else {\n            System.out.printf(\"HEY!  YOU PULLED THE RIP CORD MUCH TOO SOON.  %d SUCCESSFUL\\n\", successfulJumpCt);\n            System.out.printf(\"JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d!  GET WITH IT!\\n\", betterThanCount);\n        }\n    }\n\n    private void showSplatMessage(InitialJumpConditions initial, JumpResult jump) {\n        double timeOfSplat = computeTimeOfSplat(initial, jump);\n        System.out.printf(\"%10.2f  SPLAT\\n\", timeOfSplat);\n    }\n\n    /**\n     * Returns the number of jumps for which this jump was better\n     */\n    private double computeTimeOfSplat(InitialJumpConditions initial, JumpResult jump) {\n        final float V = initial.getTerminalVelocity();\n        final float A = initial.getAcceleration();\n        if (jump.hasReachedTerminalVelocity()) {\n            return (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V);\n        }\n        return Math.sqrt(2 * initial.getAltitude() / A);\n    }\n\n    private int countWorseHistoricalJumps(JumpResult jump) {\n        return (int) pastSuccessfulJumpDistances.stream()\n                .filter(distance -> jump.getDistance() < distance)\n                .count();\n    }\n\n    private void showCleverSplatMessage() {\n        List<String> messages = Arrays.asList(\n                \"REQUIESCAT IN PACE.\",\n                \"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\",\n                \"REST IN PEACE.\",\n                \"SON-OF-A-GUN.\",\n                \"#$%&&%!$\",\n                \"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\",\n                \"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\",\n                \"MUTTER. MUTTER. MUTTER.\",\n                \"PUSHING UP DAISIES.\",\n                \"EASY COME, EASY GO.\"\n        );\n        System.out.println(messages.get(random.nextInt(10)));\n    }\n\n    private boolean playAgain() {\n        if (askYesNo(\"DO YOU WANT TO PLAY AGAIN \")) {\n            return true;\n        }\n        return askYesNo(\"PLEASE\");\n    }\n\n    private float mphToFeetPerSec(float speed) {\n        return speed * (5280.0f / 3600.0f);\n    }\n\n    private boolean askYesNo(String prompt) {\n        System.out.printf(\"%s (YES OR NO) \", prompt);\n        while (true) {\n            String answer = scanner.next();\n            switch (answer) {\n                case \"YES\":\n                    return true;\n                case \"NO\":\n                    return false;\n                default:\n                    System.out.print(\"YES OR NO \");\n            }\n        }\n    }\n\n    private float chooseRandomAcceleration() {\n        Planet planet = Planet.pickRandom();\n        System.out.printf(\"%s %s. ACCELERATION=%.2f FT/SEC/SEC.\\n\", planet.getMessage(), planet.name(), planet.getAcceleration());\n        return planet.getAcceleration();\n    }\n\n    enum Planet {\n        MERCURY(\"FINE. YOU'RE ON\", 12.2f),\n        VENUS(\"ALL RIGHT. YOU'RE ON\", 28.3f),\n        EARTH(\"THEN YOU'RE ON\", 32.16f),\n        MOON(\"FINE. YOU'RE ON THE\", 5.15f),\n        MARS(\"ALL RIGHT. YOU'RE ON\", 12.5f),\n        JUPITER(\"THEN YOU'RE ON\", 85.2f),\n        SATURN(\"FINE. YOU'RE ON\", 37.6f),\n        URANUS(\"ALL RIGHT. YOU'RE ON\", 33.8f),\n        NEPTUNE(\"THEN YOU'RE ON\", 39.6f),\n        SUN(\"FINE. YOU'RE ON THE\", 896.0f);\n\n        private static final Random random = new Random();\n        private final String message;\n        private final float acceleration;\n\n        Planet(String message, float acceleration) {\n            this.message = message;\n            this.acceleration = acceleration;\n        }\n\n        static Planet pickRandom() {\n            return values()[random.nextInt(Planet.values().length)];\n        }\n\n        String getMessage() {\n            return message;\n        }\n\n        float getAcceleration() {\n            return acceleration;\n        }\n    }\n\n    // Mutable\n    static class JumpResult {\n        private boolean reachedTerminalVelocity = false;\n        private float distance; // from the ground\n\n        public JumpResult(float distance) {\n            this.distance = distance;\n        }\n\n        boolean isSplat() {\n            return distance <= 0;\n        }\n\n        boolean hasReachedTerminalVelocity() {\n            return reachedTerminalVelocity;\n        }\n\n        float getDistance() {\n            return distance;\n        }\n\n        void setDistance(float distance) {\n            this.distance = distance;\n        }\n\n        void setReachedTerminalVelocity() {\n            reachedTerminalVelocity = true;\n        }\n    }\n\n    // Immutable\n    static class InitialJumpConditions {\n        private final float originalTerminalVelocity;\n        private final float originalAcceleration;\n        private final float terminalVelocity;\n        private final float acceleration;\n        private final int altitude;\n\n        private InitialJumpConditions(float originalTerminalVelocity, float originalAcceleration,\n                                      float terminalVelocity, float acceleration, int altitude) {\n            this.originalTerminalVelocity = originalTerminalVelocity;\n            this.originalAcceleration = originalAcceleration;\n            this.terminalVelocity = terminalVelocity;\n            this.acceleration = acceleration;\n            this.altitude = altitude;\n        }\n\n        // Create initial jump conditions with adjusted velocity/acceleration and a random initial altitude\n        private static InitialJumpConditions create(float terminalVelocity, float gravitationalAcceleration) {\n            final int altitude = (int) (9001.0f * random.nextFloat() + 1000);\n            return new InitialJumpConditions(terminalVelocity, gravitationalAcceleration,\n                    plusMinus5Percent(terminalVelocity), plusMinus5Percent(gravitationalAcceleration), altitude);\n        }\n\n        private static float plusMinus5Percent(float value) {\n            return value + ((value * random.nextFloat()) / 20.0f) - ((value * random.nextFloat()) / 20.0f);\n        }\n\n        float getOriginalTerminalVelocity() {\n            return originalTerminalVelocity;\n        }\n\n        float getOriginalAcceleration() {\n            return originalAcceleration;\n        }\n\n        float getTerminalVelocity() {\n            return terminalVelocity;\n        }\n\n        float getAcceleration() {\n            return acceleration;\n        }\n\n        int getAltitude() {\n            return altitude;\n        }\n\n        float getTimeOfTerminalAccelerationReached() {\n            return terminalVelocity / acceleration;\n        }\n    }\n}\n"
  },
  {
    "path": "81_Splat/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "81_Splat/javascript/splat.html",
    "content": "<html>\n<head>\n<title>SPLAT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"splat.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "81_Splat/javascript/splat.js",
    "content": "// SPLAT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar aa = [];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"SPLAT\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 0; i <= 42; i++)\n        aa[i] = 0;\n    print(\"WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\\n\");\n    print(\"JUMP.  TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\\n\");\n    print(\"MOMENT WITHOUT GOING SPLAT.\\n\");\n    while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        d1 = 0;\n        v = 0;\n        a = 0;\n        n = 0;\n        m = 0;\n        d1 = Math.floor(9001 * Math.random() + 1000);\n        print(\"SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO)\");\n        while (1) {\n            a1s = await input();\n            if (a1s == \"YES\" || a1s == \"NO\")\n                break;\n            print(\"YES OR NO\");\n        }\n        if (a1s == \"YES\") {\n            print(\"WHAT TERMINAL VELOCITY (MI/HR)\");\n            v1 = parseFloat(await input());\n            v1 = v1 * (5280 / 3600);\n        } else {\n            v1 = Math.floor(1000 * Math.random());\n            print(\"OK.  TERMINAL VELOCITY = \" + v1 + \" MI/HR\\n\");\n        }\n        v = v1 + ((v1 * Math.random()) / 20) - ((v1 * Math.random()) / 20);\n        print(\"WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO)\");\n        while (1) {\n            b1s = await input();\n            if (b1s == \"YES\" || b1s == \"NO\")\n                break;\n            print(\"YES OR NO\");\n        }\n        if (b1s == \"YES\") {\n            print(\"WHAT ACCELERATION (FT/SEC/SEC)\");\n            a2 = parseFloat(await input());\n        } else {\n            switch (Math.floor(1 + (10 * Math.random()))) {\n                case 1:\n                    print(\"FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC.\\n\");\n                    a2 = 12.2;\n                    break;\n                case 2:\n                    print(\"ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC.\\n\");\n                    a2 = 28.3;\n                    break;\n                case 3:\n                    print(\"THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC.\\n\");\n                    a2 = 32.16;\n                    break;\n                case 4:\n                    print(\"FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC.\\n\");\n                    a2 = 5.15;\n                    break;\n                case 5:\n                    print(\"ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC.\\n\");\n                    a2 = 12.5;\n                    break;\n                case 6:\n                    print(\"THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC.\\n\");\n                    a2 = 85.2;\n                    break;\n                case 7:\n                    print(\"FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC.\\n\");\n                    a2 = 37.6;\n                    break;\n                case 8:\n                    print(\"ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC.\\n\");\n                    a2 = 33.8;\n                    break;\n                case 9:\n                    print(\"THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC.\\n\");\n                    a2 = 39.6;\n                    break;\n                case 10:\n                    print(\"FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC.\\n\");\n                    a2 = 896;\n                    break;\n            }\n        }\n        a = a2 + ((a2 * Math.random()) / 20) - ((a2 * Math.random()) / 20);\n        print(\"\\n\");\n        print(\"    ALTITUDE         = \" + d1 + \" FT\\n\");\n        print(\"    TERM. VELOCITY   = \" + v1 + \" FT/SEC +/-5%\\n\");\n        print(\"    ACCELERATION     = \" + a2 + \" FT/SEC/SEC +/-5%\\n\");\n        print(\"SET THE TIMER FOR YOUR FREEFALL.\\n\");\n        print(\"HOW MANY SECONDS\");\n        t = parseFloat(await input());\n        print(\"HERE WE GO.\\n\");\n        print(\"\\n\");\n        print(\"TIME (SEC)\\tDIST TO FALL (FT)\\n\");\n        print(\"==========\\t=================\\n\");\n        terminal = false;\n        crash = false;\n        for (i = 0; i <= t; i += t / 8) {\n            if (i > v / a) {\n                terminal = true;\n                break;\n            }\n            d = d1 - ((a / 2) * Math.pow(i, 2));\n            if (d <= 0) {\n                print(Math.sqrt(2 * d1 / a) + \"\\tSPLAT\\n\");\n                crash = true;\n                break;\n            }\n            print(i + \"\\t\" + d + \"\\n\");\n        }\n        if (terminal) {\n            print(\"TERMINAL VELOCITY REACHED AT T PLUS \" + v/a + \" SECONDS.\\n\");\n            for (; i <= t; i += t / 8) {\n                d = d1 - ((Math.pow(v, 2) / (2 * a)) + (v * (i - (v / a))));\n                if (d <= 0) {\n                    print(((v / a) + ((d1 - (Math.pow(v, 2) / (2 * a))) / v)) + \"\\tSPLAT\\n\");\n                    crash = true;\n                    break;\n                }\n                print(i + \"\\t\" + d + \"\\n\");\n            }\n        }\n        if (!crash) {\n            print(\"CHUTE OPEN\\n\");\n            k = 0;\n            k1 = 0;\n            for (j = 0; j <= 42; j++) {\n                if (aa[j] == 0)\n                    break;\n                k++;\n                if (d < aa[j])\n                    k1++;\n            }\n            // In original jumps to line 540 (undefined) when table is full\n            aa[j] = d;\n            if (j <= 2) {\n                print(\"AMAZING!!! NOT BAD FOR YOUR \");\n                if (j == 0)\n                    print(\"1ST \");\n                else if (j == 1)\n                    print(\"2ND \");\n                else\n                    print(\"3RD \");\n                print(\"SUCCESSFUL JUMP!!!\\n\");\n            } else {\n                if (k - k1 <= 0.1 * k) {\n                    print(\"WOW!  THAT'S SOME JUMPING.  OF THE \" + k + \" SUCCESSFUL JUMPS\\n\");\n                    print(\"BEFORE YOURS, ONLY \" + (k - k1) + \" OPENED THEIR CHUTES LOWER THAN\\n\");\n                    print(\"YOU DID.\\n\");\n                } else if (k - k1 <= 0.25 * k) {\n                    print(\"PRETTY GOOD! \" + k + \" SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\\n\");\n                    print((k - k1) + \" OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\\n\");\n                    print(\"OPENED.\\n\");\n                } else if (k - k1 <= 0.5 * k) {\n                    print(\"NOT BAD.  THERE HAVE BEEN \" + k + \" SUCCESSFUL JUMPS BEFORE YOURS.\\n\");\n                    print(\"YOU WERE BEATEN OUT BY \" + (k - k1) + \" OF THEM.\\n\");\n                } else if (k - k1 <= 0.75 * k) {\n                    print(\"CONSERVATIVE, AREN'T YOU?  YOU RANKED ONLY \" + (k - k1) + \" IN THE\\n\");\n                    print(k + \" SUCCESSFUL JUMPS BEFORE YOURS.\\n\");\n                } else if (k - k1 <= 0.9 * k) {\n                    print(\"HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD?  THERE WERE\\n\");\n                    print(k + \" SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN \" + k1 + \"JUMPS\\n\");\n                    print(\"BETTER THAN THE WORST.  SHAPE UP!!!\\n\");\n                } else {\n                    print(\"HEY!  YOU PULLED THE RIP CORD MUCH TOO SOON.  \" + k + \" SUCCESSFUL\\n\");\n                    print(\"JUMPS BEFORE YOURS AND YOU CAME IN NUMBER \" + (k - k1) + \"!  GET WITH IT!\\n\");\n                }\n            }\n        } else {\n            switch (Math.floor(1 + 10 * Math.random())) {\n                case 1:\n                    print(\"REQUIESCAT IN PACE.\\n\");\n                    break;\n                case 2:\n                    print(\"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\\n\");\n                    break;\n                case 3:\n                    print(\"REST IN PEACE.\\n\");\n                    break;\n                case 4:\n                    print(\"SON-OF-A-GUN.\\n\");\n                    break;\n                case 5:\n                    print(\"#%&&%!$\\n\");\n                    break;\n                case 6:\n                    print(\"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\\n\");\n                    break;\n                case 7:\n                    print(\"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\\n\");\n                    break;\n                case 8:\n                    print(\"MUTTER. MUTTER. MUTTER.\\n\");\n                    break;\n                case 9:\n                    print(\"PUSHING UP DAISIES.\\n\");\n                    break;\n                case 10:\n                    print(\"EASY COME, EASY GO.\\n\");\n                    break;\n            }\n            print(\"I'LL GIVE YOU ANOTHER CHANCE.\\n\");\n        }\n        while (1) {\n            print(\"DO YOU WANT TO PLAY AGAIN\");\n            str = await input();\n            if (str == \"YES\" || str == \"NO\")\n                break;\n            print(\"YES OR NO\\n\");\n        }\n        if (str == \"YES\")\n            continue;\n        print(\"PLEASE\");\n        while (1) {\n            str = await input();\n            if (str == \"YES\" || str == \"NO\")\n                break;\n            print(\"YES OR NO\");\n        }\n        if (str == \"YES\")\n            continue;\n        break;\n    }\n    print(\"SSSSSSSSSS.\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "81_Splat/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "81_Splat/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "81_Splat/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "81_Splat/perl/splat.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse List::Util qw{ shuffle };   # Shuffle an array.\nuse Scalar::Util qw{ looks_like_number };\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nuse constant ROW_TPLT => ( '%4d' x 8 ) . \"\\n\";\n\nprint <<'EOD';\n                                 SPLAT\n               Creative Computing  Morristown, New Jersey\n\n\n\nWelcome to 'Splat' -- the game that simulates a parachute\njump.  Try to open your chute at the last possible\nmoment without going splat.\nEOD\n\nwhile ( 1 ) {\n    say '';\n    my $initial_altitude = int( 9001 * rand() + 1000 );\n\n    my $nominal_terminal_velocity;\n    if ( get_yes_no( 'Select your own terminal velocity' ) ) {\n        $nominal_terminal_velocity = get_input(\n            'What terminal velocity (mi/hr)? ',\n            sub { looks_like_number( $ARG ) && $ARG > 0 },\n            'Please enter a positive number',\n        );\n        # Convert miles per hour to feet per second\n        $nominal_terminal_velocity = $nominal_terminal_velocity * 5280 / 3600;\n    } else {\n        $nominal_terminal_velocity = int( 1000 * rand() );\n        say \"OK.  Terminal velocity = $nominal_terminal_velocity mi/hr\"\n    }\n    my $terminal_velocity = dither( $nominal_terminal_velocity );\n\n    my $nominal_gravity; # Acceleration due to gravity\n    if ( get_yes_no( 'Want to select acceleration due to gravity' ) ) {\n    } else {\n        state $body = [\n            [ q<Fine. You're on Mercury. Acceleration = 12.2 ft/sec/sec.>,\n                12.2 ],\n            [ q<All right. You're on Venus. Acceleration = 28.3 ft/sec/sec.>,\n                28.3 ],\n            [ q<Then you're on Earth. Acceleration = 32.16 ft/sec/sec.>,\n                32.16 ],\n            [ q<Fine. You're on the Moon. Acceleration = 5.15 ft/sec/sec.>,\n                5.15 ],\n            [ q<All right. You're on Mars. Acceleration = 12.5 ft/sec/sec.>,\n                12.5 ],\n            [ q<Then you're on Jupiter. Acceleration = 85.2 ft/sec/sec.>,\n                85.2 ],\n            [ q<Fine. You're on Saturn. Acceleration = 37.6 ft/sec/sec.>,\n                37.6 ],\n            [ q<All right. You're on Uranus. Acceleration = 33.8 ft/sec/sec.>,\n                33.8  ],\n            [ q<Then you're on Neptune. Acceleration = 39.6 ft/sec/sec.>,\n                39.6 ],\n            [ q<Fine. You're on the Sun. Acceleration = 896 ft/sec/sec.>,\n                896 ],\n        ];\n        my $pick = $body->[ rand scalar @{ $body } ];\n        say $pick->[0];\n        $nominal_gravity = $pick->[1];\n    }\n    my $gravity = dither( $nominal_gravity );\n\n    print <<\"EOD\";\n\n    Altitude        = $initial_altitude ft\n    Term. velocity  = $nominal_terminal_velocity ft/sec +/- 5%\n    Acceleration    = $nominal_gravity ft/sec/sec +/- 5%\nSet the timer for your freefall\nEOD\n\n    my $drop_time = get_input(\n        'How many seconds? ',\n        sub { m/ \\A [0-9]+ \\z /smx },\n        \"Please enter an unsigned integer\\n\",\n    );\n\n    print <<'EOD';\nHere we go.\n\nTime (sec)      Dist to fall (ft)\n==========      =================\nEOD\n\n    if ( defined( my $altitude = make_jump(\n                $initial_altitude,\n                $gravity,\n                $terminal_velocity,\n                $drop_time ) )\n    ) {\n        # Successful jump\n        state $succesful = [];\n        state $ordinal = [ qw{ 1st 2nd 3rd } ];\n        if ( defined( my $ord = $ordinal->[ @{ $succesful } ] ) ) {\n            say \"Amazing!!! Not nad for your $ord successful jump!!!\";\n        } else {\n            my $jumps = @{ $succesful };\n            my $worse = grep { $_ > $altitude } @{ $succesful };\n            my $fractile = 1 - $worse / $jumps;\n            my $better = $jumps - $worse;\n            if ( $fractile <= 0.1 ) {\n                print <<\"EOD\";\nWow!  That's some jumping.  Of the $jumps successful jumps\nbefore yours, only $better opened their chutes lower than\nyou did.\nEOD\n            } elsif ( $fractile <= 0.25 ) {\n                print <<\"EOD\";\nPretty good! $jumps successful jumps preceded yours and only\n$better of them got lower than you did before their chutes\nopened.\nEOD\n            } elsif ( $fractile <= 0.5 ) {\n                print <<\"EOD\";\nNot bad.  There have been $jumps successful jumps before yours.\nYou were beaten out by $better of them.\nEOD\n            } elsif ( $fractile <= 0.75 ) {\n                print <<\"EOD\";\nConservative, aren't you?  You ranked only $better in the\n$jumps successful jumps before yours.\nEOD\n            } elsif ( $fractile <= 0.9 ) {\n                print <<\"EOD\";\nHumph!  Don't you have any sporting blood?  There were\n$jumps successful jumps before yours and you came in $worse jumps\nbetter than the worst.  Shape up!!!\nEOD\n            } else {\n                print <<\"EOD\";\nHey!  You pulled the rip cord much too soon.  $jumps successful\njumps before yours and you came in number $better!  Get with it!\nEOD\n            }\n        }\n        push @{ $succesful }, $altitude;\n    } else {\n        # Splat\n\n        say q<I'll give you another chance.>;\n    }\n\n    next if get_yes_no( 'Do you want to play again' );\n    next if get_yes_no( 'Please' );\n\n    print <<'EOD';\nSsssssssss.\n\nEOD\n    last;\n\n}\n\n# Return the first argument modified by up to plus or minus some\n# fraction specified by the second argument (default 0.05)\nsub dither {\n    my ( $arg, $fract ) = @_;\n    $fract //= 1 / 20;\n    return $arg + ( $arg * rand() * $fract ) - ( $arg * rand() * $fract );\n}\n\nuse constant FORMAT_FALL    => \"%10.1f      %10d\\n\";\nuse constant FORMAT_SPLAT   => \"%10.1f      %s\\n\";\nsub make_jump {\n    my ( $initial_altitude, $gravity, $terminal_velocity, $drop_time ) = @_;\n    my $altitude;\n    foreach my $step ( 0 .. 8 ) {\n        my $time = $step * $drop_time / 8;\n        if ( $time > $terminal_velocity / $gravity ) {\n            # Terminal velocity reached\n            printf \"Terminal velocity reached at T plus %.2f seconds.\\n\",\n                $terminal_velocity / $gravity;\n            for my $step ( $step .. 8 ) {\n                my $time = $step * $drop_time / 8;\n                $altitude = $initial_altitude - (\n                    $terminal_velocity * $terminal_velocity /\n                    ( 2 * $gravity ) + $terminal_velocity * (\n                        $time - $terminal_velocity / $gravity ) );\n                if ( $altitude > 0 ) {\n                    printf FORMAT_FALL, $time, $altitude;\n                } else {\n                    splat(\n                        $terminal_velocity / $gravity + (\n                            $initial_altitude -\n                            $terminal_velocity * $terminal_velocity /\n                            ( 2 * $gravity ) ) / $terminal_velocity,\n                    );\n                    return;\n                }\n            }\n            last;\n        } else {\n            $altitude = $initial_altitude - $gravity / 2 * $time * $time;\n            if ( $altitude > 0 ) {\n                printf FORMAT_FALL, $time, $altitude;\n            } else {\n                splat( sqrt( 2 * $initial_altitude / $gravity ) );\n                return;\n            }\n        }\n    }\n\n    say 'Chute open.';\n    return $altitude;\n}\n\nsub splat {\n    my ( $time ) = @_;\n    printf FORMAT_SPLAT, $time, 'Splat!';\n    state $rip = [\n        q<Requiescat in pace.>,\n        q<May the angel of heaven lead you into paradise.>,\n        q<Rest in peace.>,\n        q<Son-of-a-gun.>,\n        q<#$%&&%!$>,\n        q<A kick in the pants is a boost if you're headed right.>,\n        q<Hmmm. Should have picked a shorter time.>,\n        q<Mutter. Mutter. Mutter.>,\n        q<Pushing up daisies.>,\n        q<Easy come, easy go.>,\n    ];\n    say $rip->[ rand scalar @{ $rip } ];\n    return;\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n# Get a yes-or-no answer. The argument is the prompt, which will have\n# '? [y/n]: ' appended. The donkey work is done by get_input(), which is\n# requested to validate the response as beginning with 'y' or 'n',\n# case-insensitive. The return is a true value for 'y' and a false value\n# for 'n'.\nsub get_yes_no {\n    my ( $prompt ) = @ARG;\n    state $map_answer = {\n        n   => 0,\n        y   => 1,\n    };\n    my $resp = lc get_input(\n        \"$prompt? [y/n]: \",\n        sub { m/ \\A [yn] /smxi },\n        \"Please respond 'y' or 'n'\\n\",\n    );\n    return $map_answer->{ substr $resp, 0, 1 };\n}\n\n__END__\n\n=head1 TITLE\n\nsplat.pl - Play the game 'splat' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n splat.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of C<splat>, which is the 73rd entry in\nBasic Computer Games.\n\nThis is a very basic port. All I really did was untangle the spaghetti.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "81_Splat/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "81_Splat/python/splat.py",
    "content": "\"\"\"\nSPLAT\n\nSplat similates a parachute jump in which you try to open your parachute\nat the last possible moment without going splat! You may select your own\nterminal velocity or let the computer do it for you. You may also select\nthe acceleration due to gravity or, again, let the computer do it\nin which case you might wind up on any one of the eight planets (out to\nNeptune), the moon, or the sun.\n\nThe computer then tells you the height you're jumping from and asks for\nthe seconds of free fall. It then divides your free fall time into eight\nintervals and gives you progress reports on the way down. The computer\nalso keeps track of all prior jumps and lets you know how you compared\nwith previous successful jumps. If you want to recall information from\nprevious runs, then you should store the array `successful_jumps` on\ndisk and read it before each run.\n\nJohn Yegge created this program while at the Oak Ridge Associated\nUniversities.\n\nPorted in 2021 by Jonas Nockert / @lemonad\n\n\"\"\"\nfrom math import sqrt\nfrom random import choice, random, uniform\nfrom typing import List, Tuple\n\nPAGE_WIDTH = 72\n\n\ndef numeric_input(question, default=0) -> float:\n    \"\"\"Ask user for a numeric value.\"\"\"\n    while True:\n        answer_str = input(f\"{question} [{default}]: \").strip() or default\n        try:\n            return float(answer_str)\n        except ValueError:\n            pass\n\n\ndef yes_no_input(question: str, default=\"YES\") -> bool:\n    \"\"\"Ask user a yes/no question and returns True if yes, otherwise False.\"\"\"\n    answer = input(f\"{question} (YES OR NO) [{default}]: \").strip() or default\n    while answer.lower() not in [\"n\", \"no\", \"y\", \"yes\"]:\n        answer = input(f\"YES OR NO [{default}]: \").strip() or default\n    return answer.lower() in [\"y\", \"yes\"]\n\n\ndef get_terminal_velocity() -> float:\n    \"\"\"Terminal velocity by user or picked by computer.\"\"\"\n    if yes_no_input(\"SELECT YOUR OWN TERMINAL VELOCITY\", default=\"NO\"):\n        v1 = numeric_input(\"WHAT TERMINAL VELOCITY (MI/HR)\", default=100)\n    else:\n        # Computer picks 0-1000 terminal velocity.\n        v1 = int(1000 * random())\n        print(f\"OK.  TERMINAL VELOCITY = {v1} MI/HR\")\n\n    # Convert miles/h to feet/s.\n    return v1 * (5280 / 3600)\n\n\ndef get_acceleration() -> float:\n    \"\"\"Acceleration due to gravity by user or picked by computer.\"\"\"\n    if yes_no_input(\"WANT TO SELECT ACCELERATION DUE TO GRAVITY\", default=\"NO\"):\n        a2 = numeric_input(\"WHAT ACCELERATION (FT/SEC/SEC)\", default=32.16)\n    else:\n        body, a2 = pick_random_celestial_body()\n        print(f\"FINE. YOU'RE ON {body}. ACCELERATION={a2} FT/SEC/SEC.\")\n    return a2\n\n\ndef get_freefall_time() -> float:\n    \"\"\"User-guessed freefall time.\n\n    The idea of the game is to pick a freefall time, given initial\n    altitude, terminal velocity and acceleration, so the parachute\n    as close to the ground as possible without going splat.\n    \"\"\"\n    t_freefall: float = 0\n    # A zero or negative freefall time is not handled by the motion\n    # equations during the jump.\n    while t_freefall <= 0:\n        t_freefall = numeric_input(\"HOW MANY SECONDS\", default=10)\n    return t_freefall\n\n\ndef jump() -> float:\n    \"\"\"Simulate a jump and returns the altitude where the chute opened.\n\n    The idea is to open the chute as late as possible -- but not too late.\n    \"\"\"\n    v: float = 0  # Terminal velocity.\n    a: float = 0  # Acceleration.\n    initial_altitude = int(9001 * random() + 1000)\n\n    v1 = get_terminal_velocity()\n    # Actual terminal velocity is +/-5% of v1.\n    v = v1 * uniform(0.95, 1.05)\n\n    a2 = get_acceleration()\n    # Actual acceleration is +/-5% of a2.\n    a = a2 * uniform(0.95, 1.05)\n\n    print(\n        \"\\n\"\n        f\"    ALTITUDE         = {initial_altitude} FT\\n\"\n        f\"    TERM. VELOCITY   = {v1:.2f} FT/SEC +/-5%\\n\"\n        f\"    ACCELERATION     = {a2:.2f} FT/SEC/SEC +/-5%\\n\"\n        \"SET THE TIMER FOR YOUR FREEFALL.\"\n    )\n    t_freefall = get_freefall_time()\n    print(\n        \"HERE WE GO.\\n\\n\"\n        \"TIME (SEC)\\tDIST TO FALL (FT)\\n\"\n        \"==========\\t=================\"\n    )\n\n    terminal_velocity_reached = False\n    is_splat = False\n    for i in range(9):\n        # Divide time for freefall into 8 intervals.\n        t = i * (t_freefall / 8)\n        # From the first equation of motion, v = v_0 + a * delta_t, with\n        # initial velocity v_0 = 0, we can get the time when terminal velocity\n        # is reached: delta_t = v / a.\n        if t > v / a:\n            if not terminal_velocity_reached:\n                print(f\"TERMINAL VELOCITY REACHED AT T PLUS {v / a:.2f} SECONDS.\")\n                terminal_velocity_reached = True\n            # After having reached terminal velocity, the displacement is\n            # composed of two parts:\n            # 1. Displacement up to reaching terminal velocity:\n            #    From the third equation of motion, v^2 = v_0^2 + 2 * a * d,\n            #    with v_0 = 0, we can get the displacement using\n            #    d1 = v^2 / (2 * a).\n            # 2. Displacement beyond having reached terminal velocity:\n            #    here, the displacement is just a function of the terminal\n            #    velocity and the time passed after having reached terminal\n            #    velocity: d2 = v * (t - t_reached_term_vel)\n            d1 = (v**2) / (2 * a)\n            d2 = v * (t - (v / a))\n            altitude = initial_altitude - (d1 + d2)\n            if altitude <= 0:\n                # Time taken for an object to fall to the ground given\n                # an initial altitude is composed of two parts after having\n                # reached terminal velocity:\n                # 1. time up to reaching terminal velocity: t1 = v / a\n                # 2. time beyond having reached terminal velocity:\n                #    here, the altitude that remains after having reached\n                #    terminal velocity can just be divided by the constant\n                #    terminal velocity to get the time it takes to reach the\n                #    ground: t2 = altitude_remaining / v\n                t1 = v / a\n                t2 = (initial_altitude - d1) / v\n                print_splat(t1 + t2)\n                is_splat = True\n                break\n        else:\n            # 1. Displacement before reaching terminal velocity:\n            #    From the second equation of motion,\n            #    d = v_0 * t + 0.5 * a * t^2, with v_0 = 0, we can get\n            #    the displacement using d1 = a / 2 * t^2\n            d1 = (a / 2) * (t**2)\n            altitude = initial_altitude - d1\n            if altitude <= 0:\n                # Time taken for an object to fall to the ground given that\n                # it never reaches terminal velocity can be calculated by\n                # using the second equation of motion:\n                # d = v_0 * t + 0.5 * a * t^2, with v_0 = 0, which\n                # when solved for t becomes\n                # t1 = sqrt(2 * d / a).\n                t1 = sqrt(2 * initial_altitude / a)\n                print_splat(t1)\n                is_splat = True\n                break\n        print(f\"{t:.2f}\\t\\t{altitude:.1f}\")\n\n    if not is_splat:\n        print(\"CHUTE OPEN\")\n    return altitude\n\n\ndef pick_random_celestial_body() -> Tuple[str, float]:\n    \"\"\"Pick a random planet, the moon, or the sun with associated gravity.\"\"\"\n    return choice(\n        [\n            (\"MERCURY\", 12.2),\n            (\"VENUS\", 28.3),\n            (\"EARTH\", 32.16),\n            (\"THE MOON\", 5.15),\n            (\"MARS\", 12.5),\n            (\"JUPITER\", 85.2),\n            (\"SATURN\", 37.6),\n            (\"URANUS\", 33.8),\n            (\"NEPTUNE\", 39.6),\n            (\"THE SUN\", 896.0),\n        ]\n    )\n\n\ndef jump_stats(previous_jumps, chute_altitude) -> Tuple[int, int]:\n    \"\"\"Compare altitude when chute opened with previous successful jumps.\n\n    Return the number of previous jumps and the number of times\n    the current jump is better.\n    \"\"\"\n    n_previous_jumps = len(previous_jumps)\n    n_better = sum(1 for pj in previous_jumps if chute_altitude < pj)\n    return n_previous_jumps, n_better\n\n\ndef print_splat(time_on_impact) -> None:\n    \"\"\"Parachute opened too late!\"\"\"\n    print(f\"{time_on_impact:.2f}\\t\\tSPLAT\")\n    print(\n        choice(\n            [\n                \"REQUIESCAT IN PACE.\",\n                \"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\",\n                \"REST IN PEACE.\",\n                \"SON-OF-A-GUN.\",\n                \"#$%&&%!$\",\n                \"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\",\n                \"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\",\n                \"MUTTER. MUTTER. MUTTER.\",\n                \"PUSHING UP DAISIES.\",\n                \"EASY COME, EASY GO.\",\n            ]\n        )\n    )\n\n\ndef print_results(n_previous_jumps, n_better) -> None:\n    \"\"\"Compare current jump to previous successful jumps.\"\"\"\n    k = n_previous_jumps\n    k1 = n_better\n    n_jumps = k + 1\n    if n_jumps <= 3:\n        order = [\"1ST\", \"2ND\", \"3RD\"]\n        nth = order[n_jumps - 1]\n        print(f\"AMAZING!!! NOT BAD FOR YOUR {nth} SUCCESSFUL JUMP!!!\")\n    elif k - k1 <= 0.1 * k:\n        print(\n            f\"WOW!  THAT'S SOME JUMPING.  OF THE {k} SUCCESSFUL JUMPS\\n\"\n            f\"BEFORE YOURS, ONLY {k - k1} OPENED THEIR CHUTES LOWER THAN\\n\"\n            \"YOU DID.\"\n        )\n    elif k - k1 <= 0.25 * k:\n        print(\n            f\"PRETTY GOOD!  {k} SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\\n\"\n            f\"{k - k1} OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\\n\"\n            \"OPENED.\"\n        )\n    elif k - k1 <= 0.5 * k:\n        print(\n            f\"NOT BAD.  THERE HAVE BEEN {k} SUCCESSFUL JUMPS BEFORE YOURS.\\n\"\n            f\"YOU WERE BEATEN OUT BY {k - k1} OF THEM.\"\n        )\n    elif k - k1 <= 0.75 * k:\n        print(\n            f\"CONSERVATIVE, AREN'T YOU?  YOU RANKED ONLY {k - k1} IN THE\\n\"\n            f\"{k} SUCCESSFUL JUMPS BEFORE YOURS.\"\n        )\n    elif k - k1 <= 0.9 * k:\n        print(\n            \"HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD?  THERE WERE\\n\"\n            f\"{k} SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN {k1} JUMPS\\n\"\n            \"BETTER THAN THE WORST.  SHAPE UP!!!\"\n        )\n    else:\n        print(\n            f\"HEY!  YOU PULLED THE RIP CORD MUCH TOO SOON.  {k} SUCCESSFUL\\n\"\n            f\"JUMPS BEFORE YOURS AND YOU CAME IN NUMBER {k - k1}!\"\n            \"  GET WITH IT!\"\n        )\n\n\ndef print_centered(msg: str) -> None:\n    \"\"\"Print centered text.\"\"\"\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header() -> None:\n    print_centered(\"SPLAT\")\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\n        \"\\n\\n\\n\"\n        \"WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\\n\"\n        \"JUMP.  TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\\n\"\n        \"MOMENT WITHOUT GOING SPLAT.\\n\\n\"\n    )\n\n\ndef main() -> None:\n    print_header()\n\n    successful_jumps: List[float] = []\n    while True:\n        chute_altitude = jump()\n        if chute_altitude > 0:\n            # We want the statistics on previous jumps (i.e. not including the\n            # current jump.)\n            n_previous_jumps, n_better = jump_stats(successful_jumps, chute_altitude)\n            successful_jumps.append(chute_altitude)\n            print_results(n_previous_jumps, n_better)\n        else:\n            # Splat!\n            print(\"I'LL GIVE YOU ANOTHER CHANCE.\")\n        z = yes_no_input(\"DO YOU WANT TO PLAY AGAIN\")\n        if not z:\n            z = yes_no_input(\"PLEASE\")\n        if not z:\n            print(\"SSSSSSSSSS.\")\n            break\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "81_Splat/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "81_Splat/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "81_Splat/rust/src/celestial_body.rs",
    "content": "use rand::{prelude::SliceRandom, Rng};\n\n#[derive(Debug)]\npub enum CelestialBody {\n    MERCURY,\n    VENUS,\n    EARTH,\n    MOON,\n    MARS,\n    JUPITER,\n    SATURN,\n    URANUS,\n    NEPTUNE,\n    SUN,\n}\n\nimpl CelestialBody {\n    pub fn get_acceleration(&self) -> f32 {\n        use CelestialBody::*;\n\n        match self {\n            MERCURY => 12.2,\n            VENUS => 28.3,\n            EARTH => 32.16,\n            MOON => 5.12,\n            MARS => 12.5,\n            JUPITER => 85.2,\n            SATURN => 37.6,\n            URANUS => 33.8,\n            NEPTUNE => 39.6,\n            SUN => 896.,\n        }\n    }\n\n    pub fn print_acceleration_message(&self) {\n        let messages: [&str; 3] = [\"Fine,\", \"All right,\", \"Then\"];\n        let m = messages.choose(&mut rand::thread_rng()).unwrap();\n\n        println!(\n            \"{} YOU'RE ON {:?}. ACCELERATION = {} FT/SEC/SEC.\",\n            m.to_uppercase(),\n            self,\n            self.get_acceleration()\n        );\n    }\n}\n\npub fn random_celestial_body() -> Option<CelestialBody> {\n    use CelestialBody::*;\n\n    match rand::thread_rng().gen_range(0..10) {\n        0 => Some(MERCURY),\n        1 => Some(VENUS),\n        2 => Some(EARTH),\n        3 => Some(MOON),\n        4 => Some(MARS),\n        5 => Some(JUPITER),\n        6 => Some(SATURN),\n        7 => Some(URANUS),\n        8 => Some(NEPTUNE),\n        9 => Some(SUN),\n        _ => None,\n    }\n}\n"
  },
  {
    "path": "81_Splat/rust/src/game.rs",
    "content": "use crate::utility;\n\npub struct Game {\n    altitude: f32,\n    terminal_velocity: f32,\n    acceleration: f32,\n    interval: f32,\n}\n\nimpl Game {\n    pub fn new() -> Game {\n        let altitude = utility::get_altitude();\n\n        let terminal_velocity = utility::get_terminal_velocity(\n            \"SELECT YOUR OWN TERMINAL VELOCITY\",\n            \"WHAT TERMINAL VELOCITY (MI/HR)?\",\n        );\n\n        let acceleration = utility::get_acceleration(\n            \"WANT TO SELECT ACCELERATION DUE TO GRAVITY\",\n            \"WHAT ACCELERATION (FT/SEC/SEC)?\",\n        );\n\n        println!(\"\");\n        println!(\"      ALTITUDE        = {} FT\", altitude);\n        println!(\"      TERM. VELOCITY  = {} FT/SEC +-5%\", terminal_velocity);\n        println!(\"      ACCELERATION    = {} FT/SEC/SEC +-5%\", acceleration);\n\n        let seconds =\n            utility::prompt_numeric(\"\\nSET THE TIMER FOR YOUR FREEFALL.\\nHOW MANY SECONDS?\");\n\n        println!(\"\\nHERE WE GO.\\n\");\n\n        println!(\"TIME (SEC)\\tDIST TO FALL (FT)\");\n        println!(\"==========\\t=================\");\n\n        Game {\n            altitude,\n            terminal_velocity,\n            acceleration,\n            interval: seconds / 8.,\n        }\n    }\n\n    pub fn tick(&mut self) -> f32 {\n        let mut splat = false;\n        let mut terminal_velocity_reached = false;\n\n        let (v, a) = (self.terminal_velocity, self.acceleration);\n        let terminal_velocity_time = v / a;\n\n        let initial_altitude = self.altitude;\n\n        for i in 0..=8 {\n            let dt = i as f32 * self.interval;\n\n            if dt >= terminal_velocity_time {\n                if !terminal_velocity_reached {\n                    println!(\n                        \"TERMINAL VELOCITY REACHED AT T PLUS {} SECONDS.\",\n                        terminal_velocity_time\n                    );\n                    terminal_velocity_reached = true;\n                }\n\n                let d1 = v.powi(2) / (2. * a);\n                let d2 = v * (dt - (terminal_velocity_time));\n                self.altitude = initial_altitude - (d1 + d2);\n\n                if self.altitude <= 0. {\n                    let t = (initial_altitude - d1) / v;\n                    utility::print_splat(t + terminal_velocity_time);\n\n                    splat = true;\n                    break;\n                }\n            } else {\n                let d1 = (a * 0.5) * (dt.powi(2));\n                self.altitude = initial_altitude - d1;\n\n                if self.altitude <= 0. {\n                    let t = (2. * initial_altitude / a).sqrt();\n                    utility::print_splat(t);\n\n                    splat = true;\n                    break;\n                }\n            }\n\n            println!(\"{}\\t\\t{}\", dt, self.altitude);\n\n            std::thread::sleep(std::time::Duration::from_secs(1));\n        }\n\n        let mut a = -1.;\n\n        if !splat {\n            println!(\"\\nCHUTE OPEN\\n\");\n\n            a = self.altitude;\n        }\n\n        a\n    }\n}\n"
  },
  {
    "path": "81_Splat/rust/src/main.rs",
    "content": "use crate::{game::Game, stats::Stats};\n\nmod celestial_body;\nmod game;\nmod stats;\nmod utility;\n\nfn main() {\n    println!(\"\\n\\n\\n                       SPLAT\");\n    println!(\"      CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\\n\");\n\n    println!(\"WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES\");\n    println!(\"A PARACHUTE JUMP. TRY OPEN YOUR CHUTE AT THE\");\n    println!(\"LAST POSSIBLE MOMENT WITHOUT GOING SPLAT.\\n\");\n\n    let mut stats = Stats::new();\n\n    loop {\n        let mut game = Game::new();\n\n        let latest_altitude = game.tick();\n\n        if latest_altitude > 0. {\n            if let Some(s) = &mut stats {\n                s.add_altitude(latest_altitude);\n            }\n        }\n\n        use utility::prompt_bool;\n        if !prompt_bool(\"DO YOU WANT TO PLAY AGAIN?\", true) {\n            if !prompt_bool(\"PLEASE?\", false) {\n                if !prompt_bool(\"YES OR NO PLEASE?\", false) {\n                    println!(\"SSSSSSSSSS.\");\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "81_Splat/rust/src/stats.rs",
    "content": "use std::{\n    fs::{self, File},\n    io::Write,\n};\n\nuse crate::utility;\n\npub struct Stats {\n    altitudes: Vec<f32>,\n}\n\nimpl Stats {\n    pub fn new() -> Option<Self> {\n        if utility::prompt_bool(\"WOULD YOU LIKE TO LOAD PREVIOUS GAME DATA?\", false) {\n            let path = \"src/stats.txt\";\n            let mut altitudes = Vec::new();\n\n            if let Ok(stats) = fs::read_to_string(path) {\n                if stats.is_empty() {\n                    return Some(Stats {\n                        altitudes: Vec::new(),\n                    });\n                }\n\n                let stats: Vec<&str> = stats.trim().split(\",\").collect();\n\n                for s in stats {\n                    if s.is_empty() {\n                        continue;\n                    }\n\n                    let s = s.parse::<f32>().expect(\"Corrupt stats file!\");\n                    altitudes.push(s);\n                }\n\n                return Some(Stats { altitudes });\n            } else {\n                println!(\"PREVIOUS GAME DATA NOT FOUND!\");\n\n                if !utility::prompt_bool(\"WOULD YOU LIKE TO CREATE ONE?\", false) {\n                    return None;\n                } else {\n                    let mut file = File::create(path).expect(\"Invalid file path!\");\n                    file.write_all(\"\".as_bytes())\n                        .expect(\"Could not create file!\");\n\n                    return Some(Stats {\n                        altitudes: Vec::new(),\n                    });\n                }\n            }\n        }\n\n        println!(\"\\nRESULTS OF THIS SESSION WILL NOT BE SAVED.\");\n        None\n    }\n\n    pub fn add_altitude(&mut self, a: f32) {\n        let all_jumps = self.altitudes.len() + 1;\n        let mut placement = all_jumps;\n\n        for (i, altitude) in self.altitudes.iter().enumerate() {\n            if a <= *altitude {\n                placement = i + 1;\n                break;\n            }\n        }\n\n        utility::print_win(all_jumps, placement);\n\n        self.altitudes.push(a);\n        self.altitudes.sort_by(|a, b| a.partial_cmp(b).unwrap());\n\n        self.write();\n    }\n\n    fn write(&self) {\n        let mut file = File::create(\"src/stats.txt\").expect(\"Error loading stats data!\");\n\n        let mut altitudes = String::new();\n\n        for a in &self.altitudes {\n            altitudes.push_str(format!(\"{},\", a).as_str());\n        }\n\n        write!(&mut file, \"{}\", altitudes.trim()).expect(\"ERROR WRITING Stats FILE!\");\n    }\n}\n"
  },
  {
    "path": "81_Splat/rust/src/utility.rs",
    "content": "use crate::celestial_body;\nuse rand::Rng;\nuse std::io;\n\nconst DEATH_MESSAGES: [&str; 10] = [\n    \"REQUIESCAT IN PACE.\",\n    \"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\",\n    \"REST IN PEACE.\",\n    \"SON-OF-A-GUN.\",\n    \"#$%&&%!$\",\n    \"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\",\n    \"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\",\n    \"MUTTER. MUTTER. MUTTER.\",\n    \"PUSHING UP DAISIES.\",\n    \"EASY COME, EASY GO.\",\n];\n\npub fn read_line() -> String {\n    let mut input = String::new();\n    io::stdin()\n        .read_line(&mut input)\n        .expect(\"Failed to read line.\");\n    input.trim().to_uppercase()\n}\n\npub fn prompt_bool(msg: &str, template: bool) -> bool {\n    if template {\n        println!(\"{} (YES OR NO)?\", msg);\n    } else {\n        println!(\"{}\", msg);\n    }\n\n    loop {\n        let response = read_line();\n\n        match response.as_str() {\n            \"YES\" => return true,\n            \"NO\" => return false,\n            _ => println!(\"PLEASE ENTER YES OR NO.\"),\n        }\n    }\n}\n\npub fn prompt_numeric(msg: &str) -> f32 {\n    println!(\"{}\", msg);\n\n    loop {\n        let response = read_line();\n\n        if let Some(_) = response.chars().find(|c| !c.is_numeric()) {\n            println!(\"PLEASE ENTER A NUMBER.\");\n        } else {\n            return response.parse::<f32>().unwrap();\n        }\n    }\n}\n\npub fn get_altitude() -> f32 {\n    9001. * rand::random::<f32>() + 1000.\n}\n\npub fn get_terminal_velocity(bool_msg: &str, num_msg: &str) -> f32 {\n    let mut _num = 0.0;\n\n    if prompt_bool(bool_msg, true) {\n        _num = prompt_numeric(num_msg);\n    } else {\n        _num = get_random_float(0., 1000.);\n        println!(\"OK. TERMINAL VELOCTY = {} MI/HR\", _num);\n    }\n\n    (_num * ((5280 / 3600) as f32)) * get_random_float(0.95, 1.05)\n}\n\npub fn get_acceleration(bool_msg: &str, num_msg: &str) -> f32 {\n    let mut _num = 0.0;\n\n    if prompt_bool(bool_msg, true) {\n        _num = prompt_numeric(num_msg);\n    } else {\n        let b =\n            celestial_body::random_celestial_body().expect(\"Fatal Error: Invalid Celestial Body!\");\n\n        _num = b.get_acceleration();\n        b.print_acceleration_message();\n    }\n\n    _num * get_random_float(0.95, 1.05)\n}\n\nfn get_random_float(min: f32, max: f32) -> f32 {\n    rand::thread_rng().gen_range(min..=max)\n}\n\npub fn print_splat(t: f32) {\n    print_random(format!(\"{}\\t\\tSPLAT!\", t).as_str(), &DEATH_MESSAGES);\n    print!(\"I'LL GIVE YOU ANOTHER CHANCE.\\n\");\n}\n\nfn print_random(msg: &str, choices: &[&str]) {\n    use rand::seq::SliceRandom;\n    use rand::thread_rng;\n\n    let mut rng = thread_rng();\n\n    println!(\"{}\", msg);\n    println!(\"\\n{}\\n\", choices.choose(&mut rng).unwrap());\n}\n\npub fn print_win(total: usize, placement: usize) {\n    if total <= 3 {\n        let order;\n\n        match total {\n            1 => order = \"1ST\",\n            2 => order = \"2ND\",\n            3 => order = \"3RD\",\n            _ => order = \"#INVALID#\",\n        }\n\n        println!(\"AMAZING!!! NOT BAD FOR YOUR {} SUCCESSFUL JUMP!!!\", order);\n        return;\n    }\n\n    let (total, placement) = (total as f32, placement as f32);\n\n    let betters = placement - 1.;\n    let p: f32 = (total - betters) / total;\n\n    println!(\"{}\", p);\n\n    println!(\n        \"placement: {}, total jumps: {}, percent is: {}\",\n        placement, total, p\n    );\n\n    if p < 0.1 {\n        println!(\n            \"HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. {} SUCCESSFUL\\nJUMPS BEFORE YOURS AND YOU CAME IN NUMBER {}! GET WITH IT!\",\n            total, placement\n        );\n    } else if p < 0.25 {\n        println!(\n            \"HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE\\n{} SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN {} JUMPS\\nBETTER THAN THE WORST. SHAPE UP!!!\",\n            total, placement\n        );\n    } else if p < 0.5 {\n        println!(\n            \"CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY {} IN THE\\n{} SUCCESSFUL JUMPS BEFORE YOURS.\",\n            placement, total\n        );\n    } else if p < 0.75 {\n        println!(\n            \"NOT BAD.  THERE HAVE BEEN {} SUCCESSFUL JUMPS BEFORE YOURS.\\nYOU WERE BEATEN OUT BY {} OF THEM.\",\n            total, betters\n        );\n    } else if p < 0.9 {\n        println!(\n            \"PRETTY GOOD! {} SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\\n{} OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\\nOPENED.\",\n            total, betters\n        )\n    } else {\n        println!(\n            \"WOW!  THAT'S SOME JUMPING. OF THE {} SUCCESSFUL JUMPS\\nBEFORE YOURS, ONLY {} OPENED THEIR CHUTES LOWER THAN\\nYOU DID.\",\n            total, betters\n        )\n    }\n}\n"
  },
  {
    "path": "81_Splat/splat.bas",
    "content": "10 PRINT TAB(33);\"SPLAT\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n40 PRINT:PRINT:PRINT\n50 DIM A(42)\n95 PRINT \"WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\"\n96 PRINT \"JUMP.  TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\"\n97 PRINT \"MOMENT WITHOUT GOING SPLAT.\"\n118 PRINT:PRINT:D1=0:V=0:A=0:N=0:M=0:D1=INT(9001*RND(1)+1000)\n119 PRINT \"SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO)\";:INPUT A1$\n120 IF A1$=\"NO\" THEN 128\n121 IF A1$<>\"YES\" THEN PRINT \"YES OR NO\";:INPUT A1$:GOTO 120\n123 PRINT \"WHAT TERMINAL VELOCITY (MI/HR)\";:INPUT V1\n125 V1=V1*(5280/3600):V=V1+((V1*RND(1))/20)-((V1*RND(1))/20):GOTO 135\n128 V1=INT(1000*RND(1))\n130 PRINT \"OK.  TERMINAL VELOCITY =\"V1\"MI/HR\"\n131 V1=V1*(5280/3600):V=V1+((V1*RND(1))/20)-((V1*RND(1))/20)\n135  PRINT \"WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO)\";\n136 INPUT B1$\n140 IF B1$=\"NO\" THEN 150\n141 IF B1$<>\"YES\" THEN PRINT \"YES OR NO\";:INPUT B1$:GOTO 140\n143 PRINT \"WHAT ACCELERATION (FT/SEC/SEC)\";:INPUT A2\n145 A=A2+((A2*RND(1))/20)-((A2*RND(1))/20):GOTO 205\n150 ON INT(1+(10*RND(1)))GOTO 151,152,153,154,155,156,157,158,159,160\n151 PRINT\"FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC.\":GOTO 161\n152 PRINT\"ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC.\":GOTO 162\n153 PRINT \"THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC.\":GOTO 163\n154 PRINT\"FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC.\":GOTO 164\n155 PRINT\"ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC.\":GOTO 165\n156 PRINT\"THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC.\":GOTO 166\n157 PRINT\"FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC.\":GOTO 167\n158 PRINT\"ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC.\":GOTO 168\n159 PRINT\"THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC.\":GOTO 169\n160 PRINT\"FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC.\":GOTO 170\n161 A2=12.2:GOTO 145\n162 A2=28.3:GOTO 145\n163 A2=32.16:GOTO 145\n164 A2=5.15:GOTO 145\n165 A2=12.5:GOTO 145\n166 A2=85.2:GOTO 145\n167 A2=37.6:GOTO 145\n168 A2=33.8 :GOTO 145\n169 A2=39.6:GOTO 145\n170 A2=896:GOTO 145\n205 PRINT\n206 PRINT \"    ALTITUDE         =\"D1\"FT\"\n207 PRINT \"    TERM. VELOCITY   =\"V1\"FT/SEC +/-5%\"\n208 PRINT \"    ACCELERATION     =\"A2\"FT/SEC/SEC +/-5%\"\n210 PRINT \"SET THE TIMER FOR YOUR FREEFALL.\"\n211 PRINT \"HOW MANY SECONDS\";:INPUT T\n215 PRINT \"HERE WE GO.\"\n217 PRINT\n218 PRINT \"TIME (SEC)\",\"DIST TO FALL (FT)\"\n219 PRINT \"==========\",\"=================\"\n300 FOR I=0 TO T STEP (T/8)\n310 IF I>V/A THEN 400\n320 D=D1-((A/2)*I^2)\n330 IF D<=0 THEN 1000\n340 PRINT I,D\n350 NEXT I\n360 GOTO 500\n400 PRINT \"TERMINAL VELOCITY REACHED AT T PLUS\"V/A\"SECONDS.\"\n405 FOR I=I TO T STEP (T/8)\n410 D=D1-((V^2/(2*A))+(V*(I-(V/A))))\n420 IF D<=0 THEN 1010\n430 PRINT I,D\n440 NEXT I\n500 PRINT \"CHUTE OPEN\"\n510 K=0:K1=0\n550 FOR J=0 TO 42\n555 IF A(J)=0 THEN 620\n560 K=K+1\n570 IF D>=A(J) THEN 600\n580 K1=K1+1\n600 NEXT J\n610 GOTO 540\n620 A(J)=D\n630 IF J>2 THEN 650\n635 PRINT \"AMAZING!!! NOT BAD FOR YOUR \";\n636 IF J=0 THEN PRINT \"1ST \";\n637 IF J=1 THEN PRINT \"2ND \";\n638 IF J=2 THEN PRINT \"3RD \";\n639 PRINT \"SUCCESSFUL JUMP!!!\":GOTO 2000\n650 IF K-K1<=.1*K THEN 700\n660 IF K-K1<=.25*K THEN 710\n670 IF K-K1<=.5*K THEN 720\n680 IF K-K1<=.75*K THEN 730\n690 IF K-K1<=.9*K THEN 740\n695 GOTO 750\n700 PRINT \"WOW!  THAT'S SOME JUMPING.  OF THE\"K\"SUCCESSFUL JUMPS\"\n701 PRINT \"BEFORE YOURS, ONLY\"K-K1\"OPENED THEIR CHUTES LOWER THAN\"\n702 PRINT \"YOU DID.\"\n703 GOTO 2000\n710 PRINT \"PRETTY GOOD! \" K\"SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\"\n711 PRINT K-K1\" OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\"\n712 PRINT \"OPENED.\" :GOTO 2000\n720 PRINT \"NOT BAD.  THERE HAVE BEEN\"K\"SUCCESSFUL JUMPS BEFORE YOURS.\"\n721 PRINT\"YOU WERE BEATEN OUT BY\"K-K1\"OF THEM.\":GOTO 2000\n730 PRINT \"CONSERVATIVE, AREN'T YOU?  YOU RANKED ONLY\"K-K1\"IN THE\"\n731 PRINT K\"SUCCESSFUL JUMPS BEFORE YOURS.\":GOTO 2000\n740 PRINT \"HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD?  THERE WERE\"\n741 PRINT K\"SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN\"K1\"JUMPS\"\n742 PRINT \"BETTER THAN THE WORST.  SHAPE UP!!!\":GOTO 2000\n750 PRINT \"HEY!  YOU PULLED THE RIP CORD MUCH TOO SOON.  \"K\"SUCCESSFUL\"\n751 PRINT \"JUMPS BEFORE YOURS AND YOU CAME IN NUMBER\"K-K1\"!  GET WITH IT!\"\n752 GOTO 2000\n800 PRINT \"REQUIESCAT IN PACE.\":GOTO 1950\n801 PRINT \"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\":GOTO 1950\n802 PRINT \"REST IN PEACE.\":GOTO 1950\n803 PRINT \"SON-OF-A-GUN.\":GOTO 1950\n804 PRINT \"#$%&&%!$\":GOTO 1950\n805 PRINT \"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\":GOTO 1950\n806 PRINT \"HMMM. SHOULD HAVE PICKED A SHORTER TIME.\":GOTO 1950\n807 PRINT \"MUTTER. MUTTER. MUTTER.\":GOTO 1950\n808 PRINT \"PUSHING UP DAISIES.\":GOTO 1950\n809 PRINT \"EASY COME, EASY GO.\":GOTO 1950\n1000 PRINT SQR(2*D1/A),\"SPLAT\"\n1005 ON INT(1+(10*RND(1)))GOTO 800,801,802,803,804,805,806,807,808,809\n1010 PRINT (V/A)+((D1-(V^2/(2*A)))/V),\"SPLAT\"\n1020 GOTO 1005\n1950 PRINT \"I'LL GIVE YOU ANOTHER CHANCE.\":GOTO 2000\n2000 PRINT \"DO YOU WANT TO PLAY AGAIN\";:INPUT Z$\n2001 IF Z$=\"YES\" THEN 118\n2002 IF Z$=\"NO\" THEN 2005\n2003 PRINT \"YES OR NO\":GOTO 2000\n2005 PRINT \"PLEASE\";:INPUT Z$:IF Z$=\"YES\" THEN 118\n2006 IF Z$<>\"NO\" THEN PRINT \"YES OR NO \";:GOTO 2005\n2007 PRINT \"SSSSSSSSSS.\":PRINT:GOTO 2046\n2046 END\n"
  },
  {
    "path": "81_Splat/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "81_Splat/vbnet/Splat.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Splat\", \"Splat.vbproj\", \"{62FD7167-97B2-4EA7-8BC8-CBC5765DF721}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "81_Splat/vbnet/Splat.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Splat</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "82_Stars/README.md",
    "content": "### Stars\n\nIn this game, the computer selects a random number from 1 to 100 (or any value you set). You try to guess the number and the computer gives you clues to tell you how close you’re getting. One star (\\*) means you’re far away from the number; seven stars (\\*\\*\\*\\*\\*\\*\\*) means you’re really close. You get 7 guesses.\n\nOn the surface this game is similar to GUESS; however, the guessing strategy is quite different. See if you can come up with one or more approaches to finding the mystery number.\n\nBob Albrecht of People’s Computer Company created this game.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=153)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=166)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "82_Stars/csharp/Game.cs",
    "content": "using System;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing Stars.Resources;\n\nnamespace Stars;\n\ninternal class Game\n{\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n    private readonly int _maxNumber;\n    private readonly int _maxGuessCount;\n\n    public Game(TextIO io, IRandom random, int maxNumber, int maxGuessCount)\n    {\n        _io = io;\n        _random = random;\n        _maxNumber = maxNumber;\n        _maxGuessCount = maxGuessCount;\n    }\n\n    internal void Play(Func<bool> playAgain)\n    {\n        DisplayIntroduction();\n\n        do\n        {\n            Play();\n        } while (playAgain.Invoke());\n    }\n\n    private void DisplayIntroduction()\n    {\n        _io.Write(Resource.Streams.Title);\n\n        if (_io.ReadString(\"Do you want instructions\").Equals(\"N\", StringComparison.InvariantCultureIgnoreCase))\n        {\n            return;\n        }\n\n        _io.WriteLine(Resource.Formats.Instructions, _maxNumber, _maxGuessCount);\n    }\n\n    private void Play()\n    {\n        _io.WriteLine();\n        _io.WriteLine();\n\n        var target = _random.Next(_maxNumber) + 1;\n\n        _io.WriteLine(\"Ok, I am thinking of a number.  Start guessing.\");\n\n        AcceptGuesses(target);\n    }\n\n    private void AcceptGuesses(int target)\n    {\n        for (int guessCount = 1; guessCount <= _maxGuessCount; guessCount++)\n        {\n            _io.WriteLine();\n            var guess = _io.ReadNumber(\"Your guess\");\n\n            if (guess == target)\n            {\n                DisplayWin(guessCount);\n                return;\n            }\n\n            DisplayStars(target, guess);\n        }\n\n        DisplayLoss(target);\n    }\n\n    private void DisplayStars(int target, float guess)\n    {\n        var stars = Math.Abs(guess - target) switch\n        {\n            >= 64 => \"*\",\n            >= 32 => \"**\",\n            >= 16 => \"***\",\n            >= 8  => \"****\",\n            >= 4  => \"*****\",\n            >= 2  => \"******\",\n            _     => \"*******\"\n        };\n\n        _io.WriteLine(stars);\n    }\n\n    private void DisplayWin(int guessCount)\n    {\n        _io.WriteLine();\n        _io.WriteLine(new string('*', 79));\n        _io.WriteLine();\n        _io.WriteLine($\"You got it in {guessCount} guesses!!!  Let's play again...\");\n    }\n\n    private void DisplayLoss(int target)\n    {\n        _io.WriteLine();\n        _io.WriteLine($\"Sorry, that's {_maxGuessCount} guesses. The number was {target}.\");\n    }\n}\n"
  },
  {
    "path": "82_Stars/csharp/Program.cs",
    "content": "﻿using Games.Common.IO;\nusing Games.Common.Randomness;\nusing Stars;\n\nvar game = new Game(new ConsoleIO(), new RandomNumberGenerator(), maxNumber: 100, maxGuessCount: 7);\n\ngame.Play(() => true);\n"
  },
  {
    "path": "82_Stars/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "82_Stars/csharp/Resources/Instructions.txt",
    "content": "I am thinking of a number between 1 and {0}.\nTry to guess my number.  After you guess, I\nwill type one or more stars (*).  The more\nstars I type, the closer you are to my number.\nOne star (*) means far away, seven stars (*******)\nmeans really close!  You get {1} guesses."
  },
  {
    "path": "82_Stars/csharp/Resources/Resource.cs",
    "content": "using System.IO;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Stars.Resources;\n\ninternal static class Resource\n{\n    internal static class Streams\n    {\n        public static Stream Title => GetStream();\n    }\n\n    internal static class Formats\n    {\n        public static string Instructions => GetString();\n    }\n\n    private static string GetString([CallerMemberName] string name = null)\n    {\n        using var stream = GetStream(name);\n        using var reader = new StreamReader(stream);\n        return reader.ReadToEnd();\n    }\n\n    private static Stream GetStream([CallerMemberName] string name = null)\n        => Assembly.GetExecutingAssembly().GetManifestResourceStream($\"Stars.Resources.{name}.txt\");\n}"
  },
  {
    "path": "82_Stars/csharp/Resources/Title.txt",
    "content": "                                  Stars\n               Creative Computing  Morristown, New Jersey\n\n\n\n"
  },
  {
    "path": "82_Stars/csharp/Stars.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources/*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "82_Stars/csharp/Stars.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Stars\", \"Stars.csproj\", \"{F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {0752CA22-85F0-43AE-8B79-7A611531CAF7}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "82_Stars/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "82_Stars/java/src/Stars.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Stars\n *\n * Based on the Basic game of Stars here\n * https://github.com/coding-horror/basic-computer-games/blob/main/82%20Stars/stars.bas\n *\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n *        new features - no additional text, error checking, etc has been added.\n */\npublic class Stars {\n\n    public static final int HIGH_NUMBER_RANGE = 100;\n    public static final int MAX_GUESSES = 7;\n\n    private enum GAME_STATE {\n        STARTING,\n        INSTRUCTIONS,\n        START_GAME,\n        GUESSING,\n        WON,\n        LOST,\n        GAME_OVER\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // Players guess count;\n    private int playerTotalGuesses;\n\n    // Players current guess\n    private int playerCurrentGuess;\n\n    // Computers random number\n    private int computersNumber;\n\n    public Stars() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     *\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction the first time the game is played.\n                case STARTING:\n                    intro();\n                    gameState = GAME_STATE.INSTRUCTIONS;\n                    break;\n\n                // Ask if instructions are needed and display if yes\n                case INSTRUCTIONS:\n                    if(yesEntered(displayTextAndGetInput(\"DO YOU WANT INSTRUCTIONS? \"))) {\n                        instructions();\n                    }\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Generate computers number for player to guess, etc.\n                case START_GAME:\n                    init();\n                    System.out.println(\"OK, I AM THINKING OF A NUMBER, START GUESSING.\");\n                    gameState = GAME_STATE.GUESSING;\n                    break;\n\n                // Player guesses the number until they get it or run out of guesses\n                case GUESSING:\n                    playerCurrentGuess = playerGuess();\n\n                    // Check if the player guessed the number\n                    if(playerCurrentGuess == computersNumber) {\n                        gameState = GAME_STATE.WON;\n                    } else {\n                        // incorrect guess\n                        showStars();\n                        playerTotalGuesses++;\n                        // Ran out of guesses?\n                        if (playerTotalGuesses > MAX_GUESSES) {\n                            gameState = GAME_STATE.LOST;\n                        }\n                    }\n                    break;\n\n                // Won game.\n                case WON:\n\n                    System.out.println(stars(79));\n                    System.out.println(\"YOU GOT IT IN \" + playerTotalGuesses\n                            + \" GUESSES!!!  LET'S PLAY AGAIN...\");\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Lost game by running out of guesses\n                case LOST:\n                    System.out.println(\"SORRY, THAT'S \" + MAX_GUESSES\n                            + \" GUESSES. THE NUMBER WAS \" + computersNumber);\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n            }\n            // Endless loop since the original code did not allow the player to exit\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Shows how close a players guess is to the computers number by\n     * showing a series of stars - the more stars the closer to the\n     * number.\n     *\n     */\n    private void showStars() {\n        int d = Math.abs(playerCurrentGuess - computersNumber);\n        int starsToShow;\n        if(d >=64) {\n            starsToShow = 1;\n        } else if(d >=32) {\n            starsToShow = 2;\n        } else if (d >= 16) {\n            starsToShow = 3;\n        } else if (d >=8) {\n            starsToShow = 4;\n        } else if( d>= 4) {\n            starsToShow = 5;\n        } else if(d>= 2) {\n            starsToShow = 6;\n        } else {\n            starsToShow = 7;\n        }\n        System.out.println(stars(starsToShow));\n    }\n\n    /**\n     * Show a number of stars (asterisks)\n     * @param number the number of stars needed\n     * @return the string encoded with the number of required stars\n     */\n    private String stars(int number) {\n        char[] stars = new char[number];\n        Arrays.fill(stars, '*');\n        return new String(stars);\n    }\n\n    /**\n     * Initialise variables before each new game\n     *\n     */\n    private void init() {\n        playerTotalGuesses = 1;\n        computersNumber = randomNumber();\n    }\n\n    public void instructions() {\n        System.out.println(\"I AM THINKING OF A WHOLE NUMBER FROM 1 TO \" + HIGH_NUMBER_RANGE);\n        System.out.println(\"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\");\n        System.out.println(\"WILL TYPE ONE OR MORE STARS (*).  THE MORE\");\n        System.out.println(\"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\");\n        System.out.println(\"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\");\n        System.out.println(\"MEANS REALLY CLOSE!  YOU GET \" + MAX_GUESSES + \" GUESSES.\");\n    }\n\n    public void intro() {\n        System.out.println(\"STARS\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n    }\n\n    /**\n     * Get players guess from kb\n     *\n     * @return players guess as an int\n     */\n    private int playerGuess() {\n        return Integer.parseInt((displayTextAndGetInput(\"YOUR GUESS? \")));\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text  player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        // Cycle through the variable number of values and test each\n        for(String val:values) {\n            if(text.equalsIgnoreCase(val)) {\n                return true;\n            }\n        }\n\n        // no matches\n        return false;\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Generate random number\n     *\n     * @return random number\n     */\n    private int randomNumber() {\n        return (int) (Math.random()\n                * (HIGH_NUMBER_RANGE) + 1);\n    }\n}\n"
  },
  {
    "path": "82_Stars/java/src/StarsGame.java",
    "content": "import java.lang.reflect.AnnotatedType;\n\npublic class StarsGame {\n\n    public static void main(String[] args) {\n        Stars stars = new Stars();\n        stars.play();\n    }\n}\n"
  },
  {
    "path": "82_Stars/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "82_Stars/javascript/stars.html",
    "content": "<html>\n<head>\n<title>STARS</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"stars.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "82_Stars/javascript/stars.js",
    "content": "// STARS\n//\n// Converted from BASIC to Javascript by Qursch\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar guesses = 7;\nvar limit = 100;\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"STARS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\\n\\n\");\n\n    // Instructions\n    print(\"DO YOU WANT INSTRUCTIONS? (Y/N)\");\n    var instructions = await input();\n    if(instructions.toLowerCase()[0] == \"y\") {\n        print(`I AM THINKING OF A WHOLE NUMBER FROM 1 TO ${limit}\\n`);\n        print(\"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\\n\");\n        print(\"WILL TYPE ONE OR MORE STARS (*).  THE MORE\\n\");\n        print(\"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\\n\");\n        print(\"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\\n\");\n        print(`MEANS REALLY CLOSE!  YOU GET ${guesses} GUESSES.\\n\\n\\n`);\n    }\n\n    // Game loop\n    while (true) {\n\n        var randomNum = Math.floor(Math.random() * limit) + 1;\n        var loss = true;\n\n        print(\"\\nOK, I AM THINKING OF A NUMBER, START GUESSING.\\n\\n\");\n\n        for(var guessNum=1; guessNum <= guesses; guessNum++) {\n\n            // Input guess\n            print(\"YOUR GUESS\");\n            var guess = parseInt(await input());\n\n            // Check if guess is correct\n            if(guess == randomNum) {\n                loss = false;\n                print(\"\\n\\n\" + \"*\".repeat(50) + \"!!!\\n\");\n                print(`YOU GOT IT IN ${guessNum} GUESSES!!! LET'S PLAY AGAIN...\\n`);\n                break;\n            }\n\n            // Output distance in stars\n            var dist = Math.abs(guess - randomNum);\n            if(isNaN(dist)) print(\"*\");\n            else if(dist >= 64) print(\"*\");\n            else if(dist >= 32) print(\"**\");\n            else if(dist >= 16) print(\"***\");\n            else if(dist >= 8) print(\"****\");\n            else if(dist >= 4) print(\"*****\");\n            else if(dist >= 2) print(\"******\");\n            else print(\"*******\")\n            print(\"\\n\\n\")\n        }\n\n        if(loss) {\n            print(`SORRY, THAT'S ${guesses} GUESSES. THE NUMBER WAS ${randomNum}\\n`);\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "82_Stars/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "82_Stars/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "82_Stars/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "82_Stars/perl/stars.pl",
    "content": "#!/usr/bin/perl\n\nuse v5.11; # for say and use strict\nuse warnings;\n\nmy $MAX_NUMBER = 100;\nmy $MAX_GUESSES = 7;\n\nprint<<__END_OF_INTRO;\n                                  Stars\n               Creative Computing  Morristown, New Jersey\n\n\n\n__END_OF_INTRO\n\nprint \"Do you want instructions? \";\nchomp( my $answer = <> );\nif ( $answer !~ /^N/i ) {\n  print<<__END_OF_INSTRUCTIONS;\nI am thinking of a whole number from 1 to $MAX_NUMBER\nTry to guess my number.  After you guess, I\nwill type one or more stars (*).  The more\nstars I type, the closer you are to my number.\nOne star (*) means far away, seven stars (*******)\nmeans really close!  You get $MAX_GUESSES guesses.\n__END_OF_INSTRUCTIONS\n}\n\n\nwhile (1) {\n  my $number_to_guess = int(rand($MAX_NUMBER) + 1);\n  say \"\\n\\nOK, I am thinking of a number, start guessing.\";\n\n  my $guess_number = 1;\n  while ( $guess_number <= $MAX_GUESSES ) {\n    print \"\\nYour Guess? \";\n    chomp( my $guess = <> );\n    last if $guess == $number_to_guess;\n    $guess_number++;\n    my $difference = abs $guess - $number_to_guess;\n    print '*' if $difference < 2;\n    print '*' if $difference < 4;\n    print '*' if $difference < 8;\n    print '*' if $difference < 16;\n    print '*' if $difference < 32;\n    print '*' if $difference < 64;\n    print \"*\\n\";\n  }\n  if ( $guess_number > $MAX_GUESSES ) { # didn't guess\n    say \"\\nSorry, that's $MAX_GUESSES guesses, number was $number_to_guess\";\n  } else { # winner!\n    say '*' x 50, '!!!';\n    say \"You got it in $guess_number guesses!!!  Let's play again...\";\n  }\n}\n"
  },
  {
    "path": "82_Stars/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "82_Stars/python/stars.py",
    "content": "\"\"\"\r\nStars\r\n\r\nFrom: BASIC Computer Games (1978)\r\n      Edited by David H. Ahl\r\n\r\n\"In this game, the computer selects a random number from 1 to 100\r\n (or any value you set [for MAX_NUM]).  You try to guess the number\r\n and the computer gives you clues to tell you how close you're\r\n getting.  One star (*) means you're far away from the number; seven\r\n stars (*******) means you're really close.  You get 7  guesses.\r\n\r\n\"On the surface this game is very similar to GUESS; however, the\r\n guessing strategy is quite different.  See if you can come up with\r\n one or more approaches to finding the mystery number.\r\n\r\n\"Bob Albrecht of People's Computer Company created this game.\"\r\n\r\n\r\nPython port by Jeff Jetton, 2019\r\n\"\"\"\r\n\r\n\r\nimport random\r\n\r\n# Some contants\r\nMAX_NUM = 100\r\nMAX_GUESSES = 7\r\n\r\n\r\ndef print_instructions() -> None:\r\n    \"\"\"Instructions on how to play\"\"\"\r\n    print(\"I am thinking of a whole number from 1 to %d\" % MAX_NUM)\r\n    print(\"Try to guess my number.  After you guess, I\")\r\n    print(\"will type one or more stars (*).  The more\")\r\n    print(\"stars I type, the closer you are to my number.\")\r\n    print(\"one star (*) means far away, seven stars (*******)\")\r\n    print(\"means really close!  You get %d guesses.\" % MAX_GUESSES)\r\n\r\n\r\ndef print_stars(secret_number, guess) -> None:\r\n    diff = abs(guess - secret_number)\r\n    stars = \"\".join(\"*\" for i in range(8) if diff < 2**i)\r\n    print(stars)\r\n\r\n\r\ndef get_guess(prompt: str) -> int:\r\n    while True:\r\n        guess_str = input(prompt)\r\n        if guess_str.isdigit():\r\n            return int(guess_str)\r\n\r\n\r\ndef main() -> None:\r\n    # Display intro text\r\n    print(\"\\n                   Stars\")\r\n    print(\"Creative Computing  Morristown, New Jersey\")\r\n    print(\"\\n\\n\")\r\n    # \"*** Stars - People's Computer Center, MenloPark, CA\"\r\n\r\n    response = input(\"Do you want instructions? \")\r\n    if response.upper()[0] == \"Y\":\r\n        print_instructions()\r\n\r\n    still_playing = True\r\n    while still_playing:\r\n\r\n        # \"*** Computer thinks of a number\"\r\n        secret_number = random.randint(1, MAX_NUM)\r\n        print(\"\\n\\nOK, I am thinking of a number, start guessing.\")\r\n\r\n        # Init/start guess loop\r\n        guess_number = 0\r\n        player_has_won = False\r\n        while (guess_number < MAX_GUESSES) and not player_has_won:\r\n\r\n            print()\r\n            guess = get_guess(\"Your guess? \")\r\n            guess_number += 1\r\n\r\n            if guess == secret_number:\r\n                # \"*** We have a winner\"\r\n                player_has_won = True\r\n                print(\"**************************************************!!!\")\r\n                print(f\"You got it in {guess_number} guesses!!!\")\r\n\r\n            else:\r\n                print_stars(secret_number, guess)\r\n\r\n            # End of guess loop\r\n\r\n        # \"*** Did not guess in [MAX_GUESS] guesses\"\r\n        if not player_has_won:\r\n            print(f\"\\nSorry, that's {guess_number} guesses, number was {secret_number}\")\r\n\r\n        # Keep playing?\r\n        response = input(\"\\nPlay again? \")\r\n        if response.upper()[0] != \"Y\":\r\n            still_playing = False\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n\r\n######################################################################\r\n#\r\n# Porting Notes\r\n#\r\n#   The original program never exited--it just kept playing rounds\r\n#   over and over.  This version asks to continue each time.\r\n#\r\n#\r\n# Ideas for Modifications\r\n#\r\n#   Let the player know how many guesses they have remaining after\r\n#   each incorrect guess.\r\n#\r\n#   Ask the player to select a skill level at the start of the game,\r\n#   which will affect the values of MAX_NUM and MAX_GUESSES.\r\n#   For example:\r\n#\r\n#       Easy   = 8 guesses, 1 to 50\r\n#       Medium = 7 guesses, 1 to 100\r\n#       Hard   = 6 guesses, 1 to 200\r\n#\r\n######################################################################\r\n"
  },
  {
    "path": "82_Stars/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "82_Stars/ruby/stars.rb",
    "content": "class Stars\n  MAX_NUM = 100\n  MAX_GUESSES = 7\n\n  def start\n    print \"Do you want instructions? (Y/N) \"\n    response = gets.chomp!\n\n    if response.upcase[0] == \"Y\"\n      print_instructions()\n    end\n\n    still_playing = true\n    while still_playing\n      secret_number = rand(1..MAX_NUM)\n      puts \"\\n\\nOK, I am thinking of a number, start guessing.\"\n\n      guess_number = 0\n      player_has_won = false\n\n      while (guess_number < MAX_GUESSES) and not player_has_won\n        puts \"\\n\"\n        guess = get_guess()\n        guess_number += 1\n\n        if guess == secret_number\n          player_has_won = true\n            puts \"**************************************************!!!\"\n            puts \"You got it in #{guess_number} guesses!!!\\n\\n\"\n        else\n          print_stars(secret_number, guess)\n        end\n      end\n\n      if not player_has_won\n        puts \"\\nSorry, that's #{guess_number} guesses, number was #{secret_number}\\n\"\n      end\n\n      print \"Play again? (Y/N) \"\n      response = gets.chomp!\n\n      if response.upcase[0] != \"Y\"\n        still_playing = false\n      end\n      \n    end\n  end\n\n  private\n    def print_instructions\n      puts \"I am thinking of a whole number from 1 to #{MAX_NUM}\"\n      puts \"Try to guess my number.  After you guess, I\"\n      puts \"will type one or more stars (*).  The more\"\n      puts \"stars I type, the closer you are to my number.\"\n      puts \"one star (*) means far away, seven stars (*******)\"\n      puts \"means really close!  You get #{MAX_GUESSES} guesses.\"\n    end\n\n    def get_guess\n      valid_response = false\n      while not valid_response\n        print \"Your guess? \"\n        guess = gets.chomp!\n\n        if guess.match?(/[[:digit:]]/)\n          valid_response = true\n          guess = guess.to_i\n        end\n      end\n\n      return guess\n    end\n\n    def print_stars secret_number, guess\n      diff = (guess - secret_number).abs\n      stars = \"\"\n      for i in 0..7\n        if diff < 2**i\n          stars += \"*\"\n        end\n      end\n      print(stars)\n    end\nend\n\n\nif __FILE__ == $0\n  stars = Stars.new\n  stars.start()\nend"
  },
  {
    "path": "82_Stars/rust/Cargo.toml",
    "content": "[package]\nname = \"stars\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "82_Stars/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "82_Stars/rust/src/main.rs",
    "content": "use rand::Rng;\nuse std::io;\n\nfn main() {\n    println!(\n        \"{: >39}\\n{: >57}\\n\\n\\n\",\n        \"STARS\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    // STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA\n    // A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES\n    let a: u32 = 101;\n    let m: u32 = 7;\n    let mut need_instrut = String::new();\n\n    println!(\"DO YOU WANT INSTRUCTIONS?\");\n    io::stdin()\n        .read_line(&mut need_instrut)\n        .expect(\"Failed to get input\");\n\n    if need_instrut[..1].to_ascii_lowercase().eq(\"y\") {\n        println!(\"I AM THINKING OF A WHOLE NUMBER FROM 1 TO {}\", a - 1);\n        println!(\"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\");\n        println!(\"WILL TYPE ONE OR MORE STARS (*).  THE MORE\");\n        println!(\"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\");\n        println!(\"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\");\n        println!(\"MEANS REALLY CLOSE!  YOU GET {} GUESSES.\\n\\n\", m);\n    }\n\n    loop {\n        println!(\"\\nOK, I AM THINKING OF A NUMBER, START GUESSING.\\n\");\n        let rand_number: i32 = rand::thread_rng().gen_range(1..a) as i32; // generates a random number between 1 and 100\n\n        // GUESSING BEGINS, HUMAN GETS M GUESSES\n        for i in 0..m {\n            let mut guess = String::new();\n            println!(\"YOUR GUESS?\");\n            io::stdin()\n                .read_line(&mut guess)\n                .expect(\"Failed to get input\");\n            let guess: i32 = match guess.trim().parse() {\n                Ok(num) => num,\n                Err(_) => {\n                    println!(\"PLEASE ENTER A NUMBER VALUE.\\n\");\n                    continue;\n                }\n            };\n            if guess == rand_number {\n                print!(\"\");\n                for _i in 0..50 {\n                    print!(\"*\");\n                }\n                println!(\"!!!\");\n                println!(\"YOU GOT IT IN {} GUESSES!!!  LET'S PLAY AGAIN...\\n\", i + 1);\n                break;\n            } else {\n                match_guess(rand_number - guess);\n            }\n\n            if i == 6 {\n                println!(\n                    \"SORRY, THAT'S {} GUESSES. THE NUMBER WAS {}\",\n                    m, rand_number\n                );\n            }\n        }\n    }\n}\n\nfn match_guess(diff: i32) {\n    if diff.abs() >= 64 {\n        println!(\"*\\n\");\n    } else if diff.abs() >= 32 {\n        println!(\"**\\n\");\n    } else if diff.abs() >= 16 {\n        println!(\"***\\n\");\n    } else if diff.abs() >= 8 {\n        println!(\"****\\n\");\n    } else if diff.abs() >= 4 {\n        println!(\"*****\\n\");\n    } else if diff.abs() >= 2 {\n        println!(\"******\\n\");\n    } else {\n        println!(\"*******\\n\");\n    }\n}\n"
  },
  {
    "path": "82_Stars/rust_JWB/Cargo.toml",
    "content": "[package]\n<<<<<<< HEAD\nname = \"rust\"\n=======\nname = \"stars\"\n>>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n<<<<<<< HEAD\nrand = \"0.8.5\"\n=======\nrand = \"0.8.3\"\n>>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d\n"
  },
  {
    "path": "82_Stars/rust_JWB/README.md",
    "content": "<<<<<<< HEAD\n#STARS\n\nFrom: BASIC Computer Games (1978), edited by David H. Ahl\n\nIn this game, the computer selects a random number from 1 to 100\n(or any value you set [for MAX_NUM]).  You try to guess the number\nand the computer gives you clues to tell you how close you're\ngetting.  One star (*) means you're far away from the number; seven\nstars (*******) means you're really close.  You get 7  guesses.\n\nOn the surface this game is very similar to GUESS; however, the\nguessing strategy is quite different.  See if you can come up with\none or more approaches to finding the mystery number.\n\nBob Albrecht of People's Computer Company created this game.\n\n## NOTES\n\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by JW Bruce\n\nthanks to Jeff Jetton for his Python port which provide inspiration\n=======\nOriginal source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/)\n>>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d\n"
  },
  {
    "path": "82_Stars/rust_JWB/src/main.rs",
    "content": "<<<<<<< HEAD\n//\n// Stars\n//\n// From: BASIC Computer Games (1978), edited by David H. Ahl\n//\n// In this game, the computer selects a random number from 1 to 100\n// (or any value you set [for MAX_NUM]).  You try to guess the number\n// and the computer gives you clues to tell you how close you're\n// getting.  One star (*) means you're far away from the number; seven\n// stars (*******) means you're really close.  You get 7  guesses.\n//\n// On the surface this game is very similar to GUESS; however, the\n// guessing strategy is quite different.  See if you can come up with\n// one or more approaches to finding the mystery number.\n//\n// Bob Albrecht of People's Computer Company created this game.\n//\n// rust port by JW BRUCE 2022\n//\n// ********************************************************************\n//\n// Porting Notes (taken for Jeff Jetton's Python version)\n//\n//   The original program never exited--it just kept playing rounds\n//   over and over.  This version asks to continue each time.\n//\n// Ideas for Modifications\n//\n//   Let the player know how many guesses they have remaining after\n//   each incorrect guess.\n//\n//   Ask the player to select a skill level at the start of the game,\n//   which will affect the values of MAX_NUM and MAX_GUESSES.\n//   For example:\n//\n//       Easy   = 8 guesses, 1 to 50\n//       Medium = 7 guesses, 1 to 100\n//       Hard   = 6 guesses, 1 to 200\n//\n// *********************************************************************\n\n// I M P O R T S\nuse std::io;\nuse std::io::stdin;\n//use std::io::{stdin, stdout, Write};\nuse rand::Rng;\n\nconst   MAX_NUM: u8 = 100;\nconst   MAX_GUESSES: u8 = 7;\n\nfn main() -> io::Result<()> {\n    print_header();\n    if !read_lowercase_input()?.starts_with('n') {\n        print_rules();\n    }\n    loop {\n        let secret_number : u8 = rand::thread_rng().gen_range(1..101);\n        let mut guess_count = 0;\n        let mut player_won: bool = false;\n        \n        println!(\"\\n\\nOK, I am thinking of a number, start guessing.\");\n        while guess_count < MAX_GUESSES && !player_won {\n            \n            guess_count += 1;        \n\n            println!(\"Your guess? \");\n            let mut guess = String::new();\n            io::stdin()\n                .read_line(&mut guess)\n                .expect(\"Failed to read line\");\n\n            let guess: u8 = match guess.trim().parse() {\n                Ok(num) => num,\n                Err(_) => continue,\n            };\n            \n            // USE THIS STATEMENT FOR DEBUG PURPOSES\n            // println!(\"Guess #{} is {}. secret number is {}\",guess_count, guess, secret_number);\n            \n            if guess == secret_number {\n                // winner winner chicken dinner\n                player_won = true;\n                println!(\"**************************************************!!!\");\n                println!(\"You got it in {guess_count} guesses!!!\");\n            } else {\n                print_stars( guess, secret_number) ;\n            }      \n        }\n        \n        // player exhausted their number of guesses and did not win.\n        if !player_won {\n            println!(\"Sorry, that's {guess_count} guesses, number was {secret_number}\");\n        }\n\n        println!(\"\\nPlay again (yes or no)?\");\n        if !read_lowercase_input()?.starts_with('y') {\n            return Ok(());\n=======\nuse rand::Rng;\nuse std::io;\n\nfn main() {\n    println!(\n        \"{: >39}\\n{: >57}\\n\\n\\n\",\n        \"STARS\", \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    );\n    // STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA\n    // A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES\n    let a: u32 = 101;\n    let m: u32 = 7;\n    let mut need_instrut = String::new();\n\n    println!(\"DO YOU WANT INSTRUCTIONS?\");\n    io::stdin()\n        .read_line(&mut need_instrut)\n        .expect(\"Failed to get input\");\n\n    if need_instrut[..1].to_ascii_lowercase().eq(\"y\") {\n        println!(\"I AM THINKING OF A WHOLE NUMBER FROM 1 TO {}\", a - 1);\n        println!(\"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\");\n        println!(\"WILL TYPE ONE OR MORE STARS (*).  THE MORE\");\n        println!(\"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\");\n        println!(\"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\");\n        println!(\"MEANS REALLY CLOSE!  YOU GET {} GUESSES.\\n\\n\", m);\n    }\n\n    loop {\n        println!(\"\\nOK, I AM THINKING OF A NUMBER, START GUESSING.\\n\");\n        let rand_number: i32 = rand::thread_rng().gen_range(1..a) as i32; // generates a random number between 1 and 100\n\n        // GUESSING BEGINS, HUMAN GETS M GUESSES\n        for i in 0..m {\n            let mut guess = String::new();\n            println!(\"YOUR GUESS?\");\n            io::stdin()\n                .read_line(&mut guess)\n                .expect(\"Failed to get input\");\n            let guess: i32 = match guess.trim().parse() {\n                Ok(num) => num,\n                Err(_) => {\n                    println!(\"PLEASE ENTER A NUMBER VALUE.\\n\");\n                    continue;\n                }\n            };\n            if guess == rand_number {\n                print!(\"\");\n                for _i in 0..50 {\n                    print!(\"*\");\n                }\n                println!(\"!!!\");\n                println!(\"YOU GOT IT IN {} GUESSES!!!  LET'S PLAY AGAIN...\\n\", i + 1);\n                break;\n            } else {\n                match_guess(rand_number - guess);\n            }\n\n            if i == 6 {\n                println!(\n                    \"SORRY, THAT'S {} GUESSES. THE NUMBER WAS {}\",\n                    m, rand_number\n                );\n            }\n>>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d\n        }\n    }\n}\n\n<<<<<<< HEAD\n// guess is wrong, so print stars to show how far away they are\nfn print_stars( guess: u8, target: u8) {\n    // choose to use u8 in main, but currently (1.59.0) does not\n    //   have abs() defined for u8.  abs() is defined for i16, so\n    //   this provide an opportunity to demonstrate casting in rust\n    let diff : i16 = ((guess as i16)-(target as i16)).abs();\n    \n    // Since we only print 1-7 stars, this finite set of choices is\n    //   small enough that we can use rust's match keyword.\n    // The match \"arms\" here use the inclusive range notation.\n    //   The exlusive range notation is not an approved feature of\n    //   rust, yet.\n    match diff {\n        1..=2 => println!(\"*******\"),\n        3..=4 => println!(\"******\"),\n        5..=8 => println!(\"*****\"),\n        9..=16 => println!(\"****\"),\n        17..=32 => println!(\"***\"),\n        33..=64 => println!(\"**\"),\n        _ => println!(\"*\"),\n    }\n}\n\n//\nfn read_lowercase_input() -> io::Result<String> {\n    let mut input = String::new();\n    stdin().read_line(&mut input)?;\n    Ok(input.trim().to_lowercase())\n}\n\n// Text to print at the start of the game\nfn print_header() {\n    println!(\"\\n                   Stars\");\n    println!(\"Creative-Computing  Morristown, New Jersey\");\n    println!(\"\\n\\n\");\n    println!(\"Do you want instructions? \");\n}\n\n// Instructions on how to play\nfn print_rules() {\n    println!();\n    println!(\"I am thinking of a whole number from 1 to {}\", MAX_NUM);\n    println!(\"Try to guess my number.  After you guess, I\");\n    println!(\"will type one or more stars (*).  The more\");\n    println!(\"stars I type, the closer you are to my number.\");\n    println!(\"one star (*) means far away, seven stars (*******)\");\n    println!(\"means really close!  You get {} guesses.\", MAX_GUESSES);\n}\n=======\nfn match_guess(diff: i32) {\n    if diff.abs() >= 64 {\n        println!(\"*\\n\");\n    } else if diff.abs() >= 32 {\n        println!(\"**\\n\");\n    } else if diff.abs() >= 16 {\n        println!(\"***\\n\");\n    } else if diff.abs() >= 8 {\n        println!(\"****\\n\");\n    } else if diff.abs() >= 4 {\n        println!(\"*****\\n\");\n    } else if diff.abs() >= 2 {\n        println!(\"******\\n\");\n    } else {\n        println!(\"*******\\n\");\n    }\n}\n>>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d\n"
  },
  {
    "path": "82_Stars/stars.bas",
    "content": "10 PRINT TAB(34);\"STARS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 REM *** STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA\n140 REM *** A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES\n150 A=100:M=7\n170 INPUT \"DO YOU WANT INSTRUCTIONS\";A$\n190 IF LEFT$(A$,1)=\"N\" THEN 280\n200 REM *** INSTRUCTIONS ON HOW TO PLAY\n210 PRINT \"I AM THINKING OF A WHOLE NUMBER FROM 1 TO\";A\n220 PRINT \"TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\"\n230 PRINT \"WILL TYPE ONE OR MORE STARS (*).  THE MORE\"\n240 PRINT \"STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\"\n250 PRINT \"ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\"\n260 PRINT \"MEANS REALLY CLOSE!  YOU GET\";M;\"GUESSES.\"\n270 REM *** COMPUTER THINKS OF A NUMBER\n280 PRINT\n290 PRINT\n300 X=INT(A*RND(1)+1)\n310 PRINT \"OK, I AM THINKING OF A NUMBER, START GUESSING.\"\n320 REM *** GUESSING BEGINS, HUMAN GETS M GUESSES\n330 FOR K=1 TO M\n340 PRINT\n350 PRINT \"YOUR GUESS\";\n360 INPUT G\n370 IF G=X THEN 600\n380 D=ABS(G-X)\n390 IF D>=64 THEN 510\n400 IF D>=32 THEN 500\n410 IF D>=16 THEN 490\n420 IF D>=8 THEN 480\n430 IF D>=4 THEN 470\n440 IF D>=2 THEN 460\n450 PRINT \"*\";\n460 PRINT \"*\";\n470 PRINT \"*\";\n480 PRINT \"*\";\n490 PRINT \"*\";\n500 PRINT \"*\";\n510 PRINT \"*\";\n520 PRINT\n530 NEXT K\n540 REM *** DID NOT GUESS IN M GUESSES\n550 PRINT\n560 PRINT \"SORRY, THAT'S\";M;\"GUESSES. THE NUMBER WAS\";X\n580 GOTO 650\n590 REM *** WE HAVE A WINNER\n600 PRINT:FOR N=1 TO 79\n610 PRINT \"*\";\n620 NEXT N\n630 PRINT:PRINT\n640 PRINT \"YOU GOT IT IN\";K;\"GUESSES!!!  LET'S PLAY AGAIN...\"\n650 GOTO 280\n660 END\n"
  },
  {
    "path": "82_Stars/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "82_Stars/vbnet/Stars.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Stars\", \"Stars.vbproj\", \"{181B70F5-C2CB-4A73-9982-30C16DE89240}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{181B70F5-C2CB-4A73-9982-30C16DE89240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{181B70F5-C2CB-4A73-9982-30C16DE89240}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{181B70F5-C2CB-4A73-9982-30C16DE89240}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{181B70F5-C2CB-4A73-9982-30C16DE89240}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "82_Stars/vbnet/Stars.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Stars</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "83_Stock_Market/README.md",
    "content": "### Stock Market\n\nThis program “plays” the stock market. You will be given $10,000 and may buy or sell stocks. Stock prices and trends are generated randomly; therefore, this model does not represent exactly what happens on the exchange. (Depending upon your point of view, you may feel this is quite a good representation!)\n\nEvery trading day, a table of stocks, their prices, and number of shares in your portfolio is printed. Following this, the initials of each stock are printed followed by a question mark. You indicate your transaction in number of shares — a positive number to buy, negative to sell, or 0 to do no trading. A brokerage fee of 1% is charges on all transactions (a bargain!). Note: Even if the value of a stock drops to zero, it may rebound again — then again, it may not.\n\nThis program was created by D. Pessel, L. Braun, and C. Losik of the Huntington Computer Project at SUNY, Stony Brook, N.Y.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=154)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=166)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "83_Stock_Market/csharp/Assets.cs",
    "content": "﻿using System.Collections.Immutable;\n\nnamespace Game\n{\n    /// <summary>\n    /// Stores the player's assets.\n    /// </summary>\n    public record Assets\n    {\n        /// <summary>\n        /// Gets the player's amount of cash.\n        /// </summary>\n        public double Cash { get; init; }\n\n        /// <summary>\n        /// Gets the number of stocks owned of each company.\n        /// </summary>\n        public ImmutableArray<int> Portfolio { get; init; }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Broker.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for exchanging assets.\n    /// </summary>\n    public static class Broker\n    {\n        /// <summary>\n        /// Applies the given set of transactions to the given set of assets.\n        /// </summary>\n        /// <param name=\"assets\">\n        /// The assets to update.\n        /// </param>\n        /// <param name=\"transactions\">\n        /// The set of stocks to purchase or sell.  Positive values indicate\n        /// purchaes and negative values indicate sales.\n        /// </param>\n        /// <param name=\"companies\">\n        /// The collection of companies.\n        /// </param>\n        /// <returns>\n        /// Returns the sellers new assets and a code indicating the result\n        /// of the transaction.\n        /// </returns>\n        public static (Assets newAssets, TransactionResult result) Apply(Assets assets, IEnumerable<int> transactions, IEnumerable<Company> companies)\n        {\n            var (netCost, transactionSize) = Enumerable.Zip(\n                    transactions,\n                    companies,\n                    (amount, company) => (amount * company.SharePrice))\n                .Aggregate(\n                    (netCost: 0.0, transactionSize: 0.0),\n                    (accumulated, amount) => (accumulated.netCost + amount, accumulated.transactionSize + Math.Abs(amount)));\n\n            var brokerageFee = 0.01 * transactionSize;\n\n            var newAssets = assets with\n            {\n                Cash      = assets.Cash - netCost - brokerageFee,\n                Portfolio = ImmutableArray.CreateRange(Enumerable.Zip(\n                    assets.Portfolio,\n                    transactions,\n                    (sharesOwned, delta) => sharesOwned + delta))\n            };\n\n            if (newAssets.Portfolio.Any(amount => amount < 0))\n                return (newAssets, TransactionResult.Oversold);\n            else\n            if (newAssets.Cash < 0)\n                return (newAssets, TransactionResult.Overspent);\n            else\n                return (newAssets, TransactionResult.Ok);\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Company.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Represents a company.\n    /// </summary>\n    public record Company\n    {\n        /// <summary>\n        /// Gets the company's name.\n        /// </summary>\n        public string Name { get; }\n\n        /// <summary>\n        /// Gets the company's three letter stock symbol.\n        /// </summary>\n        public string StockSymbol { get; }\n\n        /// <summary>\n        /// Gets the company's current share price.\n        /// </summary>\n        public double SharePrice { get; init; }\n\n        /// <summary>\n        /// Initializes a new Company record.\n        /// </summary>\n        public Company(string name, string stockSymbol, double sharePrice) =>\n            (Name, StockSymbol, SharePrice) = (name, stockSymbol, sharePrice);\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Controller.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game\n{\n    public static class Controller\n    {\n        /// <summary>\n        /// Manages the initial interaction with the user.\n        /// </summary>\n        public static void StartGame()\n        {\n            View.ShowBanner();\n\n            var showInstructions = GetYesOrNo(View.PromptShowInstructions);\n            View.ShowSeparator();\n            if (showInstructions)\n                View.ShowInstructions();\n\n            View.ShowSeparator();\n        }\n\n        /// <summary>\n        /// Gets a yes or no answer from the user.\n        /// </summary>\n        /// <param name=\"prompt\">\n        /// Displays the prompt.\n        /// </param>\n        /// <returns>\n        /// True if the user answered yes and false if he or she answered no.\n        /// </returns>\n        public static bool GetYesOrNo(Action prompt)\n        {\n            prompt();\n\n            var response = default(char);\n            do\n            {\n                response = Console.ReadKey(intercept: true).KeyChar;\n            }\n            while (response != '0' && response != '1');\n\n            View.ShowChar(response);\n            return response == '1';\n        }\n\n        /// <summary>\n        /// Gets a transaction amount for each company in the given collection\n        /// of companies and returns the updated assets.\n        /// </summary>\n        /// <param name=\"assets\">\n        /// The assets to update.\n        /// </param>\n        /// <param name=\"companies\">\n        /// The collection of companies.\n        /// </param>\n        /// <returns>\n        /// The updated assets.\n        /// </returns>\n        public static Assets UpdateAssets(Assets assets, IEnumerable<Company> companies)\n        {\n            while (true)\n            {\n                View.PromptEnterTransactions();\n\n                var result = Broker.Apply (\n                    assets,\n                    companies.Select(GetTransactionAmount).ToList(),\n                    companies);\n\n                switch (result)\n                {\n                    case (Assets newAssets, TransactionResult.Ok):\n                        return newAssets;\n                    case (_, TransactionResult.Oversold):\n                        View.ShowOversold();\n                        break;\n                    case (Assets newAssets, TransactionResult.Overspent):\n                        View.ShowOverspent(-newAssets.Cash);\n                        break;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets a transaction amount for the given company.\n        /// </summary>\n        /// <param name=\"company\">\n        /// The company to buy or sell.\n        /// </param>\n        /// <returns>\n        /// The number of shares to buy or sell.\n        /// </returns>\n        public static int GetTransactionAmount(Company company)\n        {\n            while (true)\n            {\n                View.PromptBuySellCompany(company);\n\n                var input = Console.ReadLine();\n                if (input is null)\n                    Environment.Exit(0);\n                else\n                if (!Int32.TryParse(input, out var amount))\n                    View.PromptValidInteger();\n                else\n                    return amount;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Extensions/EnumerableExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Game.Extensions\n{\n    /// <summary>\n    /// Provides additional methods for the <see cref=\"IEnumerable{T}\"/>\n    /// interface.\n    /// </summary>\n    public static class EnumerableExtensions\n    {\n        /// <summary>\n        /// Simultaneously projects each element of a sequence and applies\n        /// the result of the previous projection.\n        /// </summary>\n        /// <typeparam name=\"TSource\">\n        /// The type of elements in the source sequence.\n        /// </typeparam>\n        /// <typeparam name=\"TResult\">\n        /// The type of elements in the result sequence.\n        /// </typeparam>\n        /// <param name=\"source\">\n        /// The source sequence.\n        /// </param>\n        /// <param name=\"seed\">\n        /// The seed value for the aggregation component.  This value is\n        /// passed to the first call to <paramref name=\"selector\"/>.\n        /// </param>\n        /// <param name=\"selector\">\n        /// The projection function.  This function is supplied with a value\n        /// from the source sequence and the result of the projection on the\n        /// previous value in the source sequence.\n        /// </param>\n        /// <returns>\n        /// The resulting sequence.\n        /// </returns>\n        public static IEnumerable<TResult> SelectAndAggregate<TSource, TResult>(\n            this IEnumerable<TSource> source,\n            TResult seed,\n            Func<TSource, TResult, TResult> selector)\n        {\n            foreach (var element in source)\n            {\n                seed = selector(element, seed);\n                yield return seed;\n            }\n        }\n\n        /// <summary>\n        /// Combines the results of three distinct sequences into a single\n        /// sequence.\n        /// </summary>\n        /// <typeparam name=\"T1\">\n        /// The element type of the first sequence.\n        /// </typeparam>\n        /// <typeparam name=\"T2\">\n        /// The element type of the second sequence.\n        /// </typeparam>\n        /// <typeparam name=\"T3\">\n        /// The element type of the third sequence.\n        /// </typeparam>\n        /// <typeparam name=\"TResult\">\n        /// The element type of the resulting sequence.\n        /// </typeparam>\n        /// <param name=\"first\">\n        /// The first source sequence.\n        /// </param>\n        /// <param name=\"second\">\n        /// The second source sequence.\n        /// </param>\n        /// <param name=\"third\">\n        /// The third source sequence.\n        /// </param>\n        /// <param name=\"resultSelector\">\n        /// Function that combines results from each source sequence into a\n        /// final result.\n        /// </param>\n        /// <returns>\n        /// A sequence of combined values.\n        /// </returns>\n        /// <remarks>\n        /// <para>\n        /// This function works identically to Enumerable.Zip except that it\n        /// combines three sequences instead of two.\n        /// </para>\n        /// <para>\n        /// We have defined this as an extension method for consistency with\n        /// the similar LINQ methods in the <see cref=\"Enumerable\"/> class.\n        /// However, since there is nothing special about the first sequence,\n        /// it is often more clear to call this as a regular function.  For\n        /// example:\n        /// </para>\n        /// <code>\n        /// EnumerableExtensions.Zip(\n        ///     sequence1,\n        ///     sequence2,\n        ///     sequence3,\n        ///     (a, b, c) => GetResult (a, b, c));\n        /// </code>\n        /// </remarks>\n        public static IEnumerable<TResult> Zip<T1, T2, T3, TResult>(\n            this IEnumerable<T1> first,\n            IEnumerable<T2> second,\n            IEnumerable<T3> third,\n            Func<T1, T2, T3, TResult> resultSelector)\n        {\n            using var enumerator1 = first.GetEnumerator();\n            using var enumerator2 = second.GetEnumerator();\n            using var enumerator3 = third.GetEnumerator();\n\n            while (enumerator1.MoveNext() && enumerator2.MoveNext() && enumerator3.MoveNext())\n                yield return resultSelector(enumerator1.Current, enumerator2.Current, enumerator3.Current);\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Extensions/ImmutableArrayExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Immutable;\n\nnamespace Game.Extensions\n{\n    /// <summary>\n    /// Provides additional methods for the <see cref=\"ImmutableArray{T}\"/> class.\n    /// </summary>\n    public static class ImmutableArrayExtensions\n    {\n        /// <summary>\n        /// Maps each element in an immutable array to a new value.\n        /// </summary>\n        /// <typeparam name=\"TSource\">\n        /// The type of elements in the source array.\n        /// </typeparam>\n        /// <typeparam name=\"TResult\">\n        /// The type of elements in the resulting array.\n        /// </typeparam>\n        /// <param name=\"source\">\n        /// The source array.\n        /// </param>\n        /// <param name=\"selector\">\n        /// Function which receives an element from the source array and its\n        /// index and returns the resulting element.\n        /// </param>\n        public static ImmutableArray<TResult> Map<TSource, TResult>(this ImmutableArray<TSource> source, Func<TSource, int, TResult> selector)\n        {\n            var builder = ImmutableArray.CreateBuilder<TResult>(source.Length);\n\n            for (var i = 0; i < source.Length; ++i)\n                builder.Add(selector(source[i], i));\n\n            return builder.MoveToImmutable();\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Extensions/RandomExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Game.Extensions\n{\n    /// <summary>\n    /// Provides additional methods for the <see cref=\"Random\"/> class.\n    /// </summary>\n    public static class RandomExtensions\n    {\n        /// <summary>\n        /// Generates an infinite sequence of random numbers.\n        /// </summary>\n        /// <param name=\"random\">\n        /// The random number generator.\n        /// </param>\n        /// <param name=\"min\">\n        /// The inclusive lower bound of the range to generate.\n        /// </param>\n        /// <param name=\"max\">\n        /// The exclusive upper bound of the range to generate.\n        /// </param>\n        /// <returns>\n        /// An infinite sequence of random integers in the range [min, max).\n        /// </returns>\n        /// <remarks>\n        /// <para>\n        /// We use an exclusive upper bound, even though it's a little\n        /// confusing, for the sake of consistency with Random.Next.\n        /// </para>\n        /// <para>\n        /// Since the sequence is infinite, a typical usage would be to cap\n        /// the results with a function like Enumerable.Take.  For example,\n        /// to sum the results of rolling three six sided dice, we could do:\n        /// </para>\n        /// <code>\n        /// random.Integers(1, 7).Take(3).Sum()\n        /// </code>\n        /// </remarks>\n        public static IEnumerable<int> Integers(this Random random, int min, int max)\n        {\n            while (true)\n                yield return random.Next(min, max);\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Game\n{\n    class Program\n    {\n        /// <summary>\n        /// Defines the set of companies that will be simulated in the game.\n        /// </summary>\n        private readonly static ImmutableArray<Company> Companies = ImmutableArray.CreateRange(new[]\n        {\n            new Company(\"INT. BALLISTIC MISSILES\",     \"IBM\", sharePrice:100),\n            new Company(\"RED CROSS OF AMERICA\",        \"RCA\", sharePrice:85 ),\n            new Company(\"LICHTENSTEIN, BUMRAP & JOKE\", \"LBJ\", sharePrice:150),\n            new Company(\"AMERICAN BANKRUPT CO.\",       \"ABC\", sharePrice:140),\n            new Company(\"CENSURED BOOKS STORE\",        \"CBS\", sharePrice:110)\n        });\n\n        static void Main()\n        {\n            var assets = new Assets\n            {\n                Cash      = 10000.0,\n                Portfolio = ImmutableArray.CreateRange(Enumerable.Repeat(0, Companies.Length))\n            };\n\n            var previousDay = default(TradingDay);\n\n            Controller.StartGame();\n\n            foreach (var day in StockMarket.Simulate(Companies))\n            {\n                if (previousDay is null)\n                    View.ShowCompanies(day.Companies);\n                else\n                    View.ShowTradeResults(day, previousDay, assets);\n\n                View.ShowAssets(assets, day.Companies);\n\n                if (previousDay is not null && !Controller.GetYesOrNo(View.PromptContinue))\n                    break;\n\n                assets      = Controller.UpdateAssets(assets, day.Companies);\n                previousDay = day;\n            }\n\n            View.ShowFarewell();\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "83_Stock_Market/csharp/StockMarket.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing Game.Extensions;\n\nnamespace Game\n{\n    /// <summary>\n    /// Provides a method for simulating a stock market.\n    /// </summary>\n    public static class StockMarket\n    {\n        /// <summary>\n        /// Simulates changes in the stock market over time.\n        /// </summary>\n        /// <param name=\"companies\">\n        /// The collection of companies that will participate in the market.\n        /// </param>\n        /// <returns>\n        /// An infinite sequence of trading days.  Each day represents the\n        /// state of the stock market at the start of that day.\n        /// </returns>\n        public static IEnumerable<TradingDay> Simulate(ImmutableArray<Company> companies)\n        {\n            var random = new Random();\n\n            var cyclicParameters = EnumerableExtensions.Zip(\n                Trends(random, 1, 5),\n                PriceSpikes(random, companies.Length, 1, 5),\n                PriceSpikes(random, companies.Length, 1, 5),\n                (trend, company1, company2) => (trend, positiveSpike: company1, negativeSpike: company2));\n\n            return cyclicParameters.SelectAndAggregate(\n                new TradingDay\n                {\n                    Companies = companies\n                },\n                (parameters, previousDay) => previousDay with\n                {\n                    Companies = previousDay.Companies.Map(\n                        (company, index) => AdjustSharePrice(\n                            random,\n                            company,\n                            parameters.trend,\n                            parameters.positiveSpike == index,\n                            parameters.negativeSpike == index))\n                });\n        }\n\n        /// <summary>\n        /// Creates a copy of a company with a randomly adjusted share price,\n        /// based on the given parameters.\n        /// </summary>\n        /// <param name=\"random\">\n        /// The random number generator.\n        /// </param>\n        /// <param name=\"company\">\n        /// The company to adjust.\n        /// </param>\n        /// <param name=\"trend\">\n        /// The slope of the overall market price trend.\n        /// </param>\n        /// <param name=\"positiveSpike\">\n        /// True if the function should simulate a positive spike in the\n        /// company's share price.\n        /// </param>\n        /// <param name=\"negativeSpike\">\n        /// True if the function should simulate a negative spike in the\n        /// company's share price.\n        /// </param>\n        /// <returns>\n        /// The adjusted company.\n        /// </returns>\n        private static Company AdjustSharePrice(Random random, Company company, double trend, bool positiveSpike, bool negativeSpike)\n        {\n            var boost = random.Next(4) * 0.25;\n\n            var spikeAmount = 0.0;\n\n            if (positiveSpike)\n                spikeAmount = 10;\n\n            if (negativeSpike)\n                spikeAmount = spikeAmount - 10;\n\n            var priceChange = (int)(trend * company.SharePrice) + boost + (int)(3.5 - (6 * random.NextDouble())) + spikeAmount;\n\n            var newPrice = company.SharePrice + priceChange;\n            if (newPrice < 0)\n                newPrice = 0;\n\n            return company with { SharePrice = newPrice };\n        }\n\n        /// <summary>\n        /// Generates an infinite sequence of market trends.\n        /// </summary>\n        /// <param name=\"random\">\n        /// The random number generator.\n        /// </param>\n        /// <param name=\"minDays\">\n        /// The minimum number of days each trend should last.\n        /// </param>\n        /// <param name=\"maxDays\">\n        /// The maximum number of days each trend should last.\n        /// </param>\n        public static IEnumerable<double> Trends(Random random, int minDays, int maxDays) =>\n            random.Integers(minDays, maxDays + 1).SelectMany(daysInCycle => Enumerable.Repeat(GenerateTrend(random), daysInCycle));\n\n        /// <summary>\n        /// Generates a random value for the market trend.\n        /// </summary>\n        /// <param name=\"random\">\n        /// The random number generator.\n        /// </param>\n        /// <returns>\n        /// A trend value in the range [-0.1, 0.1].\n        /// </returns>\n        private static double GenerateTrend(Random random) =>\n            ((int)(random.NextDouble() * 10 + 0.5) / 100.0) * (random.Next(2) == 0 ? 1 : -1) ;\n\n        /// <summary>\n        /// Generates an infinite sequence of price spikes.\n        /// </summary>\n        /// <param name=\"random\">\n        /// The random number generator.\n        /// </param>\n        /// <param name=\"companyCount\">\n        /// The number of companies.\n        /// </param>\n        /// <param name=\"minDays\">\n        /// The minimum number of days in between price spikes.\n        /// </param>\n        /// <param name=\"maxDays\">\n        /// The maximum number of days in between price spikes.\n        /// </param>\n        /// <returns>\n        /// An infinite sequence of random company indexes and null values.\n        /// A non-null value means that the corresponding company should\n        /// experience a price spike.\n        /// </returns>\n        private static IEnumerable<int?> PriceSpikes(Random random, int companyCount, int minDays, int maxDays) =>\n            random.Integers(minDays, maxDays + 1)\n                .SelectMany(\n                    daysInCycle => Enumerable.Range(0, daysInCycle),\n                    (daysInCycle, dayNumber) => dayNumber == 0 ? random.Next(companyCount) : default(int?));\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/StockMarket.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "83_Stock_Market/csharp/StockMarket.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"StockMarket\", \"StockMarket.csproj\", \"{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {C78DBA4A-87E2-4B31-A261-4AEF5E4C3B12}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "83_Stock_Market/csharp/TradingDay.cs",
    "content": "﻿using System.Collections.Immutable;\nusing System.Linq;\n\nnamespace Game\n{\n    /// <summary>\n    /// Represents a single trading day.\n    /// </summary>\n    public record TradingDay\n    {\n        /// <summary>\n        /// Gets the average share price of all companies in the market this\n        /// day.\n        /// </summary>\n        public double AverageSharePrice =>\n            Companies.Average (company => company.SharePrice);\n\n        /// <summary>\n        /// Gets the collection of public listed companies in the stock market\n        /// this day.\n        /// </summary>\n        public ImmutableArray<Company> Companies { get; init; }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/TransactionResult.cs",
    "content": "﻿namespace Game\n{\n    /// <summary>\n    /// Enumerates the different possible outcomes of applying a transaction.\n    /// </summary>\n    public enum TransactionResult\n    {\n        /// <summary>\n        /// The transaction was successful.\n        /// </summary>\n        Ok,\n\n        /// <summary>\n        /// The transaction failed because the seller tried to sell more shares\n        /// than he or she owns.\n        /// </summary>\n        Oversold,\n\n        /// <summary>\n        /// The transaction failed because the net cost was greater than the\n        /// seller's available cash.\n        /// </summary>\n        Overspent\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/csharp/View.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Game.Extensions;\n\nnamespace Game\n{\n    /// <summary>\n    /// Contains functions for displaying information to the user.\n    /// </summary>\n    public static class View\n    {\n        public static void ShowBanner()\n        {\n            Console.WriteLine(\"                             STOCK MARKET\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void ShowInstructions()\n        {\n            Console.WriteLine(\"THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\");\n            Console.WriteLine(\"$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\");\n            Console.WriteLine(\"BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\");\n            Console.WriteLine(\"REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\");\n            Console.WriteLine(\"OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\");\n            Console.WriteLine(\"IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\");\n            Console.WriteLine(\"INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\");\n            Console.WriteLine(\"MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\");\n            Console.WriteLine(\"TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\");\n            Console.WriteLine(\"NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\");\n            Console.WriteLine(\"ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\");\n            Console.WriteLine(\"TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\");\n            Console.WriteLine(\"HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\");\n            Console.WriteLine(\"(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\");\n            Console.WriteLine(\"10 DAYS)\");\n            Console.WriteLine(\"-----GOOD LUCK!-----\");\n        }\n\n        public static void ShowCompanies(IEnumerable<Company> companies)\n        {\n            var maxNameLength = companies.Max(company => company.Name.Length);\n\n            Console.WriteLine($\"{\"STOCK\".PadRight(maxNameLength)} INITIALS      PRICE/SHARE\");\n            foreach (var company in companies)\n                Console.WriteLine($\"{company.Name.PadRight(maxNameLength)}   {company.StockSymbol}          {company.SharePrice:0.00}\");\n\n            Console.WriteLine();\n            Console.WriteLine($\"NEW YORK STOCK EXCHANGE AVERAGE: {companies.Average(company => company.SharePrice):0.00}\");\n            Console.WriteLine();\n        }\n\n        public static void ShowTradeResults(TradingDay day, TradingDay previousDay, Assets assets)\n        {\n            var results = EnumerableExtensions.Zip(\n                day.Companies,\n                previousDay.Companies,\n                assets.Portfolio,\n                (company, previous, shares) =>\n                (\n                    stockSymbol: company.StockSymbol,\n                    price: company.SharePrice,\n                    shares,\n                    value: shares * company.SharePrice,\n                    change: company.SharePrice - previous.SharePrice\n                )).ToList();\n\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine(\"**********     END OF DAY'S TRADING     **********\");\n            Console.WriteLine();\n            Console.WriteLine();\n\n            Console.WriteLine(\"STOCK\\tPRICE/SHARE\\tHOLDINGS\\tVALUE\\tNET PRICE CHANGE\");\n            foreach (var result in results)\n                Console.WriteLine($\"{result.stockSymbol}\\t{result.price}\\t\\t{result.shares}\\t\\t{result.value:0.00}\\t\\t{result.change:0.00}\");\n\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n\n            var averagePrice = day.AverageSharePrice;\n            var averagePriceChange = averagePrice - previousDay.AverageSharePrice;\n\n            Console.WriteLine($\"NEW YORK STOCK EXCHANGE AVERAGE: {averagePrice:0.00} NET CHANGE {averagePriceChange:0.00}\");\n            Console.WriteLine();\n        }\n\n        public static void ShowAssets(Assets assets, IEnumerable<Company> companies)\n        {\n            var totalStockValue = Enumerable.Zip(\n                assets.Portfolio,\n                companies,\n                (shares, company) => shares * company.SharePrice).Sum();\n\n            Console.WriteLine($\"TOTAL STOCK ASSETS ARE   ${totalStockValue:0.00}\");\n            Console.WriteLine($\"TOTAL CASH ASSETS ARE    ${assets.Cash:0.00}\");\n            Console.WriteLine($\"TOTAL ASSETS ARE         ${totalStockValue + assets.Cash:0.00}\");\n            Console.WriteLine();\n        }\n\n        public static void ShowOversold()\n        {\n            Console.WriteLine();\n            Console.WriteLine(\"YOU HAVE OVERSOLD A STOCK; TRY AGAIN.\");\n        }\n\n        public static void ShowOverspent(double amount)\n        {\n            Console.WriteLine();\n            Console.WriteLine($\"YOU HAVE USED ${amount:0.00} MORE THAN YOU HAVE.\");\n        }\n\n        public static void ShowFarewell()\n        {\n            Console.WriteLine(\"HOPE YOU HAD FUN!!\");\n        }\n\n        public static void ShowSeparator()\n        {\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public static void ShowChar(char c)\n        {\n            Console.WriteLine(c);\n        }\n\n        public static void PromptShowInstructions()\n        {\n            Console.Write(\"DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)? \");\n        }\n\n        public static void PromptContinue()\n        {\n            Console.Write(\"DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? \");\n        }\n\n        public static void PromptEnterTransactions()\n        {\n            Console.WriteLine(\"WHAT IS YOUR TRANSACTION IN\");\n        }\n\n        public static void PromptBuySellCompany(Company company)\n        {\n            Console.Write($\"{company.StockSymbol}? \");\n        }\n\n        public static void PromptValidInteger()\n        {\n            Console.WriteLine(\"PLEASE ENTER A VALID INTEGER\");\n        }\n    }\n}\n"
  },
  {
    "path": "83_Stock_Market/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "83_Stock_Market/java/StockMarket.java",
    "content": "import java.util.ArrayList;\nimport java.util.InputMismatchException;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Scanner;\n\n/**\n * Stock Market Simulation\n *\n * Some of the original program's variables' documentation and their equivalent in this program:\n * A-MRKT TRND SLP;             marketTrendSlope\n * B5-BRKRGE FEE;               brokerageFee\n * C-TTL CSH ASSTS;             cashAssets\n * C5-TTL CSH ASSTS (TEMP);     tmpCashAssets\n * C(I)-CHNG IN STK VAL;        changeStockValue\n * D-TTL ASSTS;                 assets\n * E1,E2-LRG CHNG MISC;         largeChange1, largeChange2\n * I1,I2-STCKS W LRG CHNG;      randomStockIndex1, randomStockIndex2\n * N1,N2-LRG CHNG DAY CNTS;     largeChangeNumberDays1, largeChangeNumberDays2\n * P5-TTL DAYS PRCHSS;          totalDaysPurchases\n * P(I)-PRTFL CNTNTS;           portfolioContents\n * Q9-NEW CYCL?;                newCycle\n * S4-SGN OF A;                 slopeSign\n * S5-TTL DYS SLS;              totalDaysSales\n * S(I)-VALUE/SHR;              stockValue\n * T-TTL STCK ASSTS;            totalStockAssets\n * T5-TTL VAL OF TRNSCTNS;      totalValueOfTransactions\n * W3-LRG CHNG;                 bigChange\n * X1-SMLL CHNG(<$1);           smallChange\n * Z4,Z5,Z6-NYSE AVE.;          tmpNyseAverage, nyseAverage, nyseAverageChange\n * Z(I)-TRNSCT                  transactionQuantity\n *\n * new price = old price + (trend x old price) + (small random price\n * change) + (possible large price change)\n *\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class StockMarket {\n\n\tprivate static final Random random = new Random();\n\n\tpublic static void main(String[] args) {\n\n\t\tScanner scan = new Scanner(System.in);\n\n\t\tprintIntro();\n\t\tprintGameHelp(scan);\n\n\t\tfinal List<Stock> stocks = initStocks();\n\n\t\tdouble marketTrendSlope = Math.floor((random.nextFloat() / 10) * 100 + 0.5)/100f;\n\t\tdouble totalValueOfTransactions;\n\t\tint largeChangeNumberDays1 = 0;\n\t\tint largeChangeNumberDays2 = 0;\n\n\t\t//DAYS FOR FIRST TREND SLOPE (A)\n\t\tvar t8 = randomNumber(1, 6);\n\n\t\t//RANDOMIZE SIGN OF FIRST TREND SLOPE (A)\n\t\tif (random.nextFloat() <= 0.5) {\n\t\t\tmarketTrendSlope = -marketTrendSlope;\n\t\t}\n\n\t\t// INITIALIZE CASH ASSETS:C\n\t\tdouble cashAssets = 10000;\n\t\tboolean largeChange1 = false;\n\t\tboolean largeChange2 = false;\n\t\tdouble tmpNyseAverage;\n\t\tdouble nyseAverage = 0;\n\t\tboolean inProgress = true;\n\t\tvar firstRound = true;\n\n\t\twhile (inProgress) {\n\n\t\t\t/* Original documentation:\n\t\t\tRANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS DAY'S VALUES\n\t\t\tN1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY\n\t\t\tDETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK\n\t\t\tI2 WILL DECREASE 10 PTS.\n\t\t\tIF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1\n\t\t\t*/\n\t\t\tint randomStockIndex1 = 0;\n\t\t\tint randomStockIndex2 = 0;\n\n\t\t\tif (largeChangeNumberDays1 <= 0) {\n\t\t\t\trandomStockIndex1 = randomNumber(0, stocks.size());\n\t\t\t\tlargeChangeNumberDays1 = randomNumber(1, 6);\n\t\t\t\tlargeChange1 = true;\n\t\t\t}\n\t\t\tif (largeChangeNumberDays2 <= 0) {\n\t\t\t\trandomStockIndex2 = randomNumber(0, stocks.size());\n\t\t\t\tlargeChangeNumberDays2 = randomNumber(1, 6);\n\t\t\t\tlargeChange2 = true;\n\t\t\t}\n\t\t\tadjustAllStockValues(stocks, largeChange1, largeChange2, marketTrendSlope, stocks.get(randomStockIndex1), stocks.get(randomStockIndex2));\n\n\t\t\t//reset largeChange flags\n\t\t\tlargeChange1 = false;\n\t\t\tlargeChange2 = false;\n\t\t\tlargeChangeNumberDays1--;\n\t\t\tlargeChangeNumberDays2--;\n\n\t\t\t//AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE\n\t\t\tt8 = t8 - 1;\n\t\t\tif (t8 < 1) {\n\t\t\t\tmarketTrendSlope = newMarketTrendSlope();\n\t\t\t\tt8 = randomNumber(1, 6);\n\t\t\t}\n\n\t\t\t//PRINT PORTFOLIO\n\t\t\tprintPortfolio(firstRound, stocks);\n\n\t\t\ttmpNyseAverage = nyseAverage;\n\t\t\tnyseAverage = 0;\n\t\t\tdouble totalStockAssets = 0;\n\t\t\tfor (Stock stock : stocks) {\n\t\t\t\tnyseAverage = nyseAverage + stock.getStockValue();\n\t\t\t\ttotalStockAssets = totalStockAssets + stock.getStockValue() * stock.getPortfolioContents();\n\t\t\t}\n\t\t\tnyseAverage = Math.floor(100 * (nyseAverage / 5) + .5) / 100f;\n\t\t\tdouble nyseAverageChange = Math.floor((nyseAverage - tmpNyseAverage) * 100 + .5) / 100f;\n\n\t\t\t// TOTAL ASSETS:D\n\t\t\tdouble assets = totalStockAssets + cashAssets;\n\t\t\tif (firstRound) {\n\t\t\t\tSystem.out.printf(\"\\n\\nNEW YORK STOCK EXCHANGE AVERAGE: %.2f\", nyseAverage);\n\t\t\t} else {\n\t\t\t\tSystem.out.printf(\"\\n\\nNEW YORK STOCK EXCHANGE AVERAGE: %.2f NET CHANGE %.2f\", nyseAverage, nyseAverageChange);\n\t\t\t}\n\n\t\t\ttotalStockAssets = Math.floor(100 * totalStockAssets + 0.5) / 100d;\n\t\t\tSystem.out.printf(\"\\n\\nTOTAL STOCK ASSETS ARE   $ %.2f\", totalStockAssets);\n       \t\tcashAssets = Math.floor(100 * cashAssets + 0.5) / 100d;\n\t\t\tSystem.out.printf(\"\\nTOTAL CASH ASSETS ARE    $ %.2f\", cashAssets);\n\t\t\tassets = Math.floor(100 * assets + .5) / 100d;\n\t\t\tSystem.out.printf(\"\\nTOTAL ASSETS ARE         $ %.2f\\n\", assets);\n\n\t\t\tif (!firstRound) {\n\t\t\t\tSystem.out.print(\"\\nDO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? \");\n\t\t\t\tvar newCycle = readANumber(scan);\n\t\t\t\tif (newCycle < 1) {\n\t\t\t\t\tSystem.out.println(\"HOPE YOU HAD FUN!!\");\n\t\t\t\t\tinProgress = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (inProgress) {\n\t\t\t\tboolean validTransaction = false;\n\t\t\t\t//    TOTAL DAY'S PURCHASES IN $:P5\n\t\t\t\tdouble totalDaysPurchases = 0;\n\t\t\t\t//    TOTAL DAY'S SALES IN $:S5\n\t\t\t\tdouble totalDaysSales = 0;\n\t\t\t\tdouble tmpCashAssets;\n\t\t\t\twhile (!validTransaction) {\n\t\t\t\t\t//INPUT TRANSACTIONS\n\t\t\t\t\treadStockTransactions(stocks, scan);\n\t\t\t\t\ttotalDaysPurchases = 0;\n\t\t\t\t\ttotalDaysSales = 0;\n\n\t\t\t\t\tvalidTransaction = true;\n\t\t\t\t\tfor (Stock stock : stocks) {\n\t\t\t\t\t\tstock.setTransactionQuantity(Math.floor(stock.getTransactionQuantity() + 0.5));\n\t\t\t\t\t\tif (stock.getTransactionQuantity() > 0) {\n\t\t\t\t\t\t\ttotalDaysPurchases = totalDaysPurchases + stock.getTransactionQuantity() * stock.getStockValue();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttotalDaysSales = totalDaysSales - stock.getTransactionQuantity() * stock.getStockValue();\n\t\t\t\t\t\t\tif (-stock.getTransactionQuantity() > stock.getPortfolioContents()) {\n\t\t\t\t\t\t\t\tSystem.out.println(\"YOU HAVE OVERSOLD A STOCK; TRY AGAIN.\");\n\t\t\t\t\t\t\t\tvalidTransaction = false;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t//TOTAL VALUE OF TRANSACTIONS:T5\n\t\t\t\t\ttotalValueOfTransactions = totalDaysPurchases + totalDaysSales;\n\t\t\t\t\t// BROKERAGE FEE:B5\n\t\t\t\t\tvar brokerageFee = Math.floor(0.01 * totalValueOfTransactions * 100 + .5) / 100d;\n\t\t\t\t\t// CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES\n\t\t\t\t\t//-BROKERAGE FEES+TOTAL SALES:C5\n\t\t\t\t\ttmpCashAssets = cashAssets - totalDaysPurchases - brokerageFee + totalDaysSales;\n\t\t\t\t\tif (tmpCashAssets < 0) {\n\t\t\t\t\t\tSystem.out.printf(\"\\nYOU HAVE USED $%.2f MORE THAN YOU HAVE.\", -tmpCashAssets);\n\t\t\t\t\t\tvalidTransaction = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcashAssets = tmpCashAssets;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// CALCULATE NEW PORTFOLIO\n\t\t\t\tfor (Stock stock : stocks) {\n\t\t\t\t\tstock.setPortfolioContents(stock.getPortfolioContents() + stock.getTransactionQuantity());\n\t\t\t\t}\n\n\t\t\t\tfirstRound = false;\n\t\t\t}\n\n\t\t}\n\t}\n\n\t/**\n\t * Random int between lowerBound(inclusive) and upperBound(exclusive)\n\t */\n\tprivate static int randomNumber(int lowerBound, int upperBound) {\n\t\treturn random.nextInt((upperBound - lowerBound)) + lowerBound;\n\t}\n\n\tprivate static double newMarketTrendSlope() {\n\t\treturn randomlyChangeTrendSignAndSlopeAndDuration();\n\t}\n\n\tprivate static void printPortfolio(boolean firstRound, List<Stock> stocks) {\n\t\t//BELL RINGING-DIFFERENT ON MANY COMPUTERS\n\t\tif (firstRound) {\n\t\t\tSystem.out.printf(\"%n%-30s\\t%12s\\t%12s\", \"STOCK\", \"INITIALS\", \"PRICE/SHARE\");\n\t\t\tfor (Stock stock : stocks) {\n\t\t\t\tSystem.out.printf(\"%n%-30s\\t%12s\\t%12.2f ------ %12.2f\", stock.getStockName(), stock.getStockCode(),\n\t\t\t\t\t\tstock.getStockValue(), stock.getChangeStockValue());\n\t\t\t}\n\t\t\tSystem.out.println(\"\");\n\t\t} else {\n\t\t\tSystem.out.println(\"\\n**********     END OF DAY'S TRADING     **********\\n\\n\");\n\t\t\tSystem.out.printf(\"%n%-12s\\t%-12s\\t%-12s\\t%-12s\\t%-20s\", \"STOCK\", \"PRICE/SHARE\",\n\t\t\t\t\t\"HOLDINGS\", \"VALUE\", \"NET PRICE CHANGE\");\n\t\t\tfor (Stock stock : stocks) {\n\t\t\t\tSystem.out.printf(\"%n%-12s\\t%-12.2f\\t%-12.0f\\t%-12.2f\\t%-20.2f\",\n\t\t\t\t\t\tstock.getStockCode(), stock.getStockValue(), stock.getPortfolioContents(),\n\t\t\t\t\t\tstock.getStockValue() * stock.getPortfolioContents(), stock.getChangeStockValue());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static void readStockTransactions(List<Stock> stocks, Scanner scan) {\n\t\tSystem.out.println(\"\\n\\nWHAT IS YOUR TRANSACTION IN\");\n\t\tfor (Stock stock : stocks) {\n\t\t\tSystem.out.printf(\"%s? \", stock.getStockCode());\n\n\t\t\tstock.setTransactionQuantity(readANumber(scan));\n\t\t}\n\t}\n\n\tprivate static int readANumber(Scanner scan) {\n\t\tint choice = 0;\n\n\t\tboolean validInput = false;\n\t\twhile (!validInput) {\n\t\t\ttry {\n\t\t\t\tchoice = scan.nextInt();\n\t\t\t\tvalidInput = true;\n\t\t\t} catch (InputMismatchException ex) {\n\t\t\t\tSystem.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\");\n\t\t\t} finally {\n\t\t\t\tscan.nextLine();\n\t\t\t}\n\t\t}\n\n\t\treturn choice;\n\t}\n\n\tprivate static void adjustAllStockValues(List<Stock> stocks, boolean largeChange1,\n\t\t\tboolean largeChange2,\n\t\t\tdouble marketTrendSlope,\n\t\t\tStock stockForLargeChange1, Stock stockForLargeChange2\n\t) {\n\t\t//LOOP THROUGH ALL STOCKS\n\t\tfor (Stock stock : stocks) {\n\t\t\tdouble smallChange = random.nextFloat();\n\n\t\t\tif (smallChange <= 0.25) {\n\t\t\t\tsmallChange = 0.25;\n\t\t\t} else if (smallChange <= 0.5) {\n\t\t\t\tsmallChange = 0.5;\n\t\t\t} else if (smallChange <= 0.75) {\n\t\t\t\tsmallChange = 0.75;\n\t\t\t} else {\n\t\t\t\tsmallChange = 0;\n\t\t\t}\n\n\t\t\t//BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)\n\t\t\tvar bigChange = 0;\n\t\t\tif (largeChange1) {\n\t\t\t\tif (stock.getStockCode().equals(stockForLargeChange1.getStockCode())) {\n\t\t\t\t\t//ADD 10 PTS. TO THIS STOCK;  RESET E1\n\t\t\t\t\tbigChange = 10;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (largeChange2) {\n\t\t\t\tif (stock.getStockCode().equals(stockForLargeChange2.getStockCode())) {\n\t\t\t\t\t//SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2\n\t\t\t\t\tbigChange = bigChange - 10;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstock.setChangeStockValue(Math.floor(marketTrendSlope * stock.stockValue) + smallChange +\n\t\t\t\t\tMath.floor(3 - 6 * random.nextFloat() + .5) + bigChange);\n\t\t\tstock.setChangeStockValue(Math.floor(100 * stock.getChangeStockValue() + .5) / 100d);\n\t\t\tstock.stockValue += stock.getChangeStockValue();\n\n\t\t\tif (stock.stockValue > 0) {\n\t\t\t\tstock.stockValue = Math.floor(100 * stock.stockValue + 0.5) / 100d;\n\t\t\t} else {\n\t\t\t\tstock.setChangeStockValue(0);\n\t\t\t\tstock.stockValue = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static double randomlyChangeTrendSignAndSlopeAndDuration() {\n\t\t// RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION\n\t\tvar newTrend = Math.floor((random.nextFloat() / 10) * 100 + .5) / 100d;\n\t\tvar slopeSign = random.nextFloat();\n\t\tif (slopeSign > 0.5) {\n\t\t\tnewTrend = -newTrend;\n\t\t}\n\t\treturn newTrend;\n\t}\n\n\tprivate static List<Stock> initStocks() {\n\t\tList<Stock> stocks = new ArrayList<>();\n\t\tstocks.add(new Stock(100, \"INT. BALLISTIC MISSILES\", \"IBM\"));\n\t\tstocks.add(new Stock(85, \"RED CROSS OF AMERICA\", \"RCA\"));\n\t\tstocks.add(new Stock(150, \"LICHTENSTEIN, BUMRAP & JOKE\", \"LBJ\"));\n\t\tstocks.add(new Stock(140, \"AMERICAN BANKRUPT CO.\", \"ABC\"));\n\t\tstocks.add(new Stock(110, \"CENSURED BOOKS STORE\", \"CBS\"));\n\t\treturn stocks;\n\t}\n\n\tprivate static void printGameHelp(Scanner scan) {\n\t\tSystem.out.print(\"DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0) ? \");\n\t\tint choice = scan.nextInt();\n\t\tif (choice >= 1) {\n\t\t\tSystem.out.println(\"\");\n\t\t\tSystem.out.println(\"THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\");\n\t\t\tSystem.out.println(\"$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\");\n\t\t\tSystem.out.println(\"BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\");\n\t\t\tSystem.out.println(\"REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\");\n\t\t\tSystem.out.println(\"OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\");\n\t\t\tSystem.out.println(\"IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\");\n\t\t\tSystem.out.println(\"INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\");\n\t\t\tSystem.out.println(\"MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\");\n\t\t\tSystem.out.println(\"TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\");\n\t\t\tSystem.out.println(\"NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\");\n\t\t\tSystem.out.println(\"ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\");\n\t\t\tSystem.out.println(\"TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\");\n\t\t\tSystem.out.println(\"HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\");\n\t\t\tSystem.out.println(\"(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\");\n\t\t\tSystem.out.println(\"10 DAYS)\");\n\t\t\tSystem.out.println(\"-----GOOD LUCK!-----\");\n\t\t}\n\t\tSystem.out.println(\"\\n\\n\");\n\t}\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                STOCK MARKET\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\");\n\t}\n\n\t/**\n\t * Stock class also storing the stock information and other related information for simplicity\n\t */\n\tprivate static class Stock {\n\n\t\tprivate final String stockName;\n\t\tprivate final String stockCode;\n\t\tprivate double stockValue;\n\t\tprivate double portfolioContents = 0;\n\t\tprivate double transactionQuantity = 0;\n\t\tprivate double changeStockValue = 0;\n\n\t\tpublic Stock(double stockValue, String stockName, String stockCode) {\n\t\t\tthis.stockValue = stockValue;\n\t\t\tthis.stockName = stockName;\n\t\t\tthis.stockCode = stockCode;\n\t\t}\n\n\t\tpublic String getStockName() {\n\t\t\treturn stockName;\n\t\t}\n\n\t\tpublic String getStockCode() {\n\t\t\treturn stockCode;\n\t\t}\n\n\t\tpublic double getStockValue() {\n\t\t\treturn stockValue;\n\t\t}\n\n\t\tpublic double getPortfolioContents() {\n\t\t\treturn portfolioContents;\n\t\t}\n\n\t\tpublic void setPortfolioContents(double portfolioContents) {\n\t\t\tthis.portfolioContents = portfolioContents;\n\t\t}\n\n\t\tpublic double getTransactionQuantity() {\n\t\t\treturn transactionQuantity;\n\t\t}\n\n\t\tpublic void setTransactionQuantity(double transactionQuantity) {\n\t\t\tthis.transactionQuantity = transactionQuantity;\n\t\t}\n\n\t\tpublic double getChangeStockValue() {\n\t\t\treturn changeStockValue;\n\t\t}\n\n\t\tpublic void setChangeStockValue(double changeStockValue) {\n\t\t\tthis.changeStockValue = changeStockValue;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Stock{\" +\n\t\t\t\t\t\"stockValue=\" + stockValue +\n\t\t\t\t\t\", stockCode='\" + stockCode + '\\'' +\n\t\t\t\t\t\", portfolioContents=\" + portfolioContents +\n\t\t\t\t\t\", transactionQuantity=\" + transactionQuantity +\n\t\t\t\t\t\", changeStockValue=\" + changeStockValue +\n\t\t\t\t\t'}';\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "83_Stock_Market/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "83_Stock_Market/javascript/stockmarket.html",
    "content": "<html>\n<head>\n<title>STOCKMARKET</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"stockmarket.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "83_Stock_Market/javascript/stockmarket.js",
    "content": "// STOCKMARKET\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar sa = [];\nvar pa = [];\nvar za = [];\nvar ca = [];\nvar i1;\nvar n1;\nvar e1;\nvar i2;\nvar n2;\nvar e2;\nvar x1;\nvar w3;\nvar t8;\nvar a;\nvar s4;\n\n// New stock values - subroutine\nfunction randomize_initial()\n{\n    // RANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS\n    // DAY'S VALUES\n    // N1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY\n    // DETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK\n    // I2 WILL DECREASE 10 PTS.\n    // IF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1\n    if (n1 <= 0) {\n        i1 = Math.floor(4.99 * Math.random() + 1);\n        n1 = Math.floor(4.99 * Math.random() + 1);\n        e1 = 1;\n    }\n    // IF N2 DAYS HAVE PASSED, PICK AN I2, SET E2, DETERMINE NEW N2\n    if (n2 <= 0) {\n        i2 = Math.floor(4.99 * Math.random() + 1);\n        n2 = Math.floor(4.99 * Math.random() + 1);\n        e2 = 1;\n    }\n    // DEDUCT ONE DAY FROM N1 AND N2\n    n1--;\n    n2--;\n    // LOOP THROUGH ALL STOCKS\n    for (i = 1; i <= 5; i++) {\n        x1 = Math.random();\n        if (x1 < 0.25) {\n            x1 = 0.25;\n        } else if (x1 < 0.5) {\n            x1 = 0.5;\n        } else if (x1 < 0.75) {\n            x1 = 0.75;\n        } else {\n            x1 = 0.0;\n        }\n        // BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)\n        w3 = 0;\n        if (e1 >= 1 && Math.floor(i1 + 0.5) == Math.floor(i + 0.5)) {\n            // ADD 10 PTS. TO THIS STOCK;  RESET E1\n            w3 = 10;\n            e1 = 0;\n        }\n        if (e2 >= 1 && Math.floor(i2 + 0.5) == Math.floor(i + 0.5)) {\n            // SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2\n            w3 -= 10;\n            e2 = 0;\n        }\n        // C(I) IS CHANGE IN STOCK VALUE\n        ca[i] = Math.floor(a * sa[i]) + x1 + Math.floor(3 - 6 * Math.random() + 0.5) + w3;\n        ca[i] = Math.floor(100 * ca[i] + 0.5) / 100;\n        sa[i] += ca[i];\n        if (sa[i] <= 0) {\n            ca[i] = 0;\n            sa[i] = 0;\n        } else {\n            sa[i] = Math.floor(100 * sa[i] + 0.5) / 100;\n        }\n    }\n    // AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE\n    if (--t8 < 1) {\n        // RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION\n        // OF TREND (T8)\n        t8 = Math.floor(4.99 * Math.random() + 1);\n        a = Math.floor((Math.random() / 10) * 100 + 0.5) / 100;\n        s4 = Math.random();\n        if (s4 > 0.5)\n            a = -a;\n    }\n}\n\n// Main program\nasync function main()\n{\n    print(tab(30) + \"STOCK MARKET\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    // STOCK MARKET SIMULATION     -STOCK-\n    // REVISED 8/18/70 (D. PESSEL, L. BRAUN, C. LOSIK)\n    // IMP VRBLS: A-MRKT TRND SLP; B5-BRKRGE FEE; C-TTL CSH ASSTS;\n    // C5-TTL CSH ASSTS (TEMP); C(I)-CHNG IN STK VAL; D-TTL ASSTS;\n    // E1,E2-LRG CHNG MISC; I-STCK #; I1,I2-STCKS W LRG CHNG;\n    // N1,N2-LRG CHNG DAY CNTS; P5-TTL DAYS PRCHSS; P(I)-PRTFL CNTNTS;\n    // Q9-NEW CYCL?; S4-SGN OF A; S5-TTL DYS SLS; S(I)-VALUE/SHR;\n    // T-TTL STCK ASSTS; T5-TTL VAL OF TRNSCTNS;\n    // W3-LRG CHNG; X1-SMLL CHNG(<$1); Z4,Z5,Z6-NYSE AVE.; Z(I)-TRNSCT\n    // SLOPE OF MARKET TREND:A  (SAME FOR ALL STOCKS)\n    x = 1;\n    a = Math.floor(Math.random() / 10 * 100 + 0.5) / 100;\n    t5 = 0;\n    x9 = 0;\n    n1 = 0;\n    n2 = 0;\n    e1 = 0;\n    e2 = 0;\n    // INTRODUCTION\n    print(\"DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)\");\n    z9 = parseInt(await input());\n    print(\"\\n\");\n    print(\"\\n\");\n    if (z9 >= 1) {\n        print(\"THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\\n\");\n        print(\"$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\\n\");\n        print(\"BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\\n\");\n        print(\"REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\\n\");\n        print(\"OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\\n\");\n        print(\"IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\\n\");\n        print(\"INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\\n\");\n        print(\"MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\\n\");\n        print(\"TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\\n\");\n        print(\"NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\\n\");\n        print(\"ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\\n\");\n        print(\"TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\\n\");\n        print(\"HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\\n\");\n        print(\"(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\\n\");\n        print(\"10 DAYS)\\n\");\n        print(\"-----GOOD LUCK!-----\\n\");\n    }\n    // GENERATION OF STOCK TABLE: INPUT REQUESTS\n    // INITIAL STOCK VALUES\n    sa[1] = 100;\n    sa[2] = 85;\n    sa[3] = 150;\n    sa[4] = 140;\n    sa[5] = 110;\n    // INITIAL T8 - # DAYS FOR FIRST TREND SLOPE (A)\n    t8 = Math.floor(4.99 * Math.random() + 1);\n    // RANDOMIZE SIGN OF FIRST TREND SLOPE (A)\n    if (Math.random() <= 0.5)\n        a -= a;\n    // RANDOMIZE INITIAL VALUES\n    randomize_initial();\n    // INITIAL PORTFOLIO CONTENTS\n    for (i = 1; i <= 5; i++) {\n        pa[i] = 0;\n        za[i] = 0;\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    // INITIALIZE CASH ASSETS:C\n    c = 10000;\n    z5 = 0;\n    // PRINT INITIAL PORTFOLIO\n    print(\"STOCK\\t \\t\\t\\tINITIALS\\tPRICE/SHARE\\n\");\n    print(\"INT. BALLISTIC MISSILES\\t\\t  IBM\\t\\t\" + sa[1] + \"\\n\");\n    print(\"RED CROSS OF AMERICA\\t\\t  RCA\\t\\t\" + sa[2] + \"\\n\");\n    print(\"LICHTENSTEIN, BUMRAP & JOKE\\t  LBJ\\t\\t\" + sa[3] + \"\\n\");\n    print(\"AMERICAN BANKRUPT CO.\\t\\t  ABC\\t\\t\" + sa[4] + \"\\n\");\n    print(\"CENSURED BOOKS STORE\\t\\t  CBS\\t\\t\" + sa[5] + \"\\n\");\n    while (1) {\n        print(\"\\n\");\n        // NYSE AVERAGE:Z5; TEMP. VALUE:Z4; NET CHANGE:Z6\n        z4 = z5;\n        z5 = 0;\n        t = 0;\n        for (i = 1; i <= 5; i++) {\n            z5 += sa[i];\n            t += sa[i] * pa[i];\n        }\n        z5 = Math.floor(100 * (z5 / 5) + 0.5) / 100;\n        z6 = Math.floor((z5 - z4) * 100 + 0.5) / 100;\n        // TOTAL ASSETS:D\n        d = t + c;\n        if (x9 <= 0) {\n            print(\"NEW YORK STOCK EXCHANGE AVERAGE: \" + z5 + \"\\n\");\n        } else {\n            print(\"NEW YORK STOCK EXCHANGE AVERAGE: \" + z5 + \" NET CHANGE \" + z6 + \"\\n\");\n        }\n        print(\"\\n\");\n        t = Math.floor(100 * t + 0.5) / 100;\n        print(\"TOTAL STOCK ASSETS ARE   $\" + t + \"\\n\");\n        c = Math.floor(100 * c + 0.5) / 100;\n        print(\"TOTAL CASH ASSETS ARE    $\" + c + \"\\n\");\n        d = Math.floor(100 * d + 0.5) / 100;\n        print(\"TOTAL ASSETS ARE         $\" + d + \"\\n\");\n        print(\"\\n\");\n        if (x9 != 0) {\n            print(\"DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)\");\n            q9 = parseInt(await input());\n            if (q9 < 1) {\n                print(\"HOPE YOU HAD FUN!!\\n\");\n                return;\n            }\n        }\n        // INPUT TRANSACTIONS\n        while (1) {\n            print(\"WHAT IS YOUR TRANSACTION IN\\n\");\n            print(\"IBM\");\n            za[1] = parseInt(await input());\n            print(\"RCA\");\n            za[2] = parseInt(await input());\n            print(\"LBJ\");\n            za[3] = parseInt(await input());\n            print(\"ABC\");\n            za[4] = parseInt(await input());\n            print(\"CBS\");\n            za[5] = parseInt(await input());\n            print(\"\\n\");\n            // TOTAL DAY'S PURCHASES IN $:P5\n            p5 = 0;\n            // TOTAL DAY'S SALES IN $:S5\n            s5 = 0;\n            for (i = 1; i <= 5; i++) {\n                za[i] = Math.floor(za[i] + 0.5);\n                if (za[i] > 0) {\n                    p5 += za[i] * sa[i];\n                } else {\n                    s5 -= za[i] * sa[i];\n                    if (-za[i] > pa[i]) {\n                        print(\"YOU HAVE OVERSOLD A STOCK; TRY AGAIN.\\n\");\n                        break;\n                    }\n                }\n            }\n            if (i <= 5)\n                contine;\n            // TOTAL VALUE OF TRANSACTIONS:T5\n            t5 = p5 + s5;\n            // BROKERAGE FEE:B5\n            b5 = Math.floor(0.01 * t5 * 100 + 0.5) / 100;\n            // CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES\n            // -BROKERAGE FEES+TOTAL SALES:C5\n            c5 = c - p5 - b5 + s5;\n            if (c5 < 0) {\n                print(\"YOU HAVE USED $\" + (-c5) + \" MORE THAN YOU HAVE.\\n\");\n                continue;\n            }\n            break;\n        }\n        c = c5;\n        // CALCULATE NEW PORTFOLIO\n        for (i = 1; i <= 5; i++) {\n            pa[i] += za[i];\n        }\n        // CALCULATE NEW STOCK VALUES\n        randomize_initial();\n        // PRINT PORTFOLIO\n        // BELL RINGING-DIFFERENT ON MANY COMPUTERS\n        print(\"\\n\");\n        print(\"**********     END OF DAY'S TRADING     **********\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n        if (x9 >= 1) ;\n        print(\"STOCK\\tPRICE/SHARE\\tHOLDINGS\\tVALUE\\tNET PRICE CHANGE\\n\");\n        print(\"IBM\\t\" + sa[1] + \"\\t\\t\" + pa[1] + \"\\t\\t\" + sa[1] * pa[1] + \"\\t\" + ca[1] + \"\\n\");\n        print(\"RCA\\t\" + sa[2] + \"\\t\\t\" + pa[2] + \"\\t\\t\" + sa[2] * pa[2] + \"\\t\" + ca[2] + \"\\n\");\n        print(\"LBJ\\t\" + sa[3] + \"\\t\\t\" + pa[3] + \"\\t\\t\" + sa[3] * pa[3] + \"\\t\" + ca[3] + \"\\n\");\n        print(\"ABC\\t\" + sa[4] + \"\\t\\t\" + pa[4] + \"\\t\\t\" + sa[4] * pa[4] + \"\\t\" + ca[4] + \"\\n\");\n        print(\"CBS\\t\" + sa[5] + \"\\t\\t\" + pa[5] + \"\\t\\t\" + sa[5] * pa[5] + \"\\t\" + ca[5] + \"\\n\");\n        x9 = 1;\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "83_Stock_Market/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "83_Stock_Market/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "83_Stock_Market/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "83_Stock_Market/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "83_Stock_Market/python/Stock_Market.py",
    "content": "import random\nfrom typing import Any, Dict, List\n\n\nclass Stock_Market:\n    def __init__(self) -> None:\n        # Hard Coded Names\n        short_names = [\"IBM\", \"RCA\", \"LBJ\", \"ABC\", \"CBS\"]\n        full_names = [\n            \"INT. BALLISTIC MISSLES\",\n            \"RED CROSS OF AMERICA\",\n            \"LICHTENSTEIN, BUMRAP & JOKE\",\n            \"AMERICAN BANKRUPT CO.\",\n            \"CENSURED BOOKS STORE\",\n        ]\n\n        # Initializing Dictionary to hold all the information systematically\n        self.data: Dict[str, Any] = {}\n        for sn, fn in zip(short_names, full_names):\n            # A dictionary for each stock\n            temp = {\"Name\": fn, \"Price\": None, \"Holdings\": 0}\n            # Nested outer dictionary for all stocks\n            self.data[sn] = temp\n\n        # Initializing Randomly generated initial prices\n        for stock in self.data.values():\n            stock[\"Price\"] = round(random.uniform(80, 120), 2)  # Price b/w 60 and 120\n\n        # Initialize Assets\n        self.cash_assets = 10000\n        self.stock_assets = 0\n\n    def total_assets(self) -> float:\n        return self.cash_assets + self.stock_assets\n\n    def _generate_day_change(self) -> None:\n        self.changes: List[float] = []\n        self.changes.extend(\n            round(random.uniform(-5, 5), 2) for _ in range(len(self.data))\n        )\n\n    def update_prices(self) -> None:\n        self._generate_day_change()\n        for stock, change in zip(self.data.values(), self.changes):\n            stock[\"Price\"] = round(stock[\"Price\"] + (change / 100) * stock[\"Price\"], 2)\n\n    def print_exchange_average(self) -> None:\n\n        sum = 0\n        for stock in self.data.values():\n            sum += stock[\"Price\"]\n\n        print(f\"\\nNEW YORK STOCK EXCHANGE AVERAGE: ${sum / 5:.2f}\")\n\n    def get_average_change(self) -> float:\n        sum: float = 0\n        for change in self.changes:\n            sum += change\n\n        return round(sum / 5, 2)\n\n    def print_first_day(self) -> None:\n\n        print(\"\\nSTOCK\\t\\t\\t\\t\\tINITIALS\\tPRICE/SHARE($)\")\n        for stock, data in self.data.items():\n            if stock != \"LBJ\":\n                print(f'{data[\"Name\"]}\\t\\t\\t{stock}\\t\\t{data[\"Price\"]}')\n            else:\n                print(f'{data[\"Name\"]}\\t\\t{stock}\\t\\t{data[\"Price\"]}')\n\n        self.print_exchange_average()\n        self.print_assets()\n\n    def take_inputs(self) -> List[str]:\n        print(\"\\nWHAT IS YOUR TRANSACTION IN\")\n        flag = False\n        while not flag:\n            new_holdings = []\n            for stock in self.data.keys():\n                try:\n                    new_holdings.append(int(input(f\"{stock}? \")))\n                except Exception:\n                    print(\"\\nINVALID ENTRY, TRY AGAIN\\n\")\n                    break\n            if len(new_holdings) == 5:\n                flag = self._check_transaction(new_holdings)\n\n        return new_holdings  # type: ignore\n\n    def print_trading_day(self) -> None:\n\n        print(\"STOCK\\tPRICE/SHARE\\tHOLDINGS\\tNET. Value\\tPRICE CHANGE\")\n        for stock, data, change in zip(\n            self.data.keys(), self.data.values(), self.changes\n        ):\n            value = data[\"Price\"] * data[\"Holdings\"]\n            print(\n                \"{}\\t{}\\t\\t{}\\t\\t{:.2f}\\t\\t{}\".format(\n                    stock, data[\"Price\"], data[\"Holdings\"], value, change\n                )\n            )\n\n    def update_cash_assets(self, new_holdings) -> None:\n        sell = 0\n        buy = 0\n        for stock, holding in zip(self.data.values(), new_holdings):\n            if holding > 0:\n                buy += stock[\"Price\"] * holding\n\n            elif holding < 0:\n                sell += stock[\"Price\"] * abs(holding)\n\n        self.cash_assets = self.cash_assets + sell - buy\n\n    def update_stock_assets(self) -> None:\n        sum = 0\n        for data in self.data.values():\n            sum += data[\"Price\"] * data[\"Holdings\"]\n\n        self.stock_assets = round(sum, 2)\n\n    def print_assets(self) -> None:\n        print(f\"\\nTOTAL STOCK ASSETS ARE: ${self.stock_assets:.2f}\")\n        print(f\"TOTAL CASH ASSETS ARE: ${self.cash_assets:.2f}\")\n        print(f\"TOTAL ASSETS ARE: ${self.total_assets():.2f}\")\n\n    def _check_transaction(self, new_holdings) -> bool:\n        sum = 0\n        for stock, holding in zip(self.data.values(), new_holdings):\n            if holding > 0:\n                sum += stock[\"Price\"] * holding\n\n            elif holding < 0:\n                if abs(holding) > stock[\"Holdings\"]:\n                    print(\"\\nYOU HAVE OVERSOLD SOME STOCKS, TRY AGAIN\\n\")\n                    return False\n\n        if sum > self.cash_assets:\n            print(\n                \"\\nYOU HAVE USED ${:.2f} MORE THAN YOU HAVE, TRY AGAIN\\n\".format(\n                    sum - self.cash_assets\n                )\n            )\n            return False\n\n        return True\n\n    def update_holdings(self, new_holdings) -> None:\n        for stock, new_holding in zip(self.data.values(), new_holdings):\n            stock[\"Holdings\"] += new_holding\n\n\ndef print_instruction() -> None:\n\n    print(\n        \"\"\"\nTHIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\n$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\nBE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\nREPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\nOF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\nIN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\nINITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\nMARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\nTYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\nNUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\nON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\nTO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\nHAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\n(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\n10 DAYS)\n          ------------GOOD LUCK!------------\\n\n    \"\"\"\n    )\n\n\ndef main() -> None:\n    print(\"\\t\\t      STOCK MARKET\")\n    help = input(\"\\nDO YOU WANT INSTRUCTIONS(YES OR NO)? \")\n\n    # Printing Instruction\n    if help.lower() == \"yes\":\n        print_instruction()\n\n    # Initialize Game\n    Game = Stock_Market()\n\n    # Do first day\n    Game.print_first_day()\n    new_holdings = Game.take_inputs()\n    Game.update_holdings(new_holdings)\n    Game.update_cash_assets(new_holdings)\n    print(\"\\n------------END OF TRADING DAY--------------\\n\")\n\n    response = 1\n    while response == 1:\n\n        # Simulate a DAY\n        Game.update_prices()\n        Game.print_trading_day()\n        Game.print_exchange_average()\n        Game.update_stock_assets()\n        Game.print_assets()\n\n        response = int(input(\"\\nDO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? \"))\n        if response == 0:\n            break\n\n        new_holdings = Game.take_inputs()\n        Game.update_holdings(new_holdings)\n        Game.update_cash_assets(new_holdings)\n        print(\"\\n------------END OF TRADING DAY--------------\\n\")\n\n    print(\"\\nHOPE YOU HAD FUN!!!!\")\n    input()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "83_Stock_Market/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "83_Stock_Market/stockmarket.bas",
    "content": "10 PRINT TAB(30);\"STOCK MARKET\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 REM STOCK MARKET SIMULATION     -STOCK-\n101 REM REVISED 8/18/70 (D. PESSEL, L. BRAUN, C. LOSIK)\n102 REM IMP VRBLS: A-MRKT TRND SLP; B5-BRKRGE FEE; C-TTL CSH ASSTS;\n103 REM C5-TTL CSH ASSTS (TEMP); C(I)-CHNG IN STK VAL; D-TTL ASSTS;\n104 REM E1,E2-LRG CHNG MISC; I-STCK #; I1,I2-STCKS W LRG CHNG;\n105 REM N1,N2-LRG CHNG DAY CNTS; P5-TTL DAYS PRCHSS; P(I)-PRTFL CNTNTS;\n106 REM Q9-NEW CYCL?; S4-SGN OF A; S5-TTL DYS SLS; S(I)-VALUE/SHR;\n107 REM T-TTL STCK ASSTS; T5-TTL VAL OF TRNSCTNS;\n108 REM W3-LRG CHNG; X1-SMLL CHNG(<$1); Z4,Z5,Z6-NYSE AVE.; Z(I)-TRNSCT\n110 DIM S(5),P(5),Z(5),C(5)\n112 REM SLOPE OF MARKET TREND:A  (SAME FOR ALL STOCKS)\n113 LET X=1\n114 LET A=INT((RND(X)/10)*100+.5)/100\n115 LET T5=0\n116 LET X9=0\n117 LET N1=0\n118 LET N2=0\n119 LET E1=0\n120 LET E2=0\n121 REM INTRODUCTION\n122 PRINT \"DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)\";\n123 INPUT Z9\n124 PRINT\n125 PRINT\n126 IF Z9<1 THEN 200\n130 PRINT \"THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\"\n132 PRINT \"$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\"\n134 PRINT \"BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\"\n135 PRINT \"REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\"\n136 PRINT \"OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\"\n137 PRINT \"IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\"\n138 PRINT \"INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\"\n139 PRINT \"MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\"\n140 PRINT \"TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\"\n141 PRINT \"NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\"\n142 PRINT \"ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\"\n143 PRINT \"TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\"\n144 PRINT \"HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\"\n145 PRINT \"(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\"\n146 PRINT \"10 DAYS)\"\n147 PRINT \"-----GOOD LUCK!-----\"\n200 REM GENERATION OF STOCK TABLE; INPUT REQUESTS\n210 REM INITIAL STOCK VALUES\n220 LET S(1)=100\n230 LET S(2)=85\n240 LET S(3)=150\n250 LET S(4)=140\n260 LET S(5)=110\n265 REM INITIAL T8 - # DAYS FOR FIRST TREND SLOPE (A)\n266 LET T8=INT(4.99*RND(X)+1)\n267 REM RANDOMIZE SIGN OF FIRST TREND SLOPE (A)\n268 IF RND(X)>.5 THEN 270\n269 LET A=-A\n270 REM RANDOMIZE INITIAL VALUES\n280 GOSUB 830\n285 REM INITIAL PORTFOLIO CONTENTS\n290 FOR I=1 TO 5\n300 LET P(I)=0\n305 LET Z(I)=0\n310 NEXT I\n320 PRINT\n330 PRINT\n333 REM INITIALIZE CASH ASSETS:C\n335 LET C=10000\n338 REM PRINT INITIAL PORTFOLIO\n340 PRINT \"STOCK\",\" \",\"INITIALS\",\"PRICE/SHARE\"\n350 PRINT \"INT. BALLISTIC MISSILES\",\"  IBM\",S(1)\n352 PRINT \"RED CROSS OF AMERICA\",\"  RCA\",S(2)\n354 PRINT \"LICHTENSTEIN, BUMRAP & JOKE\",\"  LBJ\",S(3)\n356 PRINT \"AMERICAN BANKRUPT CO.\",\"  ABC\",S(4)\n358 PRINT \"CENSURED BOOKS STORE\",\"  CBS\",S(5)\n360 PRINT\n361 REM NYSE AVERAGE:Z5; TEMP. VALUE:Z4; NET CHANGE:Z6\n363 LET Z4=Z5\n364 LET Z5=0\n365 LET T=0\n370 FOR I=1 TO 5\n375 LET Z5=Z5+S(I)\n380 LET T=T+S(I)*P(I)\n390 NEXT I\n391 LET Z5=INT(100*(Z5/5)+.5)/100\n392 LET Z6=INT((Z5-Z4)*100+.5)/100\n393 REM TOTAL ASSETS:D\n394 LET D=T+C\n395 IF X9>0 THEN 398\n396 PRINT \"NEW YORK STOCK EXCHANGE AVERAGE: \"Z5\n397 GOTO 399\n398 PRINT \"NEW YORK STOCK EXCHANGE AVERAGE: \"Z5\"NET CHANGE\"Z6\n399 PRINT\n400 LET T=INT(100*T+.5)/100\n401 PRINT \"TOTAL STOCK ASSETS ARE   $\";T\n403 LET C=INT(100*C+.5)/100\n405 PRINT \"TOTAL CASH ASSETS ARE    $\";C\n407 LET D=INT(100*D+.5)/100\n408 PRINT \"TOTAL ASSETS ARE         $\";D\n410 PRINT\n411 IF X9=0 THEN 416\n412 PRINT \"DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)\";\n413 INPUT Q9\n414 IF Q9<1 THEN 998\n416 REM INPUT TRANSACTIONS\n420 PRINT \"WHAT IS YOUR TRANSACTION IN\"\n430 PRINT \"IBM\";\n440 INPUT Z(1)\n450 PRINT \"RCA\";\n460 INPUT Z(2)\n470 PRINT \"LBJ\";\n480 INPUT Z(3)\n490 PRINT \"ABC\";\n500 INPUT Z(4)\n510 PRINT \"CBS\";\n520 INPUT Z(5)\n525 PRINT\n530 REM TOTAL DAY'S PURCHASES IN $:P5\n540 LET P5=0\n550 REM TOTAL DAY'S SALES IN $:S5\n560 LET S5=0\n570 FOR I=1 TO 5\n575 LET Z(I)=INT(Z(I)+.5)\n580 IF Z(I)<=0 THEN 610\n590 LET P5=P5+Z(I)*S(I)\n600 GOTO 620\n610 LET S5=S5-Z(I)*S(I)\n612 IF -Z(I)<=P(I) THEN 620\n614 PRINT \"YOU HAVE OVERSOLD A STOCK; TRY AGAIN.\"\n616 GOTO 420\n620 NEXT I\n622 REM TOTAL VALUE OF TRANSACTIONS:T5\n625 LET T5=P5+S5\n630 REM BROKERAGE FEE:B5\n640 LET B5=INT(.01*T5*100+.5)/100\n650 REM CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES\n652 REM -BROKERAGE FEES+TOTAL SALES:C5\n654 LET C5=C-P5-B5+S5\n656 IF C5>=0 THEN 674\n658 PRINT \"YOU HAVE USED $\"-C5\" MORE THAN YOU HAVE.\"\n660 GOTO 420\n674 LET C=C5\n675 REM CALCULATE NEW PORTFOLIO\n680 FOR I=1 TO 5\n690 LET P(I)=P(I)+Z(I)\n700 NEXT I\n710 REM CALCULATE NEW STOCK VALUES\n720 GOSUB 830\n750 REM PRINT PORTFOLIO\n751 REM BELL RINGING-DIFFERENT ON MANY COMPUTERS\n755 PRINT\n756 PRINT \"**********     END OF DAY'S TRADING     **********\"\n757 PRINT\n758 PRINT\n759 IF X9<1 THEN 769\n769 PRINT \"STOCK\",\"PRICE/SHARE\",\"HOLDINGS\", \"VALUE\", \"NET PRICE CHANGE\"\n770 PRINT \"IBM\", S(1), P(1), S(1)*P(1), C(1)\n771 PRINT \"RCA\", S(2), P(2), S(2)*P(2), C(2)\n772 PRINT \"LBJ\", S(3), P(3), S(3)*P(3), C(3)\n773 PRINT \"ABC\", S(4), P(4), S(4)*P(4), C(4)\n774 PRINT \"CBS\", S(5), P(5), S(5)*P(5), C(5)\n775 LET X9=1\n780 PRINT\n790 PRINT\n810 GOTO 360\n829 REM NEW STOCK VALUES - SUBROUTINE\n830 REM RANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS\n831 REM DAY'S VALUES\n832 REM N1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY\n833 REM DETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK\n834 REM I2 WILL DECREASE 10 PTS.\n840 REM IF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1\n841 IF N1>0 THEN 850\n845 LET I1=INT(4.99*RND(X)+1)\n846 LET N1=INT(4.99*RND(X)+1)\n847 LET E1=1\n850 REM IF N2 DAYS HAVE PASSED, PICK AN I2, SET E2, DETERMINE NEW N2\n851 IF N2>0 THEN 860\n855 LET I2=INT(4.99*RND(X)+1)\n856 LET N2=INT(4.99*RND(X)+1)\n857 LET E2=1\n860 REM DEDUCT ONE DAY FROM N1 AND N2\n861 LET N1=N1-1\n862 LET N2=N2-1\n890 REM LOOP THROUGH ALL STOCKS\n900 FOR I=1 TO 5\n910 LET X1=RND(X)\n915 IF X1>.25 THEN 920\n916 LET X1=.25\n917 GOTO 935\n920 IF X1>.5 THEN 925\n921 LET X1=.5\n922 GOTO 935\n925 IF X1>.75 THEN 930\n926 LET X1=.75\n927 GOTO 935\n930 LET X1=0.0\n931 REM BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)\n935 LET W3=0\n936 IF E1<1 THEN 945\n937 IF INT(I1+.5)<>INT(I+.5) THEN 945\n938 REM ADD 10 PTS. TO THIS STOCK;  RESET E1\n939 LET W3=10\n943 LET E1=0\n945 IF E2<1 THEN 955\n947 IF INT(I2+.5)<>INT(I+.5) THEN 955\n948 REM SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2\n949 LET W3=W3-10\n953 LET E2=0\n954 REM C(I) IS CHANGE IN STOCK VALUE\n955 LET C(I)=INT(A*S(I))+X1+INT(3-6*RND(X)+.5)+W3\n956 LET C(I)=INT(100*C(I)+.5)/100\n957 LET S(I)=S(I)+C(I)\n960 IF S(I)>0 THEN 967\n964 LET C(I)=0\n965 LET S(I)=0\n966 GOTO 970\n967 LET S(I)=INT(100*S(I)+.5)/100\n970 NEXT I\n972 REM AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE\n973 LET T8=T8-1\n974 IF T8<1 THEN 985\n980 RETURN\n985 REM RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION\n986 REM OF TREND (T8)\n990 LET T8=INT(4.99*RND(X)+1)\n992 LET A=INT((RND(X)/10)*100+.5)/100\n993 LET S4=RND(X)\n994 IF S4<=.5 THEN 997\n995 LET A=-A\n997 RETURN\n998 PRINT \"HOPE YOU HAD FUN!!\"\n999 END\n"
  },
  {
    "path": "83_Stock_Market/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "83_Stock_Market/vbnet/StockMarket.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"StockMarket\", \"StockMarket.vbproj\", \"{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "83_Stock_Market/vbnet/StockMarket.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>StockMarket</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "84_Super_Star_Trek/README.md",
    "content": "### Super Star Trek\n\n#### Brief History\nMany versions of Star Trek have been kicking around various college campuses since the late sixties. I recall playing one at Carnegie-Mellon Univ. in 1967 or 68, and a very different one at Berkeley. However, these were a far cry from the one written by Mike Mayfield of Centerline Engineering and/or Custom Data. This was written for an HP2000C and completed in October 1972. It became the “standard” Star Trek in February 1973 when it was put in the HP contributed program library and onto a number of HP Data Center machines.\n\nIn the summer of 1973, I converted the HP version to BASIC-PLUS for DEC’s RSTS-11 compiler and added a few bits and pieces while I was at it. Mary Cole at DEC contributed enormously to this task too. Later that year I published it under the name SPACWR (Space War — in retrospect, an incorrect name) in my book _101 Basic Computer Games_. It is difficult today to find an interactive computer installation that does not have one of these versions of Star Trek available.\n\n#### Quadrant Nomenclature\nRecently, certain critics have professed confusion as to the origin on the “quadrant” nomenclature used on all standard CG (Cartesian Galactic) maps. Naturally, for anyone with the remotest knowledge of history, no explanation is necessary; however, the following synopsis should suffice for the critics:\n\nAs every schoolboy knows, most of the intelligent civilizations in the Milky Way had originated galactic designations of their own choosing well before the Third Magellanic Conference, at which the so-called “2⁶ Agreement” was reached. In that historic document, the participant cultures agreed, in all two-dimensional representations of the galaxy, to specify 64 major subdivisions, ordered as an 8 x 8 matrix. This was partially in deference to the Earth culture (which had done much in the initial organization of the Federation), whose century-old galactic maps had always shown 16 major regions named after celestial landmarks divided into four “quadrants,” designated by ancient “Roman Numerals” (the origin of which has been lost).\n\nTo this day, the official logs of starships originating on near-Earth starbases still refer to the major galactic areas as “quadrants.”\n\nThe relation between the Historical and Standard nomenclatures is shown in the simplified CG map below.\n\n|   | 1            | 2  | 3   | 4  | 5          | 6  | 7   | 8  |\n|---|--------------|----|-----|----|------------|----|-----|----|\n| 1 |    ANTARES   |    |     |    |   SIRIUS   |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 2 |     RIGEL    |    |     |    |    DENEB   |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 3 |    PROCYON   |    |     |    |   CAPELLA  |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 4 | VEGA         |    |     |    | BETELGUESE |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 5 |    CANOPUS   |    |     |    |  ALDEBARA  |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 6 |    ALTAIR    |    |     |    |   REGULUS  |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 7 | SAGITTARIOUS |    |     |    |  ARCTURUS  |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n| 8 |    POLLUX    |    |     |    |    SPICA   |    |     |    |\n|   | I            | II | III | IV | I          | II | III | IV |\n\n#### Super Star Trek† Rules and Notes\n1. OBJECTIVE: You are Captain of the starship “Enterprise”† with a mission to seek and destroy a fleet of Klingon† warships (usually about 17) which are menacing the United Federation of Planets.† You have a specified number of stardates in which to complete your mission. You also have two or three Federation Starbases† for resupplying your ship.\n\n2. You will be assigned a starting position somewhere in the galaxy. The galaxy is divided into an 8 x 8 quadrant grid. The astronomical name of a quadrant is called out upon entry into a new region. (See “Quadrant Nomenclature.”) Each quadrant is further divided into an 8 x 8 section grid.\n\n3. On a section diagram, the following symbols are used:\n    - `<*>` Enterprise\n    - `†††` Klingon\n    - `>!<` Starbase\n    - `*`   Star\n\n4. You have eight commands available to you (A detailed description of each command is given in the program instructions.)\n    - `NAV` Navigate the Starship by setting course and warp engine speed.\n    - `SRS` Short-range sensor scan (one quadrant)\n    - `LRS` Long-range sensor scan (9 quadrants)\n    - `PHA` Phaser† control (energy gun)\n    - `TOR` Photon torpedo control\n    - `SHE` Shield control (protects against phaser fire)\n    - `DAM` Damage and state-of-repair report\n    - `COM` Call library computer\n\n5. Library computer options are as follows (more complete descriptions are in program instructions):\n    - `0` Cumulative galactic report\n    - `1` Status report\n    - `2` Photon torpedo course data\n    - `3` Starbase navigation data\n    - `4` Direction/distance calculator\n    - `5` Quadrant nomenclature map\n\n6. Certain reports on the ship’s status are made by officers of the Enterprise who appears on the original TV Show—Spock,† Scott,† Uhura,† Chekov,† etc.\n\n7. Klingons are non-stationary within their quadrants. If you try to maneuver on them, they will move and fire on you.\n\n8. Firing and damage notes:\n    - Phaser fire diminishes with increased distance between combatants.\n    - If a Klingon zaps you hard enough (relative to your shield strength) he will generally cause damage to some part of your ship with an appropriate “Damage Control” report resulting.\n    - If you don’t zap a Klingon hard enough (relative to his shield strength) you won’t damage him at all. Your sensors will tell the story.\n    - Damage control will let you know when out-of-commission devices have been completely repaired.\n\n9. Your engines will automatically shut down if you should attempt to leave the galaxy, or if you should try to maneuver through a star, or Starbase, or—heaven help you—a Klingon warship.\n\n10. In a pinch, or if you should miscalculate slightly, some shield control energy will be automatically diverted to warp engine control (if your shield are operational!).\n\n11. While you’re docked at a Starbase, a team of technicians can repair your ship (if you’re willing for them to spend the time required—and the repairmen _always_ underestimate…)\n\n12. If, to same maneuvering time toward the end of the game, you should cold-bloodedly destroy a Starbase, you get a nasty note from Starfleet Command. If you destroy your _last_ Starbase, you lose the game! (For those who think this is too a harsh penalty, delete line 5360-5390, and you’ll just get a “you dumdum!”-type message on all future status reports.)\n\n13. End game logic has been “cleaned up” in several spots, and it is possible to get a new command after successfully completing your mission (or, after resigning your old one).\n\n14. For those of you with certain types of CRT/keyboards setups (e.g. Westinghouse 1600), a “bell” character is inserted at appropriate spots to cause the following items to flash on and off on the screen:\n    - The Phrase “\\*RED\\*” (as in Condition: Red)\n    - The character representing your present quadrant in the cumulative galactic record printout.\n\n15. This version of Star Trek was created for a Data General Nova 800 system with 32K or core. So that it would fit, the instructions are separated from the main program via a CHAIN. For conversion to DEC BASIC-PLUS, Statement 160 (Randomize) should be moved after the return from the chained instructions, say to Statement 245. For Altair BASIC, Randomize and the chain instructions should be eliminated.\n\n† Designates trademark of Paramount Pictures Corporation. Used by permission of Paramount Pictures Corporation.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=157)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=172)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\nInstructions in this directory at\ninstructions.txt\n\n#### Porting Notes\n\nMany of the programs in this book and this collection have bugs in the original code.\n\n@jkboyce has done a great job of discovering and fixing a number of bugs in the [original code](superstartrek.bas), as part of his [python implementation](python/superstartrek.py), which should be noted by other implementers:\n\n- line `4410` : `D(7)` should be `D(6)`\n- lines `8310`,`8330`,`8430`,`8450` : Division by zero is possible\n- line `440` : `B9` should be initialised to 0, not 2\n\n#### External Links\n - C++: https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Commands/Command.cs",
    "content": "using System.ComponentModel;\n\nnamespace SuperStarTrek.Commands;\n\ninternal enum Command\n{\n    [Description(\"To set course\")]\n    NAV,\n\n    [Description(\"For short range sensor scan\")]\n    SRS,\n\n    [Description(\"For long range sensor scan\")]\n    LRS,\n\n    [Description(\"To fire phasers\")]\n    PHA,\n\n    [Description(\"To fire photon torpedoes\")]\n    TOR,\n\n    [Description(\"To raise or lower shields\")]\n    SHE,\n\n    [Description(\"For damage control reports\")]\n    DAM,\n\n    [Description(\"To call on library-computer\")]\n    COM,\n\n    [Description(\"To resign your command\")]\n    XXX\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Commands/CommandExtensions.cs",
    "content": "using System.Reflection;\nusing System.ComponentModel;\n\nnamespace SuperStarTrek.Commands;\n\ninternal static class CommandExtensions\n{\n    internal static string GetDescription(this Command command) =>\n        typeof(Command)\n            .GetField(command.ToString())\n            .GetCustomAttribute<DescriptionAttribute>()\n            .Description;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Commands/CommandResult.cs",
    "content": "namespace SuperStarTrek.Commands;\n\ninternal class CommandResult\n{\n    public static readonly CommandResult Ok = new(false);\n    public static readonly CommandResult GameOver = new(true);\n\n    private CommandResult(bool isGameOver)\n    {\n        IsGameOver = isGameOver;\n    }\n\n    private CommandResult(float timeElapsed)\n    {\n        TimeElapsed = timeElapsed;\n    }\n\n    public bool IsGameOver { get; }\n    public float TimeElapsed { get; }\n\n    public static CommandResult Elapsed(float timeElapsed) => new(timeElapsed);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Game.cs",
    "content": "using System;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\nusing SuperStarTrek.Systems;\nusing SuperStarTrek.Systems.ComputerFunctions;\n\nnamespace SuperStarTrek;\n\ninternal class Game\n{\n    private readonly TextIO _io;\n    private readonly IRandom _random;\n\n    private int _initialStardate;\n    private int _finalStarDate;\n    private float _currentStardate;\n    private Coordinates _currentQuadrant;\n    private Galaxy _galaxy;\n    private int _initialKlingonCount;\n    private Enterprise _enterprise;\n\n    internal Game(TextIO io, IRandom random)\n    {\n        _io = io;\n        _random = random;\n    }\n\n    internal float Stardate => _currentStardate;\n\n    internal float StardatesRemaining => _finalStarDate - _currentStardate;\n\n    internal void DoIntroduction()\n    {\n        _io.Write(Strings.Title);\n\n        if (_io.GetYesNo(\"Do you need instructions\", IReadWriteExtensions.YesNoMode.FalseOnN))\n        {\n            _io.Write(Strings.Instructions);\n\n            _io.WaitForAnyKeyButEnter(\"to continue\");\n        }\n    }\n\n    internal void Play()\n    {\n        Initialise();\n        var gameOver = false;\n\n        while (!gameOver)\n        {\n            var command = _io.ReadCommand();\n\n            var result = _enterprise.Execute(command);\n\n            gameOver = result.IsGameOver || CheckIfStranded();\n            _currentStardate += result.TimeElapsed;\n            gameOver |= _currentStardate > _finalStarDate;\n        }\n\n        if (_galaxy.KlingonCount > 0)\n        {\n            _io.Write(Strings.EndOfMission, _currentStardate, _galaxy.KlingonCount);\n        }\n        else\n        {\n            _io.Write(Strings.Congratulations, CalculateEfficiency());\n        }\n    }\n\n    private void Initialise()\n    {\n        _currentStardate = _initialStardate = _random.Next(20, 40) * 100;\n        _finalStarDate = _initialStardate + _random.Next(25, 35);\n\n        _currentQuadrant = _random.NextCoordinate();\n\n        _galaxy = new Galaxy(_random);\n        _initialKlingonCount = _galaxy.KlingonCount;\n\n        _enterprise = new Enterprise(3000, _random.NextCoordinate(), _io, _random);\n        _enterprise\n            .Add(new WarpEngines(_enterprise, _io))\n            .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _io))\n            .Add(new LongRangeSensors(_galaxy, _io))\n            .Add(new PhaserControl(_enterprise, _io, _random))\n            .Add(new PhotonTubes(10, _enterprise, _io))\n            .Add(new ShieldControl(_enterprise, _io))\n            .Add(new DamageControl(_enterprise, _io))\n            .Add(new LibraryComputer(\n                _io,\n                new CumulativeGalacticRecord(_io, _galaxy),\n                new StatusReport(this, _galaxy, _enterprise, _io),\n                new TorpedoDataCalculator(_enterprise, _io),\n                new StarbaseDataCalculator(_enterprise, _io),\n                new DirectionDistanceCalculator(_enterprise, _io),\n                new GalaxyRegionMap(_io, _galaxy)));\n\n        _io.Write(Strings.Enterprise);\n        _io.Write(\n            Strings.Orders,\n            _galaxy.KlingonCount,\n            _finalStarDate,\n            _finalStarDate - _initialStardate,\n            _galaxy.StarbaseCount > 1 ? \"are\" : \"is\",\n            _galaxy.StarbaseCount,\n            _galaxy.StarbaseCount > 1 ? \"s\" : \"\");\n\n        _io.WaitForAnyKeyButEnter(\"when ready to accept command\");\n\n        _enterprise.StartIn(BuildCurrentQuadrant());\n    }\n\n    private Quadrant BuildCurrentQuadrant() => new(_galaxy[_currentQuadrant], _enterprise, _random, _galaxy, _io);\n\n    internal bool Replay() => _galaxy.StarbaseCount > 0 && _io.ReadExpectedString(Strings.ReplayPrompt, \"Aye\");\n\n    private bool CheckIfStranded()\n    {\n        if (_enterprise.IsStranded) { _io.Write(Strings.Stranded); }\n        return _enterprise.IsStranded;\n    }\n\n    private float CalculateEfficiency() =>\n        1000 * (float)Math.Pow(_initialKlingonCount / (_currentStardate - _initialStardate), 2);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/IRandomExtensions.cs",
    "content": "using Games.Common.Randomness;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek;\n\ninternal static class IRandomExtensions\n{\n    internal static Coordinates NextCoordinate(this IRandom random) =>\n        new Coordinates(random.Next1To8Inclusive() - 1, random.Next1To8Inclusive() - 1);\n\n    // Duplicates the algorithm used in the original code to get an integer value from 1 to 8, inclusive:\n    //     475 DEF FNR(R)=INT(RND(R)*7.98+1.01)\n    // Returns a value from 1 to 8, inclusive.\n    // Note there's a slight bias away from the extreme values, 1 and 8.\n    internal static int Next1To8Inclusive(this IRandom random) => (int)(random.NextFloat() * 7.98 + 1.01);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/IReadWriteExtensions.cs",
    "content": "using System;\nusing System.Linq;\nusing Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Space;\nusing static System.StringComparison;\n\nnamespace SuperStarTrek;\n\ninternal static class IReadWriteExtensions\n{\n    internal static void WaitForAnyKeyButEnter(this IReadWrite io, string prompt)\n    {\n        io.Write($\"Hit any key but Enter {prompt} \");\n        while (io.ReadCharacter() == '\\r');\n    }\n\n    internal static (float X, float Y) GetCoordinates(this IReadWrite io, string prompt) =>\n        io.Read2Numbers($\"{prompt} (X,Y)\");\n\n    internal static bool TryReadNumberInRange(\n        this IReadWrite io,\n        string prompt,\n        float minValue,\n        float maxValue,\n        out float value)\n    {\n        value = io.ReadNumber($\"{prompt} ({minValue}-{maxValue})\");\n\n        return value >= minValue && value <= maxValue;\n    }\n\n    internal static bool ReadExpectedString(this IReadWrite io, string prompt, string trueValue) =>\n        io.ReadString(prompt).Equals(trueValue, InvariantCultureIgnoreCase);\n\n    internal static Command ReadCommand(this IReadWrite io)\n    {\n        while(true)\n        {\n            var response = io.ReadString(\"Command\");\n\n            if (response.Length >= 3 &&\n                Enum.TryParse(response.Substring(0, 3), ignoreCase: true, out Command parsedCommand))\n            {\n                return parsedCommand;\n            }\n\n            io.WriteLine(\"Enter one of the following:\");\n            foreach (var command in Enum.GetValues(typeof(Command)).OfType<Command>())\n            {\n                io.WriteLine($\"  {command}  ({command.GetDescription()})\");\n            }\n            io.WriteLine();\n        }\n    }\n\n    internal static bool TryReadCourse(this IReadWrite io, string prompt, string officer, out Course course)\n    {\n        if (!io.TryReadNumberInRange(prompt, 1, 9, out var direction))\n        {\n            io.WriteLine($\"{officer} reports, 'Incorrect course data, sir!'\");\n            course = default;\n            return false;\n        }\n\n        course = new Course(direction);\n        return true;\n    }\n\n    internal static bool GetYesNo(this IReadWrite io, string prompt, YesNoMode mode)\n    {\n        var response = io.ReadString($\"{prompt} (Y/N)\").ToUpperInvariant();\n\n        return (mode, response) switch\n        {\n            (YesNoMode.FalseOnN, \"N\") => false,\n            (YesNoMode.FalseOnN, _) => true,\n            (YesNoMode.TrueOnY, \"Y\") => true,\n            (YesNoMode.TrueOnY, _) => false,\n            _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, \"Invalid value\")\n        };\n    }\n\n    internal enum YesNoMode\n    {\n        TrueOnY,\n        FalseOnN\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Objects/Enterprise.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\nusing SuperStarTrek.Systems;\n\nnamespace SuperStarTrek.Objects;\n\ninternal class Enterprise\n{\n    private readonly int _maxEnergy;\n    private readonly IReadWrite _io;\n    private readonly List<Subsystem> _systems;\n    private readonly Dictionary<Command, Subsystem> _commandExecutors;\n    private readonly IRandom _random;\n    private Quadrant _quadrant;\n\n    public Enterprise(int maxEnergy, Coordinates sector, IReadWrite io, IRandom random)\n    {\n        SectorCoordinates = sector;\n        TotalEnergy = _maxEnergy = maxEnergy;\n\n        _systems = new List<Subsystem>();\n        _commandExecutors = new Dictionary<Command, Subsystem>();\n        _io = io;\n        _random = random;\n    }\n\n    internal Quadrant Quadrant => _quadrant;\n\n    internal Coordinates QuadrantCoordinates => _quadrant.Coordinates;\n\n    internal Coordinates SectorCoordinates { get; private set; }\n\n    internal string Condition => GetCondition();\n\n    internal LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM];\n\n    internal ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE];\n\n    internal float Energy => TotalEnergy - ShieldControl.ShieldEnergy;\n\n    internal float TotalEnergy { get; private set; }\n\n    internal int DamagedSystemCount => _systems.Count(s => s.IsDamaged);\n\n    internal IEnumerable<Subsystem> Systems => _systems;\n\n    internal PhotonTubes PhotonTubes => (PhotonTubes)_commandExecutors[Command.TOR];\n\n    internal bool IsDocked => _quadrant.EnterpriseIsNextToStarbase;\n\n    internal bool IsStranded => TotalEnergy < 10 || Energy < 10 && ShieldControl.IsDamaged;\n\n    internal Enterprise Add(Subsystem system)\n    {\n        _systems.Add(system);\n        _commandExecutors[system.Command] = system;\n\n        return this;\n    }\n\n    internal void StartIn(Quadrant quadrant)\n    {\n        _quadrant = quadrant;\n        quadrant.Display(Strings.StartText);\n    }\n\n    private string GetCondition() =>\n        IsDocked switch\n        {\n            true => \"Docked\",\n            false when _quadrant.HasKlingons => \"*Red*\",\n            false when Energy / _maxEnergy < 0.1f => \"Yellow\",\n            false => \"Green\"\n        };\n\n    internal CommandResult Execute(Command command)\n    {\n        if (command == Command.XXX) { return CommandResult.GameOver; }\n\n        return _commandExecutors[command].ExecuteCommand(_quadrant);\n    }\n\n    internal void Refuel() => TotalEnergy = _maxEnergy;\n\n    public override string ToString() => \"<*>\";\n\n    internal void UseEnergy(float amountUsed)\n    {\n        TotalEnergy -= amountUsed;\n    }\n\n    internal CommandResult TakeHit(Coordinates sector, int hitStrength)\n    {\n        _io.WriteLine($\"{hitStrength} unit hit on Enterprise from sector {sector}\");\n        ShieldControl.AbsorbHit(hitStrength);\n\n        if (ShieldControl.ShieldEnergy <= 0)\n        {\n            _io.WriteLine(Strings.Destroyed);\n            return CommandResult.GameOver;\n        }\n\n        _io.WriteLine($\"      <Shields down to {ShieldControl.ShieldEnergy} units>\");\n\n        if (hitStrength >= 20)\n        {\n            TakeDamage(hitStrength);\n        }\n\n        return CommandResult.Ok;\n    }\n\n    private void TakeDamage(float hitStrength)\n    {\n        var hitShieldRatio = hitStrength / ShieldControl.ShieldEnergy;\n        if (_random.NextFloat() > 0.6 || hitShieldRatio <= 0.02f)\n        {\n            return;\n        }\n\n        var system = _systems[_random.Next1To8Inclusive() - 1];\n        system.TakeDamage(hitShieldRatio + 0.5f * _random.NextFloat());\n        _io.WriteLine($\"Damage Control reports, '{system.Name} damaged by the hit.'\");\n    }\n\n    internal void RepairSystems(float repairWorkDone)\n    {\n        var repairedSystems = new List<string>();\n\n        foreach (var system in _systems.Where(s => s.IsDamaged))\n        {\n            if (system.Repair(repairWorkDone))\n            {\n                repairedSystems.Add(system.Name);\n            }\n        }\n\n        if (repairedSystems.Any())\n        {\n            _io.WriteLine(\"Damage Control report:\");\n            foreach (var systemName in repairedSystems)\n            {\n                _io.WriteLine($\"        {systemName} repair completed.\");\n            }\n        }\n    }\n\n    internal void VaryConditionOfRandomSystem()\n    {\n        if (_random.NextFloat() > 0.2f) { return; }\n\n        var system = _systems[_random.Next1To8Inclusive() - 1];\n        _io.Write($\"Damage Control report:  {system.Name} \");\n        if (_random.NextFloat() >= 0.6)\n        {\n            system.Repair(_random.NextFloat() * 3 + 1);\n            _io.WriteLine(\"state of repair improved\");\n        }\n        else\n        {\n            system.TakeDamage(_random.NextFloat() * 5 + 1);\n            _io.WriteLine(\"damaged\");\n        }\n    }\n\n    internal float Move(Course course, float warpFactor, int distance)\n    {\n        var (quadrant, sector) = MoveWithinQuadrant(course, distance) ?? MoveBeyondQuadrant(course, distance);\n\n        if (quadrant != _quadrant.Coordinates)\n        {\n            _quadrant = new Quadrant(_quadrant.Galaxy[quadrant], this, _random, _quadrant.Galaxy, _io);\n        }\n        _quadrant.SetEnterpriseSector(sector);\n        SectorCoordinates = sector;\n\n        TotalEnergy -= distance + 10;\n        if (Energy < 0)\n        {\n            _io.WriteLine(\"Shield Control supplies energy to complete the maneuver.\");\n            ShieldControl.ShieldEnergy = Math.Max(0, TotalEnergy);\n        }\n\n        return GetTimeElapsed(quadrant, warpFactor);\n    }\n\n    private (Coordinates, Coordinates)? MoveWithinQuadrant(Course course, int distance)\n    {\n        var currentSector = SectorCoordinates;\n        foreach (var (sector, index) in course.GetSectorsFrom(SectorCoordinates).Select((s, i) => (s, i)))\n        {\n            if (distance == 0) { break; }\n\n            if (_quadrant.HasObjectAt(sector))\n            {\n                _io.WriteLine($\"Warp engines shut down at sector {currentSector} dues to bad navigation\");\n                distance = 0;\n                break;\n            }\n\n            currentSector = sector;\n            distance -= 1;\n        }\n\n        return distance == 0 ? (_quadrant.Coordinates, currentSector) : null;\n    }\n\n    private (Coordinates, Coordinates) MoveBeyondQuadrant(Course course, int distance)\n    {\n        var (complete, quadrant, sector) = course.GetDestination(QuadrantCoordinates, SectorCoordinates, distance);\n\n        if (!complete)\n        {\n            _io.Write(Strings.PermissionDenied, sector, quadrant);\n        }\n\n        return (quadrant, sector);\n    }\n\n    private float GetTimeElapsed(Coordinates finalQuadrant, float warpFactor) =>\n        finalQuadrant == _quadrant.Coordinates\n            ? Math.Min(1, (float)Math.Round(warpFactor, 1, MidpointRounding.ToZero))\n            : 1;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Objects/Klingon.cs",
    "content": "using Games.Common.Randomness;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Objects;\n\ninternal class Klingon\n{\n    private readonly IRandom _random;\n\n    internal Klingon(Coordinates sector, IRandom random)\n    {\n        Sector = sector;\n        _random = random;\n        Energy = _random.NextFloat(100, 300);\n    }\n\n    internal float Energy { get; private set; }\n\n    internal Coordinates Sector { get; private set; }\n\n    public override string ToString() => \"+K+\";\n\n    internal CommandResult FireOn(Enterprise enterprise)\n    {\n        var attackStrength = _random.NextFloat();\n        var distanceToEnterprise = Sector.GetDistanceTo(enterprise.SectorCoordinates);\n        var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise);\n        Energy /= 3 + attackStrength;\n\n        return enterprise.TakeHit(Sector, hitStrength);\n    }\n\n    internal bool TakeHit(int hitStrength)\n    {\n        if (hitStrength < 0.15 * Energy) { return false; }\n\n        Energy -= hitStrength;\n        return true;\n    }\n\n    internal void MoveTo(Coordinates newSector) => Sector = newSector;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Objects/Star.cs",
    "content": "namespace SuperStarTrek.Objects;\n\ninternal class Star\n{\n    public override string ToString() => \" * \";\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Objects/Starbase.cs",
    "content": "using Games.Common.IO;\nusing Games.Common.Randomness;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Objects;\n\ninternal class Starbase\n{\n    private readonly IReadWrite _io;\n    private readonly float _repairDelay;\n\n    internal Starbase(Coordinates sector, IRandom random, IReadWrite io)\n    {\n        Sector = sector;\n        _repairDelay = random.NextFloat(0.5f);\n        _io = io;\n    }\n\n    internal Coordinates Sector { get; }\n\n    public override string ToString() => \">!<\";\n\n    internal bool TryRepair(Enterprise enterprise, out float repairTime)\n    {\n        repairTime = enterprise.DamagedSystemCount * 0.1f + _repairDelay;\n        if (repairTime >= 1) { repairTime = 0.9f; }\n\n        _io.Write(Strings.RepairEstimate, repairTime);\n        if (_io.GetYesNo(Strings.RepairPrompt, IReadWriteExtensions.YesNoMode.TrueOnY))\n        {\n            foreach (var system in enterprise.Systems)\n            {\n                system.Repair();\n            }\n            return true;\n        }\n\n        repairTime = 0;\n        return false;\n    }\n\n    internal void ProtectEnterprise() => _io.WriteLine(Strings.Protected);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Program.cs",
    "content": "﻿// SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY\n//\n// ****         **** STAR TREK ****        ****\n// ****  SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n// ****  AS SEEN ON THE STAR TREK TV SHOW.\n// ****  ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n// ****  PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n// ****  MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n// ****  LEEDOM - APRIL & DECEMBER 1974,\n// ****  WITH A LITTLE HELP FROM HIS FRIENDS . . .\n// ****  COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --\n// ****  SEND TO:  R. C. LEEDOM\n// ****            WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.\n// ****            BOX 746, M.S. 338\n// ****            BALTIMORE, MD  21203\n// ****\n// ****  CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS\n// ****  LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS\n// ****  MUCH AS POSSIBLE WHILE USING MULTIPLE STATEMENTS PER LINE\n// ****  SOME LINES ARE LONGER THAN 72 CHARACTERS; THIS WAS DONE\n// ****  BY USING \"?\" INSTEAD OF \"PRINT\" WHEN ENTERING LINES\n// ****\n// ****  CONVERTED TO MICROSOFT C# 2/20/21 BY ANDREW COOPER\n// ****\n\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing SuperStarTrek;\n\nvar io = new ConsoleIO();\nvar random = new RandomNumberGenerator();\n\nvar game = new Game(io, random);\n\ngame.DoIntroduction();\n\ndo\n{\n    game.Play();\n} while (game.Replay());\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/CombatArea.txt",
    "content": "COMBAT AREA      CONDITION RED\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Congratulations.txt",
    "content": "Congratulations, Captain!  The last Klingon battle cruiser\nmenacing the Federation has been destroyed.\n\nYour efficiency rating is {0}.\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/CourtMartial.txt",
    "content": "\nStarfleet Command reviewing your record to consider\ncourt martial!"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Destroyed.txt",
    "content": "The Enterprise has been destroyed.  The Federation will be conquered.\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/EndOfMission.txt",
    "content": "Is is stardate {0}.\nThere were {1} Klingon battle cruisers left at\nthe end of your mission.\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Enterprise.txt",
    "content": "\n\n\n\n\n\n\n\n\n\n\n                                    ,------*------,\n                    ,-------------   '---  ------'\n                     '-------- --'      / /\n                         ,---' '-------/ /--,\n                          '----------------'\n\n                    THE USS ENTERPRISE --- NCC-1701\n\n\n\n\n\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Instructions.txt",
    "content": "\n      INSTRUCTIONS FOR 'SUPER STAR TREK'\n\n1. When you see \"Command ?\" printed, enter one of the legal\n     commands (NAV, SRS, LRS, PHA, TOR, SHE, DAM, COM, OR XXX).\n2. If you should type in an illegal command, you'll get a short\n     list of the legal commands printed out.\n3. Some commands require you to enter data (for example, the\n     'NAV' command comes back with 'Course (1-9) ?'.)  If you\n     type in illegal data (like negative numbers), then command\n     will be aborted.\n\n     The galaxy is divided into an 8 X 8 quadrant grid,\nand each quadrant is further divided into an 8 X 8 sector grid.\n\n     You will be assigned a starting point somewhere in the\ngalaxy to begin a tour of duty as commander of the starship\nEnterprise; your mission: to seek and destroy the fleet of\nKlingon warships which are menacing the United Federation of\nPlanets.\n\n     You have the following commands available to you as captain\nof the starship Enterprise:\n\nNAV command = Warp Engine Control\n     Course is in a circular numerical      4  3  2\n     vector arrangement as shown             . . .\n     integer and real values may be           ...\n     used.  (Thus course 1.5 is half-     5 ---*--- 1\n     way between 1 and 2.                     ...\n                                             . . .\n     Values may approach 9.0, which         6  7  8\n     itself is equivalent to 1.0\n                                            COURSE\n     One warp factor is the size of\n     one quadrant.  Therefore, to get\n     from quadrant 6,5 to 5,5, you WOULD\n     use course 3, warp factor 1.\n\nSRS command = Short Range Sensor Scan\n     Shows you a scan of your present quadrant.\n\n     Symbology on your sensor screen is as follows:\n        <*> = Your starship's position\n        +K+ = Klingon battle cruiser\n        >!< = Federation starbase (refuel/repair/re-arm here!)\n         *  = Star\n\n     A condensed 'status report' will also be presented.\n\nLRS command = Long Range Sensor Scan\n     Shows conditions in space for one quadrant on each side\n     of the Enterprise (which is in the middle of the scan).\n     The scan is coded in the form ###, where the units digit\n     is the number of stars, the tens digit is the number of\n     starbases, and the hundreds digit is the number of\n     Klingons.\n\n     Example - 207 = 2 Klingons, No starbases, & 7 stars.\n\nPHA command = Phaser Control\n     Allows you to destroy the Klingon battle cruisers by\n     zapping them with suitably large units of energy to\n     deplete their shield power.  (Remember, Klingons have\n     phasers, too!)\n\nTOR command = Photon Torpedo Control\n     Torpedo course is the same as used in warp engine control.\n     If you hit the Klingon vessel, he is destroyed and\n     cannot fire back at you.  If you miss, you are subject to\n     his phaser fire.  In either case, you are also subject to\n     the phaser fire of all other Klingons in the quadrant.\n\n     The library-computer (COM command) has an option to\n     compute torpedo trajectory for you (Option 2).\n\nSHE command = Shield Control\n     Defines the number of energy units to be assigned to the\n     shields.  Energy is taken from total ship's energy.  Note\n     that the status display total energy includes shield energy.\n\nDAM command = Damage Control Report\n     Gives the state of repair of all devices.  Where a negative\n     'state of repair' shows that the device is temporarily\n     damaged.\n\nCOM command = Library-Computer\n     The library-computer contains six options:\n     Option 0 = Cumulative Galactic Record\n        This option shows computer memory of the results of all\n        previous short and long range sensor scans.\n     Option 1 = Status Report\n        This option shows the number of Klingons, Stardates,\n        and starbases remaining in the game.\n     Option 2 = Photon Torpedo Data\n        Which gives directions and distance from the Enterprise\n        to all Klingons in your quadrant.\n     Option 3 = Starbase Nav Data\n        This option gives direction and distance to any\n        starbase within your quadrant.\n     Option 4 = Direction/Distance Calculator\n        This option allows you to enter coordinates for\n        direction/distance calculations.\n     Option 5 = Galactic Region Name Map\n        This option prints the names of the sixteen major\n        galactic regions referred to in the game.\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/LowShields.txt",
    "content": "   SHIELDS DANGEROUSLY LOW\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/NoEnemyShips.txt",
    "content": "Science Officer Spock reports, 'Sensors show no enemy ships\n                                in this quadrant'"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/NoStarbase.txt",
    "content": "Mr. Spock reports, 'Sensors show no starbases in this quadrant.'"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/NowEntering.txt",
    "content": "\nNow entering {0} quadrant . . .\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Orders.txt",
    "content": "Your orders are as follows:\n    Destroy the {0} Klingon warships which have invaded\n  the galaxy before they can attack federation headquarters\n  on stardate {1}. This gives you {2} days. There {3}\n  {4} starbase{5} in the galaxy for resupplying your ship.\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/PermissionDenied.txt",
    "content": "Lt. Uhura report message from Starfleet Command:\n  'Permission to attempt crossing of galactic perimeter\n  is hereby *Denied*. Shut down your engines.'\nChief Engineer Scott reports, 'Warp engines shut down\n  at sector {0} of quadrant {1}.'\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Protected.txt",
    "content": "Starbase shields protect the Enterprise"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/RegionNames.txt",
    "content": "      Antares                  Sirius\n       Rigel                   Deneb\n      Procyon                 Capella\n        Vega                 Betelgeuse\n      Canopus                Aldebaran\n       Altair                 Regulus\n    Sagittarius               Arcturus\n       Pollux                  Spica"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/RelievedOfCommand.txt",
    "content": "\nThat does it, Captain!!  You are hereby relieved of command\nand sentenced to 99 stardates at hard labor on Cygnus 12!!"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/RepairEstimate.txt",
    "content": "Technicians standing by to effect repairs to your ship;\nEstimated time to repair: {0} stardates.\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/RepairPrompt.txt",
    "content": "Will you authorize the repair order (Y/N)"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/ReplayPrompt.txt",
    "content": "\n\nThe Federation is in need of a new starship commander\nfor a similar mission -- if there is a volunteer\nlet him step forward and enter 'Aye'"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/ShieldsDropped.txt",
    "content": "Shields dropped for docking purposes"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/ShieldsSet.txt",
    "content": "Deflector control room report:\n  'Shields now at {0} units per your command.'\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/ShortRangeSensorsOut.txt",
    "content": "*** Short Range Sensors are out ***\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/StartText.txt",
    "content": "\n\nYour mission begins with your starship located\nin the galactic quadrant, '{0}'.\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Stranded.txt",
    "content": "** FATAL ERROR **   You've just stranded your ship in space\nYou have insufficient maneuvering energy, and shield control\nis presently incapable of cross-circuiting to engine room!!\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Strings.cs",
    "content": "﻿using System.IO;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace SuperStarTrek.Resources\n{\n    internal static class Strings\n    {\n        internal static string CombatArea => GetResource();\n\n        internal static string Congratulations => GetResource();\n\n        internal static string CourtMartial => GetResource();\n\n        internal static string Destroyed => GetResource();\n\n        internal static string EndOfMission => GetResource();\n\n        internal static string Enterprise => GetResource();\n\n        internal static string Instructions => GetResource();\n\n        internal static string LowShields => GetResource();\n\n        internal static string NoEnemyShips => GetResource();\n\n        internal static string NoStarbase => GetResource();\n\n        internal static string NowEntering => GetResource();\n\n        internal static string Orders => GetResource();\n\n        internal static string PermissionDenied => GetResource();\n\n        internal static string Protected => GetResource();\n\n        internal static string RegionNames => GetResource();\n\n        internal static string RelievedOfCommand => GetResource();\n\n        internal static string RepairEstimate => GetResource();\n\n        internal static string RepairPrompt => GetResource();\n\n        internal static string ReplayPrompt => GetResource();\n\n        internal static string ShieldsDropped => GetResource();\n\n        internal static string ShieldsSet => GetResource();\n\n        internal static string ShortRangeSensorsOut => GetResource();\n\n        internal static string StartText => GetResource();\n\n        internal static string Stranded => GetResource();\n\n        internal static string Title => GetResource();\n\n        private static string GetResource([CallerMemberName] string name = \"\")\n        {\n            var streamName = $\"SuperStarTrek.Resources.{name}.txt\";\n            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(streamName);\n            using var reader = new StreamReader(stream);\n\n            return reader.ReadToEnd();\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Resources/Title.txt",
    "content": "\n\n\n\n\n\n\n\n\n\n\n\n          *************************************\n          *                                   *\n          *                                   *\n          *      * * SUPER STAR TREK * *      *\n          *                                   *\n          *                                   *\n          *************************************\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Space/Coordinates.cs",
    "content": "using System;\nusing SuperStarTrek.Utils;\n\nnamespace SuperStarTrek.Space;\n\n// Represents the corrdintate of a quadrant in the galaxy, or a sector in a quadrant.\n// Note that the origin is top-left, x increase downwards, and y increases to the right.\ninternal record Coordinates\n{\n    internal Coordinates(int x, int y)\n    {\n        X = Validated(x, nameof(x));\n        Y = Validated(y, nameof(y));\n\n        RegionIndex = (X << 1) + (Y >> 2);\n        SubRegionIndex = Y % 4;\n    }\n\n    internal int X { get; }\n\n    internal int Y { get; }\n\n    internal int RegionIndex { get; }\n\n    internal int SubRegionIndex { get; }\n\n    private static int Validated(int value, string argumentName)\n    {\n        if (value >= 0 && value <= 7) { return value; }\n\n        throw new ArgumentOutOfRangeException(argumentName, value, \"Must be 0 to 7 inclusive\");\n    }\n\n    private static bool IsValid(int value) => value >= 0 && value <= 7;\n\n    public override string ToString() => $\"{X+1} , {Y+1}\";\n\n    internal void Deconstruct(out int x, out int y)\n    {\n        x = X;\n        y = Y;\n    }\n\n    internal static bool TryCreate(float x, float y, out Coordinates coordinates)\n    {\n        var roundedX = Round(x);\n        var roundedY = Round(y);\n\n        if (IsValid(roundedX) && IsValid(roundedY))\n        {\n            coordinates = new Coordinates(roundedX, roundedY);\n            return true;\n        }\n\n        coordinates = default;\n        return false;\n\n        static int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero);\n    }\n\n    internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) =>\n        DirectionAndDistance.From(this).To(destination);\n\n    internal float GetDistanceTo(Coordinates destination)\n    {\n        var (_, distance) = GetDirectionAndDistanceTo(destination);\n        return distance;\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Space/Course.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace SuperStarTrek.Space;\n\n// Implements the course calculations from the original code:\n//     530 FORI=1TO9:C(I,1)=0:C(I,2)=0:NEXTI\n//     540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1\n//     600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1\n//\n//     3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1))\n//     3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1))\ninternal class Course\n{\n    private static readonly (int DeltaX, int DeltaY)[] cardinals = new[]\n    {\n        (0, 1),\n        (-1, 1),\n        (-1, 0),\n        (-1, -1),\n        (0, -1),\n        (1, -1),\n        (1, 0),\n        (1, 1),\n        (0, 1)\n    };\n\n    internal Course(float direction)\n    {\n        if (direction < 1 || direction > 9)\n        {\n            throw new ArgumentOutOfRangeException(\n                nameof(direction),\n                direction,\n                \"Must be between 1 and 9, inclusive.\");\n        }\n\n        var cardinalDirection = (int)(direction - 1) % 8;\n        var fractionalDirection = direction - (int)direction;\n\n        var baseCardinal = cardinals[cardinalDirection];\n        var nextCardinal = cardinals[cardinalDirection + 1];\n\n        DeltaX = baseCardinal.DeltaX + (nextCardinal.DeltaX - baseCardinal.DeltaX) * fractionalDirection;\n        DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection;\n    }\n\n    internal float DeltaX { get; }\n\n    internal float DeltaY { get; }\n\n    internal IEnumerable<Coordinates> GetSectorsFrom(Coordinates start)\n    {\n        (float x, float y) = start;\n\n        while(true)\n        {\n            x += DeltaX;\n            y += DeltaY;\n\n            if (!Coordinates.TryCreate(x, y, out var coordinates))\n            {\n                yield break;\n            }\n\n            yield return coordinates;\n        }\n    }\n\n    internal (bool, Coordinates, Coordinates) GetDestination(Coordinates quadrant, Coordinates sector, int distance)\n    {\n        var (xComplete, quadrantX, sectorX) = GetNewCoordinate(quadrant.X, sector.X, DeltaX * distance);\n        var (yComplete, quadrantY, sectorY) = GetNewCoordinate(quadrant.Y, sector.Y, DeltaY * distance);\n\n        return (xComplete && yComplete, new Coordinates(quadrantX, quadrantY), new Coordinates(sectorX, sectorY));\n    }\n\n    private static (bool, int, int) GetNewCoordinate(int quadrant, int sector, float sectorsTravelled)\n    {\n        var galacticCoordinate = quadrant * 8 + sector + sectorsTravelled;\n        var newQuadrant = (int)(galacticCoordinate / 8);\n        var newSector = (int)(galacticCoordinate - newQuadrant * 8);\n\n        if (newSector < 0)\n        {\n            newQuadrant -= 1;\n            newSector += 8;\n        }\n\n        return newQuadrant switch\n        {\n            < 0 => (false, 0, 0),\n            > 7 => (false, 7, 7),\n            _ => (true, newQuadrant, newSector)\n        };\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Space/Galaxy.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.Randomness;\nusing SuperStarTrek.Resources;\n\nusing static System.StringSplitOptions;\n\nnamespace SuperStarTrek.Space;\n\ninternal class Galaxy\n{\n    private static readonly string[] _regionNames;\n    private static readonly string[] _subRegionIdentifiers;\n    private readonly QuadrantInfo[][] _quadrants;\n\n    static Galaxy()\n    {\n        _regionNames = Strings.RegionNames.Split(new[] { ' ', '\\n' }, RemoveEmptyEntries | TrimEntries);\n        _subRegionIdentifiers = new[] { \"I\", \"II\", \"III\", \"IV\" };\n    }\n\n    internal Galaxy(IRandom random)\n    {\n        _quadrants = Enumerable\n            .Range(0, 8)\n            .Select(x => Enumerable\n                .Range(0, 8)\n                .Select(y => new Coordinates(x, y))\n                .Select(c => QuadrantInfo.Create(c, GetQuadrantName(c), random))\n                .ToArray())\n            .ToArray();\n\n        if (StarbaseCount == 0)\n        {\n            var randomQuadrant = this[random.NextCoordinate()];\n            randomQuadrant.AddStarbase();\n\n            if (randomQuadrant.KlingonCount < 2)\n            {\n                randomQuadrant.AddKlingon();\n            }\n        }\n    }\n\n    internal QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X][coordinate.Y];\n\n    internal int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount);\n\n    internal int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase);\n\n    internal IEnumerable<IEnumerable<QuadrantInfo>> Quadrants => _quadrants;\n\n    private static string GetQuadrantName(Coordinates coordinates) =>\n        $\"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}\";\n\n    internal IEnumerable<IEnumerable<QuadrantInfo>> GetNeighborhood(Quadrant quadrant) =>\n        Enumerable.Range(-1, 3)\n            .Select(dx => dx + quadrant.Coordinates.X)\n            .Select(x => GetNeighborhoodRow(quadrant, x));\n    private IEnumerable<QuadrantInfo> GetNeighborhoodRow(Quadrant quadrant, int x) =>\n        Enumerable.Range(-1, 3)\n            .Select(dy => dy + quadrant.Coordinates.Y)\n            .Select(y => y < 0 || y > 7 || x < 0 || x > 7 ? null : _quadrants[x][y]);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Space/Quadrant.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\n\nnamespace SuperStarTrek.Space;\n\ninternal class Quadrant\n{\n    private readonly QuadrantInfo _info;\n    private readonly IRandom _random;\n    private readonly Dictionary<Coordinates, object> _sectors;\n    private readonly Enterprise _enterprise;\n    private readonly IReadWrite _io;\n    private bool _entered = false;\n\n    internal Quadrant(\n        QuadrantInfo info,\n        Enterprise enterprise,\n        IRandom random,\n        Galaxy galaxy,\n        IReadWrite io)\n    {\n        _info = info;\n        _random = random;\n        _io = io;\n        Galaxy = galaxy;\n\n        info.MarkAsKnown();\n        _sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise };\n        PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount);\n        if (_info.HasStarbase)\n        {\n            Starbase = PositionObject(sector => new Starbase(sector, _random, io));\n        }\n        PositionObject(_ => new Star(), _info.StarCount);\n    }\n\n    internal Coordinates Coordinates => _info.Coordinates;\n\n    internal bool HasKlingons => _info.KlingonCount > 0;\n\n    internal int KlingonCount => _info.KlingonCount;\n\n    internal bool HasStarbase => _info.HasStarbase;\n\n    internal Starbase Starbase { get; }\n\n    internal Galaxy Galaxy { get; }\n\n    internal bool EnterpriseIsNextToStarbase =>\n        _info.HasStarbase &&\n        Math.Abs(_enterprise.SectorCoordinates.X - Starbase.Sector.X) <= 1 &&\n        Math.Abs(_enterprise.SectorCoordinates.Y - Starbase.Sector.Y) <= 1;\n\n    internal IEnumerable<Klingon> Klingons => _sectors.Values.OfType<Klingon>();\n\n    public override string ToString() => _info.Name;\n\n    private T PositionObject<T>(Func<Coordinates, T> objectFactory)\n    {\n        var sector = GetRandomEmptySector();\n        _sectors[sector] = objectFactory.Invoke(sector);\n        return (T)_sectors[sector];\n    }\n\n    private void PositionObject(Func<Coordinates, object> objectFactory, int count)\n    {\n        for (int i = 0; i < count; i++)\n        {\n            PositionObject(objectFactory);\n        }\n    }\n\n    internal void Display(string textFormat)\n    {\n        if (!_entered)\n        {\n            _io.Write(textFormat, this);\n            _entered = true;\n        }\n\n        if (_info.KlingonCount > 0)\n        {\n            _io.Write(Strings.CombatArea);\n            if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _io.Write(Strings.LowShields); }\n        }\n\n        _enterprise.Execute(Command.SRS);\n    }\n\n    internal bool HasObjectAt(Coordinates coordinates) => _sectors.ContainsKey(coordinates);\n\n    internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver)\n    {\n        gameOver = false;\n        message = default;\n\n        switch (_sectors.GetValueOrDefault(coordinates))\n        {\n            case Klingon klingon:\n                message = Remove(klingon);\n                gameOver = Galaxy.KlingonCount == 0;\n                return true;\n\n            case Star _:\n                message = $\"Star at {coordinates} absorbed torpedo energy.\";\n                return true;\n\n            case Starbase _:\n                _sectors.Remove(coordinates);\n                _info.RemoveStarbase();\n                message = \"*** Starbase destroyed ***\" +\n                    (Galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand);\n                gameOver = Galaxy.StarbaseCount == 0;\n                return true;\n\n            default:\n                return false;\n        }\n    }\n\n    internal string Remove(Klingon klingon)\n    {\n        _sectors.Remove(klingon.Sector);\n        _info.RemoveKlingon();\n        return \"*** Klingon destroyed ***\";\n    }\n\n    internal CommandResult KlingonsMoveAndFire()\n    {\n        foreach (var klingon in Klingons.ToList())\n        {\n            var newSector = GetRandomEmptySector();\n            _sectors.Remove(klingon.Sector);\n            _sectors[newSector] = klingon;\n            klingon.MoveTo(newSector);\n        }\n\n        return KlingonsFireOnEnterprise();\n    }\n\n    internal CommandResult KlingonsFireOnEnterprise()\n    {\n        if (EnterpriseIsNextToStarbase && Klingons.Any())\n        {\n            Starbase.ProtectEnterprise();\n            return CommandResult.Ok;\n        }\n\n        foreach (var klingon in Klingons)\n        {\n            var result = klingon.FireOn(_enterprise);\n            if (result.IsGameOver) { return result; }\n        }\n\n        return CommandResult.Ok;\n    }\n\n    private Coordinates GetRandomEmptySector()\n    {\n        while (true)\n        {\n            var sector = _random.NextCoordinate();\n            if (!_sectors.ContainsKey(sector))\n            {\n                return sector;\n            }\n        }\n    }\n\n    internal IEnumerable<string> GetDisplayLines() => Enumerable.Range(0, 8).Select(x => GetDisplayLine(x));\n\n    private string GetDisplayLine(int x) =>\n        string.Join(\n            \" \",\n            Enumerable\n                .Range(0, 8)\n                .Select(y => new Coordinates(x, y))\n                .Select(c => _sectors.GetValueOrDefault(c))\n                .Select(o => o?.ToString() ?? \"   \"));\n\n    internal void SetEnterpriseSector(Coordinates sector)\n    {\n        _sectors.Remove(_enterprise.SectorCoordinates);\n        _sectors[sector] = _enterprise;\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Space/QuadrantInfo.cs",
    "content": "using Games.Common.Randomness;\n\nnamespace SuperStarTrek.Space;\n\ninternal class QuadrantInfo\n{\n    private bool _isKnown;\n\n    private QuadrantInfo(Coordinates coordinates, string name, int klingonCount, int starCount, bool hasStarbase)\n    {\n        Coordinates = coordinates;\n        Name = name;\n        KlingonCount = klingonCount;\n        StarCount = starCount;\n        HasStarbase = hasStarbase;\n    }\n\n    internal Coordinates Coordinates { get; }\n\n    internal string Name { get; }\n\n    internal int KlingonCount { get; private set; }\n\n    internal bool HasStarbase { get; private set; }\n\n    internal int StarCount { get; }\n\n    internal static QuadrantInfo Create(Coordinates coordinates, string name, IRandom random)\n    {\n        var klingonCount = random.NextFloat() switch\n        {\n            > 0.98f => 3,\n            > 0.95f => 2,\n            > 0.80f => 1,\n            _ => 0\n        };\n        var hasStarbase = random.NextFloat() > 0.96f;\n        var starCount = random.Next1To8Inclusive();\n\n        return new QuadrantInfo(coordinates, name, klingonCount, starCount, hasStarbase);\n    }\n\n    internal void AddKlingon() => KlingonCount += 1;\n\n    internal void AddStarbase() => HasStarbase = true;\n\n    internal void MarkAsKnown() => _isKnown = true;\n\n    internal string Scan()\n    {\n        _isKnown = true;\n        return ToString();\n    }\n\n    public override string ToString() => _isKnown ? $\"{KlingonCount}{(HasStarbase ? 1 : 0)}{StarCount}\" : \"***\";\n\n    internal void RemoveKlingon()\n    {\n        if (KlingonCount > 0)\n        {\n            KlingonCount -= 1;\n        }\n    }\n\n    internal void RemoveStarbase() => HasStarbase = false;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/StringExtensions.cs",
    "content": "namespace SuperStarTrek;\n\ninternal static class StringExtensions\n{\n    internal static string Pluralize(this string singular, int quantity) => singular + (quantity > 1 ? \"s\" : \"\");\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/SuperStarTrek.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources\\*.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/SuperStarTrek.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.26124.0\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"SuperStarTrek\", \"SuperStarTrek.csproj\", \"{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x64.Build.0 = Release|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal abstract class ComputerFunction\n{\n    protected ComputerFunction(string description, IReadWrite io)\n    {\n        Description = description;\n        IO = io;\n    }\n\n    internal string Description { get; }\n\n    protected IReadWrite IO { get; }\n\n    internal abstract void Execute(Quadrant quadrant);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal class CumulativeGalacticRecord : GalacticReport\n{\n    internal CumulativeGalacticRecord(IReadWrite io, Galaxy galaxy)\n        : base(\"Cumulative galactic record\", io, galaxy)\n    {\n    }\n\n    protected override void WriteHeader(Quadrant quadrant)\n    {\n        IO.WriteLine();\n        IO.WriteLine($\"Computer record of galaxy for quadrant {quadrant.Coordinates}\");\n        IO.WriteLine();\n    }\n\n    protected override IEnumerable<string> GetRowData() =>\n        Galaxy.Quadrants.Select(row => \" \" + string.Join(\"   \", row));\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal class DirectionDistanceCalculator : NavigationCalculator\n{\n    private readonly Enterprise _enterprise;\n    private readonly IReadWrite _io;\n\n    internal DirectionDistanceCalculator(Enterprise enterprise, IReadWrite io)\n        : base(\"Direction/distance calculator\", io)\n    {\n        _enterprise = enterprise;\n        _io = io;\n    }\n\n    internal override void Execute(Quadrant quadrant)\n    {\n        IO.WriteLine(\"Direction/distance calculator:\");\n        IO.Write($\"You are at quadrant {_enterprise.QuadrantCoordinates}\");\n        IO.WriteLine($\" sector {_enterprise.SectorCoordinates}\");\n        IO.WriteLine(\"Please enter\");\n\n        WriteDirectionAndDistance(\n            _io.GetCoordinates(\"  Initial coordinates\"),\n            _io.GetCoordinates(\"  Final coordinates\"));\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal abstract class GalacticReport : ComputerFunction\n{\n    internal GalacticReport(string description, IReadWrite io, Galaxy galaxy)\n        : base(description, io)\n    {\n        Galaxy = galaxy;\n    }\n\n    protected Galaxy Galaxy { get; }\n\n    protected abstract void WriteHeader(Quadrant quadrant);\n\n    protected abstract IEnumerable<string> GetRowData();\n\n    internal sealed override void Execute(Quadrant quadrant)\n    {\n        WriteHeader(quadrant);\n        IO.WriteLine(\"       1     2     3     4     5     6     7     8\");\n        IO.WriteLine(\"     ----- ----- ----- ----- ----- ----- ----- -----\");\n\n        foreach (var (row, index) in GetRowData().Select((r, i) => (r, i)))\n        {\n            IO.WriteLine($\" {index+1}   {row}\");\n            IO.WriteLine(\"     ----- ----- ----- ----- ----- ----- ----- -----\");\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal class GalaxyRegionMap : GalacticReport\n{\n    internal GalaxyRegionMap(IReadWrite io, Galaxy galaxy)\n        : base(\"Galaxy 'region name' map\", io, galaxy)\n    {\n    }\n\n    protected override void WriteHeader(Quadrant quadrant) =>\n        IO.WriteLine(\"                        The Galaxy\");\n\n    protected override IEnumerable<string> GetRowData() =>\n        Strings.RegionNames.Split('\\n').Select(n => n.TrimEnd('\\r'));\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Space;\nusing SuperStarTrek.Utils;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal abstract class NavigationCalculator : ComputerFunction\n{\n    protected NavigationCalculator(string description, IReadWrite io)\n        : base(description, io)\n    {\n    }\n\n    protected void WriteDirectionAndDistance(Coordinates from, Coordinates to)\n    {\n        var (direction, distance) = from.GetDirectionAndDistanceTo(to);\n        Write(direction, distance);\n    }\n\n    protected void WriteDirectionAndDistance((float X, float Y) from, (float X, float Y) to)\n    {\n        var (direction, distance) = DirectionAndDistance.From(from.X, from.Y).To(to.X, to.Y);\n        Write(direction, distance);\n    }\n\n    private void Write(float direction, float distance)\n    {\n        IO.WriteLine($\"Direction = {direction}\");\n        IO.WriteLine($\"Distance = {distance}\");\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal class StarbaseDataCalculator : NavigationCalculator\n{\n    private readonly Enterprise _enterprise;\n\n    internal StarbaseDataCalculator(Enterprise enterprise, IReadWrite io)\n        : base(\"Starbase nav data\", io)\n    {\n        _enterprise = enterprise;\n    }\n\n    internal override void Execute(Quadrant quadrant)\n    {\n        if (!quadrant.HasStarbase)\n        {\n            IO.WriteLine(Strings.NoStarbase);\n            return;\n        }\n\n        IO.WriteLine(\"From Enterprise to Starbase:\");\n\n        WriteDirectionAndDistance(_enterprise.SectorCoordinates, quadrant.Starbase.Sector);\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StatusReport.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal class StatusReport : ComputerFunction\n{\n    private readonly Game _game;\n    private readonly Galaxy _galaxy;\n    private readonly Enterprise _enterprise;\n\n    internal StatusReport(Game game, Galaxy galaxy, Enterprise enterprise, IReadWrite io)\n        : base(\"Status report\", io)\n    {\n        _game = game;\n        _galaxy = galaxy;\n        _enterprise = enterprise;\n    }\n\n    internal override void Execute(Quadrant quadrant)\n    {\n        IO.WriteLine(\"   Status report:\");\n        IO.Write(\"Klingon\".Pluralize(_galaxy.KlingonCount));\n        IO.WriteLine($\" left:  {_galaxy.KlingonCount}\");\n        IO.WriteLine($\"Mission must be completed in {_game.StardatesRemaining:0.#} stardates.\");\n\n        if (_galaxy.StarbaseCount > 0)\n        {\n            IO.Write($\"The Federation is maintaining {_galaxy.StarbaseCount} \");\n            IO.Write(\"starbase\".Pluralize(_galaxy.StarbaseCount));\n            IO.WriteLine(\" in the galaxy.\");\n        }\n        else\n        {\n            IO.WriteLine(\"Your stupidity has left you on your own in\");\n            IO.WriteLine(\"  the galaxy -- you have no starbases left!\");\n        }\n\n        _enterprise.Execute(Command.DAM);\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems.ComputerFunctions;\n\ninternal class TorpedoDataCalculator : NavigationCalculator\n{\n    private readonly Enterprise _enterprise;\n\n    internal TorpedoDataCalculator(Enterprise enterprise, IReadWrite io)\n        : base(\"Photon torpedo data\", io)\n    {\n        _enterprise = enterprise;\n    }\n\n    internal override void Execute(Quadrant quadrant)\n    {\n        if (!quadrant.HasKlingons)\n        {\n            IO.WriteLine(Strings.NoEnemyShips);\n            return;\n        }\n\n        IO.WriteLine(\"From Enterprise to Klingon battle cruiser\".Pluralize(quadrant.KlingonCount));\n\n        foreach (var klingon in quadrant.Klingons)\n        {\n            WriteDirectionAndDistance(_enterprise.SectorCoordinates, klingon.Sector);\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/DamageControl.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class DamageControl : Subsystem\n{\n    private readonly Enterprise _enterprise;\n    private readonly IReadWrite _io;\n\n    internal DamageControl(Enterprise enterprise, IReadWrite io)\n        : base(\"Damage Control\", Command.DAM, io)\n    {\n        _enterprise = enterprise;\n        _io = io;\n    }\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        if (IsDamaged)\n        {\n            _io.WriteLine(\"Damage Control report not available\");\n        }\n        else\n        {\n            _io.WriteLine();\n            WriteDamageReport();\n        }\n\n        if (_enterprise.DamagedSystemCount > 0 && _enterprise.IsDocked)\n        {\n            if (quadrant.Starbase.TryRepair(_enterprise, out var repairTime))\n            {\n                WriteDamageReport();\n                return CommandResult.Elapsed(repairTime);\n            }\n        }\n\n        return CommandResult.Ok;\n    }\n\n    internal void WriteDamageReport()\n    {\n        _io.WriteLine();\n        _io.WriteLine(\"Device             State of Repair\");\n        foreach (var system in _enterprise.Systems)\n        {\n            _io.Write(system.Name.PadRight(25));\n            _io.WriteLine((int)(system.Condition * 100) * 0.01F);\n        }\n        _io.WriteLine();\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/LibraryComputer.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Space;\nusing SuperStarTrek.Systems.ComputerFunctions;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class LibraryComputer : Subsystem\n{\n    private readonly IReadWrite _io;\n    private readonly ComputerFunction[] _functions;\n\n    internal LibraryComputer(IReadWrite io, params ComputerFunction[] functions)\n        : base(\"Library-Computer\", Command.COM, io)\n    {\n        _io = io;\n        _functions = functions;\n    }\n\n    protected override bool CanExecuteCommand() => IsOperational(\"Computer disabled\");\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        var index = GetFunctionIndex();\n        _io.WriteLine();\n\n        _functions[index].Execute(quadrant);\n\n        return CommandResult.Ok;\n    }\n\n    private int GetFunctionIndex()\n    {\n        while (true)\n        {\n            var index = (int)_io.ReadNumber(\"Computer active and waiting command\");\n            if (index >= 0 && index <= 5) { return index; }\n\n            for (int i = 0; i < _functions.Length; i++)\n            {\n                _io.WriteLine($\"   {i} = {_functions[i].Description}\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/LongRangeSensors.cs",
    "content": "using System.Linq;\nusing Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class LongRangeSensors : Subsystem\n{\n    private readonly Galaxy _galaxy;\n    private readonly IReadWrite _io;\n\n    internal LongRangeSensors(Galaxy galaxy, IReadWrite io)\n        : base(\"Long Range Sensors\", Command.LRS, io)\n    {\n        _galaxy = galaxy;\n        _io = io;\n    }\n\n    protected override bool CanExecuteCommand() => IsOperational(\"{name} are inoperable\");\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        _io.WriteLine($\"Long range scan for quadrant {quadrant.Coordinates}\");\n        _io.WriteLine(\"-------------------\");\n        foreach (var quadrants in _galaxy.GetNeighborhood(quadrant))\n        {\n            _io.WriteLine(\": \" + string.Join(\" : \", quadrants.Select(q => q?.Scan() ?? \"***\")) + \" :\");\n            _io.WriteLine(\"-------------------\");\n        }\n\n        return CommandResult.Ok;\n    }\n}\n\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/PhaserControl.cs",
    "content": "using System.Linq;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class PhaserControl : Subsystem\n{\n    private readonly Enterprise _enterprise;\n    private readonly IReadWrite _io;\n    private readonly IRandom _random;\n\n    internal PhaserControl(Enterprise enterprise, IReadWrite io, IRandom random)\n        : base(\"Phaser Control\", Command.PHA, io)\n    {\n        _enterprise = enterprise;\n        _io = io;\n        _random = random;\n    }\n\n    protected override bool CanExecuteCommand() => IsOperational(\"Phasers inoperative\");\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        if (!quadrant.HasKlingons)\n        {\n            _io.WriteLine(Strings.NoEnemyShips);\n            return CommandResult.Ok;\n        }\n\n        if (_enterprise.Computer.IsDamaged)\n        {\n            _io.WriteLine(\"Computer failure hampers accuracy\");\n        }\n\n        _io.Write($\"Phasers locked on target;  \");\n\n        var phaserStrength = GetPhaserStrength();\n        if (phaserStrength < 0) { return CommandResult.Ok; }\n\n        _enterprise.UseEnergy(phaserStrength);\n\n        var perEnemyStrength = GetPerTargetPhaserStrength(phaserStrength, quadrant.KlingonCount);\n\n        foreach (var klingon in quadrant.Klingons.ToList())\n        {\n            ResolveHitOn(klingon, perEnemyStrength, quadrant);\n        }\n\n        return quadrant.KlingonsFireOnEnterprise();\n    }\n\n    private float GetPhaserStrength()\n    {\n        while (true)\n        {\n            _io.WriteLine($\"Energy available = {_enterprise.Energy} units\");\n            var phaserStrength = _io.ReadNumber(\"Number of units to fire\");\n\n            if (phaserStrength <= _enterprise.Energy) { return phaserStrength; }\n        }\n    }\n\n    private float GetPerTargetPhaserStrength(float phaserStrength, int targetCount)\n    {\n        if (_enterprise.Computer.IsDamaged)\n        {\n            phaserStrength *= _random.NextFloat();\n        }\n\n        return phaserStrength / targetCount;\n    }\n\n    private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant)\n    {\n        var distance = _enterprise.SectorCoordinates.GetDistanceTo(klingon.Sector);\n        var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.NextFloat()));\n\n        if (klingon.TakeHit(hitStrength))\n        {\n            _io.WriteLine($\"{hitStrength} unit hit on Klingon at sector {klingon.Sector}\");\n            _io.WriteLine(\n                klingon.Energy <= 0\n                    ? quadrant.Remove(klingon)\n                    : $\"   (sensors show {klingon.Energy} units remaining)\");\n        }\n        else\n        {\n            _io.WriteLine($\"Sensors show no damage to enemy at {klingon.Sector}\");\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/PhotonTubes.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class PhotonTubes : Subsystem\n{\n    private readonly int _tubeCount;\n    private readonly Enterprise _enterprise;\n    private readonly IReadWrite _io;\n\n    internal PhotonTubes(int tubeCount, Enterprise enterprise, IReadWrite io)\n        : base(\"Photon Tubes\", Command.TOR, io)\n    {\n        TorpedoCount = _tubeCount = tubeCount;\n        _enterprise = enterprise;\n        _io = io;\n    }\n\n    internal int TorpedoCount { get; private set; }\n\n    protected override bool CanExecuteCommand() => HasTorpedoes() && IsOperational(\"{name} are not operational\");\n\n    private bool HasTorpedoes()\n    {\n        if (TorpedoCount > 0) { return true; }\n\n        _io.WriteLine(\"All photon torpedoes expended\");\n        return false;\n    }\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        if (!_io.TryReadCourse(\"Photon torpedo course\", \"Ensign Chekov\", out var course))\n        {\n            return CommandResult.Ok;\n        }\n\n        TorpedoCount -= 1;\n\n        var isHit = false;\n        _io.WriteLine(\"Torpedo track:\");\n        foreach (var sector in course.GetSectorsFrom(_enterprise.SectorCoordinates))\n        {\n            _io.WriteLine($\"                {sector}\");\n\n            if (quadrant.TorpedoCollisionAt(sector, out var message, out var gameOver))\n            {\n                _io.WriteLine(message);\n                isHit = true;\n                if (gameOver) { return CommandResult.GameOver; }\n                break;\n            }\n        }\n\n        if (!isHit) { _io.WriteLine(\"Torpedo missed!\"); }\n\n        return quadrant.KlingonsFireOnEnterprise();\n    }\n\n    internal void ReplenishTorpedoes() => TorpedoCount = _tubeCount;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ShieldControl.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class ShieldControl : Subsystem\n{\n    private readonly Enterprise _enterprise;\n    private readonly IReadWrite _io;\n\n    internal ShieldControl(Enterprise enterprise, IReadWrite io)\n        : base(\"Shield Control\", Command.SHE, io)\n    {\n        _enterprise = enterprise;\n        _io = io;\n    }\n\n    internal float ShieldEnergy { get; set; }\n\n    protected override bool CanExecuteCommand() => IsOperational(\"{name} inoperable\");\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        _io.WriteLine($\"Energy available = {_enterprise.TotalEnergy}\");\n        var requested = _io.ReadNumber($\"Number of units to shields\");\n\n        if (Validate(requested))\n        {\n            ShieldEnergy = requested;\n            _io.Write(Strings.ShieldsSet, requested);\n        }\n        else\n        {\n            _io.WriteLine(\"<SHIELDS UNCHANGED>\");\n        }\n\n        return CommandResult.Ok;\n    }\n\n    private bool Validate(float requested)\n    {\n        if (requested > _enterprise.TotalEnergy)\n        {\n            _io.WriteLine(\"Shield Control reports, 'This is not the Federation Treasury.'\");\n            return false;\n        }\n\n        return requested >= 0 && requested != ShieldEnergy;\n    }\n\n    internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength;\n\n    internal void DropShields() => ShieldEnergy = 0;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/ShortRangeSensors.cs",
    "content": "\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal class ShortRangeSensors : Subsystem\n{\n    private readonly Enterprise _enterprise;\n    private readonly Galaxy _galaxy;\n    private readonly Game _game;\n    private readonly IReadWrite _io;\n\n    internal ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, IReadWrite io)\n        : base(\"Short Range Sensors\", Command.SRS, io)\n    {\n        _enterprise = enterprise;\n        _galaxy = galaxy;\n        _game = game;\n        _io = io;\n    }\n\n    protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n    {\n        if (_enterprise.IsDocked)\n        {\n            _io.WriteLine(Strings.ShieldsDropped);\n        }\n\n        if (Condition < 0)\n        {\n            _io.WriteLine(Strings.ShortRangeSensorsOut);\n        }\n\n        _io.WriteLine(\"---------------------------------\");\n        quadrant.GetDisplayLines()\n            .Zip(GetStatusLines(), (sectors, status) => $\" {sectors}         {status}\")\n            .ToList()\n            .ForEach(l => _io.WriteLine(l));\n        _io.WriteLine(\"---------------------------------\");\n\n        return CommandResult.Ok;\n    }\n\n    internal IEnumerable<string> GetStatusLines()\n    {\n        yield return $\"Stardate           {_game.Stardate}\";\n        yield return $\"Condition          {_enterprise.Condition}\";\n        yield return $\"Quadrant           {_enterprise.QuadrantCoordinates}\";\n        yield return $\"Sector             {_enterprise.SectorCoordinates}\";\n        yield return $\"Photon torpedoes   {_enterprise.PhotonTubes.TorpedoCount}\";\n        yield return $\"Total energy       {Math.Ceiling(_enterprise.TotalEnergy)}\";\n        yield return $\"Shields            {(int)_enterprise.ShieldControl.ShieldEnergy}\";\n        yield return $\"Klingons remaining {_galaxy.KlingonCount}\";\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/Subsystem.cs",
    "content": "using Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems;\n\ninternal abstract class Subsystem\n{\n    private readonly IReadWrite _io;\n\n    protected Subsystem(string name, Command command, IReadWrite io)\n    {\n        Name = name;\n        Command = command;\n        Condition = 0;\n        _io = io;\n    }\n\n    internal string Name { get; }\n\n    internal float Condition { get; private set; }\n\n    internal bool IsDamaged => Condition < 0;\n\n    internal Command Command { get; }\n\n    protected virtual bool CanExecuteCommand() => true;\n\n    protected bool IsOperational(string notOperationalMessage)\n    {\n        if (IsDamaged)\n        {\n            _io.WriteLine(notOperationalMessage.Replace(\"{name}\", Name));\n            return false;\n        }\n\n        return true;\n    }\n\n    internal CommandResult ExecuteCommand(Quadrant quadrant)\n        => CanExecuteCommand() ? ExecuteCommandCore(quadrant) : CommandResult.Ok;\n\n    protected abstract CommandResult ExecuteCommandCore(Quadrant quadrant);\n\n    internal virtual void Repair()\n    {\n        if (IsDamaged)\n        {\n            Condition = 0;\n        }\n    }\n\n    internal virtual bool Repair(float repairWorkDone)\n    {\n        if (IsDamaged)\n        {\n            Condition += repairWorkDone;\n            if (Condition > -0.1f && Condition < 0)\n            {\n                Condition = -0.1f;\n            }\n        }\n\n        return !IsDamaged;\n    }\n\n    internal void TakeDamage(float damage) => Condition -= damage;\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Systems/WarpEngines.cs",
    "content": "using System;\nusing Games.Common.IO;\nusing SuperStarTrek.Commands;\nusing SuperStarTrek.Objects;\nusing SuperStarTrek.Resources;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Systems\n{\n    internal class WarpEngines : Subsystem\n    {\n        private readonly Enterprise _enterprise;\n        private readonly IReadWrite _io;\n\n        internal WarpEngines(Enterprise enterprise, IReadWrite io)\n            : base(\"Warp Engines\", Command.NAV, io)\n        {\n            _enterprise = enterprise;\n            _io = io;\n        }\n\n        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)\n        {\n            if (_io.TryReadCourse(\"Course\", \"   Lt. Sulu\", out var course) &&\n                TryGetWarpFactor(out var warpFactor) &&\n                TryGetDistanceToMove(warpFactor, out var distanceToMove))\n            {\n                var result = quadrant.KlingonsMoveAndFire();\n                if (result.IsGameOver) { return result; }\n\n                _enterprise.RepairSystems(warpFactor);\n                _enterprise.VaryConditionOfRandomSystem();\n                var timeElapsed = _enterprise.Move(course, warpFactor, distanceToMove);\n\n                if (_enterprise.IsDocked)\n                {\n                    _enterprise.ShieldControl.DropShields();\n                    _enterprise.Refuel();\n                    _enterprise.PhotonTubes.ReplenishTorpedoes();\n                }\n\n                _enterprise.Quadrant.Display(Strings.NowEntering);\n\n                return CommandResult.Elapsed(timeElapsed);\n            }\n\n            return CommandResult.Ok;\n        }\n\n        private bool TryGetWarpFactor(out float warpFactor)\n        {\n            var maximumWarp = IsDamaged ? 0.2f : 8;\n            if (_io.TryReadNumberInRange(\"Warp Factor\", 0, maximumWarp, out warpFactor))\n            {\n                return warpFactor > 0;\n            }\n\n            _io.WriteLine(\n                IsDamaged && warpFactor > maximumWarp\n                    ? \"Warp engines are damaged.  Maximum speed = warp 0.2\"\n                    : $\"  Chief Engineer Scott reports, 'The engines won't take warp {warpFactor} !'\");\n\n            return false;\n        }\n\n        private bool TryGetDistanceToMove(float warpFactor, out int distanceToTravel)\n        {\n            distanceToTravel = (int)Math.Round(warpFactor * 8, MidpointRounding.AwayFromZero);\n            if (distanceToTravel <= _enterprise.Energy) { return true; }\n\n            _io.WriteLine(\"Engineering reports, 'Insufficient energy available\");\n            _io.WriteLine($\"                      for maneuvering at warp {warpFactor} !'\");\n\n            if (distanceToTravel <= _enterprise.TotalEnergy && !_enterprise.ShieldControl.IsDamaged)\n            {\n                _io.Write($\"Deflector control room acknowledges {_enterprise.ShieldControl.ShieldEnergy} \");\n                _io.WriteLine(\"units of energy\");\n                _io.WriteLine(\"                         presently deployed to shields.\");\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/csharp/Utils/DirectionAndDistance.cs",
    "content": "using System;\nusing SuperStarTrek.Space;\n\nnamespace SuperStarTrek.Utils\n{\n    internal class DirectionAndDistance\n    {\n        private readonly float _fromX;\n        private readonly float _fromY;\n\n        private DirectionAndDistance(float fromX, float fromY)\n        {\n            _fromX = fromX;\n            _fromY = fromY;\n        }\n\n        internal static DirectionAndDistance From(Coordinates coordinates) => From(coordinates.X, coordinates.Y);\n\n        internal static DirectionAndDistance From(float x, float y) => new DirectionAndDistance(x, y);\n\n        internal (float Direction, float Distance) To(Coordinates coordinates) => To(coordinates.X, coordinates.Y);\n\n        internal (float Direction, float Distance) To(float x, float y)\n        {\n            var deltaX = x - _fromX;\n            var deltaY = y - _fromY;\n\n            return (GetDirection(deltaX, deltaY), GetDistance(deltaX, deltaY));\n        }\n\n        // The algorithm here is mathematically equivalent to the following code in the original,\n        // where X is deltaY and A is deltaX\n        //     8220 X=X-A:A=C1-W1:IFX<0THEN8350\n        //     8250 IFA<0THEN8410\n        //     8260 IFX>0THEN8280\n        //     8270 IFA=0THENC1=5:GOTO8290\n        //     8280 C1=1\n        //     8290 IFABS(A)<=ABS(X)THEN8330\n        //     8310 PRINT\"DIRECTION =\";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO8460\n        //     8330 PRINT\"DIRECTION =\";C1+(ABS(A)/ABS(X)):GOTO8460\n        //     8350 IFA>0THENC1=3:GOTO8420\n        //     8360 IFX<>0THENC1=5:GOTO8290\n        //     8410 C1=7\n        //     8420 IFABS(A)>=ABS(X)THEN8450\n        //     8430 PRINT\"DIRECTION =\";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO8460\n        //     8450 PRINT\"DIRECTION =\";C1+(ABS(X)/ABS(A))\n        //     8460 PRINT\"DISTANCE =\";SQR(X^2+A^2):IFH8=1THEN1990\n        private static float GetDirection(float deltaX, float deltaY)\n        {\n            var deltaXDominant = Math.Abs(deltaX) > Math.Abs(deltaY);\n            var fractionalPart = deltaXDominant ? deltaY / deltaX : -deltaX / deltaY;\n            var nearestCardinal = deltaXDominant switch\n            {\n                true => deltaX > 0 ? 7 : 3,\n                false => deltaY > 0 ? 1 : 5\n            };\n\n            var direction = nearestCardinal + fractionalPart;\n            return direction < 1 ? direction + 8 : direction;\n        }\n\n        private static float GetDistance(float deltaX, float deltaY) =>\n            (float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/instructions.txt",
    "content": "\n\n\n\n\n\n\n\n\n\n*************************************\n*                                   *\n*                                   *\n*      * * SUPER STAR TREK * *      *\n*                                   *\n*                                   *\n*************************************\n\n\n\n\n\n\n\n\n      INSTRUCTIONS FOR 'SUPER STAR TREK'\n\n1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL\n     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\n2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\n     LIST OF THE LEGAL COMMANDS PRINTED OUT.\n3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\n     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\n     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\n     WILL BE ABORTED\n\n     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\nAND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\n\n     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\nGALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\n\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\nKLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\nPLANETS.\n\n     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\nOF THE STARSHIP ENTERPRISE:\n\n\\NAV\\ COMMAND = WARP ENGINE CONTROL --\n     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\n     VECTOR ARRANGEMENT AS SHOWN             . . .\n     INTEGER AND REAL VALUES MAY BE           ...\n     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\n     WAY BETWEEN 1 AND 2                      ...\n                                             . . .\n     VALUES MAY APPROACH 9.0, WHICH         6  7  8\n     ITSELF IS EQUIVALENT TO 1.0\"\n                                            COURSE\n     ONE WARP FACTOR IS THE SIZE OF\n     ONE QUADTANT.  THEREFORE, TO GET\n     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\n     USE COURSE 3, WARP FACTOR 1.\n\n\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN\n     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\n\n     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\n        <*> = YOUR STARSHIP'S POSITION\n        +K+ = KLINGON BATTLE CRUISER\n        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\n         *  = STAR\n\n     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\n\n\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN\n     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\n     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\n     THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT\n     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\n     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF\n     KLINGONS.\n\n     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\n\n\\PHA\\ COMMAND = PHASER CONTROL.\n     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY\n     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\n     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE\n     PHASERS TOO!)\n\n\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL\n     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\n     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\n     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\n     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO\n     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\n\n     THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO\n     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\n\n\\SHE\\ COMMAND = SHIELD CONTROL\n     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\n     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\n     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\n\n\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT\n     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\n     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\n     DAMAGED.\n\n\\COM\\ COMMAND = LIBRARY-COMPUTER\n     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\n     OPTION 0 = CUMULATIVE GALACTIC RECORD\n        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\n        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\n     OPTION 1 = STATUS REPORT\n        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\n        AND STARBASES REMAINING IN THE GAME.\n     OPTION 2 = PHOTON TORPEDO DATA\n        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\n        TO ALL KLINGONS IN YOUR QUADRANT\n     OPTION 3 = STARBASE NAV DATA\n        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY\n        STARBASE WITHIN YOUR QUADRANT\n     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\n        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\n        DIRECTION/DISTANCE CALCULATIONS\n     OPTION 5 = GALACTIC /REGION NAME/ MAP\n        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR\n        GALACTIC REGIONS REFERRED TO IN THE GAME.\n"
  },
  {
    "path": "84_Super_Star_Trek/java/Enterprise.java",
    "content": "import java.util.stream.IntStream;\n\n/**\n * The starship Enterprise.\n */\npublic class Enterprise {\n\n    public static final int COORD_X = 0;\n    public static final int COORD_Y = 1;\n\n    // devices\n    static final int DEVICE_WARP_ENGINES = 1;\n    static final int DEVICE_SHORT_RANGE_SENSORS = 2;\n    static final int DEVICE_LONG_RANGE_SENSORS = 3;\n    static final int DEVICE_PHASER_CONTROL = 4;\n    static final int DEVICE_PHOTON_TUBES = 5;\n    static final int DEVICE_DAMAGE_CONTROL = 6;\n    static final int DEVICE_SHIELD_CONTROL = 7;\n    static final int DEVICE_LIBRARY_COMPUTER = 8;\n    final double[] deviceStatus = new double[9];   // 8  device damage stats\n\n    // position\n    final int[][] cardinalDirections = new int[10][3];   // 9x2 vectors in cardinal directions\n    int quadrantX;\n    int quadrantY;\n    int sectorX;\n    int sectorY;\n\n    // ship status\n    boolean docked = false;\n    int energy = 3000;\n    int torpedoes = 10;\n    int shields = 0;\n    double repairCost;\n\n    final int initialEnergy = energy;\n    final int initialTorpedoes = torpedoes;\n\n    public Enterprise() {\n        // random initial position\n        this.setQuadrant(new int[]{ Util.fnr(), Util.fnr() });\n        this.setSector(new int[]{ Util.fnr(), Util.fnr() });\n        // init cardinal directions\n        IntStream.range(1, 9).forEach(i -> {\n            cardinalDirections[i][1] = 0;\n            cardinalDirections[i][2] = 0;\n        });\n        cardinalDirections[3][1] = -1;\n        cardinalDirections[2][1] = -1;\n        cardinalDirections[4][1] = -1;\n        cardinalDirections[4][2] = -1;\n        cardinalDirections[5][2] = -1;\n        cardinalDirections[6][2] = -1;\n        cardinalDirections[1][2] = 1;\n        cardinalDirections[2][2] = 1;\n        cardinalDirections[6][1] = 1;\n        cardinalDirections[7][1] = 1;\n        cardinalDirections[8][1] = 1;\n        cardinalDirections[8][2] = 1;\n        cardinalDirections[9][2] = 1;\n        // init devices\n        IntStream.range(1, 8).forEach(i -> deviceStatus[i] = 0);\n    }\n\n    public int getShields() {\n        return shields;\n    }\n\n    /**\n     * Enterprise is hit by enemies.\n     * @param hits the number of hit points\n     */\n    public void sufferHitPoints(int hits) {\n        this.shields = shields - hits;\n    }\n\n    public int getEnergy() {\n        return energy;\n    }\n\n    public void replenishSupplies() {\n        this.energy = this.initialEnergy;\n        this.torpedoes = this.initialTorpedoes;\n    }\n\n    public void decreaseEnergy(final double amount) {\n        this.energy -= amount;\n    }\n\n    public void decreaseTorpedoes(final int amount) {\n        torpedoes -= amount;\n    }\n\n    public void dropShields() {\n        this.shields = 0;\n    }\n\n    public int getTotalEnergy() {\n        return (shields + energy);\n    }\n\n    public int getInitialEnergy() {\n        return initialEnergy;\n    }\n\n    public int getTorpedoes() {\n        return torpedoes;\n    }\n\n    public double[] getDeviceStatus() {\n        return deviceStatus;\n    }\n\n    public int[][] getCardinalDirections() {\n        return cardinalDirections;\n    }\n\n    public void setDeviceStatus(final int device, final double status) {\n        this.deviceStatus[device] = status;\n    }\n\n    public boolean isDocked() {\n        return docked;\n    }\n\n    public void setDocked(boolean docked) {\n        this.docked = docked;\n    }\n\n    public int[] getQuadrant() {\n        return new int[] {quadrantX, quadrantY};\n    }\n\n    public void setQuadrant(final int[] quadrant) {\n        this.quadrantX = quadrant[COORD_X];\n        this.quadrantY = quadrant[COORD_Y];\n    }\n\n    public int[] getSector() {\n        return new int[] {sectorX, sectorY};\n    }\n\n    public void setSector(final int[] sector) {\n        this.sectorX = sector[COORD_X];\n        this.sectorY = sector[COORD_Y];\n    }\n\n    public int[] moveShip(final float course, final int n, final String quadrantMap, final double stardate, final double initialStardate, final int missionDuration, final GameCallback callback) {\n        int ic1 = Util.toInt(course);\n        float x1 = cardinalDirections[ic1][1] + (cardinalDirections[ic1 + 1][1] - cardinalDirections[ic1][1]) * (course - ic1);\n        float x = sectorX;\n        float y = sectorY;\n        float x2 = cardinalDirections[ic1][2] + (cardinalDirections[ic1 + 1][2] - cardinalDirections[ic1][2]) * (course - ic1);\n        final int initialQuadrantX = quadrantX;\n        final int initialQuadrantY = quadrantY;\n        for (int i = 1; i <= n; i++) {\n            sectorX += x1;\n            sectorY += x2;\n            if (sectorX < 1 || sectorX >= 9 || sectorY < 1 || sectorY >= 9) {\n                // exceeded quadrant limits\n                x = 8 * quadrantX + x + n * x1;\n                y = 8 * quadrantY + y + n * x2;\n                quadrantX = Util.toInt(x / 8);\n                quadrantY = Util.toInt(y / 8);\n                sectorX = Util.toInt(x - quadrantX * 8);\n                sectorY = Util.toInt(y - quadrantY * 8);\n                if (sectorX == 0) {\n                    quadrantX = quadrantX - 1;\n                    sectorX = 8;\n                }\n                if (sectorY == 0) {\n                    quadrantY = quadrantY - 1;\n                    sectorY = 8;\n                }\n                boolean hitEdge = false;\n                if (quadrantX < 1) {\n                    hitEdge = true;\n                    quadrantX = 1;\n                    sectorX = 1;\n                }\n                if (quadrantX > 8) {\n                    hitEdge = true;\n                    quadrantX = 8;\n                    sectorX = 8;\n                }\n                if (quadrantY < 1) {\n                    hitEdge = true;\n                    quadrantY = 8;\n                    sectorY = 8;\n                }\n                if (quadrantY > 8) {\n                    hitEdge = true;\n                    quadrantY = 8;\n                    sectorY = 8;\n                }\n                if (hitEdge) {\n                    Util.println(\"LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:\");\n                    Util.println(\"  'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER\");\n                    Util.println(\"  IS HEREBY *DENIED*.  SHUT DOWN YOUR ENGINES.'\");\n                    Util.println(\"CHIEF ENGINEER SCOTT REPORTS  'WARP ENGINES SHUT DOWN\");\n                    Util.println(\"  AT SECTOR \" + sectorX + \",\" + sectorY + \" OF QUADRANT \" + quadrantX + \",\" + quadrantY + \".'\");\n                    if (stardate > initialStardate + missionDuration) callback.endGameFail(false);\n                }\n                if (8 * quadrantX + quadrantY == 8 * initialQuadrantX + initialQuadrantY) {\n                    break;\n                }\n                callback.incrementStardate(1);\n                maneuverEnergySR(n);\n                callback.enterNewQuadrant();\n                return this.getSector();\n            } else {\n                int S8 = Util.toInt(sectorX) * 24 + Util.toInt(sectorY) * 3 - 26; // S8 = pos\n                if (!(\"  \".equals(Util.midStr(quadrantMap, S8, 2)))) {\n                    sectorX = Util.toInt(sectorX - x1);\n                    sectorY = Util.toInt(sectorY - x2);\n                    Util.println(\"WARP ENGINES SHUT DOWN AT \");\n                    Util.println(\"SECTOR \" + sectorX + \",\" + sectorY + \" DUE TO BAD NAVIGATION\");\n                    break;\n                }\n            }\n        }\n        sectorX = Util.toInt(sectorX);\n        sectorY = Util.toInt(sectorY);\n        return this.getSector();\n    }\n\n    void randomRepairCost() {\n        repairCost = .5 * Util.random();\n    }\n\n    public void repairDamagedDevices(final float warp) {\n        // repair damaged devices and print damage report\n        for (int i = 1; i <= 8; i++) {\n            if (deviceStatus[i] < 0) {\n                deviceStatus[i] += Math.min(warp, 1);\n                if ((deviceStatus[i] > -.1) && (deviceStatus[i] < 0)) {\n                    deviceStatus[i] = -.1;\n                    break;\n                } else if (deviceStatus[i] >= 0) {\n                    Util.println(\"DAMAGE CONTROL REPORT:  \");\n                    Util.println(Util.tab(8) + printDeviceName(i) + \" REPAIR COMPLETED.\");\n                }\n            }\n        }\n    }\n\n    public void maneuverEnergySR(final int N) {\n        energy = energy - N - 10;\n        if (energy >= 0) return;\n        Util.println(\"SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.\");\n        shields = shields + energy;\n        energy = 0;\n        if (shields <= 0) shields = 0;\n    }\n\n    void shieldControl() {\n        if (deviceStatus[DEVICE_SHIELD_CONTROL] < 0) {\n            Util.println(\"SHIELD CONTROL INOPERABLE\");\n            return;\n        }\n        Util.println(\"ENERGY AVAILABLE = \" + (energy + shields));\n        int energyToShields = Util.toInt(Util.inputFloat(\"NUMBER OF UNITS TO SHIELDS\"));\n        if (energyToShields < 0 || shields == energyToShields) {\n            Util.println(\"<SHIELDS UNCHANGED>\");\n            return;\n        }\n        if (energyToShields > energy + energyToShields) {\n            Util.println(\"SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION TREASURY.'\");\n            Util.println(\"<SHIELDS UNCHANGED>\");\n            return;\n        }\n        energy = energy + shields - energyToShields;\n        shields = energyToShields;\n        Util.println(\"DEFLECTOR CONTROL ROOM REPORT:\");\n        Util.println(\"  'SHIELDS NOW AT \" + Util.toInt(shields) + \" UNITS PER YOUR COMMAND.'\");\n    }\n\n    void damageControl(GameCallback callback) {\n        if (deviceStatus[DEVICE_DAMAGE_CONTROL] < 0) {\n            Util.println(\"DAMAGE CONTROL REPORT NOT AVAILABLE\");\n        } else {\n            Util.println(\"\\nDEVICE             STATE OF REPAIR\");\n            for (int deviceNr = 1; deviceNr <= 8; deviceNr++) {\n                Util.print(printDeviceName(deviceNr) + Util.leftStr(GalaxyMap.QUADRANT_ROW, 25 - Util.strlen(printDeviceName(deviceNr))) + \" \" + Util.toInt(deviceStatus[deviceNr] * 100) * .01 + \"\\n\");\n            }\n        }\n        if (!docked) return;\n\n        double deltaToRepair = 0;\n        for (int i = 1; i <= 8; i++) {\n            if (deviceStatus[i] < 0) deltaToRepair += .1;\n        }\n        if (deltaToRepair > 0) {\n            deltaToRepair += repairCost;\n            if (deltaToRepair >= 1) deltaToRepair = .9;\n            Util.println(\"TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;\");\n            Util.println(\"ESTIMATED TIME TO REPAIR:'\" + .01 * Util.toInt(100 * deltaToRepair) + \" STARDATES\");\n            final String reply = Util.inputStr(\"WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)\");\n            if (\"Y\".equals(reply)) {\n                for (int deviceNr = 1; deviceNr <= 8; deviceNr++) {\n                    if (deviceStatus[deviceNr] < 0) deviceStatus[deviceNr] = 0;\n                }\n                callback.incrementStardate(deltaToRepair + .1);\n            }\n        }\n    }\n\n    public static String printDeviceName(final int deviceNumber) {  // 8790\n        // PRINTS DEVICE NAME\n        switch (deviceNumber) {\n            case DEVICE_WARP_ENGINES:\n                return \"WARP ENGINES\";\n            case DEVICE_SHORT_RANGE_SENSORS:\n                return \"SHORT RANGE SENSORS\";\n            case DEVICE_LONG_RANGE_SENSORS:\n                return \"LONG RANGE SENSORS\";\n            case DEVICE_PHASER_CONTROL:\n                return \"PHASER CONTROL\";\n            case DEVICE_PHOTON_TUBES:\n                return \"PHOTON TUBES\";\n            case DEVICE_DAMAGE_CONTROL:\n                return \"DAMAGE CONTROL\";\n            case DEVICE_SHIELD_CONTROL:\n                return \"SHIELD CONTROL\";\n            case DEVICE_LIBRARY_COMPUTER:\n                return \"LIBRARY-COMPUTER\";\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/java/GalaxyMap.java",
    "content": "import java.util.stream.IntStream;\n\n/**\n * Map of the galaxy divided in Quadrants and Sectors,\n * populated with stars, starbases, klingons, and the Enterprise.\n */\npublic class GalaxyMap {\n\n    // markers\n    static final String MARKER_EMPTY = \"   \";\n    static final String MARKER_ENTERPRISE = \"<*>\";\n    static final String MARKER_KLINGON = \"+K+\";\n    static final String MARKER_STARBASE = \">!<\";\n    static final String MARKER_STAR = \" * \";\n\n    static final int AVG_KLINGON_SHIELD_ENERGY = 200;\n\n    // galaxy map\n    public static final String QUADRANT_ROW = \"                         \";\n    String quadrantMap = QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + Util.leftStr(QUADRANT_ROW, 17);       // current quadrant map\n    final int[][] galaxy = new int[9][9];    // 8x8 galaxy map G\n    final int[][] klingonQuadrants = new int[4][4];    // 3x3 position of klingons K\n    final int[][] chartedGalaxy = new int[9][9];    // 8x8 charted galaxy map Z\n\n    // galaxy state\n    int basesInGalaxy = 0;\n    int remainingKlingons;\n    int klingonsInGalaxy = 0;\n    final Enterprise enterprise = new Enterprise();\n\n    // quadrant state\n    int klingons = 0;\n    int starbases = 0;\n    int stars = 0;\n    int starbaseX = 0; // X coordinate of starbase\n    int starbaseY = 0; // Y coord of starbase\n\n    public Enterprise getEnterprise() {\n        return enterprise;\n    }\n\n    public int getBasesInGalaxy() {\n        return basesInGalaxy;\n    }\n\n    public int getRemainingKlingons() {\n        return remainingKlingons;\n    }\n\n    public int getKlingonsInGalaxy() {\n        return klingonsInGalaxy;\n    }\n\n    double fnd(int i) {\n        return Math.sqrt((klingonQuadrants[i][1] - enterprise.getSector()[Enterprise.COORD_X]) ^ 2 + (klingonQuadrants[i][2] - enterprise.getSector()[Enterprise.COORD_Y]) ^ 2);\n    }\n\n    public GalaxyMap() {\n        int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n        int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n        // populate Klingons, Starbases, Stars\n        IntStream.range(1, 8).forEach(x -> {\n            IntStream.range(1, 8).forEach(y -> {\n                klingons = 0;\n                chartedGalaxy[x][y] = 0;\n                float random = Util.random();\n                if (random > .98) {\n                    klingons = 3;\n                    klingonsInGalaxy += 3;\n                } else if (random > .95) {\n                    klingons = 2;\n                    klingonsInGalaxy += 2;\n                } else if (random > .80) {\n                    klingons = 1;\n                    klingonsInGalaxy += 1;\n                }\n                starbases = 0;\n                if (Util.random() > .96) {\n                    starbases = 1;\n                    basesInGalaxy = +1;\n                }\n                galaxy[x][y] = klingons * 100 + starbases * 10 + Util.fnr();\n            });\n        });\n        if (basesInGalaxy == 0) {\n            if (galaxy[quadrantX][quadrantY] < 200) {\n                galaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY] + 120;\n                klingonsInGalaxy = +1;\n            }\n            basesInGalaxy = 1;\n            galaxy[quadrantX][quadrantY] = +10;\n            enterprise.setQuadrant(new int[]{ Util.fnr(), Util.fnr() });\n        }\n        remainingKlingons = klingonsInGalaxy;\n    }\n\n    void newQuadrant(final double stardate, final double initialStardate) {   // 1320\n        final int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n        final int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n        klingons = 0;\n        starbases = 0;\n        stars = 0;\n        enterprise.randomRepairCost();\n        chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY];\n        if (!(quadrantX < 1 || quadrantX > 8 || quadrantY < 1 || quadrantY > 8)) {\n            final String quadrantName = getQuadrantName(false, quadrantX, quadrantY);\n            if (initialStardate == stardate) {\n                Util.println(\"YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\\n\" +\n                        \"IN THE GALACTIC QUADRANT, '\" + quadrantName + \"'.\");\n            } else {\n                Util.println(\"NOW ENTERING \" + quadrantName + \" QUADRANT . . .\");\n            }\n            Util.println(\"\");\n            klingons = (int) Math.round(galaxy[quadrantX][quadrantY] * .01);\n            starbases = (int) Math.round(galaxy[quadrantX][quadrantY] * .1) - 10 * klingons;\n            stars = galaxy[quadrantX][quadrantY] - 100 * klingons - 10 * starbases;\n            if (klingons != 0) {\n                Util.println(\"COMBAT AREA      CONDITION RED\");\n                if (enterprise.getShields() <= 200) {\n                    Util.println(\"   SHIELDS DANGEROUSLY LOW\");\n                }\n            }\n            IntStream.range(1, 3).forEach(i -> {\n                klingonQuadrants[i][1] = 0;\n                klingonQuadrants[i][2] = 0;\n            });\n        }\n        IntStream.range(1, 3).forEach(i -> {\n            klingonQuadrants[i][3] = 0;\n        });\n        // position enterprise in quadrant\n        insertMarker(MARKER_ENTERPRISE, enterprise.getSector()[Enterprise.COORD_X], enterprise.getSector()[Enterprise.COORD_Y]);\n        // position klingons\n        if (klingons >= 1) {\n            for (int i = 1; i <= klingons; i++) {\n                final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap);\n                insertMarker(MARKER_KLINGON, emptyCoordinate[0], emptyCoordinate[1]);\n                klingonQuadrants[i][1] = emptyCoordinate[0];\n                klingonQuadrants[i][2] = emptyCoordinate[1];\n                klingonQuadrants[i][3] = (int) Math.round(AVG_KLINGON_SHIELD_ENERGY * (0.5 + Util.random()));\n            }\n        }\n        // position bases\n        if (starbases >= 1) {\n            final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap);\n            starbaseX = emptyCoordinate[0];\n            starbaseY = emptyCoordinate[1];\n            insertMarker(MARKER_STARBASE, emptyCoordinate[0], emptyCoordinate[1]);\n        }\n        // position stars\n        for (int i = 1; i <= stars; i++) {\n            final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap);\n            insertMarker(MARKER_STAR, emptyCoordinate[0], emptyCoordinate[1]);\n        }\n    }\n\n    public void klingonsMoveAndFire(GameCallback callback) {\n        for (int i = 1; i <= klingons; i++) {\n            if (klingonQuadrants[i][3] == 0) continue;\n            insertMarker(MARKER_EMPTY, klingonQuadrants[i][1], klingonQuadrants[i][2]);\n            final int[] newCoords = findEmptyPlaceInQuadrant(quadrantMap);\n            klingonQuadrants[i][1] = newCoords[0];\n            klingonQuadrants[i][2] = newCoords[1];\n            insertMarker(MARKER_KLINGON, klingonQuadrants[i][1], klingonQuadrants[i][2]);\n        }\n        klingonsShoot(callback);\n    }\n\n    void klingonsShoot(GameCallback callback) {\n        if (klingons <= 0) return; // no klingons\n        if (enterprise.isDocked()) {\n            Util.println(\"STARBASE SHIELDS PROTECT THE ENTERPRISE\");\n            return;\n        }\n        for (int i = 1; i <= 3; i++) {\n            if (klingonQuadrants[i][3] <= 0) continue;\n            int hits = Util.toInt((klingonQuadrants[i][3] / fnd(1)) * (2 + Util.random()));\n            enterprise.sufferHitPoints(hits);\n            klingonQuadrants[i][3] = Util.toInt(klingonQuadrants[i][3] / (3 + Util.random()));\n            Util.println(hits + \" UNIT HIT ON ENTERPRISE FROM SECTOR \" + klingonQuadrants[i][1] + \",\" + klingonQuadrants[i][2]);\n            if (enterprise.getShields() <= 0) callback.endGameFail(true);\n            Util.println(\"      <SHIELDS DOWN TO \" + enterprise.getShields() + \" UNITS>\");\n            if (hits < 20) continue;\n            if ((Util.random() > .6) || (hits / enterprise.getShields() <= .02)) continue;\n            int randomDevice = Util.fnr();\n            enterprise.setDeviceStatus(randomDevice, enterprise.getDeviceStatus()[randomDevice]- hits / enterprise.getShields() - .5 * Util.random());\n            Util.println(\"DAMAGE CONTROL REPORTS \" + Enterprise.printDeviceName(randomDevice) + \" DAMAGED BY THE HIT'\");\n        }\n    }\n\n    public void moveEnterprise(final float course, final float warp, final int n, final double stardate, final double initialStardate, final int missionDuration, final GameCallback callback) {\n        insertMarker(MARKER_EMPTY, Util.toInt(enterprise.getSector()[Enterprise.COORD_X]), Util.toInt(enterprise.getSector()[Enterprise.COORD_Y]));\n        final int[] sector = enterprise.moveShip(course, n, quadrantMap, stardate, initialStardate, missionDuration, callback);\n        int sectorX = sector[Enterprise.COORD_X];\n        int sectorY = sector[Enterprise.COORD_Y];\n        insertMarker(MARKER_ENTERPRISE, Util.toInt(sectorX), Util.toInt(sectorY));\n        enterprise.maneuverEnergySR(n);\n        double stardateDelta = 1;\n        if (warp < 1) stardateDelta = .1 * Util.toInt(10 * warp);\n        callback.incrementStardate(stardateDelta);\n        if (stardate > initialStardate + missionDuration) callback.endGameFail(false);\n    }\n\n    void shortRangeSensorScan(final double stardate) {\n        final int sectorX = enterprise.getSector()[Enterprise.COORD_X];\n        final int sectorY = enterprise.getSector()[Enterprise.COORD_Y];\n        boolean docked = false;\n        String shipCondition; // ship condition (docked, red, yellow, green)\n        for (int i = sectorX - 1; i <= sectorX + 1; i++) {\n            for (int j = sectorY - 1; j <= sectorY + 1; j++) {\n                if ((Util.toInt(i) >= 1) && (Util.toInt(i) <= 8) && (Util.toInt(j) >= 1) && (Util.toInt(j) <= 8)) {\n                    if (compareMarker(quadrantMap, MARKER_STARBASE, i, j)) {\n                        docked = true;\n                    }\n                }\n            }\n        }\n        if (!docked) {\n            enterprise.setDocked(false);\n            if (klingons > 0) {\n                shipCondition = \"*RED*\";\n            } else {\n                shipCondition = \"GREEN\";\n                if (enterprise.getEnergy() < enterprise.getInitialEnergy() * .1) {\n                    shipCondition = \"YELLOW\";\n                }\n            }\n        } else {\n            enterprise.setDocked(true);\n            shipCondition = \"DOCKED\";\n            enterprise.replenishSupplies();\n            Util.println(\"SHIELDS DROPPED FOR DOCKING PURPOSES\");\n            enterprise.dropShields();\n        }\n        if (enterprise.getDeviceStatus()[Enterprise.DEVICE_SHORT_RANGE_SENSORS] < 0) { // are short range sensors out?\n            Util.println(\"\\n*** SHORT RANGE SENSORS ARE OUT ***\\n\");\n            return;\n        }\n        final String row = \"---------------------------------\";\n        Util.println(row);\n        for (int i = 1; i <= 8; i++) {\n            String sectorMapRow = \"\";\n            for (int j = (i - 1) * 24 + 1; j <= (i - 1) * 24 + 22; j += 3) {\n                sectorMapRow += \" \" + Util.midStr(quadrantMap, j, 3);\n            }\n            switch (i) {\n                case 1:\n                    Util.println(sectorMapRow + \"        STARDATE           \" + Util.toInt(stardate * 10) * .1);\n                    break;\n                case 2:\n                    Util.println(sectorMapRow + \"        CONDITION          \" + shipCondition);\n                    break;\n                case 3:\n                    Util.println(sectorMapRow + \"        QUADRANT           \" + enterprise.getQuadrant()[Enterprise.COORD_X] + \",\" + enterprise.getQuadrant()[Enterprise.COORD_Y]);\n                    break;\n                case 4:\n                    Util.println(sectorMapRow + \"        SECTOR             \" + sectorX + \",\" + sectorY);\n                    break;\n                case 5:\n                    Util.println(sectorMapRow + \"        PHOTON TORPEDOES   \" + Util.toInt(enterprise.getTorpedoes()));\n                    break;\n                case 6:\n                    Util.println(sectorMapRow + \"        TOTAL ENERGY       \" + Util.toInt(enterprise.getTotalEnergy()));\n                    break;\n                case 7:\n                    Util.println(sectorMapRow + \"        SHIELDS            \" + Util.toInt(enterprise.getShields()));\n                    break;\n                case 8:\n                    Util.println(sectorMapRow + \"        KLINGONS REMAINING \" + Util.toInt(klingonsInGalaxy));\n            }\n        }\n        Util.println(row);\n    }\n\n    void longRangeSensorScan() {\n        final int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n        final int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n        if (enterprise.getDeviceStatus()[Enterprise.DEVICE_LONG_RANGE_SENSORS] < 0) {\n            Util.println(\"LONG RANGE SENSORS ARE INOPERABLE\");\n            return;\n        }\n        Util.println(\"LONG RANGE SCAN FOR QUADRANT \" + quadrantX + \",\" + quadrantY);\n        final String rowStr = \"-------------------\";\n        Util.println(rowStr);\n        final int[] n = new int[4];\n        for (int i = quadrantX - 1; i <= quadrantX + 1; i++) {\n            n[1] = -1;\n            n[2] = -2;\n            n[3] = -3;\n            for (int j = quadrantY - 1; j <= quadrantY + 1; j++) {\n                if (i > 0 && i < 9 && j > 0 && j < 9) {\n                    n[j - quadrantY + 2] = galaxy[i][j];\n                    chartedGalaxy[i][j] = galaxy[i][j];\n                }\n            }\n            for (int l = 1; l <= 3; l++) {\n                Util.print(\": \");\n                if (n[l] < 0) {\n                    Util.print(\"*** \");\n                    continue;\n                }\n                Util.print(Util.rightStr(Integer.toString(n[l] + 1000), 3) + \" \");\n            }\n            Util.println(\": \\n\" + rowStr);\n        }\n    }\n\n    void firePhasers(GameCallback callback) {\n        final double[] deviceStatus = enterprise.getDeviceStatus();\n        final int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n        final int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n        if (deviceStatus[Enterprise.DEVICE_PHASER_CONTROL] < 0) {\n            Util.println(\"PHASERS INOPERATIVE\");\n            return;\n        }\n        if (klingons <= 0) {\n            printNoEnemyShipsMessage();\n            return;\n        }\n        if (deviceStatus[Enterprise.DEVICE_LIBRARY_COMPUTER] < 0) Util.println(\"COMPUTER FAILURE HAMPERS ACCURACY\");\n        Util.println(\"PHASERS LOCKED ON TARGET;  \");\n        int nrUnitsToFire;\n        while (true) {\n            Util.println(\"ENERGY AVAILABLE = \" + enterprise.getEnergy() + \" UNITS\");\n            nrUnitsToFire = Util.toInt(Util.inputFloat(\"NUMBER OF UNITS TO FIRE\"));\n            if (nrUnitsToFire <= 0) return;\n            if (enterprise.getEnergy() - nrUnitsToFire >= 0) break;\n        }\n        enterprise.decreaseEnergy(nrUnitsToFire);\n        if (deviceStatus[Enterprise.DEVICE_SHIELD_CONTROL] < 0) nrUnitsToFire = Util.toInt(nrUnitsToFire * Util.random());\n        int h1 = Util.toInt(nrUnitsToFire / klingons);\n        for (int i = 1; i <= 3; i++) {\n            if (klingonQuadrants[i][3] <= 0) break;\n            int hitPoints = Util.toInt((h1 / fnd(0)) * (Util.random() + 2));\n            if (hitPoints <= .15 * klingonQuadrants[i][3]) {\n                Util.println(\"SENSORS SHOW NO DAMAGE TO ENEMY AT \" + klingonQuadrants[i][1] + \",\" + klingonQuadrants[i][2]);\n                continue;\n            }\n            klingonQuadrants[i][3] = klingonQuadrants[i][3] - hitPoints;\n            Util.println(hitPoints + \" UNIT HIT ON KLINGON AT SECTOR \" + klingonQuadrants[i][1] + \",\" + klingonQuadrants[i][2]);\n            if (klingonQuadrants[i][3] <= 0) {\n                Util.println(\"*** KLINGON DESTROYED ***\");\n                klingons -= 1;\n                klingonsInGalaxy -= 1;\n                insertMarker(MARKER_EMPTY, klingonQuadrants[i][1], klingonQuadrants[i][2]);\n                klingonQuadrants[i][3] = 0;\n                galaxy[quadrantX][quadrantY] -= 100;\n                chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY];\n                if (klingonsInGalaxy <= 0) callback.endGameSuccess();\n            } else {\n                Util.println(\"   (SENSORS SHOW \" + klingonQuadrants[i][3] + \" UNITS REMAINING)\");\n            }\n        }\n        klingonsShoot(callback);\n    }\n\n    void firePhotonTorpedo(final double stardate, final double initialStardate, final double missionDuration, GameCallback callback) {\n        if (enterprise.getTorpedoes() <= 0) {\n            Util.println(\"ALL PHOTON TORPEDOES EXPENDED\");\n            return;\n        }\n        if (enterprise.getDeviceStatus()[Enterprise.DEVICE_PHOTON_TUBES] < 0) {\n            Util.println(\"PHOTON TUBES ARE NOT OPERATIONAL\");\n        }\n        float c1 = Util.inputFloat(\"PHOTON TORPEDO COURSE (1-9)\");\n        if (c1 == 9) c1 = 1;\n        if (c1 < 1 && c1 >= 9) {\n            Util.println(\"ENSIGN CHEKOV REPORTS,  'INCORRECT COURSE DATA, SIR!'\");\n            return;\n        }\n        int ic1 = Util.toInt(c1);\n        final int[][] cardinalDirections = enterprise.getCardinalDirections();\n        float x1 = cardinalDirections[ic1][1] + (cardinalDirections[ic1 + 1][1] - cardinalDirections[ic1][1]) * (c1 - ic1);\n        enterprise.decreaseEnergy(2);\n        enterprise.decreaseTorpedoes(1);\n        float x2 = cardinalDirections[ic1][2] + (cardinalDirections[ic1 + 1][2] - cardinalDirections[ic1][2]) * (c1 - ic1);\n        float x = enterprise.getSector()[Enterprise.COORD_X];\n        float y = enterprise.getSector()[Enterprise.COORD_Y];\n        Util.println(\"TORPEDO TRACK:\");\n        while (true) {\n            x = x + x1;\n            y = y + x2;\n            int x3 = Math.round(x);\n            int y3 = Math.round(y);\n            if (x3 < 1 || x3 > 8 || y3 < 1 || y3 > 8) {\n                Util.println(\"TORPEDO MISSED\"); // 5490\n                klingonsShoot(callback);\n                return;\n            }\n            Util.println(\"               \" + x3 + \",\" + y3);\n            if (compareMarker(quadrantMap, MARKER_EMPTY, Util.toInt(x), Util.toInt(y)))  {\n                continue;\n            } else if (compareMarker(quadrantMap, MARKER_KLINGON, Util.toInt(x), Util.toInt(y))) {\n                Util.println(\"*** KLINGON DESTROYED ***\");\n                klingons = klingons - 1;\n                klingonsInGalaxy = klingonsInGalaxy - 1;\n                if (klingonsInGalaxy <= 0) callback.endGameSuccess();\n                for (int i = 1; i <= 3; i++) {\n                    if (x3 == klingonQuadrants[i][1] && y3 == klingonQuadrants[i][2]) break;\n                }\n                int i = 3;\n                klingonQuadrants[i][3] = 0;\n            } else if (compareMarker(quadrantMap, MARKER_STAR, Util.toInt(x), Util.toInt(y))) {\n                Util.println(\"STAR AT \" + x3 + \",\" + y3 + \" ABSORBED TORPEDO ENERGY.\");\n                klingonsShoot(callback);\n                return;\n            } else if (compareMarker(quadrantMap, MARKER_STARBASE, Util.toInt(x), Util.toInt(y))) {\n                Util.println(\"*** STARBASE DESTROYED ***\");\n                starbases = starbases - 1;\n                basesInGalaxy = basesInGalaxy - 1;\n                if (basesInGalaxy == 0 && klingonsInGalaxy <= stardate - initialStardate - missionDuration) {\n                    Util.println(\"THAT DOES IT, CAPTAIN!!  YOU ARE HEREBY RELIEVED OF COMMAND\");\n                    Util.println(\"AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!\");\n                    callback.endGameFail(false);\n                } else {\n                    Util.println(\"STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER\");\n                    Util.println(\"COURT MARTIAL!\");\n                    enterprise.setDocked(false);\n                }\n            }\n            insertMarker(MARKER_EMPTY, Util.toInt(x), Util.toInt(y));\n            final int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n            final int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n            galaxy[quadrantX][quadrantY] = klingons * 100 + starbases * 10 + stars;\n            chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY];\n            klingonsShoot(callback);\n        }\n    }\n\n    public void cumulativeGalacticRecord(final boolean cumulativeReport) {\n        final int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n        final int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n        if (cumulativeReport) {\n            Util.println(\"\");\n            Util.println(\"        \");\n            Util.println(\"COMPUTER RECORD OF GALAXY FOR QUADRANT \" + quadrantX + \",\" + quadrantY);\n            Util.println(\"\");\n        } else {\n            Util.println(\"                        THE GALAXY\");\n        }\n        Util.println(\"       1     2     3     4     5     6     7     8\");\n        final String rowDivider = \"     ----- ----- ----- ----- ----- ----- ----- -----\";\n        Util.println(rowDivider);\n        for (int i = 1; i <= 8; i++) {\n            Util.print(i + \"  \");\n            if (cumulativeReport) {\n                int y = 1;\n                String quadrantName = getQuadrantName(false, i, y);\n                int tabLen = Util.toInt(15 - .5 * Util.strlen(quadrantName));\n                Util.println(Util.tab(tabLen) + quadrantName);\n                y = 5;\n                quadrantName = getQuadrantName(false, i, y);\n                tabLen = Util.toInt(39 - .5 * Util.strlen(quadrantName));\n                Util.println(Util.tab(tabLen) + quadrantName);\n            } else {\n                for (int j = 1; j <= 8; j++) {\n                    Util.print(\"   \");\n                    if (chartedGalaxy[i][j] == 0) {\n                        Util.print(\"***\");\n                    } else {\n                        Util.print(Util.rightStr(Integer.toString(chartedGalaxy[i][j] + 1000), 3));\n                    }\n                }\n            }\n            Util.println(\"\");\n            Util.println(rowDivider);\n        }\n        Util.println(\"\");\n    }\n\n    public void photonTorpedoData() {\n        int sectorX = enterprise.getSector()[Enterprise.COORD_X];\n        int sectorY = enterprise.getSector()[Enterprise.COORD_Y];\n        if (klingons <= 0) {\n            printNoEnemyShipsMessage();\n            return;\n        }\n        Util.println(\"FROM ENTERPRISE TO KLINGON BATTLE CRUISER\" + ((klingons > 1)? \"S\" : \"\"));\n        for (int i = 1; i <= 3; i++) {\n            if (klingonQuadrants[i][3] > 0) {\n                printDirection(sectorX, sectorY, klingonQuadrants[i][1], klingonQuadrants[i][2]);\n            }\n        }\n    }\n\n    void directionDistanceCalculator() {\n        int quadrantX = enterprise.getQuadrant()[Enterprise.COORD_X];\n        int quadrantY = enterprise.getQuadrant()[Enterprise.COORD_Y];\n        int sectorX = enterprise.getSector()[Enterprise.COORD_X];\n        int sectorY = enterprise.getSector()[Enterprise.COORD_Y];\n        Util.println(\"DIRECTION/DISTANCE CALCULATOR:\");\n        Util.println(\"YOU ARE AT QUADRANT \" + quadrantX + \",\" + quadrantY + \" SECTOR \" + sectorX + \",\" + sectorY);\n        Util.print(\"PLEASE ENTER \");\n        int[] initialCoords = Util.inputCoords(\"  INITIAL COORDINATES (X,Y)\");\n        int[] finalCoords = Util.inputCoords(\"  FINAL COORDINATES (X,Y)\");\n        printDirection(initialCoords[0], initialCoords[1], finalCoords[0], finalCoords[1]);\n    }\n\n    void printDirection(int from_x, int from_y, int to_x, int to_y) {\n        to_y = to_y - from_y;  // delta 2\n        from_y = from_x - to_x;    // delta 1\n        if (to_y > 0) {\n            if (from_y < 0) {\n                from_x = 7;\n            } else {\n                from_x = 1;\n                int tempA = from_y;\n                from_y = to_y;\n                to_y = tempA;\n            }\n        } else {\n            if (from_y > 0) {\n                from_x = 3;\n            } else {\n                from_x = 5;\n                int tempA = from_y;\n                from_y = to_y;\n                to_y = tempA;\n            }\n        }\n\n        from_y = Math.abs(from_y);\n        to_y = Math.abs(to_y);\n\n        if (from_y > 0 || to_y > 0) {\n            if (from_y >= to_y) {\n                Util.println(\"DIRECTION = \" + (from_x + to_y / from_y));\n            } else {\n                Util.println(\"DIRECTION = \" + (from_x + 2 - to_y / from_y));\n            }\n        }\n        Util.println(\"DISTANCE = \" + Util.round(Math.sqrt(to_y ^ 2 + from_y ^ 2), 6));\n    }\n\n    void starbaseNavData() {\n        int sectorX = enterprise.getSector()[Enterprise.COORD_X];\n        int sectorY = enterprise.getSector()[Enterprise.COORD_Y];\n        if (starbases != 0) {\n            Util.println(\"FROM ENTERPRISE TO STARBASE:\");\n            printDirection(sectorX, sectorY, starbaseX, starbaseY);\n        } else {\n            Util.println(\"MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS\");\n            Util.println(\" QUADRANT.'\");\n        }\n    }\n\n    void printNoEnemyShipsMessage() {\n        Util.println(\"SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS\");\n        Util.println(\"                                IN THIS QUADRANT'\");\n    }\n\n    String getRegionName(final boolean regionNameOnly, final int y) {\n        if (!regionNameOnly) {\n            switch (y % 4) {\n                case 0:\n                    return \" I\";\n                case 1:\n                    return \" II\";\n                case 2:\n                    return \" III\";\n                case 3:\n                    return \" IV\";\n            }\n        }\n        return \"\";\n    }\n\n    String getQuadrantName(final boolean regionNameOnly, final int x, final int y) {\n        if (y <= 4) {\n            switch (x) {\n                case 1:\n                    return \"ANTARES\" + getRegionName(regionNameOnly, y);\n                case 2:\n                    return \"RIGEL\" + getRegionName(regionNameOnly, y);\n                case 3:\n                    return \"PROCYON\" + getRegionName(regionNameOnly, y);\n                case 4:\n                    return \"VEGA\" + getRegionName(regionNameOnly, y);\n                case 5:\n                    return \"CANOPUS\" + getRegionName(regionNameOnly, y);\n                case 6:\n                    return \"ALTAIR\" + getRegionName(regionNameOnly, y);\n                case 7:\n                    return \"SAGITTARIUS\" + getRegionName(regionNameOnly, y);\n                case 8:\n                    return \"POLLUX\" + getRegionName(regionNameOnly, y);\n            }\n        } else {\n            switch (x) {\n                case 1:\n                    return \"SIRIUS\" + getRegionName(regionNameOnly, y);\n                case 2:\n                    return \"DENEB\" + getRegionName(regionNameOnly, y);\n                case 3:\n                    return \"CAPELLA\" + getRegionName(regionNameOnly, y);\n                case 4:\n                    return \"BETELGEUSE\" + getRegionName(regionNameOnly, y);\n                case 5:\n                    return \"ALDEBARAN\" + getRegionName(regionNameOnly, y);\n                case 6:\n                    return \"REGULUS\" + getRegionName(regionNameOnly, y);\n                case 7:\n                    return \"ARCTURUS\" + getRegionName(regionNameOnly, y);\n                case 8:\n                    return \"SPICA\" + getRegionName(regionNameOnly, y);\n            }\n        }\n        return \"UNKNOWN - ERROR\";\n    }\n\n    void insertMarker(final String marker, final int x, final int y) {\n        final int pos = Util.toInt(y) * 3 + Util.toInt(x) * 24 + 1;\n        if (marker.length() != 3) {\n            System.err.println(\"ERROR\");\n            System.exit(-1);\n        }\n        if (pos == 1) {\n            quadrantMap = marker + Util.rightStr(quadrantMap, 189);\n        }\n        if (pos == 190) {\n            quadrantMap = Util.leftStr(quadrantMap, 189) + marker;\n        }\n        quadrantMap = Util.leftStr(quadrantMap, (pos - 1)) + marker + Util.rightStr(quadrantMap, (190 - pos));\n    }\n\n    /**\n     * Finds random empty coordinates in a quadrant.\n     *\n     * @param quadrantString\n     * @return an array with a pair of coordinates x, y\n     */\n    int[] findEmptyPlaceInQuadrant(final String quadrantString) {\n        final int x = Util.fnr();\n        final int y = Util.fnr();\n        if (!compareMarker(quadrantString, MARKER_EMPTY, x, y)) {\n            return findEmptyPlaceInQuadrant(quadrantString);\n        }\n        return new int[]{x, y};\n    }\n\n    boolean compareMarker(final String quadrantString, final String marker, final int x, final int y) {\n        final int markerRegion = (y - 1) * 3 + (x - 1) * 24 + 1;\n        if (Util.midStr(quadrantString, markerRegion, 3).equals(marker)) {\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/java/GameCallback.java",
    "content": "/**\n * Interface for decoupling inversion of control from GalaxyMap and Enterprise towards the game class.\n */\npublic interface GameCallback {\n    void enterNewQuadrant();\n    void incrementStardate(double increment);\n    void endGameSuccess();\n    void endGameFail(boolean enterpriseDestroyed);\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/) by [Taciano Dreckmann Perez](https://github.com/taciano-perez).\n\nOverview of Java classes:\n- SuperStarTrekInstructions: displays game instructions\n- SuperStarTrekGame: main game class\n- GalaxyMap: map of the galaxy divided in quadrants and sectors, containing stars, bases, klingons, and the Enterprise\n- Enterprise: the starship Enterprise\n- GameCallback: interface allowing other classes to interact with the game class without circular dependencies \n- Util: utility methods\n\n[This video](https://www.youtube.com/watch?v=cU3NKOnRNCI) describes the approach and the different steps followed to translate the game."
  },
  {
    "path": "84_Super_Star_Trek/java/SuperStarTrekGame.java",
    "content": "import java.util.stream.IntStream;\n\n/**\n * SUPER STARTREK - MAY 16,1978\n * ****        **** STAR TREK ****        ****\n * **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n * **** AS SEEN ON THE STAR TREK TV SHOW.\n * **** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n * **** PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n * **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n * *** LEEDOM - APRIL & DECEMBER 1974,\n * *** WITH A LITTLE HELP FROM HIS FRIENDS . . .\n *\n * Ported to Java in Jan-Mar 2022 by\n * Taciano Dreckmann Perez (taciano.perez@gmail.com)\n */\npublic class SuperStarTrekGame implements GameCallback {\n\n    // commands\n    static final int COMMAND_NAV = 1;\n    static final int COMMAND_SRS = 2;\n    static final int COMMAND_LRS = 3;\n    static final int COMMAND_PHA = 4;\n    static final int COMMAND_TOR = 5;\n    static final int COMMAND_SHE = 6;\n    static final int COMMAND_DAM = 7;\n    static final int COMMAND_COM = 8;\n    static final int COMMAND_XXX = 9;\n\n    // computer commands\n    static final int COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD = 1;\n    static final int COMPUTER_COMMAND_STATUS_REPORT = 2;\n    static final int COMPUTER_COMMAND_PHOTON_TORPEDO_DATA = 3;\n    static final int COMPUTER_COMMAND_STARBASE_NAV_DATA = 4;\n    static final int COMPUTER_COMMAND_DIR_DIST_CALC = 5;\n    static final int COMPUTER_COMMAND_GALAXY_MAP = 6;\n\n    // other constants\n    static final String COMMANDS = \"NAVSRSLRSPHATORSHEDAMCOMXXX\";\n\n    // game state\n    final GalaxyMap galaxyMap = new GalaxyMap();\n    double stardate = Util.toInt(Util.random() * 20 + 20);\n    int missionDuration = Math.max((25 + Util.toInt(Util.random() * 10)), galaxyMap.getKlingonsInGalaxy()+1);    // T9 (mission duration in stardates)\n    boolean restart = false;\n\n    // initial values\n    final double initialStardate = stardate;\n\n    public static void main(String[] args) {\n        final SuperStarTrekGame game = new SuperStarTrekGame();\n        printBanner();\n        while (true) {\n            game.orders();\n            game.enterNewQuadrant();\n            game.restart = false;\n            game.commandLoop();\n        }\n    }\n\n    static void printBanner() {\n        IntStream.range(1, 10).forEach(i -> {\n            Util.println(\"\");\n        });\n        Util.println(\n                \"\"\"\n                                                            ,------*------,\n                                            ,-------------   '---  ------'\n                                             '-------- --'      / /\n                                                 ,---' '-------/ /--,\n                                                  '----------------'\n\n                                            THE USS ENTERPRISE --- NCC-1701\"\n\n                        \"\"\"\n        );\n    }\n\n    void orders() {\n        Util.println(\"YOUR ORDERS ARE AS FOLLOWS:\\n\" +\n                \"     DESTROY THE \" + galaxyMap.getKlingonsInGalaxy() + \" KLINGON WARSHIP\" + ((galaxyMap.getKlingonsInGalaxy() == 1) ? \"\" : \"S\") + \" WHICH HAVE INVADED\\n\" +\n                \"   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\\n\" +\n                \"   ON STARDATE \" + initialStardate + missionDuration + \"  THIS GIVES YOU \" + missionDuration + \" DAYS.  THERE \" + ((galaxyMap.getBasesInGalaxy() == 1) ? \"IS\" : \"ARE\") + \"\\n\" +\n                \"  \" + galaxyMap.getBasesInGalaxy() + \" STARBASE\" + ((galaxyMap.getBasesInGalaxy() == 1) ? \"\" : \"S\") + \" IN THE GALAXY FOR RESUPPLYING YOUR SHIP\");\n    }\n\n    public void enterNewQuadrant() {\n        galaxyMap.newQuadrant(stardate, initialStardate);\n        shortRangeSensorScan();\n    }\n\n    void commandLoop() {\n        while (!this.restart) {\n            checkShipEnergy();\n            String cmdStr = \"\";\n            while (\"\".equals(cmdStr)) cmdStr = Util.inputStr(\"COMMAND\");\n            boolean foundCommand = false;\n            for (int i = 1; i <= 9; i++) {\n                if (Util.leftStr(cmdStr, 3).equals(Util.midStr(COMMANDS, 3 * i - 2, 3))) {\n                    switch (i) {\n                        case COMMAND_NAV:\n                            navigation();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_SRS:\n                            shortRangeSensorScan();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_LRS:\n                            longRangeSensorScan();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_PHA:\n                            firePhasers();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_TOR:\n                            firePhotonTorpedo();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_SHE:\n                            shieldControl();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_DAM:\n                            galaxyMap.getEnterprise().damageControl(this);\n                            foundCommand = true;\n                            break;\n                        case COMMAND_COM:\n                            libraryComputer();\n                            foundCommand = true;\n                            break;\n                        case COMMAND_XXX:\n                            endGameFail(false);\n                            foundCommand = true;\n                            break;\n                        default:\n                            printCommandOptions();\n                            foundCommand = true;\n                    }\n                }\n            }\n            if (!foundCommand) printCommandOptions();\n        }\n    }\n\n    void checkShipEnergy() {\n        final Enterprise enterprise = galaxyMap.getEnterprise();\n        if (enterprise.getTotalEnergy() < 10 && (enterprise.getEnergy() <= 10 || enterprise.getDeviceStatus()[Enterprise.DEVICE_SHIELD_CONTROL] != 0)) {\n            Util.println(\"\\n** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP IN \");\n            Util.println(\"SPACE\");\n            Util.println(\"YOU HAVE INSUFFICIENT MANEUVERING ENERGY,\");\n            Util.println(\" AND SHIELD CONTROL\");\n            Util.println(\"IS PRESENTLY INCAPABLE OF CROSS\");\n            Util.println(\"-CIRCUITING TO ENGINE ROOM!!\");\n            endGameFail(false);\n        }\n    }\n\n    void printCommandOptions() {\n        Util.println(\"ENTER ONE OF THE FOLLOWING:\");\n        Util.println(\"  NAV  (TO SET COURSE)\");\n        Util.println(\"  SRS  (FOR SHORT RANGE SENSOR SCAN)\");\n        Util.println(\"  LRS  (FOR LONG RANGE SENSOR SCAN)\");\n        Util.println(\"  PHA  (TO FIRE PHASERS)\");\n        Util.println(\"  TOR  (TO FIRE PHOTON TORPEDOES)\");\n        Util.println(\"  SHE  (TO RAISE OR LOWER SHIELDS)\");\n        Util.println(\"  DAM  (FOR DAMAGE CONTROL REPORTS)\");\n        Util.println(\"  COM  (TO CALL ON LIBRARY-COMPUTER)\");\n        Util.println(\"  XXX  (TO RESIGN YOUR COMMAND)\\n\");\n    }\n\n    void navigation() {\n        float course = Util.toInt(Util.inputFloat(\"COURSE (0-9)\"));\n        if (course == 9) course = 1;\n        if (course < 1 || course >= 9) {\n            Util.println(\"   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'\");\n            return;\n        }\n        final Enterprise enterprise = galaxyMap.getEnterprise();\n        final double[] deviceStatus = enterprise.getDeviceStatus();\n        Util.println(\"WARP FACTOR (0-\" + ((deviceStatus[Enterprise.DEVICE_WARP_ENGINES] < 0) ? \"0.2\" : \"8\") + \")\");\n        float warp = Util.inputFloat(\"\");\n        if (deviceStatus[Enterprise.DEVICE_WARP_ENGINES] < 0 && warp > .2) {\n            Util.println(\"WARP ENGINES ARE DAMAGED.  MAXIMUM SPEED = WARP 0.2\");\n            return;\n        }\n        if (warp == 0) return;\n        if (warp > 0 && warp <= 8) {\n            int n = Util.toInt(warp * 8);\n            if (enterprise.getEnergy() - n >= 0) {\n                galaxyMap.klingonsMoveAndFire(this);\n                repairDamagedDevices(course, warp, n);\n                galaxyMap.moveEnterprise(course, warp, n, stardate, initialStardate, missionDuration, this);\n            } else {\n                Util.println(\"ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE\");\n                Util.println(\"                       FOR MANEUVERING AT WARP \" + warp + \"!'\");\n                if (enterprise.getShields() < n - enterprise.getEnergy() || deviceStatus[Enterprise.DEVICE_SHIELD_CONTROL] < 0) return;\n                Util.println(\"DEFLECTOR CONTROL ROOM ACKNOWLEDGES \" + enterprise.getShields() + \" UNITS OF ENERGY\");\n                Util.println(\"                         PRESENTLY DEPLOYED TO SHIELDS.\");\n            }\n        } else {\n            Util.println(\"   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE\");\n            Util.println(\" WARP \" + warp + \"!'\");\n        }\n    }\n\n    void repairDamagedDevices(final float course, final float warp, final int N) {\n        final Enterprise enterprise = galaxyMap.getEnterprise();\n        // repair damaged devices and print damage report\n        enterprise.repairDamagedDevices(warp);\n        if (Util.random() > .2) return;  // 80% chance no damage nor repair\n        int randomDevice = Util.fnr();    // random device\n        final double[] deviceStatus = enterprise.getDeviceStatus();\n        if (Util.random() >= .6) {   // 40% chance of repair of random device\n            enterprise.setDeviceStatus(randomDevice, deviceStatus[randomDevice] + Util.random() * 3 + 1);\n            Util.println(\"DAMAGE CONTROL REPORT:  \" + Enterprise.printDeviceName(randomDevice) + \" STATE OF REPAIR IMPROVED\\n\");\n        } else {            // 60% chance of damage of random device\n            enterprise.setDeviceStatus(randomDevice, deviceStatus[randomDevice] - (Util.random() * 5 + 1));\n            Util.println(\"DAMAGE CONTROL REPORT:  \" + Enterprise.printDeviceName(randomDevice) + \" DAMAGED\");\n        }\n    }\n\n    void longRangeSensorScan() {\n        // LONG RANGE SENSOR SCAN CODE\n        galaxyMap.longRangeSensorScan();\n    }\n\n    void firePhasers() {\n        galaxyMap.firePhasers(this);\n    }\n\n    void firePhotonTorpedo() {\n        galaxyMap.firePhotonTorpedo(stardate, initialStardate, missionDuration, this);\n    }\n\n    void shieldControl() {\n        galaxyMap.getEnterprise().shieldControl();\n    }\n\n    void shortRangeSensorScan() {\n        // SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE\n        galaxyMap.shortRangeSensorScan(stardate);\n    }\n\n    void libraryComputer() {\n        // REM LIBRARY COMPUTER CODE\n        if (galaxyMap.getEnterprise().getDeviceStatus()[Enterprise.DEVICE_LIBRARY_COMPUTER] < 0) {\n            Util.println(\"COMPUTER DISABLED\");\n            return;\n        }\n        while (true) {\n            final float commandInput = Util.inputFloat(\"COMPUTER ACTIVE AND AWAITING COMMAND\");\n            if (commandInput < 0) return;\n            Util.println(\"\");\n            int command = Util.toInt(commandInput) + 1;\n            if (command >= COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD && command <= COMPUTER_COMMAND_GALAXY_MAP) {\n                switch (command) {\n                    case COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD:\n                        galaxyMap.cumulativeGalacticRecord(true);\n                        return;\n                    case COMPUTER_COMMAND_STATUS_REPORT:\n                        statusReport();\n                        return;\n                    case COMPUTER_COMMAND_PHOTON_TORPEDO_DATA:\n                        galaxyMap.photonTorpedoData();\n                        return;\n                    case COMPUTER_COMMAND_STARBASE_NAV_DATA:\n                        galaxyMap.starbaseNavData();\n                        return;\n                    case COMPUTER_COMMAND_DIR_DIST_CALC:\n                        galaxyMap.directionDistanceCalculator();\n                        return;\n                    case COMPUTER_COMMAND_GALAXY_MAP:\n                        galaxyMap.cumulativeGalacticRecord(false);\n                        return;\n                }\n            } else {\n                // invalid command\n                Util.println(\"FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\");\n                Util.println(\"   0 = CUMULATIVE GALACTIC RECORD\");\n                Util.println(\"   1 = STATUS REPORT\");\n                Util.println(\"   2 = PHOTON TORPEDO DATA\");\n                Util.println(\"   3 = STARBASE NAV DATA\");\n                Util.println(\"   4 = DIRECTION/DISTANCE CALCULATOR\");\n                Util.println(\"   5 = GALAXY 'REGION NAME' MAP\");\n                Util.println(\"\");\n            }\n        }\n    }\n\n    void statusReport() {\n        Util.println(\"   STATUS REPORT:\");\n        Util.println(\"KLINGON\" + ((galaxyMap.getKlingonsInGalaxy() > 1)? \"S\" : \"\")  + \" LEFT: \" + galaxyMap.getKlingonsInGalaxy());\n        Util.println(\"MISSION MUST BE COMPLETED IN \" + .1 * Util.toInt((initialStardate + missionDuration - stardate) * 10) + \" STARDATES\");\n        if (galaxyMap.getBasesInGalaxy() >= 1) {\n            Util.println(\"THE FEDERATION IS MAINTAINING \" + galaxyMap.getBasesInGalaxy() + \" STARBASE\" + ((galaxyMap.getBasesInGalaxy() > 1)? \"S\" : \"\") + \" IN THE GALAXY\");\n        } else {\n            Util.println(\"YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN\");\n            Util.println(\"  THE GALAXY -- YOU HAVE NO STARBASES LEFT!\");\n        }\n        galaxyMap.getEnterprise().damageControl(this);\n    }\n\n    public void incrementStardate(double increment) {\n        this.stardate += increment;\n    }\n\n    public void endGameFail(final boolean enterpriseDestroyed) {    // 6220\n        if (enterpriseDestroyed) {\n            Util.println(\"\\nTHE ENTERPRISE HAS BEEN DESTROYED.  THEN FEDERATION \");\n            Util.println(\"WILL BE CONQUERED\");\n        }\n        Util.println(\"\\nIT IS STARDATE \" + stardate);\n        Util.println(\"THERE WERE \" + galaxyMap.getKlingonsInGalaxy() + \" KLINGON BATTLE CRUISERS LEFT AT\");\n        Util.println(\"THE END OF YOUR MISSION.\");\n        repeatGame();\n    }\n\n    public void endGameSuccess() {\n        Util.println(\"CONGRATULATION, CAPTAIN!  THE LAST KLINGON BATTLE CRUISER\");\n        Util.println(\"MENACING THE FEDERATION HAS BEEN DESTROYED.\\n\");\n        Util.println(\"YOUR EFFICIENCY RATING IS \" + (Math.sqrt(1000 * (galaxyMap.getRemainingKlingons() / (stardate - initialStardate)))));\n        repeatGame();\n    }\n\n    void repeatGame() {\n        Util.println(\"\\n\");\n        if (galaxyMap.getBasesInGalaxy() != 0) {\n            Util.println(\"THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER\");\n            Util.println(\"FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,\");\n            final String reply = Util.inputStr(\"LET HIM STEP FORWARD AND ENTER 'AYE'\");\n            if (\"AYE\".equals(reply)) {\n                this.restart = true;\n            } else {\n                System.exit(0);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/java/SuperStarTrekInstructions.java",
    "content": "import java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\n/**\n * SUPER STARTREK INSTRUCTIONS\n * MAR 5, 1978\n * Just the instructions for SUPERSTARTREK\n *\n * Ported to Java in Jan-Feb 2022 by\n * Taciano Dreckmann Perez (taciano.perez@gmail.com)\n */\npublic class SuperStarTrekInstructions {\n\n    public static void main(String[] args) {\n        printBanner();\n        final String reply = inputStr(\"DO YOU NEED INSTRUCTIONS (Y/N)? \");\n        if (\"Y\".equals(reply)) {\n            printInstructions();\n        }\n    }\n\n    static void printBanner() {\n        print(tab(10)+\"*************************************\");\n        print(tab(10)+\"*                                   *\");\n        print(tab(10)+\"*                                   *\");\n        print(tab(10)+\"*      * * SUPER STAR TREK * *      *\");\n        print(tab(10)+\"*                                   *\");\n        print(tab(10)+\"*                                   *\");\n        print(tab(10)+\"*************************************\");\n    }\n\n    static void printInstructions() {\n        print(\"      INSTRUCTIONS FOR 'SUPER STAR TREK'\");\n        print(\"\");\n        print(\"1. WHEN YOU SEE \\\\COMMAND ?\\\\ PRINTED, ENTER ONE OF THE LEGAL\");\n        print(\"     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\");\n        print(\"2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\");\n        print(\"     LIST OF THE LEGAL COMMANDS PRINTED OUT.\");\n        print(\"3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\");\n        print(\"     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\");\n        print(\"     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\");\n        print(\"     WILL BE ABORTED\");\n        print(\"\");\n        print(\"     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\");\n        print(\"AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\");\n        print(\"\");\n        print(\"     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\");\n        print(\"GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\");\n        print(\"\\\\ENTERPRISE\\\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\");\n        print(\"KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\");\n        print(\"PLANETS.\");\n        print(\"\");\n        print(\"     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\");\n        print(\"OF THE STARSHIP ENTERPRISE:\");\n        print(\"\");\n        print(\"\\\\NAV\\\\ COMMAND = WARP ENGINE CONTROL --\");\n        print(\"     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\");\n        print(\"     VECTOR ARRANGEMENT AS SHOWN             . . .\");\n        print(\"     INTEGER AND REAL VALUES MAY BE           ...\");\n        print(\"     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\");\n        print(\"     WAY BETWEEN 1 AND 2                      ...\");\n        print(\"                                             . . .\");\n        print(\"     VALUES MAY APPROACH 9.0, WHICH         6  7  8\");\n        print(\"     ITSELF IS EQUIVALENT TO 1.0\");\n        print(\"                                            COURSE\");\n        print(\"     ONE WARP FACTOR IS THE SIZE OF \");\n        print(\"     ONE QUADTANT.  THEREFORE, TO GET\");\n        print(\"     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\");\n        print(\"     USE COURSE 3, WARP FACTOR 1.\");\n        print(\"\");\n        print(\"\\\\SRS\\\\ COMMAND = SHORT RANGE SENSOR SCAN\");\n        print(\"     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\");\n        print(\"\");\n        print(\"     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\");\n        print(\"        <*> = YOUR STARSHIP'S POSITION\");\n        print(\"        +K+ = KLINGON BATTLE CRUISER\");\n        print(\"        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\");\n        print(\"         *  = STAR\");\n        print(\"\");\n        print(\"     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\");\n        print(\"\");\n        print(\"\\\\LRS\\\\ COMMAND = LONG RANGE SENSOR SCAN\");\n        print(\"     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\");\n        print(\"     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\");\n        print(\"     THE SCAN IS CODED IN THE FORM \\\\###\\\\, WHERE TH UNITS DIGIT\");\n        print(\"     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\");\n        print(\"     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF\");\n        print(\"     KLINGONS.\");\n        print(\"\");\n        print(\"     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\");\n        print(\"\");\n        print(\"\\\\PHA\\\\ COMMAND = PHASER CONTROL.\");\n        print(\"     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY \");\n        print(\"     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\");\n        print(\"     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE\");\n        print(\"     PHASERS TOO!)\");\n        print(\"\");\n        print(\"\\\\TOR\\\\ COMMAND = PHOTON TORPEDO CONTROL\");\n        print(\"     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\");\n        print(\"     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\");\n        print(\"     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\");\n        print(\"     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO \");\n        print(\"     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\");\n        print(\"\");\n        print(\"     THE LIBRARY-COMPUTER (\\\\COM\\\\ COMMAND) HAS AN OPTION TO \");\n        print(\"     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\");\n        print(\"\");\n        print(\"\\\\SHE\\\\ COMMAND = SHIELD CONTROL\");\n        print(\"     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\");\n        print(\"     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\");\n        print(\"     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\");\n        print(\"\");\n        print(\"\\\\DAM\\\\ COMMAND = DAMMAGE CONTROL REPORT\");\n        print(\"     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\");\n        print(\"     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\");\n        print(\"     DAMAGED.\");\n        print(\"\");\n        print(\"\\\\COM\\\\ COMMAND = LIBRARY-COMPUTER\");\n        print(\"     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\");\n        print(\"     OPTION 0 = CUMULATIVE GALACTIC RECORD\");\n        print(\"        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\");\n        print(\"        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\");\n        print(\"     OPTION 1 = STATUS REPORT\");\n        print(\"        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\");\n        print(\"        AND STARBASES REMAINING IN THE GAME.\");\n        print(\"     OPTION 2 = PHOTON TORPEDO DATA\");\n        print(\"        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\");\n        print(\"        TO ALL KLINGONS IN YOUR QUADRANT\");\n        print(\"     OPTION 3 = STARBASE NAV DATA\");\n        print(\"        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY \");\n        print(\"        STARBASE WITHIN YOUR QUADRANT\");\n        print(\"     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\");\n        print(\"        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\");\n        print(\"        DIRECTION/DISTANCE CALCULATIONS\");\n        print(\"     OPTION 5 = GALACTIC /REGION NAME/ MAP\");\n        print(\"        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR \");\n        print(\"        GALACTIC REGIONS REFERRED TO IN THE GAME.\");\n    }\n\n    static void print(final String s) {\n        System.out.println(s);\n    }\n\n    static String tab(final int n) {\n        return IntStream.range(1, n).mapToObj(num -> \" \").collect(Collectors.joining());\n    }\n\n    static String inputStr(final String message) {\n        System.out.print(message + \"? \");\n        final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));\n        try {\n            return reader.readLine();\n        } catch (IOException ioe) {\n            ioe.printStackTrace();\n            return \"\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/java/Util.java",
    "content": "import java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\n/**\n * Convenience utility methods for the Super Star Trek game.\n */\npublic class Util {\n\n    static final Random random = new Random();\n\n    public static float random() {\n        return random.nextFloat();\n    }\n\n    public static int fnr() {    // 475\n        // Generate a random integer from 1 to 8 inclusive.\n        return toInt(random() * 7 + 1);\n    }\n\n    public static int toInt(final double num) {\n        int x = (int) Math.floor(num);\n        if (x < 0) x *= -1;\n        return x;\n    }\n\n    public static void println(final String s) {\n        System.out.println(s);\n    }\n\n    public static void print(final String s) {\n        System.out.print(s);\n    }\n\n    public static String tab(final int n) {\n        return IntStream.range(1, n).mapToObj(num -> \" \").collect(Collectors.joining());\n    }\n\n    public static int strlen(final String s) {\n        return s.length();\n    }\n\n    public static String inputStr(final String message) {\n        System.out.print(message + \"? \");\n        final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));\n        try {\n            return reader.readLine();\n        } catch (IOException ioe) {\n            ioe.printStackTrace();\n            return \"\";\n        }\n    }\n\n    public static int[] inputCoords(final String message) {\n        while (true) {\n            final String input = inputStr(message);\n            try {\n                final String[] splitInput = input.split(\",\");\n                if (splitInput.length == 2) {\n                    int x = Integer.parseInt(splitInput[0]);\n                    int y = Integer.parseInt(splitInput[0]);\n                    return new int[]{x, y};\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static float inputFloat(final String message) {\n        while (true) {\n            System.out.print(message + \"? \");\n            final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));\n            try {\n                final String input = reader.readLine();\n                if (input.length() > 0) {\n                    return Float.parseFloat(input);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static String leftStr(final String input, final int len) {\n        if (input == null || input.length() < len) return input;\n        return input.substring(0, len);\n    }\n\n    public static String midStr(final String input, final int start, final int len) {\n        if (input == null || input.length() < ((start - 1) + len)) return input;\n        return input.substring(start - 1, (start - 1) + len);\n    }\n\n    public static String rightStr(final String input, final int len) {\n        if (input == null || input.length() < len) return \"\";\n        return input.substring(input.length() - len);\n    }\n\n    public static double round(double value, int places) {\n        if (places < 0) throw new IllegalArgumentException();\n        BigDecimal bd = new BigDecimal(Double.toString(value));\n        bd = bd.setScale(places, RoundingMode.HALF_UP);\n        return bd.doubleValue();\n    }\n\n\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic][def]\n\nConversion to [****J****avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n\n\n[def]: http://www.vintage-basic.net/games.html"
  },
  {
    "path": "84_Super_Star_Trek/javascript/cli.mjs",
    "content": "import {\n  onExit,\n  onPrint,\n  onInput,\n  gameMain,\n} from \"./superstartrek.mjs\";\n\nimport readline from \"readline\";\n\nonExit(function exit() {\n  process.exit();\n});\n\nonPrint(function print(...messages) {\n  console.log(messages.join(\"\"));\n});\n\nonInput(async function input(prompt) {\n  const rl = readline.createInterface({\n    input: process.stdin,\n    output: process.stdout,\n    terminal: false,\n  });\n  return new Promise((resolve, reject) => {\n    rl.question(`${prompt}? `, (response) => {\n      rl.close();\n      resolve(response);\n    });\n  });\n});\n\ngameMain().then(process.exit).catch(console.log);\n"
  },
  {
    "path": "84_Super_Star_Trek/javascript/index.html",
    "content": "<html>\n  <head>\n    <title>Super Star Trek</title>\n    <meta charset=\"UTF-8\" />\n    <link\n      rel=\"stylesheet\"\n      href=\"https://unpkg.com/xterm@4.10.0/css/xterm.css\"\n    />\n    <style type=\"text/css\">\n      html,\n      body {\n        padding: 0;\n        margin: 0;\n        background: rgba(0, 0, 0, 0.7);\n        color: rgba(192, 255, 192, 0.8);\n      }\n      a {\n        color: rgba(192, 255, 192, 1);\n      }\n      .game {\n        display: flex;\n        flex-direction: row;\n        width: 100%;\n        height: 100%;\n      }\n      .terminalFrame {\n        background: rgba(0, 0, 0, 1);\n        padding: 1.25em;\n        width: calc(100% - 2.5em);\n        height: calc(100% - 2.5em);\n      }\n      .terminal {\n        width: 100%;\n        height: 100%;\n      }\n      .instructions {\n        width: 100%;\n        padding: 1em 2em;\n        overflow-y: scroll;\n      }\n    </style>\n  </head>\n  <body>\n    <section class=\"game\">\n      <div class=\"terminalFrame\">\n        <div class=\"terminal\"></div>\n      </div>\n      <div class=\"instructions\">\n        <h1>Super Star Trek</h1>\n        <p>\n          Originally found in\n          <a\n            href=\"https://www.atariarchives.org/basicgames/showpage.php?page=157\"\n            >David Ahl's BASIC Computer Games (1978)</a\n          >\n        </p>\n        <p>\n          <a\n            href=\"https://github.com/lmorchard/basic-computer-games/tree/84-js-super-star-trek/84%20Super%20Star%20Trek/javascript\"\n            >Converted to JavaScript</a\n          >\n          in February 2021\n          by <a href=\"https://lmorchard.com\">Les Orchard</a>\n          &lt;me@lmorchard.com&gt;\n        </p>\n\n        <pre>\n      INSTRUCTIONS FOR 'SUPER STAR TREK'\n\n1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL\n     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\n\n2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\n     LIST OF THE LEGAL COMMANDS PRINTED OUT.\n\n3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\n     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\n     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\n     WILL BE ABORTED\n     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\nAND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\n     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\nGALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\n\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\nKLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\nPLANETS.\n\n     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\nOF THE STARSHIP ENTERPRISE:\n\n\\NAV\\ COMMAND = WARP ENGINE CONTROL --\n     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\n     VECTOR ARRANGEMENT AS SHOWN             . . .\n     INTEGER AND REAL VALUES MAY BE           ...\n     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\n     WAY BETWEEN 1 AND 2                      ...\n                                             . . .\n     VALUES MAY APPROACH 9.0, WHICH         6  7  8\n     ITSELF IS EQUIVALENT TO 1.0\"\n                                            COURSE\n     ONE WARP FACTOR IS THE SIZE OF\n     ONE QUADTANT.  THEREFORE, TO GET\n     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\n     USE COURSE 3, WARP FACTOR 1.\n\n\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN\n     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\n     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\n        <*> = YOUR STARSHIP'S POSITION\n        +K+ = KLINGON BATTLE CRUISER\n        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\n         *  = STAR\n     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\n\n\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN\n     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\n     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\n     THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT\n     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\n     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF\n     KLINGONS.\n     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\n\n\\PHA\\ COMMAND = PHASER CONTROL.\n     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY\n     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\n     DEPLETE THEIR SHIELD POWER.  (REMBER, KLINGONS HAVE\n     PHASERS TOO!)\n\n\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL\n     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\n     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\n     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\n     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO\n     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\n     THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO\n     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\n\n\\SHE\\ COMMAND = SHIELD CONTROL\n     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\n     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\n     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\n\n\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT\n     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\n     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\n     DAMAGED.\"\n\n\\COM\\ COMMAND = LIBRARY-COMPUTER\n     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\n     OPTION 0 = CUMULATIVE GALACTIC RECORD\n        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\n        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\n     OPTION 1 = STATUS REPORT\n        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\n        AND STARBASES REMAINING IN THE GAME.\n     OPTION 2 = PHOTON TORPEDO DATA\n        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\n        TO ALL KLINGONS IN YOUR QUADRANT\n     OPTION 3 = STARBASE NAV DATA\n        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY\n        STARBASE WITHIN YOUR QUADRANT\n     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\n        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\n        DIRECTION/DISTANCE CALCULATIONS\n     OPTION 5 = GALACTIC /REGION NAME/ MAP\n        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR\n        GALACTIC REGIONS REFERRED TO IN THE GAME.\n    </pre\n        >\n      </div>\n    </section>\n\n    <script src=\"https://unpkg.com/xterm@4.10.0/lib/xterm.js\"></script>\n    <script src=\"https://unpkg.com/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.js\"></script>\n\n    <script type=\"module\">\n      import {\n        onExit,\n        onPrint,\n        onInput,\n        setGameOptions,\n        getGameState,\n        gameMain,\n      } from \"./superstartrek.mjs\";\n\n      var term = new Terminal({\n        fontSize: 14,\n      });\n      const fitAddon = new FitAddon.FitAddon();\n      term.loadAddon(fitAddon);\n      term.open(document.querySelector(\".terminal\"));\n      fitAddon.fit();\n      term.focus();\n\n      function print(...messages) {\n        term.write(messages.join(\"\").replace(/\\n/g, \"\\r\\n\") + \"\\r\\n\");\n      }\n\n      function input(prompt) {\n        return new Promise((resolve) => {\n          let str = \"\";\n          term.write(`${prompt}? `);\n          const initialX = term._core.buffer.x;\n          const disposeOnData = term.onData((data) => {\n            if (data == \"\\n\" || data == \"\\r\") {\n              term.write(\"\\r\\n\");\n              disposeOnData.dispose();\n              resolve(str);\n            } else if (/^[a-zA-Z0-9,\\.]+$/.test(data)) {\n              str += data;\n              term.write(data);\n            } else if (data == \"\\u007F\" && str.length > 0) {\n              str = str.slice(0, -1);\n              term.write(\"\\b \\b\");\n            }\n          });\n        });\n      }\n\n      async function exit() {\n        print();\n        await input(\"GAME EXITED, PRESS ENTER TO RESTART\");\n        window.location.reload();\n      }\n\n      onPrint(print);\n      onInput(input);\n      onExit(exit);\n\n      gameMain().then().catch(window.alert);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "84_Super_Star_Trek/javascript/package.json",
    "content": "{\n  \"name\": \"super-star-trek\",\n  \"version\": \"1.0.0\",\n  \"description\": \"As published in Basic Computer Games (1978) https://www.atariarchives.org/basicgames/showpage.php?page=157\",\n  \"main\": \"superstartrek.mjs\",\n  \"scripts\": {\n    \"start\": \"node cli.mjs\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"eslint\": \"^7.20.0\"\n  }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/javascript/superstartrek.mjs",
    "content": "/**\n * SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY\n *\n *        **** STAR TREK ****        ****\n * SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n * AS SEEN ON THE STAR TREK TV SHOW.\n * ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n * PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n * MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n * LEEDOM - APRIL & DECEMBER 1974,\n * WITH A LITTLE HELP FROM HIS FRIENDS . . .\n * COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --\n * SEND TO:  R. C. LEEDOM\n *           WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.\n *           BOX 746, M.S. 338\n *           BALTIMORE, MD  21203\n *\n * CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS\n * LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS\n * MUCH AS POSSIBLE WHILE USING MULTIPLE STATEMENTS PER LINE\n * SOME LINES ARE LONGER THAN 72 CHARACTERS; THIS WAS DONE\n * BY USING \"?\" INSTEAD OF \"PRINT\" WHEN ENTERING LINES\n *\n * Translated and reworked into JavaScript in February 2021\n * by Les Orchard <me@lmorchard.com>\n */\n\nexport const setGameOptions = (options = {}) =>\n  Object.assign(gameOptions, options);\nexport const getGameState = () => ({ ...gameState });\nexport const onPrint = (fn) => (print = fn);\nexport const onInput = (fn) => (input = fn);\nexport const onExit = (fn) => (exit = fn);\n\nexport async function gameMain() {\n  await gameReset();\n  await gameLoop();\n  await exit();\n}\n\nlet gameState = {};\nlet print = () => {};\nlet input = () => {};\nlet exit = () => {};\n\nexport const gameOptions = {\n  stardateStart: Math.floor(Math.random() * 20 + 20) * 100,\n  timeLimit: 25 + Math.floor(Math.random() * 10),\n  energyMax: 3000,\n  photonTorpedoesMax: 10,\n  starbaseSpawnChance: 0.96,\n  enemyMaxShield: 200,\n  enemySpawnChance: [0.8, 0.85, 0.98],\n  maxStarsPerSector: 8,\n  sectorWidth: 8,\n  sectorHeight: 8,\n  galaxyWidth: 8,\n  galaxyHeight: 8,\n  systemDamageChanceOnHit: 0.6,\n  systemDamageHitThroughShields: 0.02,\n  systemChanceAffectedInWarp: 0.2,\n  systemChanceDamageInWarp: 0.6,\n  nameEnemy: \"KLINGON\",\n  nameEnemies: \"KLINGONS\",\n  nameScienceOfficer: \"SPOCK\",\n  nameNavigationOfficer: \"LT. SULU\",\n  nameWeaponsOfficer: \"ENSIGN CHEKOV\",\n  nameCommunicationsOfficer: \"LT. UHURA\",\n  nameChiefEngineer: \"SCOTT\",\n  sectorMapSymbols: {\n    empty: \"   \",\n    star: \" * \",\n    base: \">!<\",\n    hero: \"<*>\",\n    enemy: \"+K+\",\n  },\n  shipSystems: [\n    \"WARP ENGINES\",\n    \"SHORT RANGE SENSORS\",\n    \"LONG RANGE SENSORS\",\n    \"PHASER CONTROL\",\n    \"PHOTON TUBES\",\n    \"DAMAGE CONTROL\",\n    \"SHIELD CONTROL\",\n    \"LIBRARY-COMPUTER\",\n  ],\n  quadrantNames: [\n    [\n      \"ANTARES\",\n      \"RIGEL\",\n      \"PROCYON\",\n      \"VEGA\",\n      \"CANOPUS\",\n      \"ALTAIR\",\n      \"SAGITTARIUS\",\n      \"POLLUX\",\n    ],\n    [\n      \"SIRIUS\",\n      \"DENEB\",\n      \"CAPELLA\",\n      \"BETELGEUSE\",\n      \"ALDEBARAN\",\n      \"REGULUS\",\n      \"ARCTURUS\",\n      \"SPICA\",\n    ],\n  ],\n  quadrantNumbers: [\"I\", \"II\", \"III\", \"IV\"],\n};\n\nlet SYSTEM_WARP_ENGINES,\n  SYSTEM_SHORT_RANGE_SENSORS,\n  SYSTEM_LONG_RANGE_SENSORS,\n  SYSTEM_PHASER_CONTROL,\n  SYSTEM_PHOTON_TUBES,\n  SYSTEM_DAMAGE_CONTROL,\n  SYSTEM_SHIELD_CONTROL,\n  SYSTEM_LIBRARY_COMPUTER;\n\nasync function gameIntro() {\n  print(\"\\n\".repeat(10));\n  print(\"                                    ,------*------,\");\n  print(\"                    ,-------------   '---  ------'\");\n  print(\"                     '-------- --'      / /\");\n  print(\"                         ,---' '-------/ /--,\");\n  print(\"                          '----------------'\");\n  print(\"\");\n  print(\"                    THE USS ENTERPRISE --- NCC-1701\");\n  print(\"\\n\".repeat(4));\n\n  print(\"YOUR ORDERS ARE AS FOLLOWS:\");\n  print();\n  print(\n    `  DESTROY THE ${gameState.enemiesRemaining} ${gameOptions.nameEnemy} WARSHIPS WHICH HAVE INVADED`\n  );\n  print(\"  THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\");\n  print(\n    `  ON STARDATE ${formatStardate(\n      gameOptions.stardateStart + gameOptions.timeLimit\n    )} THIS GIVES YOU ${gameOptions.timeLimit} DAYS.  THERE${\n      gameState.starbasesRemaining > 1 ? \" ARE \" : \" IS \"\n    }`\n  );\n  print(\n    `  ${gameState.starbasesRemaining} STARBASE${\n      gameState.starbasesRemaining > 1 ? \"S\" : \" ARE\"\n    } IN THE GALAXY FOR RESUPPLYING YOUR SHIP`\n  );\n}\n\nasync function gameReset() {\n  [\n    SYSTEM_WARP_ENGINES,\n    SYSTEM_SHORT_RANGE_SENSORS,\n    SYSTEM_LONG_RANGE_SENSORS,\n    SYSTEM_PHASER_CONTROL,\n    SYSTEM_PHOTON_TUBES,\n    SYSTEM_DAMAGE_CONTROL,\n    SYSTEM_SHIELD_CONTROL,\n    SYSTEM_LIBRARY_COMPUTER,\n  ] = gameOptions.shipSystems;\n\n  gameState = {\n    gameOver: false,\n    gameWon: false,\n    gameQuit: false,\n    destroyed: false,\n    shouldRestart: false,\n    sectorMap: \"\",\n    alertCondition: \"\",\n    stardateCurrent: gameOptions.stardateStart,\n    isDocked: false,\n    energyRemaining: gameOptions.energyMax,\n    photonTorpedoesRemaining: gameOptions.photonTorpedoesMax,\n    shieldsCurrent: 0,\n    starbasesRemaining: 0,\n    enemiesRemaining: 0,\n    quadrantPositionY: randomInt(gameOptions.galaxyHeight, 1),\n    quadrantPositionX: randomInt(gameOptions.galaxyWidth, 1),\n    sectorPositionY: randomInt(gameOptions.sectorHeight, 1),\n    sectorPositionX: randomInt(gameOptions.sectorWidth, 1),\n    sectorEnemiesCount: 0,\n    sectorStarbasesCount: 0,\n    sectorStarsCount: 0,\n    galacticMap: [],\n    galacticMapDiscovered: [],\n  };\n\n  gameState.systemsDamage = {};\n  for (const systemName of gameOptions.shipSystems) {\n    gameState.systemsDamage[systemName] = 0;\n  }\n\n  for (let mapY = 1; mapY <= gameOptions.galaxyHeight; mapY++) {\n    gameState.galacticMap[mapY] = [];\n    gameState.galacticMapDiscovered[mapY] = [];\n    for (let mapX = 1; mapX <= gameOptions.galaxyWidth; mapX++) {\n      gameState.galacticMapDiscovered[mapY][mapX] = 0;\n\n      gameState.sectorEnemiesCount = 0;\n\n      const enemySpawnRoll = Math.random();\n      if (enemySpawnRoll > gameOptions.enemySpawnChance[2]) {\n        gameState.sectorEnemiesCount = 3;\n        gameState.enemiesRemaining = gameState.enemiesRemaining + 3;\n      } else if (enemySpawnRoll > gameOptions.enemySpawnChance[1]) {\n        gameState.sectorEnemiesCount = 2;\n        gameState.enemiesRemaining = gameState.enemiesRemaining + 2;\n      } else if (enemySpawnRoll > gameOptions.enemySpawnChance[0]) {\n        gameState.sectorEnemiesCount = 1;\n        gameState.enemiesRemaining = gameState.enemiesRemaining + 1;\n      }\n\n      gameState.sectorStarbasesCount = 0;\n      if (Math.random() > gameOptions.starbaseSpawnChance) {\n        gameState.sectorStarbasesCount = 1;\n        gameState.starbasesRemaining = gameState.starbasesRemaining + 1;\n      }\n\n      // 1040\n      gameState.galacticMap[mapY][mapX] =\n        gameState.sectorEnemiesCount * 100 +\n        gameState.sectorStarbasesCount * 10 +\n        randomInt(gameOptions.maxStarsPerSector, 1);\n    }\n  }\n\n  if (gameState.enemiesRemaining > gameOptions.timeLimit) {\n    // Ensure the player has at least one more stardate than the number of enemies\n    gameOptions.timeLimit = gameState.enemiesRemaining + 1;\n  }\n\n  if (gameState.starbasesRemaining === 0) {\n    if (\n      gameState.galacticMap[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] < 200\n    ) {\n      gameState.galacticMap[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] =\n        gameState.galacticMap[gameState.quadrantPositionY][\n          gameState.quadrantPositionX\n        ] + 120;\n    }\n    gameState.enemiesRemaining = gameState.enemiesRemaining + 1;\n    gameState.starbasesRemaining = 1;\n    gameState.galacticMap[gameState.quadrantPositionY][\n      gameState.quadrantPositionX\n    ] =\n      gameState.galacticMap[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] + 10;\n    gameState.quadrantPositionY = randomInt(gameOptions.galaxyHeight, 1);\n    gameState.quadrantPositionX = randomInt(gameOptions.galaxyWidth, 1);\n  }\n\n  gameState.enemiesInitialCount = gameState.enemiesRemaining;\n\n  await gameIntro();\n  await newQuadrantEntered();\n}\n\nasync function newQuadrantEntered() {\n  gameState.sectorEnemiesCount = 0;\n  gameState.sectorStarbasesCount = 0;\n  gameState.sectorStarsCount = 0;\n  gameState.starbaseRepairDelay = 0.5 * Math.random();\n\n  // Add this sector to the known map\n  gameState.galacticMapDiscovered[gameState.quadrantPositionY][\n    gameState.quadrantPositionX\n  ] =\n    gameState.galacticMap[gameState.quadrantPositionY][\n      gameState.quadrantPositionX\n    ];\n\n  // Initialize a sector enemy for each that had a chance to spawn\n  gameState.sectorEnemies = gameOptions.enemySpawnChance.map((c) => ({\n    health: 0,\n    posY: 0,\n    posX: 0,\n  }));\n\n  if (\n    gameState.quadrantPositionY >= 1 &&\n    gameState.quadrantPositionY <= gameOptions.galaxyHeight &&\n    gameState.quadrantPositionX >= 1 &&\n    gameState.quadrantPositionX <= gameOptions.galaxyWidth\n  ) {\n    let currentQuadrantName = buildQuadrantName(\n      gameState.quadrantPositionY,\n      gameState.quadrantPositionX\n    );\n    print();\n    if (gameOptions.stardateStart == gameState.stardateCurrent) {\n      print(\"YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\");\n      print(`IN THE GALACTIC QUADRANT, '${currentQuadrantName}'.`);\n    } else {\n      print(`NOW ENTERING ${currentQuadrantName} QUADRANT . . .`);\n    }\n    print();\n    gameState.sectorEnemiesCount = Math.floor(\n      gameState.galacticMap[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] * 0.01\n    );\n    gameState.sectorStarbasesCount =\n      Math.floor(\n        gameState.galacticMap[gameState.quadrantPositionY][\n          gameState.quadrantPositionX\n        ] * 0.1\n      ) -\n      10 * gameState.sectorEnemiesCount;\n    gameState.sectorStarsCount =\n      gameState.galacticMap[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] -\n      100 * gameState.sectorEnemiesCount -\n      10 * gameState.sectorStarbasesCount;\n\n    if (gameState.sectorEnemiesCount != 0) {\n      print(\"COMBAT AREA      CONDITION RED\");\n      if (gameState.shieldsCurrent <= 200) {\n        print(\"   SHIELDS DANGEROUSLY LOW\");\n      }\n    }\n\n    for (\n      let enemyIdx = 0;\n      enemyIdx < gameOptions.enemySpawnChance.length;\n      enemyIdx++\n    ) {\n      gameState.sectorEnemies[enemyIdx].posY = 0;\n      gameState.sectorEnemies[enemyIdx].posX = 0;\n    }\n  }\n\n  for (\n    let enemyIdx = 0;\n    enemyIdx < gameOptions.enemySpawnChance.length;\n    enemyIdx++\n  ) {\n    gameState.sectorEnemies[enemyIdx].health = 0;\n  }\n\n  gameState.sectorMap = \" \".repeat(\n    gameOptions.sectorMapSymbols.empty.length *\n      gameOptions.sectorHeight *\n      gameOptions.sectorWidth\n  );\n\n  insertInSectorMap(\n    gameOptions.sectorMapSymbols.hero,\n    gameState.sectorPositionY,\n    gameState.sectorPositionX\n  );\n\n  if (gameState.sectorEnemiesCount >= 1) {\n    // 1720\n    for (\n      let enemyIdx = 0;\n      enemyIdx < gameState.sectorEnemiesCount;\n      enemyIdx++\n    ) {\n      const [posY, posX] = findSpaceInSectorMap();\n      insertInSectorMap(gameOptions.sectorMapSymbols.enemy, posY, posX);\n      gameState.sectorEnemies[enemyIdx] = {\n        posY,\n        posX,\n        health: gameOptions.enemyMaxShield * (0.5 + Math.random()),\n      };\n    }\n  }\n\n  if (gameState.sectorStarbasesCount >= 1) {\n    const [R1, R2] = findSpaceInSectorMap();\n    gameState.sectorStarbaseY = R1;\n    gameState.sectorStarbaseX = R2;\n    insertInSectorMap(gameOptions.sectorMapSymbols.base, R1, R2);\n  }\n\n  for (let i = 1; i <= gameState.sectorStarsCount; i++) {\n    insertInSectorMap(\n      gameOptions.sectorMapSymbols.star,\n      ...findSpaceInSectorMap()\n    );\n  }\n\n  return shortRangeSensorScanAndStartup();\n}\n\nasync function gameLoop() {\n  while (!gameState.gameOver) {\n    await acceptCommand();\n    if (gameState.gameOver) {\n      await endOfGame();\n    }\n    if (gameState.shouldRestart) {\n      await gameReset();\n    }\n  }\n}\n\nasync function acceptCommand() {\n  if (\n    gameState.shieldsCurrent + gameState.energyRemaining <= 10 ||\n    (gameState.energyRemaining < 10 &&\n      gameState.systemsDamage[SYSTEM_SHIELD_CONTROL] != 0)\n  ) {\n    print();\n    print(\"** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP IN SPACE\");\n    print(\"YOU HAVE INSUFFICIENT MANEUVERING ENERGY, AND SHIELD CONTROL\");\n    print(\"IS PRESENTLY INCAPABLE OF CROSS-CIRCUITING TO ENGINE ROOM!!\");\n    print();\n    gameState.gameOver = true;\n    return;\n  }\n\n  const commandInput = (await input(\"COMMAND\")).trim().toUpperCase();\n  const command = COMMANDS[commandInput] || commandHelp;\n  await command();\n}\n\n/************************************************************************/\n\nconst COMMANDS = {\n  NAV: commandCourseControl,\n  SRS: shortRangeSensorScanAndStartup,\n  LRS: commandLongRangeScan,\n  PHA: commandPhaserControl,\n  TOR: commandPhotonTorpedo,\n  SHE: commandShieldControl,\n  DAM: commandDamageControl,\n  COM: commandLibraryComputer,\n  XXX: () => {\n    // todo more confirmation here?\n    gameState.gameOver = true;\n    gameState.gameQuit = true;\n  },\n  DUMP: () => {\n    console.log(JSON.stringify(gameState));\n  },\n};\n\nasync function commandHelp() {\n  print(\"ENTER ONE OF THE FOLLOWING:\");\n  print(\"  NAV  (TO SET COURSE)\");\n  print(\"  SRS  (FOR SHORT RANGE SENSOR SCAN)\");\n  print(\"  LRS  (FOR LONG RANGE SENSOR SCAN)\");\n  print(\"  PHA  (TO FIRE PHASERS)\");\n  print(\"  TOR  (TO FIRE PHOTON TORPEDOES)\");\n  print(\"  SHE  (TO RAISE OR LOWER SHIELDS)\");\n  print(\"  DAM  (FOR DAMAGE CONTROL REPORTS)\");\n  print(\"  COM  (TO CALL ON LIBRARY-COMPUTER)\");\n  print(\"  XXX  (TO RESIGN YOUR COMMAND)\");\n  print();\n}\n\nasync function shortRangeSensorScanAndStartup() {\n  checkIfDocked();\n\n  if (gameState.isDocked) {\n    gameState.alertCondition = \"DOCKED\";\n    gameState.energyRemaining = gameOptions.energyMax;\n    gameState.photonTorpedoesRemaining = gameOptions.photonTorpedoesMax;\n    print(\"SHIELDS DROPPED FOR DOCKING PURPOSES\");\n    gameState.shieldsCurrent = 0;\n  } else {\n    gameState.alertCondition = \"GREEN\";\n    if (gameState.energyRemaining < gameOptions.energyMax * 0.1)\n      gameState.alertCondition = \"YELLOW\";\n    if (gameState.sectorEnemiesCount > 0) gameState.alertCondition = \"RED\";\n  }\n\n  if (gameState.systemsDamage[SYSTEM_SHORT_RANGE_SENSORS] < 0) {\n    print();\n    print(\"*** SHORT RANGE SENSORS ARE OUT ***\");\n    print();\n    return;\n  }\n\n  const statusLines = [\n    `STARDATE           ${formatStardate(gameState.stardateCurrent)}`,\n    `CONDITION          ${gameState.alertCondition}`,\n    `QUADRANT           ${gameState.quadrantPositionY} , ${gameState.quadrantPositionX}`,\n    `SECTOR             ${gameState.sectorPositionY} , ${gameState.sectorPositionX}`,\n    `PHOTON TORPEDOES   ${gameState.photonTorpedoesRemaining}`,\n    `TOTAL ENERGY       ${\n      gameState.energyRemaining + gameState.shieldsCurrent\n    }`,\n    `SHIELDS            ${gameState.shieldsCurrent}`,\n    `${gameOptions.nameEnemies} REMAINING ${gameState.enemiesRemaining}`,\n  ];\n\n  const lineSplit = new RegExp(\n    `.{${gameOptions.sectorMapSymbols.empty.length * gameOptions.sectorWidth}}`,\n    \"g\"\n  );\n  const cellSplit = new RegExp(\n    `.{${gameOptions.sectorMapSymbols.empty.length}}`,\n    \"g\"\n  );\n  const borderLine = \"-\".repeat(\n    (gameOptions.sectorMapSymbols.empty.length + 1) * gameOptions.sectorWidth\n  );\n  print(borderLine);\n  print(\n    gameState.sectorMap\n      // Split the map into lines of 24 chars\n      .match(lineSplit)\n      // Split each line into cells of 3 chars\n      .map((line) => line.match(cellSplit))\n      // Format each line with Y coord, spaced out cells, and a line of status\n      .map((line, idx) => line.join(\" \") + \" \".repeat(4) + statusLines[idx])\n      // Finally, join all the lines with returns\n      .join(\"\\n\")\n  );\n  print(borderLine);\n  print();\n}\n\nfunction checkIfDocked() {\n  const { sectorPositionY: sY, sectorPositionX: sX } = gameState;\n  for (let posY = sY - 1; posY <= sY + 1; posY++) {\n    for (let posX = sX - 1; posX <= sX + 1; posX++) {\n      if (\n        posY >= 1 ||\n        posY <= gameOptions.sectorHeight ||\n        posX >= 1 ||\n        posX <= gameOptions.sectorWidth\n      ) {\n        if (findInsectorMap(gameOptions.sectorMapSymbols.base, posY, posX)) {\n          gameState.isDocked = true;\n          return;\n        }\n      }\n    }\n  }\n  gameState.isDocked = false;\n}\n\nasync function commandCourseControl() {\n  let courseInput = parseFloat(await input(\"COURSE (0-9)\"));\n  if (courseInput == 9) courseInput = 1;\n  if (isNaN(courseInput) || courseInput < 1 || courseInput > 9) {\n    print(\n      `   ${gameOptions.nameNavigationOfficer} REPORTS, 'INCORRECT COURSE DATA, SIR!'`\n    );\n    return;\n  }\n\n  const warpFactorInput = parseFloat(\n    await input(\n      `WARP FACTOR (0-${\n        gameState.systemsDamage[SYSTEM_WARP_ENGINES] < 0 ? \"0.2\" : \"8\"\n      })`\n    )\n  );\n  if (warpFactorInput == 0 || isNaN(warpFactorInput)) return;\n  if (\n    gameState.systemsDamage[SYSTEM_WARP_ENGINES] < 0 &&\n    warpFactorInput > 0.2\n  ) {\n    return print(\"WARP ENGINES ARE DAMAGED.  MAXIMUM SPEED = WARP 0.2\");\n  }\n  if (warpFactorInput < 0 && warpFactorInput > 8) {\n    return print(\n      `   CHIEF ENGINEER ${gameOptions.nameChiefEngineer} REPORTS 'THE ENGINES WON'T TAKE WARP ${warpFactorInput}!'`\n    );\n  }\n\n  // FIXME: This seems to depend on square sectors - which we have, but could be changed in config\n  const sectorsToWarp = Math.floor(warpFactorInput * gameOptions.sectorWidth + 0.5);\n\n  if (gameState.energyRemaining - sectorsToWarp < 0) {\n    print(\"ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE\");\n    print(\n      \"                       FOR MANEUVERING AT WARP \",\n      warpFactorInput,\n      \" !'\"\n    );\n    if (\n      gameState.shieldsCurrent > sectorsToWarp - gameState.energyRemaining &&\n      gameState.systemsDamage[SYSTEM_SHIELD_CONTROL] > 0\n    ) {\n      print(\n        \"DEFLECTOR CONTROL ROOM ACKNOWLEDGES \",\n        gameState.shieldsCurrent,\n        \" UNITS OF ENERGY\"\n      );\n      print(\"                         PRESENTLY DEPLOYED TO SHIELDS.\");\n    }\n  }\n\n  for (\n    let enemyIdx = 0;\n    enemyIdx < gameOptions.enemySpawnChance.length;\n    enemyIdx++\n  ) {\n    if (gameState.sectorEnemies[enemyIdx].health > 0) {\n      insertInSectorMap(\n        gameOptions.sectorMapSymbols.empty,\n        gameState.sectorEnemies[enemyIdx].posY,\n        gameState.sectorEnemies[enemyIdx].posX\n      );\n      const [rY, rX] = findSpaceInSectorMap();\n      gameState.sectorEnemies[enemyIdx].posY = rY;\n      gameState.sectorEnemies[enemyIdx].posX = rX;\n      insertInSectorMap(\n        gameOptions.sectorMapSymbols.enemy,\n        gameState.sectorEnemies[enemyIdx].posY,\n        gameState.sectorEnemies[enemyIdx].posX\n      );\n    }\n  }\n\n  enemiesShoot();\n\n  let damageControlHeaderPrinted = false;\n  const printDamageReport = (msg) => {\n    if (!damageControlHeaderPrinted) {\n      damageControlHeaderPrinted = true;\n      print(\"DAMAGE CONTROL REPORT:\");\n    }\n    print(msg);\n  };\n\n  let repairFactorDuringWarp = Math.min(1, warpFactorInput);\n\n  // Continually repair damaged systems during warp\n  for (const systemName of gameOptions.shipSystems) {\n    if (gameState.systemsDamage[systemName] >= 0) continue;\n\n    gameState.systemsDamage[systemName] =\n      gameState.systemsDamage[systemName] + repairFactorDuringWarp;\n\n    if (\n      gameState.systemsDamage[systemName] > -0.1 &&\n      gameState.systemsDamage[systemName] < 0\n    ) {\n      gameState.systemsDamage[systemName] = -0.1;\n      continue;\n    }\n\n    if (gameState.systemsDamage[systemName] < 0) continue;\n\n    printDamageReport(`        ${systemName} REPAIR COMPLETED.`);\n  }\n\n  // 20% chance of a random system being damaged, repaired, or improved in warp\n  if (Math.random() < gameOptions.systemChanceAffectedInWarp) {\n    const systemIdx = randomInt(gameOptions.shipSystems.length);\n    const systemName = gameOptions.shipSystems[systemIdx];\n\n    if (Math.random() < gameOptions.systemChanceDamageInWarp) {\n      // 60% chance of random system damage\n      gameState.systemsDamage[systemName] =\n        gameState.systemsDamage[systemName] - (Math.random() * 5 + 1);\n      printDamageReport(`        ${systemName} DAMAGED`);\n    } else {\n      // 40% chance of random system repair or improvement\n      gameState.systemsDamage[systemName] =\n        gameState.systemsDamage[systemName] + Math.random() * 3 + 1;\n      printDamageReport(`        ${systemName} STATE OF REPAIR IMPROVED`);\n    }\n    print();\n  }\n\n  // 3060 REM BEGIN MOVING STARSHIP\n  insertInSectorMap(\n    gameOptions.sectorMapSymbols.empty,\n    Math.floor(gameState.sectorPositionY),\n    Math.floor(gameState.sectorPositionX)\n  );\n\n  const [courseDeltaY, courseDeltaX] = courseToDeltaXY(courseInput);\n  let currentSectorPositionY = gameState.sectorPositionY;\n  let currentSectorPositionX = gameState.sectorPositionX;\n  let currentQuadrantPosY = gameState.quadrantPositionY;\n  let currentQuadrantPosX = gameState.quadrantPositionX;\n\n  for (let sectorsWarped = 1; sectorsWarped < sectorsToWarp; sectorsWarped++) {\n    gameState.sectorPositionY = gameState.sectorPositionY + courseDeltaY;\n    gameState.sectorPositionX = gameState.sectorPositionX + courseDeltaX;\n\n    if (\n      gameState.sectorPositionY < 1 ||\n      gameState.sectorPositionY >= 9 ||\n      gameState.sectorPositionX < 1 ||\n      gameState.sectorPositionX >= 9\n    ) {\n      // 3490 REM EXCEEDED QUADRANT LIMITS\n      currentSectorPositionY =\n        gameOptions.sectorHeight * gameState.quadrantPositionY +\n        currentSectorPositionY +\n        sectorsToWarp * courseDeltaY;\n\n      currentSectorPositionX =\n        gameOptions.sectorWidth * gameState.quadrantPositionX +\n        currentSectorPositionX +\n        sectorsToWarp * courseDeltaX;\n\n      gameState.quadrantPositionY = Math.floor(currentSectorPositionY / 8);\n      gameState.quadrantPositionX = Math.floor(currentSectorPositionX / 8);\n\n      gameState.sectorPositionY = Math.floor(\n        currentSectorPositionY - gameState.quadrantPositionY * 8\n      );\n      gameState.sectorPositionX = Math.floor(\n        currentSectorPositionX - gameState.quadrantPositionX * 8\n      );\n\n      if (gameState.sectorPositionY == 0) {\n        gameState.quadrantPositionY = gameState.quadrantPositionY - 1;\n        gameState.sectorPositionY = 8;\n      }\n      if (gameState.sectorPositionX == 0) {\n        gameState.quadrantPositionX = gameState.quadrantPositionX - 1;\n        gameState.sectorPositionX = 8;\n      }\n\n      let galacticPerimeterHit = false;\n      if (gameState.quadrantPositionY < 1) {\n        galacticPerimeterHit = true;\n        gameState.quadrantPositionY = 1;\n        gameState.sectorPositionY = 1;\n      }\n      if (gameState.quadrantPositionY > 8) {\n        galacticPerimeterHit = true;\n        gameState.quadrantPositionY = 8;\n        gameState.sectorPositionY = 8;\n      }\n      if (gameState.quadrantPositionX < 1) {\n        galacticPerimeterHit = true;\n        gameState.quadrantPositionX = 1;\n        gameState.sectorPositionX = 1;\n      }\n      if (gameState.quadrantPositionX > 8) {\n        galacticPerimeterHit = true;\n        gameState.quadrantPositionX = 8;\n        gameState.sectorPositionX = 8;\n      }\n\n      if (galacticPerimeterHit) {\n        print(\n          `${gameOptions.nameCommunicationsOfficer} REPORTS MESSAGE FROM STARFLEET COMMAND:`\n        );\n        print(\"  'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER\");\n        print(\"  IS HEREBY *DENIED*.  SHUT DOWN YOUR ENGINES.'\");\n        print(\n          `CHIEF ENGINEER ${gameOptions.nameChiefEngineer} REPORTS  'WARP ENGINES SHUT DOWN`\n        );\n        print(\n          `  AT SECTOR ${gameState.sectorPositionY} , ${gameState.sectorPositionX} OF QUADRANT ${gameState.quadrantPositionY} , ${gameState.quadrantPositionX}.'`\n        );\n\n        if (checkIfTimeExpired()) {\n          return;\n        }\n      }\n\n      if (\n        gameOptions.sectorHeight * gameState.quadrantPositionY + gameState.quadrantPositionX ==\n        gameOptions.sectorHeight * currentQuadrantPosY + currentQuadrantPosX\n      ) {\n        break;\n      }\n\n      gameState.stardateCurrent = gameState.stardateCurrent + 1;\n      consumeEnergyForWarp(sectorsToWarp);\n      return newQuadrantEntered();\n    }\n\n    if (\n      !findInsectorMap(\n        gameOptions.sectorMapSymbols.empty,\n        gameState.sectorPositionY,\n        gameState.sectorPositionX\n      )\n    ) {\n      // Undo this step of warp travel if the space isn't empty\n      gameState.sectorPositionY = Math.floor(\n        gameState.sectorPositionY - courseDeltaY\n      );\n      gameState.sectorPositionX = Math.floor(\n        gameState.sectorPositionX - courseDeltaX\n      );\n      print(\n        `WARP ENGINES SHUT DOWN AT SECTOR ${gameState.sectorPositionY} , ${gameState.sectorPositionX} DUE TO BAD NAVAGATION`\n      );\n      break;\n    }\n  }\n\n  gameState.sectorPositionY = Math.floor(gameState.sectorPositionY);\n  gameState.sectorPositionX = Math.floor(gameState.sectorPositionX);\n\n  insertInSectorMap(\n    gameOptions.sectorMapSymbols.hero,\n    Math.floor(gameState.sectorPositionY),\n    Math.floor(gameState.sectorPositionX)\n  );\n\n  consumeEnergyForWarp(sectorsToWarp);\n\n  let timeElapsedDuringWarp = 1;\n  if (warpFactorInput < 1) {\n    timeElapsedDuringWarp = 0.1 * Math.floor(10 * warpFactorInput);\n  }\n\n  gameState.stardateCurrent = gameState.stardateCurrent + timeElapsedDuringWarp;\n  if (checkIfTimeExpired()) {\n    return;\n  }\n\n  await shortRangeSensorScanAndStartup();\n}\n\nfunction checkIfTimeExpired() {\n  if (\n    gameState.stardateCurrent >\n    gameOptions.stardateStart + gameOptions.timeLimit\n  ) {\n    gameState.gameOver = true;\n  }\n  return gameState.gameOver;\n}\n\nfunction consumeEnergyForWarp(sectorsToWarp) {\n  // 3900 REM MANEUVER ENERGY S/R **\n  gameState.energyRemaining = gameState.energyRemaining - sectorsToWarp - 10;\n  if (gameState.energyRemaining >= 0) {\n    return;\n  }\n\n  print(\"SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.\");\n  gameState.shieldsCurrent =\n    gameState.shieldsCurrent + gameState.energyRemaining;\n  gameState.energyRemaining = 0;\n  if (gameState.shieldsCurrent <= 0) {\n    gameState.shieldsCurrent = 0;\n  }\n}\n\nasync function commandLongRangeScan() {\n  // 3990 REM LONG RANGE SENSOR SCAN CODE\n  if (gameState.systemsDamage[SYSTEM_LONG_RANGE_SENSORS] < 0) {\n    print(\"LONG RANGE SENSORS ARE INOPERABLE\");\n    return;\n  }\n\n  print(\n    \"LONG RANGE SCAN FOR QUADRANT \",\n    gameState.quadrantPositionY,\n    \" , \",\n    gameState.quadrantPositionX\n  );\n\n  const separatorLine = \"-------------------\";\n  print(separatorLine);\n\n  for (\n    let posY = gameState.quadrantPositionY - 1;\n    posY <= gameState.quadrantPositionY + 1;\n    posY++\n  ) {\n    // Scan a line of sectors\n    const lineSectors = [null, null, null];\n    for (\n      let posX = gameState.quadrantPositionX - 1;\n      posX <= gameState.quadrantPositionX + 1;\n      posX++\n    ) {\n      if (posY > 0 && posY < 9 && posX > 0 && posX < 9) {\n        // Add the scanned cell to the current scan output\n        lineSectors[posX - gameState.quadrantPositionX + 1] =\n          gameState.galacticMap[posY][posX];\n        // Add the scanned cell to the discovered map\n        gameState.galacticMapDiscovered[posY][posX] =\n          gameState.galacticMap[posY][posX];\n      }\n    }\n\n    // Print a formatted line of the scan - e.g. \": 004 : 205 : 004 :\"\n    print(\n      \": \" +\n        lineSectors\n          .map((sector) =>\n            sector === null ? \"***\" : sector.toString().padStart(3, \"0\")\n          )\n          .join(\" : \") +\n        \" :\"\n    );\n\n    print(separatorLine);\n  }\n}\n\nasync function commandPhaserControl() {\n  // 4250 REM PHASER CONTROL CODE BEGINS HERE\n  if (gameState.systemsDamage[SYSTEM_PHASER_CONTROL] < 0) {\n    print(\"PHASERS INOPERATIVE\");\n    return;\n  }\n\n  if (gameState.sectorEnemiesCount <= 0) {\n    print(\n      `SCIENCE OFFICER ${gameOptions.nameScienceOfficer} REPORTS  'SENSORS SHOW NO ENEMY SHIPS`\n    );\n    print(\"                                IN THIS QUADRANT'\");\n    return;\n  }\n\n  if (gameState.systemsDamage[SYSTEM_LIBRARY_COMPUTER] < 0) {\n    print(\"COMPUTER FAILURE HAMPERS ACCURACY\");\n  }\n\n  print(\n    \"PHASERS LOCKED ON TARGET;  ENERGY AVAILABLE = \",\n    gameState.energyRemaining,\n    \" UNITS\"\n  );\n  let phaserUnitsToFire;\n  const continueCommandLoop = true;\n  while (continueCommandLoop) {\n    phaserUnitsToFire = parseFloat(await input(\"NUMBER OF UNITS TO FIRE\"));\n    if (phaserUnitsToFire <= 0) return;\n    if (gameState.energyRemaining - phaserUnitsToFire >= 0) {\n      break;\n    }\n    print(`ENERGY AVAILABLE = ${gameState.energyRemaining} UNITS`);\n  }\n\n  gameState.energyRemaining = gameState.energyRemaining - phaserUnitsToFire;\n\n  // FIXED: in the original, this was shield system. Changed to phaser system.\n  if (gameState.systemsDamage[SYSTEM_PHASER_CONTROL] < 0) {\n    phaserUnitsToFire = phaserUnitsToFire * Math.random();\n  }\n\n  // Spread phaser fire between all enemies\n  let phaserUnitsPerEnemy = Math.floor(\n    phaserUnitsToFire / gameState.sectorEnemiesCount\n  );\n  for (\n    let enemyIdx = 0;\n    enemyIdx < gameOptions.enemySpawnChance.length;\n    enemyIdx++\n  ) {\n    if (gameState.sectorEnemies[enemyIdx].health <= 0) {\n      // Skip dead enemies\n      continue;\n    }\n    print();\n\n    // Phaser damage falls off based on distance and a bit of chance\n    let phaserDamage = Math.floor(\n      (phaserUnitsPerEnemy / distanceFromEnemy(enemyIdx)) * (Math.random() + 2)\n    );\n    if (phaserDamage <= 0.15 * gameState.sectorEnemies[enemyIdx].health) {\n      print(\n        \"SENSORS SHOW NO DAMAGE TO ENEMY AT \",\n        gameState.sectorEnemies[enemyIdx].posY,\n        \" , \",\n        gameState.sectorEnemies[enemyIdx].posX\n      );\n      continue;\n    }\n    gameState.sectorEnemies[enemyIdx].health -= phaserDamage;\n\n    print(\n      `${phaserDamage} UNIT HIT ON ${gameOptions.nameEnemy} AT SECTOR ${gameState.sectorEnemies[enemyIdx].posY} , ${gameState.sectorEnemies[enemyIdx].posX}`\n    );\n\n    if (gameState.sectorEnemies[enemyIdx].health > 0) {\n      print(\n        `   (SENSORS SHOW ${gameState.sectorEnemies[enemyIdx].health} UNITS REMAINING)`\n      );\n      print();\n    } else {\n      print(`*** ${gameOptions.nameEnemy} DESTROYED ***`);\n      print();\n      gameState.sectorEnemiesCount = gameState.sectorEnemiesCount - 1;\n      gameState.enemiesRemaining = gameState.enemiesRemaining - 1;\n\n      // Remove enemy from display\n      insertInSectorMap(\n        gameOptions.sectorMapSymbols.empty,\n        gameState.sectorEnemies[enemyIdx].posY,\n        gameState.sectorEnemies[enemyIdx].posX\n      );\n\n      // Set enemy health at exactly zero\n      gameState.sectorEnemies[enemyIdx].health = 0;\n\n      // Update the galactic map with one fewer enemy\n      gameState.galacticMap[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] -= 100;\n\n      // Copy updated galactic map sector to discovered map.\n      gameState.galacticMapDiscovered[gameState.quadrantPositionY][\n        gameState.quadrantPositionX\n      ] =\n        gameState.galacticMap[gameState.quadrantPositionY][\n          gameState.quadrantPositionX\n        ];\n\n      if (gameState.enemiesRemaining <= 0) {\n        // If that was the last enemy, we've won!\n        gameState.gameOver = true;\n        gameState.gameWon = true;\n        return;\n      }\n    }\n  }\n\n  enemiesShoot();\n}\n\nasync function commandPhotonTorpedo() {\n  // 4690 REM PHOTON TORPEDO CODE BEGINS HERE\n  // 4700\n  if (gameState.photonTorpedoesRemaining <= 0) {\n    return print(\"ALL PHOTON TORPEDOES EXPENDED\");\n  }\n  if (gameState.systemsDamage[SYSTEM_PHOTON_TUBES] < 0) {\n    return print(\"PHOTON TUBES ARE NOT OPERATIONAL\");\n  }\n\n  let torpedoCourse = parseFloat(await input(\"PHOTON TORPEDO COURSE (1-9)\"));\n  if (torpedoCourse == 9) torpedoCourse = 1;\n\n  if (torpedoCourse < 1 || torpedoCourse > 9) {\n    print(\n      `${gameOptions.nameWeaponsOfficer} REPORTS,  'INCORRECT COURSE DATA, SIR!'`\n    );\n  }\n\n  const [courseDeltaY, courseDeltaX] = courseToDeltaXY(torpedoCourse);\n\n  gameState.energyRemaining = gameState.energyRemaining - 2;\n  gameState.photonTorpedoesRemaining = gameState.photonTorpedoesRemaining - 1;\n  let currPosY = gameState.sectorPositionY;\n  let currPosX = gameState.sectorPositionX;\n\n  print(\"TORPEDO TRACK:\");\n\n  // Fly the torpedo along its course...\n  let quantizedPosY, quantizedPosX;\n  const forever = true;\n  while (forever) {\n    currPosY = currPosY + courseDeltaY;\n    currPosX = currPosX + courseDeltaX;\n\n    // The course will move in decimals, quantize to whole numbers\n    quantizedPosY = Math.floor(currPosY + 0.5);\n    quantizedPosX = Math.floor(currPosX + 0.5);\n\n    // Exiting the sector means the torpedo missed\n    if (\n      quantizedPosY < 1 ||\n      quantizedPosY > gameOptions.sectorHeight ||\n      quantizedPosX < 1 ||\n      quantizedPosX > gameOptions.sectorWidth\n    ) {\n      print(\"TORPEDO MISSED\");\n      return enemiesShoot();\n    }\n\n    print(`               ${quantizedPosY} , ${quantizedPosX}`);\n\n    if (\n      !findInsectorMap(\n        gameOptions.sectorMapSymbols.empty,\n        quantizedPosY,\n        quantizedPosX\n      )\n    ) {\n      // Torpedo hit something solid, so stop flying.\n      break;\n    }\n  }\n\n  // Did the torpedo hit an enemy?\n  if (\n    findInsectorMap(\n      gameOptions.sectorMapSymbols.enemy,\n      quantizedPosY,\n      quantizedPosX\n    )\n  ) {\n    print(`*** ${gameOptions.nameEnemy} DESTROYED ***`);\n    gameState.sectorEnemiesCount = gameState.sectorEnemiesCount - 1;\n    gameState.enemiesRemaining = gameState.enemiesRemaining - 1;\n\n    if (gameState.enemiesRemaining <= 0) {\n      // If that was the last enemy, then we've won!\n      gameState.gameOver = true;\n      gameState.gameWon = true;\n      return;\n    }\n\n    // Find which enemy was hit and set health to zero\n    for (\n      let enemyIdx = 0;\n      enemyIdx < gameOptions.enemySpawnChance.length;\n      enemyIdx++\n    ) {\n      if (\n        quantizedPosY == gameState.sectorEnemies[enemyIdx].posY &&\n        quantizedPosX == gameState.sectorEnemies[enemyIdx].posX\n      ) {\n        gameState.sectorEnemies[enemyIdx].health = 0;\n        break;\n      }\n    }\n  }\n\n  // Did the torpedo hit a star?\n  if (\n    findInsectorMap(\n      gameOptions.sectorMapSymbols.star,\n      quantizedPosY,\n      quantizedPosX\n    )\n  ) {\n    print(\n      `STAR AT ${quantizedPosY} , ${quantizedPosX} ABSORBED TORPEDO ENERGY.`\n    );\n    return enemiesShoot();\n  }\n\n  // Did the torpedo hit a starbase?\n  if (\n    findInsectorMap(\n      gameOptions.sectorMapSymbols.base,\n      quantizedPosY,\n      quantizedPosX\n    )\n  ) {\n    print(\"*** STARBASE DESTROYED ***\");\n    gameState.sectorStarbasesCount = gameState.sectorStarbasesCount - 1;\n    gameState.starbasesRemaining = gameState.starbasesRemaining - 1;\n    if (\n      gameState.starbasesRemaining <= 0 ||\n      gameState.enemiesRemaining <=\n        gameState.stardateCurrent -\n          gameOptions.stardateStart -\n          gameOptions.timeLimit\n    ) {\n      print(\"THAT DOES IT, CAPTAIN!!  YOU ARE HEREBY RELIEVED OF COMMAND\");\n      print(\"AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!\");\n      gameState.gameOver = true;\n      return;\n    } else {\n      print(\"STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER\");\n      print(\"COURT MARTIAL!\");\n      gameState.isDocked = false;\n    }\n  }\n\n  // If we hit an enemy or a starbase, update the sector and galaxy map to\n  // remove the thing destroyed\n  insertInSectorMap(\n    gameOptions.sectorMapSymbols.empty,\n    quantizedPosY,\n    quantizedPosX\n  );\n  gameState.galacticMap[gameState.quadrantPositionY][\n    gameState.quadrantPositionX\n  ] =\n    gameState.sectorEnemiesCount * 100 +\n    gameState.sectorStarbasesCount * 10 +\n    gameState.sectorStarsCount;\n  gameState.galacticMapDiscovered[gameState.quadrantPositionY][\n    gameState.quadrantPositionX\n  ] =\n    gameState.galacticMap[gameState.quadrantPositionY][\n      gameState.quadrantPositionX\n    ];\n\n  return enemiesShoot();\n}\n\nasync function enemiesShoot() {\n  if (gameState.sectorEnemiesCount <= 0) {\n    return;\n  }\n\n  if (gameState.isDocked) {\n    print(\"STARBASE SHIELDS PROTECT THE ENTERPRISE\");\n    return;\n  }\n\n  for (\n    let enemyIdx = 0;\n    enemyIdx < gameOptions.enemySpawnChance.length;\n    enemyIdx++\n  ) {\n    if (gameState.sectorEnemies[enemyIdx].health <= 0) {\n      continue;\n    }\n\n    // Enemy damage based on health with drop-off for distance and chance\n    const enemyWeaponDamage = Math.floor(\n      (gameState.sectorEnemies[enemyIdx].health / distanceFromEnemy(enemyIdx)) *\n        (2 + Math.random())\n    );\n    gameState.shieldsCurrent = gameState.shieldsCurrent - enemyWeaponDamage;\n\n    // Consume enemy health for firing weapon\n    gameState.sectorEnemies[enemyIdx].health = Math.floor(\n      gameState.sectorEnemies[enemyIdx].health / (3 + Math.random())\n    );\n\n    print(\n      `${enemyWeaponDamage} UNIT HIT ON ENTERPRISE FROM SECTOR ${gameState.sectorEnemies[enemyIdx].posY} , ${gameState.sectorEnemies[enemyIdx].posX}`\n    );\n\n    if (gameState.shieldsCurrent <= 0) {\n      // If we're out of shields, we're out of luck\n      gameState.gameOver = true;\n      gameState.destroyed = true;\n      return;\n    }\n\n    print(`      <SHIELDS DOWN TO ${gameState.shieldsCurrent} UNITS>`);\n    if (enemyWeaponDamage < 20) {\n      continue;\n    }\n\n    // Systems damage with 60% chance or a hit of more than 2% of shields\n    if (\n      Math.random() > gameOptions.systemDamageChanceOnHit ||\n      enemyWeaponDamage / gameState.shieldsCurrent <=\n        gameOptions.systemDamageHitThroughShields\n    ) {\n      continue;\n    }\n\n    // Random system damaged proportional to enemy damage and current shields\n    const systemIdx = randomInt(gameOptions.shipSystems.length);\n    const systemName = gameOptions.shipSystems[systemIdx];\n    gameState.systemsDamage[systemName] =\n      gameState.systemsDamage[systemName] -\n      enemyWeaponDamage / gameState.shieldsCurrent -\n      0.5 * Math.random();\n\n    print(`DAMAGE CONTROL REPORTS ${systemName} DAMAGED BY THE HIT`);\n  }\n}\n\nasync function commandShieldControl() {\n  // 5520 REM SHIELD CONTROL\n  if (gameState.systemsDamage[SYSTEM_SHIELD_CONTROL] < 0) {\n    print(\"SHIELD CONTROL INOPERABLE\");\n    return;\n  }\n\n  print(\n    \"ENERGY AVAILABLE = \",\n    gameState.energyRemaining + gameState.shieldsCurrent\n  );\n  const shieldUnits = parseFloat(await input(\"NUMBER OF UNITS TO SHIELDS\"));\n  if (shieldUnits < 0 || gameState.shieldsCurrent == shieldUnits) {\n    print(\"<SHIELDS UNCHANGED>\");\n    return;\n  }\n  if (shieldUnits > gameState.energyRemaining + gameState.shieldsCurrent) {\n    print(\"SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION TREASURY.'\");\n    print(\"<SHIELDS UNCHANGED>\");\n    return;\n  }\n\n  gameState.energyRemaining =\n    gameState.energyRemaining + gameState.shieldsCurrent - shieldUnits;\n  gameState.shieldsCurrent = shieldUnits;\n\n  print(\"DEFLECTOR CONTROL ROOM REPORT:\");\n  print(\n    `  'SHIELDS NOW AT ${Math.floor(\n      gameState.shieldsCurrent\n    )} UNITS PER YOUR COMMAND.`\n  );\n}\n\nasync function commandDamageControl() {\n  // 5680 REM DAMAGE CONTROL\n  // 5690\n  // FIXME: Seems like damage control should work while docked?\n  if (gameState.systemsDamage[SYSTEM_DAMAGE_CONTROL] < 0) {\n    print(\"DAMAGE CONTROL REPORT NOT AVAILABLE\");\n    return;\n  }\n\n  // 5910\n  print();\n  print(\"DEVICE             STATE OF REPAIR\");\n  for (const systemName of gameOptions.shipSystems) {\n    print(\n      systemName.padEnd(25, \" \"),\n      Math.floor(gameState.systemsDamage[systemName] * 100) * 0.01\n    );\n  }\n  print();\n\n  if (gameState.isDocked) {\n    let repairTimeEstimate = 0;\n    for (const systemName of gameOptions.shipSystems) {\n      if (gameState.systemsDamage[systemName] < 0) {\n        repairTimeEstimate = repairTimeEstimate + 0.1;\n      }\n    }\n    if (repairTimeEstimate == 0) {\n      return;\n    }\n    print();\n    repairTimeEstimate = repairTimeEstimate + gameState.starbaseRepairDelay;\n    if (repairTimeEstimate >= 1) {\n      repairTimeEstimate = 0.9;\n    }\n    print(\"TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;\");\n    print(\n      `ESTIMATED TIME TO REPAIR: ${\n        0.01 * Math.floor(100 * repairTimeEstimate)\n      } STARDATES`\n    );\n    const authorizeRepairInput = await input(\n      \"WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)\"\n    );\n    if (authorizeRepairInput.toUpperCase() != \"Y\") {\n      return;\n    }\n    for (const systemName of gameOptions.shipSystems) {\n      gameState.systemsDamage[systemName] = 0;\n    }\n    gameState.stardateCurrent =\n      gameState.stardateCurrent + repairTimeEstimate + 0.1;\n  }\n}\n\nasync function commandLibraryComputer() {\n  // 7280 REM LIBRARY COMPUTER CODE\n  // 7290\n  if (gameState.systemsDamage[SYSTEM_LIBRARY_COMPUTER] < 0) {\n    print(\"COMPUTER DISABLED\");\n    return;\n  }\n  const commandInput = parseInt(\n    await input(\"COMPUTER ACTIVE AND AWAITING COMMAND\")\n  );\n  if (commandInput < 0) return;\n  const command = COMMANDS_COMPUTER[commandInput] || computerHelp;\n  print();\n  await command();\n}\n\nconst COMMANDS_COMPUTER = [\n  computerCumulativeRecord,\n  computerStatusReport,\n  computerPhotonData,\n  computerStarbaseData,\n  computerDirectionData,\n  computerGalaxyMap,\n];\n\nasync function computerHelp() {\n  print(\"FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\");\n  print(\"   0 = CUMULATIVE GALACTIC RECORD\");\n  print(\"   1 = STATUS REPORT\");\n  print(\"   2 = PHOTON TORPEDO DATA\");\n  print(\"   3 = STARBASE NAV DATA\");\n  print(\"   4 = DIRECTION/DISTANCE CALCULATOR\");\n  print(\"   5 = GALAXY 'REGION NAME' MAP\");\n  print();\n}\n\nasync function computerPhotonData() {\n  if (gameState.sectorEnemiesCount <= 0) {\n    print(\n      `SCIENCE OFFICER ${gameOptions.nameScienceOfficer} REPORTS  'SENSORS SHOW NO ENEMY SHIPS`\n    );\n    print(\"                                IN THIS QUADRANT'\");\n    return;\n  }\n\n  print(\n    `FROM ENTERPRISE TO ${gameOptions.nameEnemy} BATTLE CRUISER${\n      gameState.sectorEnemiesCount > 1 ? \"S\" : \"\"\n    }`\n  );\n\n  for (\n    let enemyIdx = 0;\n    enemyIdx < gameOptions.enemySpawnChance.length;\n    enemyIdx++\n  ) {\n    if (gameState.sectorEnemies[enemyIdx].health <= 0) continue;\n    computerDirectionCommon({\n      fromY: gameState.sectorPositionY,\n      fromX: gameState.sectorPositionX,\n      toY: gameState.sectorEnemies[enemyIdx].posY,\n      toX: gameState.sectorEnemies[enemyIdx].posX,\n    });\n  }\n}\n\nasync function computerStarbaseData() {\n  if (gameState.sectorStarbasesCount == 0) {\n    print(\n      `MR. ${gameOptions.nameScienceOfficer} REPORTS,  'SENSORS SHOW NO STARBASES IN THIS QUADRANT.'`\n    );\n    return;\n  }\n  print(\"FROM ENTERPRISE TO STARBASE:\");\n  computerDirectionCommon({\n    fromY: gameState.sectorPositionY,\n    fromX: gameState.sectorPositionX,\n    toY: gameState.sectorStarbaseY,\n    toX: gameState.sectorStarbaseX,\n  });\n}\n\nconst inputCoords = async (prompt) =>\n  (await input(prompt)).split(\",\").map((s) => parseInt(s.trim()));\n\nasync function computerDirectionData() {\n  print(\"DIRECTION/DISTANCE CALCULATOR:\");\n  print(\n    `YOU ARE AT QUADRANT ${gameState.quadrantPositionY} , ${gameState.quadrantPositionX} SECTOR ${gameState.sectorPositionY} , ${gameState.sectorPositionX}`\n  );\n  print(\"PLEASE ENTER\");\n  const [fromY, fromX] = await inputCoords(\"  INITIAL COORDINATES (Y,X)\");\n  const [toY, toX] = await inputCoords(\"  FINAL COORDINATES (Y,X)\");\n  computerDirectionCommon({ fromX, fromY, toX, toY });\n}\n\nasync function computerDirectionCommon({ fromX, fromY, toX, toY }) {\n  const distance = Math.sqrt(\n    Math.pow(toX - fromX, 2) + Math.pow(toY - fromY, 2)\n  );\n  const direction =\n    1 +\n    (8 / (Math.PI * 2)) *\n      ((Math.atan2(0 - fromY - (0 - toY), fromX - toX) + Math.PI) %\n        (Math.PI * 2));\n\n  print(`DIRECTION = ${direction}`);\n  print(`DISTANCE = ${distance}`);\n}\n\nasync function computerStatusReport() {\n  print(\"STATUS REPORT:\");\n  print();\n  print(\n    `${\n      gameState.enemiesRemaining > 1\n        ? gameOptions.nameEnemies\n        : gameOptions.nameEnemy\n    } LEFT: ${gameState.enemiesRemaining}`\n  );\n  print(\n    `MISSION MUST BE COMPLETED IN ${\n      0.1 *\n      Math.floor(\n        (gameOptions.stardateStart +\n          gameOptions.timeLimit -\n          gameState.stardateCurrent) *\n          10\n      )\n    }  STARDATES`\n  );\n  if (gameState.starbasesRemaining < 1) {\n    print(\"YOUR STUPIDITY HAS LEFT YOU ON YOUR ON IN\");\n    print(\"  THE GALAXY -- YOU HAVE NO STARBASES LEFT!\");\n  } else {\n    print(\n      `THE FEDERATION IS MAINTAINING ${gameState.starbasesRemaining} STARBASE${\n        gameState.starbasesRemaining < 2 ? \"\" : \"S\"\n      } IN THE GALAXY`\n    );\n  }\n  commandDamageControl();\n}\n\nasync function computerGalaxyMap() {\n  print(\"                        THE GALAXY\");\n  computerCommonMap(false);\n}\n\nasync function computerCumulativeRecord() {\n  print();\n  print(\n    `        COMPUTER RECORD OF GALAXY FOR QUADRANT ${gameState.quadrantPositionY} , ${gameState.quadrantPositionX}`\n  );\n  print();\n  computerCommonMap();\n}\n\nasync function computerCommonMap(showMapCells = true) {\n  // Print the X column number header based on width of first galaxy row\n  print(\n    \"  \" +\n      gameState.galacticMap[1]\n        .map((_, idx) => idx.toString().padStart(3, \" \"))\n        .join(\"   \")\n  );\n\n  // Assemble X column separator based on width of first galaxy row\n  const separator =\n    \"     \" + gameState.galacticMap[1].map((_, idx) => \"----- \").join(\"\");\n\n  print(separator);\n  for (let mapY = 1; mapY <= gameOptions.galaxyHeight; mapY++) {\n    let out = mapY.toString().padStart(3, \" \");\n\n    if (showMapCells) {\n      // 7630\n      for (let mapX = 1; mapX <= gameOptions.galaxyWidth; mapX++) {\n        out += `   ${\n          gameState.galacticMapDiscovered[mapY][mapX] == 0\n            ? \"***\"\n            : (\"\" + gameState.galacticMapDiscovered[mapY][mapX]).padStart(\n                3,\n                \"0\"\n              )\n        }`;\n      }\n    } else {\n      let quadrantName = buildQuadrantName(mapY, 1, true);\n      let centerSpacing = Math.floor(12 - 0.5 * quadrantName.length);\n      out += `  ${\" \".repeat(centerSpacing)}${quadrantName}${\" \".repeat(\n        centerSpacing\n      )}`;\n      quadrantName = buildQuadrantName(mapY, 5, true);\n      centerSpacing = Math.floor(12 - 0.5 * quadrantName.length);\n      out += `${\" \".repeat(centerSpacing)}${quadrantName}`;\n    }\n\n    print(out);\n    print(separator);\n  }\n}\n\nasync function endOfGame() {\n  if (gameState.destroyed) {\n    print();\n    print(\n      \"THE ENTERPRISE HAS BEEN DESTROYED.  THEN FEDERATION WILL BE CONQUERED\"\n    );\n  }\n\n  print(`IT IS STARDATE ${formatStardate(gameState.stardateCurrent)}`);\n\n  if (!gameState.gameWon) {\n    print(\n      `THERE WERE ${gameState.enemiesRemaining} ${gameOptions.nameEnemy} BATTLE CRUISERS LEFT AT`\n    );\n    print(\"THE END OF YOUR MISSION.\");\n  } else {\n    print(\n      `CONGRULATION, CAPTAIN!  THEN LAST ${gameOptions.nameEnemy} BATTLE CRUISER`\n    );\n    print(\"MENACING THE FEDERATION HAS BEEN DESTROYED.\");\n    print();\n    print(\n      \"YOUR EFFICIENCY RATING IS \",\n      (1000 *\n        (gameState.enemiesInitialCount /\n          (gameState.stardateCurrent - gameOptions.stardateStart))) ^\n        2\n    );\n  }\n\n  print();\n  print();\n\n  if (gameState.starbasesRemaining > 0) {\n    print(\"THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER\");\n    print(\"FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,\");\n    const playAgainInput = await input(\"LET HIM STEP FORWARD AND ENTER 'AYE'\");\n    if (playAgainInput.toUpperCase() == \"AYE\") {\n      gameState.shouldRestart = true;\n      return;\n    }\n  }\n}\n\nconst COURSE_TO_XY = [\n  [0, 1],\n  [-1, 1],\n  [-1, 0],\n  [-1, -1],\n  [0, -1],\n  [1, -1],\n  [1, 0],\n  [1, 1],\n  [0, 1],\n];\n\nfunction courseToDeltaXY(course) {\n  const courseIdx = Math.floor(course) - 1;\n  //3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):X=S1:Y=S2\n  //3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):Q4=Q1:Q5=Q2\n  const courseDeltaY =\n    COURSE_TO_XY[courseIdx][0] +\n    (COURSE_TO_XY[courseIdx + 1][0] - COURSE_TO_XY[courseIdx][0]) *\n      (course - Math.floor(course));\n  const courseDeltaX =\n    COURSE_TO_XY[courseIdx][1] +\n    (COURSE_TO_XY[courseIdx + 1][1] - COURSE_TO_XY[courseIdx][1]) *\n      (course - Math.floor(course));\n  return [courseDeltaY, courseDeltaX];\n}\n\nfunction findSpaceInSectorMap() {\n  let posY,\n    posX,\n    foundEmptyPlace = false;\n  while (!foundEmptyPlace) {\n    posY = randomInt(8, 1);\n    posX = randomInt(8, 1);\n    foundEmptyPlace = findInsectorMap(\n      gameOptions.sectorMapSymbols.empty,\n      posY,\n      posX\n    );\n  }\n  return [posY, posX];\n}\n\nfunction findInsectorMap(str, y, x) {\n  const idx = (x - 1) * 3 + (y - 1) * 24;\n  return gameState.sectorMap.substring(idx, idx + 3) == str;\n}\n\n// 8660 REM INSERT IN STRING ARRAY FOR QUADRANT\nfunction insertInSectorMap(str, y, x) {\n  // 8670\n  const strPos = (x - 1) * 3 + (y - 1) * 24;\n  if (str.length != 3) {\n    throw \"ERROR\";\n  }\n  gameState.sectorMap =\n    gameState.sectorMap.slice(0, strPos) +\n    str +\n    gameState.sectorMap.slice(strPos + 3);\n}\n\nfunction buildQuadrantName(y, x, regionNameOnly = false) {\n  const xIdx = x - 1;\n  const yIdx = y - 1;\n  const name = gameOptions.quadrantNames[xIdx < 4 ? 0 : 1][yIdx];\n  return `${name}${\n    regionNameOnly ? \"\" : ` ${gameOptions.quadrantNumbers[xIdx % 4]}`\n  }`;\n}\n\nconst randomInt = (max, min = 0) =>\n  Math.floor(min + Math.random() * (max - min));\n\nconst formatStardate = (stardate) => Math.floor(stardate * 10) / 10;\n\nconst distanceFromEnemy = (sectorEnemyIndex) =>\n  Math.sqrt(\n    Math.pow(\n      gameState.sectorEnemies[sectorEnemyIndex].posY -\n        gameState.sectorPositionY,\n      2\n    ) +\n      Math.pow(\n        gameState.sectorEnemies[sectorEnemyIndex].posX -\n          gameState.sectorPositionX,\n        2\n      )\n  );\n"
  },
  {
    "path": "84_Super_Star_Trek/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "84_Super_Star_Trek/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "84_Super_Star_Trek/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "84_Super_Star_Trek/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "84_Super_Star_Trek/python/superstartrek.py",
    "content": "\"\"\"\n****        **** STAR TREK ****        ****\n**** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n**** AS SEEN ON THE STAR TREK TV SHOW.\n**** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n**** PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n**** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n**** LEEDOM - APRIL & DECEMBER 1974,\n**** WITH A LITTLE HELP FROM HIS FRIENDS . . .\n\n  Output is identical to BASIC version except for a few\n  fixes (as noted, search `bug`) and minor cleanup.\n\"\"\"\n\n\nimport random\nimport sys\nfrom dataclasses import dataclass\nfrom enum import Enum\nfrom math import sqrt\nfrom typing import Callable, Dict, Final, List, Optional, Tuple\n\n\ndef get_user_float(prompt: str) -> float:\n    \"\"\"Get input from user and return it.\"\"\"\n    while True:\n        answer = input(prompt)\n        try:\n            return float(answer)\n        except ValueError:\n            pass\n\n\nclass Entity(Enum):\n    klingon = \"+K+\"\n    ship = \"<*>\"\n    empty = \"***\"\n    starbase = \">!<\"\n    star = \" * \"\n    void = \"   \"\n\n\n@dataclass\nclass Point:\n    x: int\n    y: int\n\n    def __str__(self) -> str:\n        return f\"{self.x + 1} , {self.y + 1}\"\n\n\n@dataclass\nclass Position:\n    \"\"\"\n    Every quadrant has 8 sectors\n\n    Hence the position could also be represented as:\n    x = quadrant.x * 8 + sector.x\n    y = quadrant.y * 8 + sector.y\n    \"\"\"\n\n    quadrant: Point\n    sector: Point\n\n\n@dataclass\nclass QuadrantData:\n    klingons: int\n    bases: int\n    stars: int\n\n    def num(self) -> int:\n        return 100 * self.klingons + 10 * self.bases + self.stars\n\n\n@dataclass\nclass KlingonShip:\n    sector: Point\n    shield: float\n\n\nclass Ship:\n    energy_capacity: int = 3000\n    torpedo_capacity: int = 10\n\n    def __init__(self) -> None:\n        self.position = Position(Point(fnr(), fnr()), Point(fnr(), fnr()))\n        self.energy: int = Ship.energy_capacity\n        self.devices: Tuple[str, ...] = (\n            \"WARP ENGINES\",\n            \"SHORT RANGE SENSORS\",\n            \"LONG RANGE SENSORS\",\n            \"PHASER CONTROL\",\n            \"PHOTON TUBES\",\n            \"DAMAGE CONTROL\",\n            \"SHIELD CONTROL\",\n            \"LIBRARY-COMPUTER\",\n        )\n        self.damage_stats: List[float] = [0] * len(self.devices)\n        self.shields = 0\n        self.torpedoes = Ship.torpedo_capacity\n        self.docked: bool = False  # true when docked at starbase\n\n    def refill(self) -> None:\n        self.energy = Ship.energy_capacity\n        self.torpedoes = Ship.torpedo_capacity\n\n    def maneuver_energy(self, n: int) -> None:\n        \"\"\"Deduct the energy for navigation from energy/shields.\"\"\"\n        self.energy -= n + 10\n\n        if self.energy <= 0:\n            print(\"SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.\")\n            self.shields += self.energy\n            self.energy = 0\n            self.shields = max(0, self.shields)\n\n    def shield_control(self) -> None:\n        \"\"\"Raise or lower the shields.\"\"\"\n        if self.damage_stats[6] < 0:\n            print(\"SHIELD CONTROL INOPERABLE\")\n            return\n\n        while True:\n            energy_to_shield = input(\n                f\"ENERGY AVAILABLE = {self.energy + self.shields} NUMBER OF UNITS TO SHIELDS? \"\n            )\n            if len(energy_to_shield) > 0:\n                x = int(energy_to_shield)\n                break\n\n        if x < 0 or self.shields == x:\n            print(\"<SHIELDS UNCHANGED>\")\n            return\n\n        if x > self.energy + self.shields:\n            print(\n                \"SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION \"\n                \"TREASURY.'\\n\"\n                \"<SHIELDS UNCHANGED>\"\n            )\n            return\n\n        self.energy += self.shields - x\n        self.shields = x\n        print(\"DEFLECTOR CONTROL ROOM REPORT:\")\n        print(f\"  'SHIELDS NOW AT {self.shields} UNITS PER YOUR COMMAND.'\")\n\n\nclass Quadrant:\n    def __init__(\n        self,\n        point: Point,  # position of the quadrant\n        population: QuadrantData,\n        ship_position: Position,\n    ) -> None:\n        \"\"\"Populate quadrant map\"\"\"\n        assert 0 <= point.x <= 7 and 0 <= point.y <= 7\n        self.name = Quadrant.quadrant_name(point.x, point.y, False)\n\n        self.nb_klingons = population.klingons\n        self.nb_bases = population.bases\n        self.nb_stars = population.stars\n\n        # extra delay in repairs at base\n        self.delay_in_repairs_at_base: float = 0.5 * random.random()\n\n        # Klingons in current quadrant\n        self.klingon_ships: List[KlingonShip] = []\n\n        # Initialize empty: save what is at which position\n        self.data = [[Entity.void for _ in range(8)] for _ in range(8)]\n\n        self.populate_quadrant(ship_position)\n\n    @classmethod\n    def quadrant_name(cls, row: int, col: int, region_only: bool = False) -> str:\n        \"\"\"Return quadrant name visible on scans, etc.\"\"\"\n        region1 = [\n            \"ANTARES\",\n            \"RIGEL\",\n            \"PROCYON\",\n            \"VEGA\",\n            \"CANOPUS\",\n            \"ALTAIR\",\n            \"SAGITTARIUS\",\n            \"POLLUX\",\n        ]\n        region2 = [\n            \"SIRIUS\",\n            \"DENEB\",\n            \"CAPELLA\",\n            \"BETELGEUSE\",\n            \"ALDEBARAN\",\n            \"REGULUS\",\n            \"ARCTURUS\",\n            \"SPICA\",\n        ]\n        modifier = [\"I\", \"II\", \"III\", \"IV\"]\n\n        quadrant = region1[row] if col < 4 else region2[row]\n\n        if not region_only:\n            quadrant += f\" {modifier[col % 4]}\"\n\n        return quadrant\n\n    def set_value(self, x: float, y: float, entity: Entity) -> None:\n        self.data[round(x)][round(y)] = entity\n\n    def get_value(self, x: float, y: float) -> Entity:\n        return self.data[round(x)][round(y)]\n\n    def find_empty_place(self) -> Tuple[int, int]:\n        \"\"\"Find an empty location in the current quadrant.\"\"\"\n        while True:\n            row, col = fnr(), fnr()\n            if self.get_value(row, col) == Entity.void:\n                return row, col\n\n    def populate_quadrant(self, ship_position: Position) -> None:\n        self.set_value(ship_position.sector.x, ship_position.sector.y, Entity.ship)\n        for _ in range(self.nb_klingons):\n            x, y = self.find_empty_place()\n            self.set_value(x, y, Entity.klingon)\n            self.klingon_ships.append(\n                KlingonShip(\n                    Point(x, y), klingon_shield_strength * (0.5 + random.random())\n                )\n            )\n        if self.nb_bases > 0:\n            # Position of starbase in current sector\n            starbase_x, starbase_y = self.find_empty_place()\n            self.starbase = Point(starbase_x, starbase_y)\n            self.set_value(starbase_x, starbase_y, Entity.starbase)\n        for _ in range(self.nb_stars):\n            x, y = self.find_empty_place()\n            self.set_value(x, y, Entity.star)\n\n    def __str__(self) -> str:\n        quadrant_string = \"\"\n        for row in self.data:\n            for entity in row:\n                quadrant_string += entity.value\n        return quadrant_string\n\n\nclass World:\n    def __init__(\n        self,\n        total_klingons: int = 0,  # Klingons at start of game\n        bases_in_galaxy: int = 0,\n    ) -> None:\n        self.ship = Ship()\n        self.initial_stardate = 100 * random.randint(20, 39)\n        self.stardate: float = self.initial_stardate\n        self.mission_duration = random.randint(25, 34)\n\n        # Enemy\n        self.remaining_klingons = total_klingons\n\n        # Player starbases\n        self.bases_in_galaxy = bases_in_galaxy\n\n        self.galaxy_map: List[List[QuadrantData]] = [\n            [QuadrantData(0, 0, 0) for _ in range(8)] for _ in range(8)\n        ]\n        self.charted_galaxy_map: List[List[QuadrantData]] = [\n            [QuadrantData(0, 0, 0) for _ in range(8)] for _ in range(8)\n        ]\n\n        # initialize contents of galaxy\n        for x in range(8):\n            for y in range(8):\n                r1 = random.random()\n\n                if r1 > 0.98:\n                    quadrant_klingons = 3\n                elif r1 > 0.95:\n                    quadrant_klingons = 2\n                elif r1 > 0.80:\n                    quadrant_klingons = 1\n                else:\n                    quadrant_klingons = 0\n                self.remaining_klingons += quadrant_klingons\n\n                quadrant_bases = 0\n                if random.random() > 0.96:\n                    quadrant_bases = 1\n                    self.bases_in_galaxy += 1\n                self.galaxy_map[x][y] = QuadrantData(\n                    quadrant_klingons, quadrant_bases, 1 + fnr()\n                )\n\n        if self.remaining_klingons > self.mission_duration:\n            self.mission_duration = self.remaining_klingons + 1\n\n        if self.bases_in_galaxy == 0:  # original has buggy extra code here\n            self.bases_in_galaxy = 1\n            self.galaxy_map[self.ship.position.quadrant.x][\n                self.ship.position.quadrant.y\n            ].bases += 1\n\n        curr = self.ship.position.quadrant\n        self.quadrant = Quadrant(\n            self.ship.position.quadrant,\n            self.galaxy_map[curr.x][curr.y],\n            self.ship.position,\n        )\n\n    def remaining_time(self) -> float:\n        return self.initial_stardate + self.mission_duration - self.stardate\n\n    def has_mission_ended(self) -> bool:\n        return self.remaining_time() < 0\n\n\nclass Game:\n    \"\"\"Handle user actions\"\"\"\n\n    def __init__(self) -> None:\n        self.restart = False\n        self.world = World()\n\n    def startup(self) -> None:\n        \"\"\"Initialize the game variables and map, and print startup messages.\"\"\"\n        print(\n            \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\"\n            \"                                    ,------*------,\\n\"\n            \"                    ,-------------   '---  ------'\\n\"\n            \"                     '-------- --'      / /\\n\"\n            \"                         ,---' '-------/ /--,\\n\"\n            \"                          '----------------'\\n\\n\"\n            \"                    THE USS ENTERPRISE --- NCC-1701\\n\"\n            \"\\n\\n\\n\\n\"\n        )\n        world = self.world\n        print(\n            \"YOUR ORDERS ARE AS FOLLOWS:\\n\"\n            f\"     DESTROY THE {world.remaining_klingons} KLINGON WARSHIPS WHICH HAVE INVADED\\n\"\n            \"   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\\n\"\n            f\"   ON STARDATE {world.initial_stardate+world.mission_duration}. \"\n            f\" THIS GIVES YOU {world.mission_duration} DAYS. THERE \"\n            f\"{'IS' if world.bases_in_galaxy == 1 else 'ARE'}\\n\"\n            f\"   {world.bases_in_galaxy} \"\n            f\"STARBASE{'' if world.bases_in_galaxy == 1 else 'S'} IN THE GALAXY FOR \"\n            \"RESUPPLYING YOUR SHIP.\\n\"\n        )\n\n    def new_quadrant(self) -> None:\n        \"\"\"Enter a new quadrant: populate map and print a short range scan.\"\"\"\n        world = self.world\n        ship = world.ship\n        q = ship.position.quadrant\n\n        world.quadrant = Quadrant(\n            q,\n            world.galaxy_map[q.x][q.y],\n            ship.position,\n        )\n\n        world.charted_galaxy_map[q.x][q.y] = world.galaxy_map[q.x][q.y]\n\n        if world.stardate == world.initial_stardate:\n            print(\"\\nYOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\")\n            print(f\"IN THE GALACTIC QUADRANT, '{world.quadrant.name}'.\\n\")\n        else:\n            print(f\"\\nNOW ENTERING {world.quadrant.name} QUADRANT . . .\\n\")\n\n        if world.quadrant.nb_klingons != 0:\n            print(\"COMBAT AREA      CONDITION RED\")\n            if ship.shields <= 200:\n                print(\"   SHIELDS DANGEROUSLY LOW\")\n        self.short_range_scan()\n\n    def fnd(self, i: int) -> float:\n        \"\"\"Find distance between Enterprise and i'th Klingon warship.\"\"\"\n        ship = self.world.ship.position.sector\n        klingons = self.world.quadrant.klingon_ships[i].sector\n        return sqrt((klingons.x - ship.x) ** 2 + (klingons.y - ship.y) ** 2)\n\n    def klingons_fire(self) -> None:\n        \"\"\"Process nearby Klingons firing on Enterprise.\"\"\"\n        ship = self.world.ship\n\n        if self.world.quadrant.nb_klingons <= 0:\n            return\n        if ship.docked:\n            print(\"STARBASE SHIELDS PROTECT THE ENTERPRISE\")\n            return\n\n        for i, klingon_ship in enumerate(self.world.quadrant.klingon_ships):\n            if klingon_ship.shield <= 0:\n                continue\n\n            h = int((klingon_ship.shield / self.fnd(i)) * (random.random() + 2))\n            ship.shields -= h\n            klingon_ship.shield /= random.random() + 3\n            print(f\" {h} UNIT HIT ON ENTERPRISE FROM SECTOR {klingon_ship.sector} \")\n            if ship.shields <= 0:\n                self.end_game(won=False, quit=False, enterprise_killed=True)\n                return\n            print(f\"      <SHIELDS DOWN TO {ship.shields} UNITS>\")\n            if h >= 20 and random.random() < 0.60 and h / ship.shields > 0.02:\n                device = fnr()\n                ship.damage_stats[device] -= h / ship.shields + 0.5 * random.random()\n                print(\n                    f\"DAMAGE CONTROL REPORTS  '{ship.devices[device]} DAMAGED BY THE HIT'\"\n                )\n\n    def phaser_control(self) -> None:\n        \"\"\"Take phaser control input and fire phasers.\"\"\"\n        world = self.world\n        klingon_ships = world.quadrant.klingon_ships\n        ship = world.ship\n\n        if ship.damage_stats[3] < 0:\n            print(\"PHASERS INOPERATIVE\")\n            return\n\n        if self.world.quadrant.nb_klingons <= 0:\n            print(\"SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS\")\n            print(\"                                IN THIS QUADRANT'\")\n            return\n\n        if ship.damage_stats[7] < 0:\n            print(\"COMPUTER FAILURE HAMPERS ACCURACY\")\n\n        print(f\"PHASERS LOCKED ON TARGET;  ENERGY AVAILABLE = {ship.energy} UNITS\")\n        phaser_firepower: float = 0\n        while True:\n            while True:\n                units_to_fire = input(\"NUMBER OF UNITS TO FIRE? \")\n                if len(units_to_fire) > 0:\n                    phaser_firepower = int(units_to_fire)\n                    break\n            if phaser_firepower <= 0:\n                return\n            if ship.energy >= phaser_firepower:\n                break\n            print(f\"ENERGY AVAILABLE = {ship.energy} UNITS\")\n\n        ship.energy -= phaser_firepower\n        if ship.damage_stats[7] < 0:  # bug in original, was d[6]\n            phaser_firepower *= random.random()\n\n        phaser_per_klingon = int(phaser_firepower / self.world.quadrant.nb_klingons)\n        for i, klingon_ship in enumerate(klingon_ships):\n            if klingon_ship.shield <= 0:\n                continue\n\n            h = int((phaser_per_klingon / self.fnd(i)) * (random.random() + 2))\n            if h <= 0.15 * klingon_ship.shield:\n                print(f\"SENSORS SHOW NO DAMAGE TO ENEMY AT {klingon_ship.sector}\")\n            else:\n                klingon_ship.shield -= h\n                print(f\" {h} UNIT HIT ON KLINGON AT SECTOR {klingon_ship.sector}\")\n                if klingon_ship.shield <= 0:\n                    print(\"*** KLINGON DESTROYED ***\")\n                    self.world.quadrant.nb_klingons -= 1\n                    world.remaining_klingons -= 1\n                    world.quadrant.set_value(\n                        klingon_ship.sector.x, klingon_ship.sector.y, Entity.void\n                    )\n                    klingon_ship.shield = 0\n                    world.galaxy_map[ship.position.quadrant.x][\n                        ship.position.quadrant.y\n                    ].klingons -= 1\n                    world.charted_galaxy_map[ship.position.quadrant.x][\n                        ship.position.quadrant.y\n                    ] = world.galaxy_map[ship.position.quadrant.x][\n                        ship.position.quadrant.y\n                    ]\n                    if world.remaining_klingons <= 0:\n                        self.end_game(won=True, quit=False)\n                        return\n                else:\n                    print(\n                        f\"   (SENSORS SHOW {round(klingon_ship.shield,6)} UNITS REMAINING)\"\n                    )\n\n        self.klingons_fire()\n\n    def photon_torpedoes(self) -> None:\n        \"\"\"Take photon torpedo input and process firing of torpedoes.\"\"\"\n        world = self.world\n        klingon_ships = world.quadrant.klingon_ships\n        ship = world.ship\n\n        if ship.torpedoes <= 0:\n            print(\"ALL PHOTON TORPEDOES EXPENDED\")\n            return\n        if ship.damage_stats[4] < 0:\n            print(\"PHOTON TUBES ARE NOT OPERATIONAL\")\n            return\n\n        cd = get_user_float(\"PHOTON TORPEDO COURSE (1-9)? \")\n        if cd == 9:\n            cd = 1\n        if cd < 1 or cd >= 9:\n            print(\"ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'\")\n            return\n\n        cdi = int(cd)\n\n        # Interpolate direction:\n        dx = dirs[cdi - 1][0] + (dirs[cdi][0] - dirs[cdi - 1][0]) * (cd - cdi)\n        dy = dirs[cdi - 1][1] + (dirs[cdi][1] - dirs[cdi - 1][1]) * (cd - cdi)\n\n        ship.energy -= 2\n        ship.torpedoes -= 1\n\n        # Exact position\n        x: float = ship.position.sector.x\n        y: float = ship.position.sector.y\n\n        # Rounded position (to coordinates)\n        torpedo_x, torpedo_y = x, y\n        print(\"TORPEDO TRACK:\")\n        while True:\n            x += dx\n            y += dy\n            torpedo_x, torpedo_y = round(x), round(y)\n            if torpedo_x < 0 or torpedo_x > 7 or torpedo_y < 0 or torpedo_y > 7:\n                print(\"TORPEDO MISSED\")\n                self.klingons_fire()\n                return\n            print(f\"                {torpedo_x + 1} , {torpedo_y + 1}\")\n            if world.quadrant.get_value(torpedo_x, torpedo_y) != Entity.void:\n                break\n\n        if world.quadrant.get_value(torpedo_x, torpedo_y) == Entity.klingon:\n            print(\"*** KLINGON DESTROYED ***\")\n            self.world.quadrant.nb_klingons -= 1\n            world.remaining_klingons -= 1\n            if world.remaining_klingons <= 0:\n                self.end_game(won=True, quit=False)\n                return\n            for klingon_ship in klingon_ships:\n                if (\n                    torpedo_x == klingon_ship.sector.x\n                    and torpedo_y == klingon_ship.sector.y\n                ):\n                    klingon_ship.shield = 0\n        elif world.quadrant.get_value(torpedo_x, torpedo_y) == Entity.star:\n            print(f\"STAR AT {torpedo_x + 1} , {torpedo_y + 1} ABSORBED TORPEDO ENERGY.\")\n            self.klingons_fire()\n            return\n        elif world.quadrant.get_value(torpedo_x, torpedo_y) == Entity.starbase:\n            print(\"*** STARBASE DESTROYED ***\")\n            self.world.quadrant.nb_bases -= 1\n            world.bases_in_galaxy -= 1\n            if (\n                world.bases_in_galaxy == 0\n                and world.remaining_klingons\n                <= world.stardate - world.initial_stardate - world.mission_duration\n            ):\n                print(\"THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND\")\n                print(\"AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!\")\n                self.end_game(won=False)\n                return\n            print(\"STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER\")\n            print(\"COURT MARTIAL!\")\n            ship.docked = False\n\n        world.quadrant.set_value(torpedo_x, torpedo_y, Entity.void)\n        world.galaxy_map[ship.position.quadrant.x][\n            ship.position.quadrant.y\n        ] = QuadrantData(\n            self.world.quadrant.nb_klingons,\n            self.world.quadrant.nb_bases,\n            self.world.quadrant.nb_stars,\n        )\n        world.charted_galaxy_map[ship.position.quadrant.x][\n            ship.position.quadrant.y\n        ] = world.galaxy_map[ship.position.quadrant.x][ship.position.quadrant.y]\n        self.klingons_fire()\n\n    def short_range_scan(self) -> None:\n        \"\"\"Print a short range scan.\"\"\"\n        self.world.ship.docked = False\n        ship = self.world.ship\n        for x in (\n            ship.position.sector.x - 1,\n            ship.position.sector.x,\n            ship.position.sector.x + 1,\n        ):\n            for y in (\n                ship.position.sector.y - 1,\n                ship.position.sector.y,\n                ship.position.sector.y + 1,\n            ):\n                if (\n                    0 <= x <= 7\n                    and 0 <= y <= 7\n                    and self.world.quadrant.get_value(x, y) == Entity.starbase\n                ):\n                    ship.docked = True\n                    cs = \"DOCKED\"\n                    ship.refill()\n                    print(\"SHIELDS DROPPED FOR DOCKING PURPOSES\")\n                    ship.shields = 0\n                    break\n            else:\n                continue\n            break\n        else:\n            if self.world.quadrant.nb_klingons > 0:\n                cs = \"*RED*\"\n            elif ship.energy < Ship.energy_capacity * 0.1:\n                cs = \"YELLOW\"\n            else:\n                cs = \"GREEN\"\n\n        if ship.damage_stats[1] < 0:\n            print(\"\\n*** SHORT RANGE SENSORS ARE OUT ***\\n\")\n            return\n\n        sep = \"---------------------------------\"\n        print(sep)\n        for x in range(8):\n            line = \"\"\n            for y in range(8):\n                line = f\"{line} {self.world.quadrant.data[x][y].value}\"\n\n            if x == 0:\n                line += f\"        STARDATE           {round(int(self.world.stardate * 10) * 0.1, 1)}\"\n            elif x == 1:\n                line += f\"        CONDITION          {cs}\"\n            elif x == 2:\n                line += f\"        QUADRANT           {ship.position.quadrant}\"\n            elif x == 3:\n                line += f\"        SECTOR             {ship.position.sector}\"\n            elif x == 4:\n                line += f\"        PHOTON TORPEDOES   {int(ship.torpedoes)}\"\n            elif x == 5:\n                line += f\"        TOTAL ENERGY       {int(ship.energy + ship.shields)}\"\n            elif x == 6:\n                line += f\"        SHIELDS            {int(ship.shields)}\"\n            else:\n                line += f\"        KLINGONS REMAINING {self.world.remaining_klingons}\"\n\n            print(line)\n        print(sep)\n\n    def long_range_scan(self) -> None:\n        \"\"\"Print a long range scan.\"\"\"\n        if self.world.ship.damage_stats[2] < 0:\n            print(\"LONG RANGE SENSORS ARE INOPERABLE\")\n            return\n\n        print(f\"LONG RANGE SCAN FOR QUADRANT {self.world.ship.position.quadrant}\")\n        print_scan_results(\n            self.world.ship.position.quadrant,\n            self.world.galaxy_map,\n            self.world.charted_galaxy_map,\n        )\n\n    def navigation(self) -> None:\n        \"\"\"\n        Take navigation input and move the Enterprise.\n\n        1/8 warp goes 1 sector in the direction dirs[course]\n        \"\"\"\n        world = self.world\n        ship = world.ship\n\n        cd = get_user_float(\"COURSE (1-9)? \") - 1  # Convert to 0-8\n        if cd == len(dirs) - 1:\n            cd = 0\n        if cd < 0 or cd >= len(dirs):\n            print(\"   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'\")\n            return\n\n        warp = get_user_float(\n            f\"WARP FACTOR (0-{'0.2' if ship.damage_stats[0] < 0 else '8'})? \"\n        )\n        if ship.damage_stats[0] < 0 and warp > 0.2:\n            print(\"WARP ENGINES ARE DAMAGED. MAXIMUM SPEED = WARP 0.2\")\n            return\n        if warp == 0:\n            return\n        if warp < 0 or warp > 8:\n            print(\n                f\"   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE WARP {warp}!'\"\n            )\n            return\n\n        warp_rounds = round(warp * 8)\n        if ship.energy < warp_rounds:\n            print(\"ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE\")\n            print(f\"                       FOR MANEUVERING AT WARP {warp}!'\")\n            if ship.shields >= warp_rounds - ship.energy and ship.damage_stats[6] >= 0:\n                print(\n                    f\"DEFLECTOR CONTROL ROOM ACKNOWLEDGES {ship.shields} UNITS OF ENERGY\"\n                )\n                print(\"                         PRESENTLY DEPLOYED TO SHIELDS.\")\n            return\n\n        # klingons move and fire\n        for klingon_ship in self.world.quadrant.klingon_ships:\n            if klingon_ship.shield != 0:\n                world.quadrant.set_value(\n                    klingon_ship.sector.x, klingon_ship.sector.y, Entity.void\n                )\n                (\n                    klingon_ship.sector.x,\n                    klingon_ship.sector.y,\n                ) = world.quadrant.find_empty_place()\n                world.quadrant.set_value(\n                    klingon_ship.sector.x, klingon_ship.sector.y, Entity.klingon\n                )\n\n        self.klingons_fire()\n\n        # repair damaged devices and print damage report\n        line = \"\"\n        for i in range(8):\n            if ship.damage_stats[i] < 0:\n                ship.damage_stats[i] += min(warp, 1)\n                if -0.1 < ship.damage_stats[i] < 0:\n                    ship.damage_stats[i] = -0.1\n                elif ship.damage_stats[i] >= 0:\n                    if len(line) == 0:\n                        line = \"DAMAGE CONTROL REPORT:\"\n                    line += f\"   {ship.devices[i]} REPAIR COMPLETED\\n\"\n        if len(line) > 0:\n            print(line)\n        if random.random() <= 0.2:\n            device = fnr()\n            if random.random() < 0.6:\n                ship.damage_stats[device] -= random.random() * 5 + 1\n                print(f\"DAMAGE CONTROL REPORT:   {ship.devices[device]} DAMAGED\\n\")\n            else:\n                ship.damage_stats[device] += random.random() * 3 + 1\n                print(\n                    f\"DAMAGE CONTROL REPORT:   {ship.devices[device]} STATE OF REPAIR IMPROVED\\n\"\n                )\n\n        self.move_ship(warp_rounds, cd)\n        world.stardate += 0.1 * int(10 * warp) if warp < 1 else 1\n        if world.has_mission_ended():\n            self.end_game(won=False, quit=False)\n            return\n\n        self.short_range_scan()\n\n    def move_ship(self, warp_rounds: int, cd: float) -> None:\n        assert cd >= 0\n        assert cd < len(dirs) - 1\n        # cd is the course data which points to 'dirs'\n        world = self.world\n        ship = self.world.ship\n        world.quadrant.set_value(\n            int(ship.position.sector.x), int(ship.position.sector.y), Entity.void\n        )\n        cdi = int(cd)\n\n        # Interpolate direction:\n        dx = dirs[cdi][0] + (dirs[cdi + 1][0] - dirs[cdi][0]) * (cd - cdi)\n        dy = dirs[cdi][1] + (dirs[cdi + 1][1] - dirs[cdi][1]) * (cd - cdi)\n\n        start_quadrant = Point(ship.position.quadrant.x, ship.position.quadrant.y)\n        sector_start_x: float = ship.position.sector.x\n        sector_start_y: float = ship.position.sector.y\n\n        for _ in range(warp_rounds):\n            ship.position.sector.x += dx  # type: ignore\n            ship.position.sector.y += dy  # type: ignore\n\n            if (\n                ship.position.sector.x < 0\n                or ship.position.sector.x > 7\n                or ship.position.sector.y < 0\n                or ship.position.sector.y > 7\n            ):\n                # exceeded quadrant limits; calculate final position\n                sector_start_x += ship.position.quadrant.x * 8 + warp_rounds * dx\n                sector_start_y += ship.position.quadrant.y * 8 + warp_rounds * dy\n                ship.position.quadrant.x = int(sector_start_x / 8)\n                ship.position.quadrant.y = int(sector_start_y / 8)\n                ship.position.sector.x = int(\n                    sector_start_x - ship.position.quadrant.x * 8\n                )\n                ship.position.sector.y = int(\n                    sector_start_y - ship.position.quadrant.y * 8\n                )\n                if ship.position.sector.x < 0:\n                    ship.position.quadrant.x -= 1\n                    ship.position.sector.x = 7\n                if ship.position.sector.y < 0:\n                    ship.position.quadrant.y -= 1\n                    ship.position.sector.y = 7\n\n                hit_edge = False\n                if ship.position.quadrant.x < 0:\n                    hit_edge = True\n                    ship.position.quadrant.x = ship.position.sector.x = 0\n                if ship.position.quadrant.x > 7:\n                    hit_edge = True\n                    ship.position.quadrant.x = ship.position.sector.x = 7\n                if ship.position.quadrant.y < 0:\n                    hit_edge = True\n                    ship.position.quadrant.y = ship.position.sector.y = 0\n                if ship.position.quadrant.y > 7:\n                    hit_edge = True\n                    ship.position.quadrant.y = ship.position.sector.y = 7\n                if hit_edge:\n                    print(\"LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:\")\n                    print(\"  'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER\")\n                    print(\"  IS HEREBY *DENIED*. SHUT DOWN YOUR ENGINES.'\")\n                    print(\"CHIEF ENGINEER SCOTT REPORTS  'WARP ENGINES SHUT DOWN\")\n                    print(\n                        f\"  AT SECTOR {ship.position.sector} OF \"\n                        f\"QUADRANT {ship.position.quadrant}.'\"\n                    )\n                    if world.has_mission_ended():\n                        self.end_game(won=False, quit=False)\n                        return\n\n                stayed_in_quadrant = (\n                    ship.position.quadrant.x == start_quadrant.x\n                    and ship.position.quadrant.y == start_quadrant.y\n                )\n                if stayed_in_quadrant:\n                    break\n                world.stardate += 1\n                ship.maneuver_energy(warp_rounds)\n                self.new_quadrant()\n                return\n            ship_sector = self.world.ship.position.sector\n            ship_x = int(ship_sector.x)\n            ship_y = int(ship_sector.y)\n            if self.world.quadrant.data[ship_x][ship_y] != Entity.void:\n                ship_sector.x = int(ship_sector.x - dx)\n                ship_sector.y = int(ship_sector.y - dy)\n                print(\n                    \"WARP ENGINES SHUT DOWN AT SECTOR \"\n                    f\"{ship_sector} DUE TO BAD NAVIGATION\"\n                )\n                break\n        else:\n            ship.position.sector.x, ship.position.sector.y = int(\n                ship.position.sector.x\n            ), int(ship.position.sector.y)\n\n        world.quadrant.set_value(\n            int(ship.position.sector.x), int(ship.position.sector.y), Entity.ship\n        )\n        ship.maneuver_energy(warp_rounds)\n\n    def damage_control(self) -> None:\n        \"\"\"Print a damage control report.\"\"\"\n        ship = self.world.ship\n\n        if ship.damage_stats[5] < 0:\n            print(\"DAMAGE CONTROL REPORT NOT AVAILABLE\")\n        else:\n            print(\"\\nDEVICE             STATE OF REPAIR\")\n            for r1 in range(8):\n                print(\n                    f\"{ship.devices[r1].ljust(26, ' ')}{int(ship.damage_stats[r1] * 100) * 0.01:g}\"\n                )\n            print()\n\n        if not ship.docked:\n            return\n\n        damage_sum = sum(0.1 for i in range(8) if ship.damage_stats[i] < 0)\n        if damage_sum == 0:\n            return\n\n        damage_sum += self.world.quadrant.delay_in_repairs_at_base\n        if damage_sum >= 1:\n            damage_sum = 0.9\n        print(\"\\nTECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;\")\n        print(\n            f\"ESTIMATED TIME TO REPAIR: {round(0.01 * int(100 * damage_sum), 2)} STARDATES\"\n        )\n        if input(\"WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)? \").upper().strip() != \"Y\":\n            return\n\n        for i in range(8):\n            ship.damage_stats[i] = max(ship.damage_stats[i], 0)\n        self.world.stardate += damage_sum + 0.1\n\n    def computer(self) -> None:\n        \"\"\"Perform the various functions of the library computer.\"\"\"\n        world = self.world\n        ship = world.ship\n\n        if ship.damage_stats[7] < 0:\n            print(\"COMPUTER DISABLED\")\n            return\n\n        while True:\n            command = input(\"COMPUTER ACTIVE AND AWAITING COMMAND? \")\n            if len(command) == 0:\n                com = 6\n            else:\n                try:\n                    com = int(command)\n                except ValueError:\n                    com = 6\n            if com < 0:\n                return\n\n            print()\n\n            if com in {0, 5}:\n                if com == 5:\n                    print(\"                        THE GALAXY\")\n                else:\n                    print(\n                        \"\\n        COMPUTER RECORD OF GALAXY FOR \"\n                        f\"QUADRANT {ship.position.quadrant}\\n\"\n                    )\n\n                print(\"       1     2     3     4     5     6     7     8\")\n                sep = \"     ----- ----- ----- ----- ----- ----- ----- -----\"\n                print(sep)\n\n                for i in range(8):\n                    line = f\" {str(i + 1)} \"\n\n                    if com == 5:\n                        g2s = Quadrant.quadrant_name(i, 0, True)\n                        line += (\" \" * int(12 - 0.5 * len(g2s))) + g2s\n                        g2s = Quadrant.quadrant_name(i, 4, True)\n                        line += (\" \" * int(39 - 0.5 * len(g2s) - len(line))) + g2s\n                    else:\n                        for j in range(8):\n                            line += \"   \"\n                            if world.charted_galaxy_map[i][j].num() == 0:\n                                line += \"***\"\n                            else:\n                                line += str(\n                                    world.charted_galaxy_map[i][j].num() + 1000\n                                )[-3:]\n\n                    print(line)\n                    print(sep)\n\n                print()\n            elif com == 1:\n                print(\"   STATUS REPORT:\")\n                print(\n                    f\"KLINGON{'S' if world.remaining_klingons > 1 else ''} LEFT: {world.remaining_klingons}\"\n                )\n                print(\n                    \"MISSION MUST BE COMPLETED IN \"\n                    f\"{round(0.1 * int(world.remaining_time() * 10), 1)} STARDATES\"\n                )\n\n                if world.bases_in_galaxy == 0:\n                    print(\"YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN\")\n                    print(\"  THE GALAXY -- YOU HAVE NO STARBASES LEFT!\")\n                else:\n                    print(\n                        f\"THE FEDERATION IS MAINTAINING {world.bases_in_galaxy} \"\n                        f\"STARBASE{'S' if world.bases_in_galaxy > 1 else ''} IN THE GALAXY\"\n                    )\n\n                self.damage_control()\n            elif com == 2:\n                if self.world.quadrant.nb_klingons <= 0:\n                    print(\n                        \"SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY \"\n                        \"SHIPS\\n\"\n                        \"                                IN THIS QUADRANT'\"\n                    )\n                    return\n\n                print(\n                    f\"FROM ENTERPRISE TO KLINGON BATTLE CRUISER{'S' if self.world.quadrant.nb_klingons > 1 else ''}\"\n                )\n\n                for klingon_ship in self.world.quadrant.klingon_ships:\n                    if klingon_ship.shield > 0:\n                        print_direction(\n                            Point(ship.position.sector.x, ship.position.sector.y),\n                            Point(\n                                int(klingon_ship.sector.x),\n                                int(klingon_ship.sector.y),\n                            ),\n                        )\n            elif com == 3:\n                if self.world.quadrant.nb_bases == 0:\n                    print(\n                        \"MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS \"\n                        \"QUADRANT.'\"\n                    )\n                    return\n\n                print(\"FROM ENTERPRISE TO STARBASE:\")\n                print_direction(\n                    Point(ship.position.sector.x, ship.position.sector.y),\n                    self.world.quadrant.starbase,\n                )\n            elif com == 4:\n                print(\"DIRECTION/DISTANCE CALCULATOR:\")\n                print(\n                    f\"YOU ARE AT QUADRANT {ship.position.quadrant} \"\n                    f\"SECTOR {ship.position.sector}\"\n                )\n                print(\"PLEASE ENTER\")\n                while True:\n                    coordinates = input(\"  INITIAL COORDINATES (X,Y)? \").split(\",\")\n                    if len(coordinates) == 2:\n                        from1, from2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1\n                        if 0 <= from1 <= 7 and 0 <= from2 <= 7:\n                            break\n                while True:\n                    coordinates = input(\"  FINAL COORDINATES (X,Y)? \").split(\",\")\n                    if len(coordinates) == 2:\n                        to1, to2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1\n                        if 0 <= to1 <= 7 and 0 <= to2 <= 7:\n                            break\n                print_direction(Point(from1, from2), Point(to1, to2))\n            else:\n                print(\n                    \"FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\\n\"\n                    \"   0 = CUMULATIVE GALACTIC RECORD\\n\"\n                    \"   1 = STATUS REPORT\\n\"\n                    \"   2 = PHOTON TORPEDO DATA\\n\"\n                    \"   3 = STARBASE NAV DATA\\n\"\n                    \"   4 = DIRECTION/DISTANCE CALCULATOR\\n\"\n                    \"   5 = GALAXY 'REGION NAME' MAP\\n\"\n                )\n\n    def end_game(\n        self, won: bool = False, quit: bool = True, enterprise_killed: bool = False\n    ) -> None:\n        \"\"\"Handle end-of-game situations.\"\"\"\n        if won:\n            print(\"CONGRATULATIONS, CAPTAIN! THE LAST KLINGON BATTLE CRUISER\")\n            print(\"MENACING THE FEDERATION HAS BEEN DESTROYED.\\n\")\n            print(\n                f\"YOUR EFFICIENCY RATING IS {round(1000 * (self.world.remaining_klingons / (self.world.stardate - self.world.initial_stardate))**2, 4)}\\n\\n\"\n            )\n        else:\n            if not quit:\n                if enterprise_killed:\n                    print(\n                        \"\\nTHE ENTERPRISE HAS BEEN DESTROYED. THE FEDERATION \"\n                        \"WILL BE CONQUERED.\"\n                    )\n                print(f\"IT IS STARDATE {round(self.world.stardate, 1)}\")\n\n            print(\n                f\"THERE WERE {self.world.remaining_klingons} KLINGON BATTLE CRUISERS LEFT AT\"\n            )\n            print(\"THE END OF YOUR MISSION.\\n\\n\")\n\n            if self.world.bases_in_galaxy == 0:\n                sys.exit()\n\n        print(\"THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER\")\n        print(\"FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,\")\n        if input(\"LET HIM STEP FORWARD AND ENTER 'AYE'? \").upper().strip() != \"AYE\":\n            sys.exit()\n        self.restart = True\n\n\nklingon_shield_strength: Final = 200\n# 8 sectors = 1 quadrant\ndirs: Final = [  # (down-up, left,right)\n    [0, 1],  # 1: go right (same as #9)\n    [-1, 1],  # 2: go up-right\n    [-1, 0],  # 3: go up  (lower x-coordines; north)\n    [-1, -1],  # 4: go up-left (north-west)\n    [0, -1],  # 5: go left (west)\n    [1, -1],  # 6: go down-left (south-west)\n    [1, 0],  # 7: go down (higher x-coordines; south)\n    [1, 1],  # 8: go down-right\n    [0, 1],  # 9: go right (east)\n]  # vectors in cardinal directions\n\n\ndef fnr() -> int:\n    \"\"\"Generate a random integer from 0 to 7 inclusive.\"\"\"\n    return random.randint(0, 7)\n\n\ndef print_scan_results(\n    quadrant: Point,\n    galaxy_map: List[List[QuadrantData]],\n    charted_galaxy_map: List[List[QuadrantData]],\n) -> None:\n    sep = \"-------------------\"\n    print(sep)\n    for x in (quadrant.x - 1, quadrant.x, quadrant.x + 1):\n        n: List[Optional[int]] = [None, None, None]\n\n        # Reveal parts of the current map\n        for y in (quadrant.y - 1, quadrant.y, quadrant.y + 1):\n            if 0 <= x <= 7 and 0 <= y <= 7:\n                n[y - quadrant.y + 1] = galaxy_map[x][y].num()\n                charted_galaxy_map[x][y] = galaxy_map[x][y]\n\n        line = \": \"\n        for line_col in n:\n            if line_col is None:\n                line += \"*** : \"\n            else:\n                line += str(line_col + 1000).rjust(4, \" \")[-3:] + \" : \"\n        print(line)\n        print(sep)\n\n\ndef print_direction(source: Point, to: Point) -> None:\n    \"\"\"Print direction and distance between two locations in the grid.\"\"\"\n    delta1 = -(to.x - source.x)  # flip so positive is up (heading = 3)\n    delta2 = to.y - source.y\n\n    if delta2 > 0:\n        if delta1 < 0:\n            base = 7\n        else:\n            base = 1\n            delta1, delta2 = delta2, delta1\n    elif delta1 > 0:\n        base = 3\n    else:\n        base = 5\n        delta1, delta2 = delta2, delta1\n\n    delta1, delta2 = abs(delta1), abs(delta2)\n\n    if delta1 > 0 or delta2 > 0:  # bug in original; no check for divide by 0\n        if delta1 >= delta2:\n            print(f\"DIRECTION = {round(base + delta2 / delta1, 6)}\")\n        else:\n            print(f\"DIRECTION = {round(base + 2 - delta1 / delta2, 6)}\")\n\n    print(f\"DISTANCE = {round(sqrt(delta1 ** 2 + delta2 ** 2), 6)}\")\n\n\ndef main() -> None:\n    game = Game()\n    world = game.world\n    ship = world.ship\n\n    f: Dict[str, Callable[[], None]] = {\n        \"NAV\": game.navigation,\n        \"SRS\": game.short_range_scan,\n        \"LRS\": game.long_range_scan,\n        \"PHA\": game.phaser_control,\n        \"TOR\": game.photon_torpedoes,\n        \"SHE\": ship.shield_control,\n        \"DAM\": game.damage_control,\n        \"COM\": game.computer,\n        \"XXX\": game.end_game,\n    }\n\n    while True:\n        game.startup()\n        game.new_quadrant()\n        restart = False\n\n        while not restart:\n            if ship.shields + ship.energy <= 10 or (\n                ship.energy <= 10 and ship.damage_stats[6] != 0\n            ):\n                print(\n                    \"\\n** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP \"\n                    \"IN SPACE.\\nYOU HAVE INSUFFICIENT MANEUVERING ENERGY, \"\n                    \"AND SHIELD CONTROL\\nIS PRESENTLY INCAPABLE OF CROSS-\"\n                    \"CIRCUITING TO ENGINE ROOM!!\"\n                )\n\n            command = input(\"COMMAND? \").upper().strip()\n\n            if command in f:\n                f[command]()\n            else:\n                print(\n                    \"ENTER ONE OF THE FOLLOWING:\\n\"\n                    \"  NAV  (TO SET COURSE)\\n\"\n                    \"  SRS  (FOR SHORT RANGE SENSOR SCAN)\\n\"\n                    \"  LRS  (FOR LONG RANGE SENSOR SCAN)\\n\"\n                    \"  PHA  (TO FIRE PHASERS)\\n\"\n                    \"  TOR  (TO FIRE PHOTON TORPEDOES)\\n\"\n                    \"  SHE  (TO RAISE OR LOWER SHIELDS)\\n\"\n                    \"  DAM  (FOR DAMAGE CONTROL REPORTS)\\n\"\n                    \"  COM  (TO CALL ON LIBRARY-COMPUTER)\\n\"\n                    \"  XXX  (TO RESIGN YOUR COMMAND)\\n\"\n                )\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "84_Super_Star_Trek/python/superstartrekins.py",
    "content": "\"\"\"\nSUPER STARTREK INSTRUCTIONS\nMAR 5, 1978\n\nJust the instructions for SUPERSTARTREK\n\nPorted by Dave LeCompte\n\"\"\"\n\n\ndef get_yes_no(prompt: str) -> bool:\n    response = input(prompt).upper()\n    return response[0] != \"N\"\n\n\ndef print_header() -> None:\n    for _ in range(12):\n        print()\n    t10 = \" \" * 10\n    print(f\"{t10}*************************************\")\n    print(f\"{t10}*                                   *\")\n    print(f\"{t10}*                                   *\")\n    print(f\"{t10}*      * * SUPER STAR TREK * *      *\")\n    print(f\"{t10}*                                   *\")\n    print(f\"{t10}*                                   *\")\n    print(f\"{t10}*************************************\")\n    for _ in range(8):\n        print()\n\n\ndef print_instructions() -> None:\n    # Back in the 70s, at this point, the user would be prompted to\n    # turn on their (printing) TTY to capture the output to hard copy.\n\n    print(\"      INSTRUCTIONS FOR 'SUPER STAR TREK'\")\n    print()\n    print(\"1. WHEN YOU SEE \\\\COMMAND ?\\\\ PRINTED, ENTER ONE OF THE LEGAL\")\n    print(\"     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\")\n    print(\"2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\")\n    print(\"     LIST OF THE LEGAL COMMANDS PRINTED OUT.\")\n    print(\"3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\")\n    print(\"     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\")\n    print(\"     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\")\n    print(\"     WILL BE ABORTED\")\n    print()\n    print(\"     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\")\n    print(\"AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\")\n    print()\n    print(\"     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\")\n    print(\"GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\")\n    print(\"\\\\ENTERPRISE\\\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\")\n    print(\"KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\")\n    print(\"PLANETS.\")\n    print()\n    print(\"     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\")\n    print(\"OF THE STARSHIP ENTERPRISE:\")\n    print()\n    print(\"\\\\NAV\\\\ COMMAND = WARP ENGINE CONTROL --\")\n    print(\"     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\")\n    print(\"     VECTOR ARRANGEMENT AS SHOWN             . . .\")\n    print(\"     INTEGER AND REAL VALUES MAY BE           ...\")\n    print(\"     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\")\n    print(\"     WAY BETWEEN 1 AND 2                      ...\")\n    print(\"                                             . . .\")\n    print(\"     VALUES MAY APPROACH 9.0, WHICH         6  7  8\")\n    print(\"     ITSELF IS EQUIVALENT TO 1.0\")\n    print(\"                                            COURSE\")\n    print(\"     ONE WARP FACTOR IS THE SIZE OF \")\n    print(\"     ONE QUADTANT.  THEREFORE, TO GET\")\n    print(\"     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\")\n    print(\"     USE COURSE 3, WARP FACTOR 1.\")\n    print()\n    print(\"\\\\SRS\\\\ COMMAND = SHORT RANGE SENSOR SCAN\")\n    print(\"     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\")\n    print()\n    print(\"     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\")\n    print(\"        <*> = YOUR STARSHIP'S POSITION\")\n    print(\"        +K+ = KLINGON BATTLE CRUISER\")\n    print(\"        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\")\n    print(\"         *  = STAR\")\n    print()\n    print(\"     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\")\n    print()\n    print(\"\\\\LRS\\\\ COMMAND = LONG RANGE SENSOR SCAN\")\n    print(\"     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\")\n    print(\"     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\")\n    print(\"     THE SCAN IS CODED IN THE FORM \\\\###\\\\, WHERE TH UNITS DIGIT\")\n    print(\"     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\")\n    print(\"     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF\")\n    print(\"     KLINGONS.\")\n    print()\n    print(\"     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\")\n    print()\n    print(\"\\\\PHA\\\\ COMMAND = PHASER CONTROL.\")\n    print(\"     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY \")\n    print(\"     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\")\n    print(\"     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE\")\n    print(\"     PHASERS TOO!)\")\n    print()\n    print(\"\\\\TOR\\\\ COMMAND = PHOTON TORPEDO CONTROL\")\n    print(\"     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\")\n    print(\"     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\")\n    print(\"     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\")\n    print(\"     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO \")\n    print(\"     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\")\n    print()\n    print(\"     THE LIBRARY-COMPUTER (\\\\COM\\\\ COMMAND) HAS AN OPTION TO \")\n    print(\"     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\")\n    print()\n    print(\"\\\\SHE\\\\ COMMAND = SHIELD CONTROL\")\n    print(\"     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\")\n    print(\"     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\")\n    print(\"     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\")\n    print()\n    print(\"\\\\DAM\\\\ COMMAND = DAMMAGE CONTROL REPORT\")\n    print(\"     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\")\n    print(\"     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\")\n    print(\"     DAMAGED.\")\n    print()\n    print(\"\\\\COM\\\\ COMMAND = LIBRARY-COMPUTER\")\n    print(\"     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\")\n    print(\"     OPTION 0 = CUMULATIVE GALACTIC RECORD\")\n    print(\"        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\")\n    print(\"        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\")\n    print(\"     OPTION 1 = STATUS REPORT\")\n    print(\"        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\")\n    print(\"        AND STARBASES REMAINING IN THE GAME.\")\n    print(\"     OPTION 2 = PHOTON TORPEDO DATA\")\n    print(\"        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\")\n    print(\"        TO ALL KLINGONS IN YOUR QUADRANT\")\n    print(\"     OPTION 3 = STARBASE NAV DATA\")\n    print(\"        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY \")\n    print(\"        STARBASE WITHIN YOUR QUADRANT\")\n    print(\"     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\")\n    print(\"        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\")\n    print(\"        DIRECTION/DISTANCE CALCULATIONS\")\n    print(\"     OPTION 5 = GALACTIC /REGION NAME/ MAP\")\n    print(\"        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR \")\n    print(\"        GALACTIC REGIONS REFERRED TO IN THE GAME.\")\n\n\ndef main() -> None:\n    print_header()\n    if not get_yes_no(\"DO YOU NEED INSTRUCTIONS (Y/N)? \"):\n        return\n    print_instructions()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "84_Super_Star_Trek/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "84_Super_Star_Trek/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nctrlc = \"3.2.5\"\nrand = \"0.8.5\"\n"
  },
  {
    "path": "84_Super_Star_Trek/rust/readme.md",
    "content": "# Super Star Trek - Rust version\n\nExplanation of modules:\n\n- [main.rs](./src/main.rs) - creates the galaxy (generation functions are in model.rs as impl methods) then loops listening for commands. after each command checks for victory or defeat condtions.\n- [model.rs](./src/model.rs) - all the structs and enums that represent the galaxy. key methods in here (as impl methods) are generation functions on galaxy and quadrant, and various comparison methods on the 'Pos' tuple type.\n- [commands.rs](./src/commands.rs) - most of the code that implements instructions given by the player (some code logic is in the model impls, and some in view.rs if its view only).\n- [view.rs](./src/view.rs) - all text printed to the output, mostly called by command.rs (like view::bad_nav for example). also contains the prompts printed to the user (e.g. view::prompts::COMMAND).\n- [input.rs](./src/input.rs) - utility methods for getting input from the user, including logic for parsing numbers, repeating prompts until a correct value is provided etc.\n\nBasically the user is asked for the next command, this runs a function that usually checks if the command system is working, and if so will gather additional input (see next note for a slight change here), then either the model is read and info printed, or its mutated in some way (e.g. firing a torpedo, which reduces the torpedo count on the enterprise and can destroy klingons and star bases; finally the klingons fire back and can destroy the enterprise). Finally the win/lose conditions are checked before the loop repeats.\n\n## Changes from the original\n\nI have tried to keep it as close as possible. Notable changes are:\n\n- commands can be given with parameters in line. e.g. while 'nav' will ask for course and then warp speed in the original, here you can *optionally* also do this as one line, e.g. `nav 1 0.1` to move one sector east. I'm sorry - it was driving me insane in its original form (which is still sorted, as is partial application e.g. nav 1 to preset direction and then provide speed).\n- text is mostly not uppercase, as text was in the basic version. this would be easy to change however as all text is in view.rs, but I chose not to.\n- the navigation system (plotting direction, paths and collision detection) is as close as I could make it to the basic version (by using other language conversions as specification sources) but I suspect is not perfect. seems to work well enough however."
  },
  {
    "path": "84_Super_Star_Trek/rust/src/commands.rs",
    "content": "use rand::Rng;\n\nuse crate::{model::*, view, input::{self, param_or_prompt_value, prompt_two_values}};\n\npub fn perform_short_range_scan(galaxy: &Galaxy) {\n    if galaxy.enterprise.damaged.contains_key(systems::SHORT_RANGE_SCAN) {\n        view::scanners_out();\n        return;\n    }\n\n    view::short_range_scan(&galaxy)\n}\n\npub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec<String>) {\n\n    if galaxy.enterprise.damaged.contains_key(systems::SHIELD_CONTROL) {\n        view::inoperable(&systems::name_for(systems::SHIELD_CONTROL));\n        return;\n    }\n\n    view::energy_available(galaxy.enterprise.total_energy);\n    let value = input::param_or_prompt_value(&provided, 0, view::prompts::SHIELDS, 0, i32::MAX);\n    if value.is_none() {\n        view::shields_unchanged();\n        return;\n    }\n\n    let value = value.unwrap() as u16;\n    if value > galaxy.enterprise.total_energy {\n        view::ridiculous();\n        view::shields_unchanged();\n        return;\n    }\n\n    galaxy.enterprise.shields = value;\n    view::shields_set(value);\n}\n\npub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec<String>) {\n\n    let course = input::param_or_prompt_value(&provided, 0, view::prompts::COURSE, 1.0, 9.0);\n    if course.is_none() {\n        view::bad_course_data();\n        return;\n    }\n\n    let course = course.unwrap();\n\n    let mut max_warp = 8.0;\n    if galaxy.enterprise.damaged.contains_key(systems::WARP_ENGINES) {\n        max_warp = 0.2;\n    }\n\n    let speed = input::param_or_prompt_value(&provided, 1, &view::prompts::warp_factor(max_warp), 0.0, 8.0);\n    if speed.is_none() {\n        view::bad_course_data();\n        return;\n    }\n    \n    let speed = speed.unwrap();\n\n    if speed > max_warp {\n        view::damaged_engines(max_warp, speed);\n        return;\n    }\n\n    klingons_move(galaxy);\n    klingons_fire(galaxy);\n\n    if galaxy.enterprise.destroyed {\n        return;\n    }\n\n    repair_systems(&mut galaxy.enterprise, speed);\n    repair_or_damage_random_system(&mut galaxy.enterprise);\n\n    move_enterprise(course, speed, galaxy);\n}\n\nfn repair_systems(enterprise: &mut Enterprise, amount: f32) {\n\n    let keys: Vec<String> = enterprise.damaged.keys().map(|k| k.to_string()).collect();\n    let mut repaired = Vec::new();\n    for key in keys {\n        let fully_fixed = enterprise.repair_system(&key, amount);\n        if fully_fixed {\n            repaired.push(systems::name_for(&key));\n        }\n    }\n\n    if repaired.len() <= 0 {\n        return;\n    }\n\n    view::damage_control_report();\n    for name in repaired {\n        view::system_repair_completed(name);\n    }\n}\n\nfn repair_or_damage_random_system(enterprise: &mut Enterprise) {\n    let mut rng = rand::thread_rng();\n\n    if rng.gen::<f32>() > 0.2 {\n        return;\n    }\n\n    if rng.gen::<f32>() >= 0.6 {\n        if enterprise.damaged.len() == 0 {\n            return;\n        }\n\n        let damaged: Vec<String> = enterprise.damaged.keys().map(|k| k.to_string()).collect();\n        let system = damaged[rng.gen_range(0..damaged.len())].to_string();\n        let system_name = &systems::name_for(&system);\n\n        enterprise.repair_system(&system, rng.gen::<f32>() * 3.0 + 1.0);\n        view::random_repair_report_for(system_name, false);\n        return;\n    }\n    \n    let system = systems::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string();\n    let system_name = &systems::name_for(&system);\n\n    enterprise.damage_system(&system, rng.gen::<f32>() * 5.0 + 1.0);\n    view::random_repair_report_for(system_name, true);\n}\n\nfn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) {\n\n    let ship = &mut galaxy.enterprise;\n\n    let (mut path, mut hit_edge) = find_nav_path(ship.quadrant, ship.sector, course, warp_speed);\n    for i in 0..path.len() {\n        let (quadrant, sector) = path[i].to_local_quadrant_sector();\n        if quadrant != ship.quadrant {\n            break; // have left current quadrant, so collision checks removed. if there is a collision at the dest... /shrug?\n        }\n        let quadrant = &galaxy.quadrants[quadrant.as_index()];\n        if quadrant.sector_status(sector) != SectorStatus::Empty {\n            path = path[..i].into();\n            hit_edge = false;\n            if i > 0 {\n                let (_, last_sector) = path[path.len() - 1].to_local_quadrant_sector();\n                view::bad_nav(last_sector);\n            } else {\n                view::bad_nav(ship.sector);\n                return;\n            }\n            break;\n        }\n    }\n\n    if path.len() == 0 {\n        if hit_edge {\n            view::hit_edge(ship.quadrant, ship.sector);\n        }\n        return;   \n    }\n\n    let energy_cost = path.len() as u16 + 10;\n\n    if energy_cost > ship.total_energy {\n        view::insuffient_warp_energy(warp_speed);\n        return\n    }\n\n    let (end_quadrant, end_sector) = path[path.len() - 1].to_local_quadrant_sector();\n    if hit_edge {\n        view::hit_edge(end_quadrant, end_sector);\n    }\n    \n    if ship.quadrant != end_quadrant {\n        view::enter_quadrant(end_quadrant);\n        galaxy.scanned.insert(end_quadrant);\n        \n        if galaxy.quadrants[end_quadrant.as_index()].klingons.len() > 0 {\n            view::condition_red();\n            if ship.shields <= 200 {\n                view::danger_shields();\n            }\n        }\n    }\n\n    ship.quadrant = end_quadrant;\n    ship.sector = end_sector;\n\n    let quadrant = &galaxy.quadrants[end_quadrant.as_index()];\n    if quadrant.docked_at_starbase(ship.sector) {\n        ship.shields = 0;\n        ship.photon_torpedoes = MAX_PHOTON_TORPEDOES;\n        ship.total_energy = MAX_ENERGY;\n    } else {\n        ship.total_energy = ship.total_energy - energy_cost;\n        if ship.shields > ship.total_energy {\n            view::divert_energy_from_shields();\n            ship.shields = ship.total_energy;\n        }\n    }\n\n    view::short_range_scan(&galaxy)\n}\n\nfn find_nav_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> (Vec<Pos>, bool) {\n\n    let (dx, dy) = calculate_delta(course);\n\n    let mut distance = (warp_speed * 8.0) as i8;\n    if distance == 0 {\n        distance = 1;\n    }\n\n    let mut last_sector = start_sector.as_galactic_sector(start_quadrant);\n    let mut path = Vec::new();\n    let mut hit_edge;\n\n    loop {\n        let nx = (last_sector.0 as f32 + dx) as i8;\n        let ny = (last_sector.1 as f32 + dy) as i8;\n        hit_edge = nx < 0 || ny < 0 || nx >= 64 || ny >= 64;\n        if hit_edge {\n            break;\n        }\n        last_sector = Pos(nx as u8, ny as u8);\n        path.push(last_sector);\n\n        distance -= 1;\n        if distance == 0 {\n            break;\n        }\n    }\n  \n    (path, hit_edge)\n}\n\nfn calculate_delta(course: f32) -> (f32, f32) {\n    // this course delta stuff is a translation (of a translation, of a translation...) of the original basic calcs\n    let dir = (course - 1.0) % 8.0;\n    let (dx1, dy1) = COURSES[dir as usize];\n    let (dx2, dy2) = COURSES[(dir + 1.0) as usize];\n    let frac = dir - (dir as i32) as f32;\n\n    let dx = dx1 + (dx2 - dx1) * frac;\n    let dy = dy1 + (dy2 - dy1) * frac;\n\n    (dx, dy)\n}\n\nfn klingons_move(galaxy: &mut Galaxy) {\n    let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()];\n    for k in 0..quadrant.klingons.len() {\n        let new_sector: Pos;\n        loop {\n            let candidate = quadrant.find_empty_sector();\n            if candidate != galaxy.enterprise.sector {\n                new_sector = candidate;\n                break;\n            }\n        }\n        quadrant.klingons[k].sector = new_sector;\n    }\n}\n\nfn klingons_fire(galaxy: &mut Galaxy) {\n    let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()];\n    if quadrant.docked_at_starbase(galaxy.enterprise.sector) {\n        view::starbase_shields();\n        return;\n    }\n\n    for k in 0..quadrant.klingons.len() {\n        quadrant.klingons[k].fire_on(&mut galaxy.enterprise);\n    }\n}\n\npub fn run_damage_control(galaxy: &Galaxy) {\n    if galaxy.enterprise.damaged.contains_key(systems::DAMAGE_CONTROL) {\n        view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL));\n        return;\n    }\n    \n    view::damage_control(&galaxy.enterprise);\n}\n\npub fn try_starbase_ship_repair(galaxy: &mut Galaxy) {\n    let ship = &mut galaxy.enterprise;\n    let quadrant = &galaxy.quadrants[ship.quadrant.as_index()];\n    if ship.damaged.len() == 0 || !quadrant.docked_at_starbase(ship.sector) {\n        return;\n    }\n\n    let repair_delay = quadrant.star_base.as_ref().unwrap().repair_delay;\n    let repair_time = (ship.damaged.len() as f32 * 0.1 + repair_delay).max(0.9);\n\n    view::repair_estimate(repair_time);\n    if !input::prompt_yes_no(view::prompts::REPAIR) {\n        return;\n    }\n\n    ship.damaged.clear();\n    galaxy.stardate += repair_time;\n    view::damage_control(&ship);\n}\n\npub fn perform_long_range_scan(galaxy: &mut Galaxy) {\n    if galaxy.enterprise.damaged.contains_key(systems::LONG_RANGE_SCAN) {\n        view::inoperable(&systems::name_for(systems::LONG_RANGE_SCAN));\n        return;\n    }\n\n    let seen = view::long_range_scan(galaxy);\n    for pos in seen {\n        galaxy.scanned.insert(pos);\n    }\n}\n\npub fn access_computer(galaxy: &Galaxy, provided: Vec<String>) {\n    if galaxy.enterprise.damaged.contains_key(systems::COMPUTER) {\n        view::inoperable(&systems::name_for(systems::COMPUTER));\n        return;\n    }\n\n    let operation : i32;\n    loop {\n        let entered = input::param_or_prompt_value(&provided, 0, view::prompts::COMPUTER, 0, 5);\n        if entered.is_none() {\n            view::computer_options();\n        } else {\n            operation = entered.unwrap();\n            break;\n        }\n    } \n    \n    match operation {\n        0 => view::galaxy_scanned_map(galaxy),\n        1 => {\n            view::status_report(galaxy);\n            run_damage_control(galaxy);\n        },\n        2 => show_klingon_direction_data(galaxy),\n        3 => show_starbase_direction_data(galaxy),\n        4 => direction_dist_calculator(galaxy),\n        5 => view::galaxy_region_map(),\n        _ => () // unreachable\n    }\n}\n\nfn show_klingon_direction_data(galaxy: &Galaxy) {\n    let quadrant = &galaxy.quadrants[galaxy.enterprise.quadrant.as_index()];\n    if quadrant.klingons.len() == 0 {\n        view::no_local_enemies();\n        return;\n    }\n\n    view::klingon_report(quadrant.klingons.len() > 1);\n    let origin = galaxy.enterprise.sector;\n    for k in &quadrant.klingons {\n        let target = k.sector;\n        view::direction_distance(origin.direction(target), origin.dist(target))\n    }\n}\n\nfn show_starbase_direction_data(galaxy: &Galaxy) {\n    let quadrant = &galaxy.quadrants[galaxy.enterprise.quadrant.as_index()];\n    match &quadrant.star_base {\n        None => {\n            view::no_local_starbase();\n            return;\n        },\n        Some(s) => {\n            view::starbase_report();\n            let origin = galaxy.enterprise.sector;\n            let target = s.sector;\n            view::direction_distance(origin.direction(target), origin.dist(target))\n        }\n    }\n}\n\nfn direction_dist_calculator(galaxy: &Galaxy) {\n    view::direction_dist_intro(&galaxy.enterprise);\n    loop {\n        let coords1 = prompt_two_values(view::prompts::INITIAL_COORDS, 1, 8).map(|(x, y)| Pos(x, y));\n        if coords1.is_none() {\n            continue;\n        }\n        let coords2 = prompt_two_values(view::prompts::TARGET_COORDS, 1, 8).map(|(x, y)| Pos(x, y));\n        if coords2.is_none() {\n            continue;\n        }\n        let dir = coords1.unwrap().direction(coords2.unwrap());\n        let dist = coords1.unwrap().dist(coords2.unwrap());\n        view::direction_distance(dir, dist);\n        break;\n    }\n}\n\npub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec<String>) {\n    if galaxy.enterprise.damaged.contains_key(systems::PHASERS) {\n        view::inoperable(&systems::name_for(systems::PHASERS));\n        return;\n    }\n\n    let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()];\n    if quadrant.klingons.len() == 0 {\n        view::no_local_enemies();\n        return;\n    }\n\n    let computer_damaged = galaxy.enterprise.damaged.contains_key(systems::COMPUTER);\n    if computer_damaged {\n        view::computer_accuracy_issue();\n    }\n\n    let available_energy = galaxy.enterprise.total_energy - galaxy.enterprise.shields;\n    view::phasers_locked(available_energy);\n    let mut power: f32;\n    loop {\n        let setting = param_or_prompt_value(&provided, 0, view::prompts::PHASERS, 0, available_energy);\n        if setting.is_some() {\n            power = setting.unwrap() as f32;\n            break;\n        }\n    }\n\n    if power == 0.0 {\n        return;\n    }\n\n    galaxy.enterprise.total_energy -= power as u16;\n    \n    let mut rng = rand::thread_rng();\n    if computer_damaged {\n        power *= rng.gen::<f32>();\n    }\n\n    let per_enemy = power / quadrant.klingons.len() as f32;\n\n    for k in &mut quadrant.klingons {\n        let dist = k.sector.abs_diff(galaxy.enterprise.sector) as f32;\n        let hit_strength = per_enemy / dist * (2.0 + rng.gen::<f32>());\n        if hit_strength < 0.15 * k.energy {\n            view::no_damage(k.sector);\n        } else {\n            k.energy -= hit_strength;\n            view::hit_on_klingon(hit_strength, k.sector);\n            if k.energy > 0.0 {\n                view::klingon_remaining_energy(k.energy);\n            } else {\n                view::klingon_destroyed();\n            }\n        }\n    }\n\n    quadrant.klingons.retain(|k| k.energy > 0.0);\n\n    klingons_fire(galaxy);\n}\n\npub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec<String>) {\n    let star_bases = galaxy.remaining_starbases();\n    let ship = &mut galaxy.enterprise;\n\n    if ship.damaged.contains_key(systems::TORPEDOES) {\n        view::inoperable(&systems::name_for(systems::TORPEDOES));\n        return;\n    }\n\n    if ship.photon_torpedoes == 0 {\n        view::no_torpedoes_remaining();\n        return;\n    }\n\n    let course = input::param_or_prompt_value(&provided, 0, view::prompts::TORPEDO_COURSE, 1.0, 9.0);\n    if course.is_none() {\n        view::bad_torpedo_course();\n        return;\n    }\n\n    ship.photon_torpedoes -= 1;\n    view::torpedo_track();\n\n    let path = find_torpedo_path(ship.sector, course.unwrap());\n    let quadrant = &mut galaxy.quadrants[ship.quadrant.as_index()];\n    let mut hit = false;\n    for p in path {\n        view::torpedo_path(p);\n        match quadrant.sector_status(p) {\n            SectorStatus::Empty => continue,\n            SectorStatus::Star => {\n                hit = true;\n                view::star_absorbed_torpedo(p);\n                break;\n            },\n            SectorStatus::Klingon => {\n                hit = true;\n                quadrant.get_klingon(p).unwrap().energy = 0.0;\n                quadrant.klingons.retain(|k| k.energy > 0.0);\n                view::klingon_destroyed();\n                break;\n            },\n            SectorStatus::StarBase => {\n                hit = true;\n                quadrant.star_base = None;\n                let remaining = star_bases - 1;\n                view::destroyed_starbase(remaining > 0);\n                if remaining == 0 {\n                    ship.destroyed = true;\n                }\n                break;\n            }\n        }\n    }\n\n    if ship.destroyed { // if you wiped out the last starbase, trigger game over\n        return;\n    }\n\n    if !hit {\n        view::torpedo_missed();\n    }\n\n    klingons_fire(galaxy);\n}\n\nfn find_torpedo_path(start_sector: Pos, course: f32) -> Vec<Pos> {\n\n    let (dx, dy) = calculate_delta(course);\n\n    let mut last_sector = start_sector;\n    let mut path = Vec::new();\n\n    loop {\n        let nx = (last_sector.0 as f32 + dx) as i8;\n        let ny = (last_sector.1 as f32 + dy) as i8;\n        if nx < 0 || ny < 0 || nx >= 8 || ny >= 8 {\n            break;\n        }\n        last_sector = Pos(nx as u8, ny as u8);\n        path.push(last_sector);\n    }\n  \n    path\n}"
  },
  {
    "path": "84_Super_Star_Trek/rust/src/input.rs",
    "content": "use std::{io::{stdin, stdout, Write}, str::FromStr};\n\npub fn prompt(prompt_text: &str) -> Vec<String> {\n    let stdin = stdin();\n    let mut stdout = stdout();\n\n    print!(\"{prompt_text} \");\n    let _ = stdout.flush();\n\n    let mut buffer = String::new();\n    if let Ok(_) = stdin.read_line(&mut buffer) {\n        return buffer.trim_end().split([' ', ',']).map(|s| s.to_string()).collect();\n    }\n    Vec::new()\n}\n\npub fn prompt_yes_no(prompt_text: &str) -> bool {\n    loop {\n        let response = prompt(&format!(\"{prompt_text} (Y/N)\"));\n        if response.len() == 0 {\n            continue;\n        }\n        let first_word = response[0].to_uppercase();\n        if first_word.starts_with(\"Y\") {\n            return true;\n        }\n        if first_word.starts_with(\"N\") {\n            return false;\n        }\n    }\n}\n\npub fn prompt_value<T: FromStr + PartialOrd>(prompt_text: &str, min: T, max: T) -> Option<T> {\n    let passed = prompt(prompt_text);\n    if passed.len() != 1 {\n        return None\n    }\n    match passed[0].parse::<T>() {\n        Ok(n) if (n >= min && n <= max) => Some(n),\n        _ => None\n    }\n}\n\npub fn param_or_prompt_value<T: FromStr + PartialOrd>(params: &Vec<String>, param_pos: usize, prompt_text: &str, min: T, max: T) -> Option<T> {\n    let mut res: Option<T> = None;\n    if params.len() > param_pos {\n        match params[param_pos].parse::<T>() {\n            Ok(n) if (n >= min && n <= max) => res = Some(n),\n            _ => ()\n        }\n    }\n    if res.is_some() {\n        return res;\n    }\n    return prompt_value::<T>(prompt_text, min, max);    \n}\n\npub fn prompt_two_values<T: FromStr + PartialOrd>(prompt_text: &str, min: T, max: T) -> Option<(T, T)> {\n    let passed = prompt(prompt_text);\n    if passed.len() != 2 {\n        return None\n    }\n    match passed[0].parse::<T>() {\n        Ok(n1) if (n1 >= min && n1 <= max) => {\n            match passed[1].parse::<T>() {\n                Ok(n2) if (n2 >= min && n2 <= max) => \n                    Some((n1, n2)),\n                _ => None\n            }\n        }\n        _ => None\n    }\n}"
  },
  {
    "path": "84_Super_Star_Trek/rust/src/main.rs",
    "content": "use std::process::exit;\n\nuse input::{prompt, prompt_yes_no};\nuse model::{Galaxy, systems};\n\nmod input;\nmod model;\nmod commands;\nmod view;\n\nfn main() {\n    ctrlc::set_handler(move || { exit(0) })\n    .expect(\"Error setting Ctrl-C handler\");\n\n    view::title();\n    if prompt_yes_no(view::prompts::INSTRUCTIONS) {\n        view::full_instructions();\n        let _ = input::prompt(view::prompts::WHEN_READY);\n    }\n\n    let mut galaxy = Galaxy::generate_new();\n    let initial_klingons = galaxy.remaining_klingons();\n    let initial_stardate = galaxy.stardate;\n    \n    view::enterprise();\n    view::intro(&galaxy);\n    let _ = input::prompt(view::prompts::WHEN_READY);\n\n    view::starting_quadrant(galaxy.enterprise.quadrant);\n    view::short_range_scan(&galaxy);\n\n    loop {\n        let command = input::prompt(view::prompts::COMMAND);\n        if command.len() == 0 {\n            continue;\n        }\n        match command[0].to_uppercase().as_str() { // order is weird because i built it in this order :)\n            systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy),\n            systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()),\n            systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()),\n            systems::DAMAGE_CONTROL => {\n                commands::run_damage_control(&galaxy);\n                commands::try_starbase_ship_repair(&mut galaxy);\n            }\n            systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy),\n            systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()),\n            systems::PHASERS => commands::get_power_and_fire_phasers(&mut galaxy, command[1..].into()),\n            systems::TORPEDOES => commands::gather_dir_and_launch_torpedo(&mut galaxy, command[1..].into()),\n            systems::RESIGN => galaxy.enterprise.destroyed = true,\n            _ => view::print_command_help()\n        }\n\n        if galaxy.enterprise.destroyed || galaxy.enterprise.is_stranded() || galaxy.stardate >= galaxy.final_stardate {\n            view::end_game_failure(&galaxy);\n            if galaxy.remaining_klingons() > 0 && galaxy.remaining_starbases() > 0 && galaxy.stardate < galaxy.final_stardate {\n                view::replay();\n                let result = prompt(\"\");\n                if result.len() > 0 && result[0].to_uppercase() == \"AYE\" {\n                    galaxy.enterprise = Galaxy::new_captain(&galaxy.quadrants);\n                    continue;\n                }\n            }\n            break;\n        } else if galaxy.remaining_klingons() == 0 {\n            let efficiency = 1000.0 * f32::powi(initial_klingons as f32 / (galaxy.stardate - initial_stardate), 2);\n            view::congratulations(efficiency);\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/rust/src/model.rs",
    "content": "use std::{ops::{Mul, Add}, fmt::Display, collections::{HashMap, HashSet}};\n\nuse rand::Rng;\n\nuse crate::view;\n\npub struct Galaxy {\n    pub stardate: f32,\n    pub final_stardate: f32,\n    pub quadrants: Vec<Quadrant>,\n    pub scanned: HashSet<Pos>,\n    pub enterprise: Enterprise\n}\n\npub struct Quadrant {\n    pub stars: Vec<Pos>,\n    pub star_base: Option<StarBase>,\n    pub klingons: Vec<Klingon>\n}\n\npub struct StarBase {\n    pub sector: Pos,\n    pub repair_delay: f32,\n}\n\npub struct Klingon {\n    pub sector: Pos,\n    pub energy: f32\n}\n\nimpl Klingon {\n    pub fn fire_on(&mut self, enterprise: &mut Enterprise) {\n        let mut rng = rand::thread_rng();\n        let attack_strength = rng.gen::<f32>();\n        let dist_to_enterprise = self.sector.abs_diff(enterprise.sector) as f32;\n        let hit_strength = self.energy * (2.0 + attack_strength) / dist_to_enterprise;\n        \n        self.energy /= 3.0 + attack_strength;\n\n        enterprise.take_hit(self.sector, hit_strength as u16);\n    }\n}\n\npub struct Enterprise {\n    pub destroyed: bool,\n    pub damaged: HashMap<String, f32>,\n    pub quadrant: Pos,\n    pub sector: Pos,\n    pub photon_torpedoes: u8,\n    pub total_energy: u16,\n    pub shields: u16,\n}\nimpl Enterprise {\n    fn take_hit(&mut self, sector: Pos, hit_strength: u16) {\n        if self.destroyed {\n            return;\n        }\n        \n        view::enterprise_hit(&hit_strength, sector);\n\n        if self.shields <= hit_strength {\n            view::enterprise_destroyed();\n            self.destroyed = true;\n            return;\n        }\n\n        self.shields -= hit_strength;\n\n        view::shields_hit(self.shields);\n        \n        if hit_strength >= 20 {\n            self.take_damage(hit_strength)\n        }\n    }\n\n    fn take_damage(&mut self, hit_strength: u16) {\n        let mut rng = rand::thread_rng();\n\n        let hit_past_shield = hit_strength as f32 / self.shields as f32;\n        if rng.gen::<f32>() > 0.6 || hit_past_shield < 0.02 {\n            return\n        }\n\n        let system = systems::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string();\n        let damage = hit_past_shield + rng.gen::<f32>() * 0.5;\n        self.damage_system(&system, damage);\n    }\n\n    pub fn damage_system(&mut self, system: &str, damage: f32) {\n        self.damaged.entry(system.to_string()).and_modify(|d| *d -= damage).or_insert(-damage);\n    }\n\n    pub fn repair_system(&mut self, system: &str, amount: f32) -> bool {\n        let existing_damage = self.damaged[system];\n        if existing_damage + amount >= -0.1 {\n            self.damaged.remove(system);\n            return true;\n        }\n    \n        self.damaged.entry(system.to_string()).and_modify(|d| *d += amount);\n        return false;\n    }\n\n    pub fn is_stranded(&self) -> bool {\n        if self.total_energy < 10 || (self.shields + 10 > self.total_energy && self.damaged.contains_key(systems::SHIELD_CONTROL)) {\n            view::stranded();\n            return true;\n        }\n        return false;\n    }\n}\n\npub mod systems {\n\n    pub const SHORT_RANGE_SCAN: &str = \"SRS\";\n    pub const WARP_ENGINES: &str = \"NAV\";\n    pub const SHIELD_CONTROL: &str = \"SHE\";\n    pub const DAMAGE_CONTROL: &str = \"DAM\";\n    pub const LONG_RANGE_SCAN: &str = \"LRS\";\n    pub const COMPUTER: &str = \"COM\";\n    pub const PHASERS: &str = \"PHA\";\n    pub const TORPEDOES: &str = \"TOR\";\n\n    pub const RESIGN: &str = \"XXX\";\n\n    pub const KEYS: [&str; 8] = [\n        SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN, COMPUTER, PHASERS, TORPEDOES\n    ];\n\n    pub fn name_for(key: &str) -> String {\n        match key {\n            SHORT_RANGE_SCAN => \"Short Range Scanners\".into(),\n            WARP_ENGINES => \"Warp Engines\".into(),\n            SHIELD_CONTROL => \"Shield Control\".into(),\n            DAMAGE_CONTROL => \"Damage Control\".into(),\n            LONG_RANGE_SCAN => \"Long Range Scanners\".into(),\n            COMPUTER => \"Library-Computer\".into(),\n            PHASERS => \"Phaser Control\".into(),\n            TORPEDOES => \"Photon Tubes\".into(),\n            _ => \"Unknown\".into()\n        }\n    }\n}\n\n#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)]\npub struct Pos(pub u8, pub u8);\n\nimpl Pos {\n    pub fn as_index(&self) -> usize {\n        (self.0 * 8 + self.1).into()\n    }\n\n    pub fn abs_diff(&self, other: Pos) -> u8 {\n        self.0.abs_diff(other.0) + self.1.abs_diff(other.1)\n    }\n\n    pub fn dist(&self, other: Pos) -> u8 {\n        let dx = other.0 as f32 - self.0 as f32;\n        let dy = other.1 as f32 - self.1 as f32;\n        (f32::powi(dx, 2) + f32::powi(dy, 2)).sqrt() as u8\n    }\n\n    pub fn direction(&self, other: Pos) -> f32 {\n        // this is a replication of the original BASIC code\n        let dx = other.0 as f32 - self.0 as f32;\n        let dy = other.1 as f32 - self.1 as f32;\n        let dx_dominant = dx.abs() > dy.abs();\n\n        let frac = if dx_dominant { dy / dx } else { -dx / dy };\n        let nearest_cardinal = \n            if dx_dominant {\n                if dx > 0. { 7. } else { 3. }\n            } else {\n                if dy > 0. { 1. } else { 5. }\n            };\n        \n        let mut dir = nearest_cardinal + frac;\n        if dir < 1. {\n            dir += 8.\n        }\n        dir\n    }\n\n    pub fn as_galactic_sector(&self, containing_quadrant: Pos) -> Self {\n        Pos(containing_quadrant.0 * 8 + self.0, containing_quadrant.1 * 8 + self.1)\n    }\n\n    pub fn to_local_quadrant_sector(&self) -> (Self, Self) {\n        (Pos(self.0 / 8, self.1 / 8), Pos(self.0 % 8, self.1 % 8))\n    }\n}\n\nimpl Mul<u8> for Pos {\n    type Output = Self;\n\n    fn mul(self, rhs: u8) -> Self::Output {\n        Pos(self.0 * rhs, self.1 * rhs)\n    }\n}\n\nimpl Add<Pos> for Pos {\n    type Output = Self;\n\n    fn add(self, rhs: Pos) -> Self::Output {\n        Pos(self.0 + rhs.0, self.1 + rhs.1)\n    }\n}\n\nimpl Display for Pos {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{} , {}\", self.0 + 1, self.1 + 1)\n    }\n}\n\npub const COURSES : [(f32, f32); 9] = [\n    (0., 1.),\n    (-1., 1.),\n    (-1., 0.),\n    (-1., -1.),\n    (0., -1.),\n    (1., -1.),\n    (1., 0.),\n    (1., 1.),\n    (0., 1.), // course 9 is equal to course 1\n];\n\n#[derive(PartialEq)]\npub enum SectorStatus {\n    Empty, Star, StarBase, Klingon\n}\n\npub const MAX_PHOTON_TORPEDOES: u8 = 28;\npub const MAX_ENERGY: u16 = 3000;\n\nimpl Galaxy {\n    pub fn remaining_klingons(&self) -> u8 {\n        let quadrants = &self.quadrants;\n        quadrants.into_iter().map(|q| { q.klingons.len() as u8 }).sum::<u8>()\n    }\n\n    pub fn remaining_starbases(&self) -> u8 {\n        let quadrants = &self.quadrants;\n        quadrants.into_iter().filter(|q| q.star_base.is_some()).count() as u8\n    }\n\n    pub fn generate_new() -> Self {\n        let quadrants = Self::generate_quadrants();\n\n        let mut rng = rand::thread_rng();\n        let stardate = rng.gen_range(20..=40) as f32 * 100.0;\n\n        let enterprise = Self::new_captain(&quadrants);\n\n        let mut scanned = HashSet::new();\n        scanned.insert(enterprise.quadrant);\n\n        Galaxy { \n            stardate,\n            final_stardate: stardate + rng.gen_range(25..=35) as f32,\n            quadrants, \n            scanned,\n            enterprise\n        }\n    } \n\n    pub fn new_captain(quadrants: &Vec<Quadrant>) -> Enterprise {\n        let mut rng = rand::thread_rng();\n        let enterprise_quadrant = Pos(rng.gen_range(0..8), rng.gen_range(0..8));\n        let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector();\n        Enterprise { \n            destroyed: false,\n            damaged: HashMap::new(),\n            quadrant: enterprise_quadrant, \n            sector: enterprise_sector,\n            photon_torpedoes: MAX_PHOTON_TORPEDOES,\n            total_energy: MAX_ENERGY,\n            shields: 0 }\n    }   \n\n    fn generate_quadrants() -> Vec<Quadrant> {\n        let mut rng = rand::thread_rng();\n        let mut result = Vec::new();\n        for _ in 0..64 {\n\n            let mut quadrant = Quadrant { stars: Vec::new(), star_base: None, klingons: Vec::new() };\n            let star_count = rng.gen_range(0..=7);\n            for _ in 0..star_count {\n                quadrant.stars.push(quadrant.find_empty_sector());\n            }\n\n            if rng.gen::<f64>() > 0.96 {\n                quadrant.star_base = Some(StarBase { sector: quadrant.find_empty_sector(), repair_delay: rng.gen::<f32>() * 0.5 });\n            }\n\n            let klingon_count = \n                match rng.gen::<f64>() {\n                    n if n > 0.98 => 3,\n                    n if n > 0.95 => 2,\n                    n if n > 0.8 => 1,\n                    _ => 0\n                };\n                for _ in 0..klingon_count {\n                    quadrant.klingons.push(Klingon { sector: quadrant.find_empty_sector(), energy: rng.gen_range(100..=300) as f32 });\n                }\n\n            result.push(quadrant);\n        }\n        result\n    }\n}\n\nimpl Quadrant {\n    pub fn sector_status(&self, sector: Pos) -> SectorStatus {\n        if self.stars.contains(&sector) {\n            SectorStatus::Star\n        } else if self.is_starbase(sector) {\n            SectorStatus::StarBase\n        } else if self.has_klingon(sector) {\n            SectorStatus::Klingon\n        } else {\n            SectorStatus::Empty\n        }\n    }\n\n    fn is_starbase(&self, sector: Pos) -> bool {\n        match &self.star_base {\n            None => false,\n            Some(p) => p.sector == sector\n        }\n    }\n\n    fn has_klingon(&self, sector: Pos) -> bool {\n        let klingons = &self.klingons;\n        klingons.into_iter().find(|k| k.sector == sector).is_some()\n    }\n\n    pub fn get_klingon(&mut self, sector: Pos) -> Option<&mut Klingon> {\n        let klingons = &mut self.klingons;\n        klingons.into_iter().find(|k| k.sector == sector)\n    }\n\n    pub fn find_empty_sector(&self) -> Pos {\n        let mut rng = rand::thread_rng();\n        loop {\n            let pos = Pos(rng.gen_range(0..8), rng.gen_range(0..8));\n            if self.sector_status(pos) == SectorStatus::Empty {\n                return pos\n            }\n        }\n    }\n\n    pub fn docked_at_starbase(&self, enterprise_sector: Pos) -> bool {\n        self.star_base.is_some() && self.star_base.as_ref().unwrap().sector.abs_diff(enterprise_sector) == 1\n    }\n}\n"
  },
  {
    "path": "84_Super_Star_Trek/rust/src/view.rs",
    "content": "use crate::model::{Galaxy, Pos, SectorStatus, Enterprise, systems};\n\npub mod prompts {\n    pub const INSTRUCTIONS: &str = \"Do you need instructions\";\n    pub const COURSE: &str = \"Course (1-9)?\";\n    pub const TORPEDO_COURSE: &str = \"Photon torpedo course (1-9)?\";\n    pub const SHIELDS: &str = \"Number of units to shields\";\n    pub const REPAIR: &str = \"Will you authorize the repair order\";\n    pub const COMPUTER: &str = \"Computer active and waiting command?\";\n    pub const PHASERS: &str = \"Number of units to fire\";\n    pub const WHEN_READY: &str = \"Press Enter when ready to accept command\";\n    pub const COMMAND: &str = \"Command?\";\n    pub const INITIAL_COORDS: &str = \"  Initial coordinates (X/Y)\";\n    pub const TARGET_COORDS: &str = \"  Final coordinates (X/Y)\";\n\n    pub fn warp_factor(max_warp: f32) -> String {\n        format!(\"Warp Factor (0-{})?\", max_warp)\n    }\n}\n\npub fn title() {\n    println!(\"\n\n\n\n\n\n\n\n\n\n\n\n          *************************************\n          *                                   *\n          *                                   *\n          *      * * SUPER STAR TREK * *      *\n          *                                   *\n          *                                   *\n          *************************************\n\n\n\n\n\n\n\n\n\n    \");\n}\n\npub fn full_instructions() {\n    println!(\n\"        INSTRUCTIONS FOR 'SUPER STAR TREK'\n\n    1. When you see \\\"Command ?\\\" printed, enter one of the legal\n         commands (NAV, SRS, LRS, PHA, TOR, SHE, DAM, COM, OR XXX).\n    2. If you should type in an illegal command, you'll get a short\n         list of the legal commands printed out.\n    3. Some commands require you to enter data (for example, the\n         'NAV' command comes back with 'Course (1-9) ?'.)  If you\n         type in illegal data (like negative numbers), then command\n         will be aborted.\n    \n         The galaxy is divided into an 8 X 8 quadrant grid,\n    and each quadrant is further divided into an 8 X 8 sector grid.\n    \n         You will be assigned a starting point somewhere in the\n    galaxy to begin a tour of duty as commander of the starship\n    Enterprise; your mission: to seek and destroy the fleet of\n    Klingon warships which are menacing the United Federation of\n    Planets.\n    \n         You have the following commands available to you as captain\n    of the starship Enterprise:\n    \n    NAV command = Warp Engine Control\n         Course is in a circular numerical      4  3  2\n         vector arrangement as shown             . . .\n         integer and real values may be           ...\n         used.  (Thus course 1.5 is half-     5 ---*--- 1\n         way between 1 and 2.                     ...\n                                                 . . .\n         Values may approach 9.0, which         6  7  8\n         itself is equivalent to 1.0\n                                                COURSE\n         One warp factor is the size of\n         one quadrant.  Therefore, to get\n         from quadrant 6,5 to 5,5, you WOULD\n         use course 3, warp factor 1.\n    \n    SRS command = Short Range Sensor Scan\n         Shows you a scan of your present quadrant.\n    \n         Symbology on your sensor screen is as follows:\n            <*> = Your starship's position\n            +K+ = Klingon battle cruiser\n            >!< = Federation starbase (refuel/repair/re-arm here!)\n             *  = Star\n    \n         A condensed 'status report' will also be presented.\n    \n    LRS command = Long Range Sensor Scan\n         Shows conditions in space for one quadrant on each side\n         of the Enterprise (which is in the middle of the scan).\n         The scan is coded in the form ###, where the units digit\n         is the number of stars, the tens digit is the number of\n         starbases, and the hundreds digit is the number of\n         Klingons.\n    \n         Example - 207 = 2 Klingons, No starbases, & 7 stars.\n    \n    PHA command = Phaser Control\n         Allows you to destroy the Klingon battle cruisers by\n         zapping them with suitably large units of energy to\n         deplete their shield power.  (Remember, Klingons have\n         phasers, too!)\n    \n    TOR command = Photon Torpedo Control\n         Torpedo course is the same as used in warp engine control.\n         If you hit the Klingon vessel, he is destroyed and\n         cannot fire back at you.  If you miss, you are subject to\n         his phaser fire.  In either case, you are also subject to\n         the phaser fire of all other Klingons in the quadrant.\n    \n         The library-computer (COM command) has an option to\n         compute torpedo trajectory for you (Option 2).\n    \n    SHE command = Shield Control\n         Defines the number of energy units to be assigned to the\n         shields.  Energy is taken from total ship's energy.  Note\n         that the status display total energy includes shield energy.\n    \n    DAM command = Damage Control Report\n         Gives the state of repair of all devices.  Where a negative\n         'state of repair' shows that the device is temporarily\n         damaged.\n    \n    COM command = Library-Computer\n         The library-computer contains six options:\n         Option 0 = Cumulative Galactic Record\n            This option shows computer memory of the results of all\n            previous short and long range sensor scans.\n         Option 1 = Status Report\n            This option shows the number of Klingons, Stardates,\n            and starbases remaining in the game.\n         Option 2 = Photon Torpedo Data\n            Which gives directions and distance from the Enterprise\n            to all Klingons in your quadrant.\n         Option 3 = Starbase Nav Data\n            This option gives direction and distance to any\n            starbase within your quadrant.\n         Option 4 = Direction/Distance Calculator\n            This option allows you to enter coordinates for\n            direction/distance calculations.\n         Option 5 = Galactic Region Name Map\n            This option prints the names of the sixteen major\n            galactic regions referred to in the game.\n\n\")\n}\n\npub fn enterprise() {\n    println!(\"\n\n\n\n\n\n\n\n\n\n\n                                    ,------*------,\n                    ,-------------   '---  ------'\n                     '-------- --'      / /\n                         ,---' '-------/ /--,\n                          '----------------'\n\n                    THE USS ENTERPRISE --- NCC-1701\n\n\n\n\n\n\n\")\n}\n\npub fn intro(model: &Galaxy) {\n    let star_bases = model.remaining_starbases();\n    let mut star_base_message: String = \"There is 1 starbase\".into();\n    if star_bases > 1 {\n        star_base_message = format!(\"There are {} starbases\", star_bases);\n    }\n    println!(\n\"Your orders are as follows:\n    Destroy the {} Klingon warships which have invaded\n    the galaxy before they can attack federation headquarters\n    on stardate {:.1}. This gives you {} days. {} in the galaxy for resupplying your ship.\\n\", \n    model.remaining_klingons(), model.final_stardate, model.final_stardate - model.stardate, star_base_message)\n}\n\nconst REGION_NAMES: [&str; 16] = [\n    \"Antares\",\n    \"Sirius\",\n    \"Rigel\",\n    \"Deneb\",\n    \"Procyon\",\n    \"Capella\",\n    \"Vega\",\n    \"Betelgeuse\",\n    \"Canopus\",\n    \"Aldebaran\",\n    \"Altair\",\n    \"Regulus\",\n    \"Sagittarius\",\n    \"Arcturus\",\n    \"Pollux\",\n    \"Spica\"\n];\n\nconst SUB_REGION_NAMES: [&str; 4] = [\"I\", \"II\", \"III\", \"IV\"];\n\nfn quadrant_name(quadrant: Pos) -> String {\n    format!(\"{} {}\", \n        REGION_NAMES[((quadrant.0 << 1) + (quadrant.1 >> 2)) as usize],\n        SUB_REGION_NAMES[(quadrant.1 % 4) as usize])\n}\n\npub fn starting_quadrant(quadrant: Pos) {\n    println!(\n\"\\nYour mission begins with your starship located\nin the galactic quadrant, '{}'.\\n\", quadrant_name(quadrant))\n}\n\npub fn enter_quadrant(quadrant: Pos) {\n    println!(\"\\nNow entering {} quadrant . . .\\n\", quadrant_name(quadrant))\n}\n\npub fn short_range_scan(model: &Galaxy) {\n    let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()];\n    let mut condition = \"GREEN\";\n    if quadrant.docked_at_starbase(model.enterprise.sector) {\n        println!(\"Shields dropped for docking purposes\");\n        condition = \"DOCKED\";\n    } else if quadrant.klingons.len() > 0 {\n        condition = \"*RED*\";\n    } else if model.enterprise.damaged.len() > 0 {\n        condition = \"YELLOW\";\n    }\n\n    let data : [String; 8] = [\n        format!(\"Stardate           {:.1}\", model.stardate),\n        format!(\"Condition          {}\", condition),\n        format!(\"Quadrant           {}\", model.enterprise.quadrant),\n        format!(\"Sector             {}\", model.enterprise.sector),\n        format!(\"Photon torpedoes   {}\", model.enterprise.photon_torpedoes),\n        format!(\"Total energy       {}\", model.enterprise.total_energy),\n        format!(\"Shields            {}\", model.enterprise.shields),\n        format!(\"Klingons remaining {}\", model.remaining_klingons()),\n    ];\n\n    println!(\"{:-^33}\", \"\");\n    for x in 0..=7 {\n        for y in 0..=7 {\n            let pos = Pos(x, y);\n            if &pos == &model.enterprise.sector {\n                print!(\"<*> \")\n            } else {\n                match quadrant.sector_status(pos) {\n                    SectorStatus::Star => print!(\" *  \"),\n                    SectorStatus::StarBase => print!(\">!< \"),\n                    SectorStatus::Klingon => print!(\"+K+ \"),\n                    _ => print!(\"    \"),\n                }                \n            } \n        }\n        println!(\"{:>9}{}\", \"\", data[x as usize])\n    }\n    println!(\"{:-^33}\", \"\");\n}\n\npub fn print_command_help() {\n    println!(\n\"Enter one of the following:\n  NAV  (To set course)\n  SRS  (For short range sensor scan)\n  LRS  (For long range sensor scan)\n  PHA  (To fire phasers)\n  TOR  (To fire photon torpedoes)\n  SHE  (To raise or lower shields)\n  DAM  (For damage control reports)\n  COM  (To call on library-computer)\n  XXX  (To resign your command)\n    \")\n}\n\npub fn end_game_failure(galaxy: &Galaxy) {\n    println!(\n\"Is is stardate {:.1}.\nThere were {} Klingon battle cruisers left at\nthe end of your mission.\n\", galaxy.stardate, galaxy.remaining_klingons());\n}\n\npub fn enterprise_destroyed() {\n    println!(\"The Enterprise has been destroyed.  The Federation will be conquered.\");\n}\n\npub fn bad_course_data() {\n    println!(\"   Lt. Sulu reports, 'Incorrect course data, sir!'\")\n}\n\npub fn bad_nav(current_sector: Pos) {\n    println!(\"Warp engines shut down at sector {current_sector} dues to bad navigation\")\n}\n\npub fn bad_torpedo_course() {\n    println!(\"   Ensign Chekov reports, 'Incorrect course data, sir!'\")\n}\n\npub fn enterprise_hit(hit_strength: &u16, from_sector: Pos) {\n    println!(\"{hit_strength} unit hit on Enterprise from sector {from_sector}\");\n}\n\npub fn hit_edge(quadrant: Pos, sector: Pos) {\n    println!(\n\"Lt. Uhura report message from Starfleet Command:\n    'Permission to attempt crossing of galactic perimeter\n        is hereby *Denied*. Shut down your engines.'\n    Chief Engineer Scott reports, 'Warp engines shut down\n        at sector {} of quadrant {}.'\", sector, quadrant);\n}\n\npub fn condition_red() {\n    println!(\"COMBAT AREA      CONDITION RED\")\n}\n\npub fn danger_shields() {\n    println!(\"   SHIELDS DANGEROUSLY LOW    \")\n}\n\npub fn insuffient_warp_energy(warp_speed: f32) {\n    println!(\n\"Engineering reports, 'Insufficient energy available\n    for maneuvering at warp {warp_speed} !'\")\n}\n\npub fn divert_energy_from_shields() {\n    println!(\"Shield Control supplies energy to complete the maneuver.\")\n}\n\npub fn energy_available(total_energy: u16) {\n    println!(\"Energy available = {{{total_energy}}}\")\n}\n\npub fn shields_unchanged() {\n    println!(\"<SHIELDS UNCHANGED>\")\n}\n\npub fn ridiculous() {\n    println!(\"Shield Control reports, 'This is not the Federation Treasury.'\")\n}\n\npub fn shields_set(value: u16) {\n    println!(\n\"Deflector control room report:\n  'Shields now at {value} units per your command.'\")\n}\n\npub fn shields_hit(shields: u16) {\n    println!(\"      <Shields down to {shields} units>\")\n}\n\npub fn inoperable(arg: &str) {\n    println!(\"{} inoperable\", arg)\n}\n\npub fn scanners_out() {\n    println!(\"*** Short Range Sensors are out ***\")\n}\n\npub fn damaged_engines(max_warp: f32, warp_factor: f32) {\n    println!(\n\"Warp engines are damaged.  Maximum speed = warp {max_warp}\n    Chief Engineer Scott reports, 'The engines won't take warp {warp_factor} !'\")\n}\n\npub fn damage_control_report() {\n    println!(\"Damage Control report:\")\n}\n\npub fn random_repair_report_for(name: &str, damaged: bool) {\n    let mut message = \"state of repair improved\";\n    if damaged {\n        message = \"damaged\";\n    }\n    println!(\"Damage Control report:  {name} {message}\")\n}\n\npub fn system_repair_completed(name: String) {\n    println!(\"        {name} repair completed.\")\n}\n\npub fn damage_control(enterprise: &Enterprise) {\n    println!(\"Device             State of Repair\");\n    for key in systems::KEYS {\n        let damage = enterprise.damaged.get(key).unwrap_or(&0.0);\n        println!(\"{:<25}{}\", systems::name_for(key), damage)\n    }\n    println!();\n}\n\npub fn long_range_scan(galaxy: &Galaxy) -> Vec<Pos> {\n\n    let cx = galaxy.enterprise.quadrant.0 as i8;\n    let cy = galaxy.enterprise.quadrant.1 as i8;\n\n    let mut seen = Vec::new();\n\n    println!(\"Long range scan for quadrant {}\", galaxy.enterprise.quadrant);\n    println!(\"{:-^19}\", \"\");\n    for x in cx - 1..=cx + 1 {\n        for y in cy - 1..=cy + 1 {\n            let mut klingons = \"*\".into();\n            let mut star_bases = \"*\".into();\n            let mut stars = \"*\".into();\n\n            if y >= 0 && y < 8 && x >= 0 && x < 8 {\n                let pos = Pos(x as u8, y as u8);\n                seen.push(pos);\n                \n                let quadrant = &galaxy.quadrants[pos.as_index()];\n                klingons = format!(\"{}\", quadrant.klingons.len());\n                star_bases = quadrant.star_base.as_ref().map_or(\"0\", |_| \"1\");\n                stars = format!(\"{}\", quadrant.stars.len());\n            }\n\n            print!(\": {}{}{} \", klingons, star_bases, stars)\n        }\n        println!(\":\");\n        println!(\"{:-^19}\", \"\");\n    } \n\n    seen\n}\n\npub fn stranded() {\n    println!(\n\"** FATAL ERROR **   You've just stranded your ship in space\nYou have insufficient maneuvering energy, and shield control\nis presently incapable of cross-circuiting to engine room!!\")\n}\n\npub fn computer_options() {\n    println!(\n\"   0 = Cumulative galactic record\n    1 = Status report\n    2 = Photon torpedo data\n    3 = Starbase nav data\n    4 = Direction/distance calculator\n    5 = Galaxy 'region name' map\")\n}\n\npub fn galaxy_region_map() {\n    println!(\n\"                        The Galaxy\n      1     2     3     4     5     6     7     8\n    ----- ----- ----- ----- ----- ----- ----- -----\");\n    for i in (0..REGION_NAMES.len()-1).step_by(2) {\n        println!(\n\"{} {:^23} {:^23}\n    ----- ----- ----- ----- ----- ----- ----- -----\", (i/2)+1, REGION_NAMES[i], REGION_NAMES[i+1]);\n    }    \n}\n\npub fn galaxy_scanned_map(galaxy: &Galaxy) {\n    println!(\n\"Computer record of galaxy for quadrant {}\n      1     2     3     4     5     6     7     8\n    ----- ----- ----- ----- ----- ----- ----- -----\", galaxy.enterprise.quadrant);\n    for x in 0..8 {\n        print!(\"{}   \", x+1);\n        for y in 0..8 {\n            let pos = Pos(x, y);\n            if galaxy.scanned.contains(&pos) {\n                let quadrant = &galaxy.quadrants[pos.as_index()];\n                print!(\" {}{}{}  \", quadrant.klingons.len(), quadrant.star_base.as_ref().map_or(\"0\", |_| \"1\"), quadrant.stars.len())\n            } else {\n                print!(\" ***  \");\n            }\n        }\n        println!(\n\"\\n    ----- ----- ----- ----- ----- ----- ----- -----\")\n    }\n}\n\npub fn no_local_enemies() {\n    println!(\n\"Science Officer Spock reports, 'Sensors show no enemy ships\n                                 in this quadrant'\")\n}\n\npub fn computer_accuracy_issue() {\n    println!(\"Computer failure hampers accuracy\")\n}\n\npub fn phasers_locked(available_energy: u16) {\n    println!(\"Phasers locked on target;  Energy available = {available_energy} units\")\n}\n\npub fn starbase_shields() {\n    println!(\"Starbase shields protect the Enterprise\")\n}\n\npub fn repair_estimate(repair_time: f32) {\n    println!(\n\"Technicians standing by to effect repairs to your ship;\nEstimated time to repair: {repair_time:.1} stardates.\")\n}\n\npub fn no_damage(sector: Pos) {\n    println!(\"Sensors show no damage to enemy at {sector}\")\n}\n\npub fn hit_on_klingon(hit_strength: f32, sector: Pos) {\n    println!(\"{hit_strength} unit hit on Klingon at sector {sector}\")\n}\n\npub fn klingon_remaining_energy(energy: f32) {\n    println!(\"   (sensors show {energy} units remaining)\")\n}\n\npub fn klingon_destroyed() {\n    println!(\"*** Klingon destroyed ***\")\n}\n\npub fn congratulations(efficiency: f32) {\n    println!(\"\nCongratulations, Captain!  The last Klingon battle cruiser\nmenacing the Federation has been destroyed.\n\nYour efficiency rating is {efficiency}.\n    \")\n}\n\npub fn replay() {\n    println!(\"\nThe Federation is in need of a new starship commander\nfor a similar mission -- if there is a volunteer\nlet him step forward and enter 'Aye'\")\n}\n\npub fn no_torpedoes_remaining() {\n    println!(\"All photon torpedoes expended\")\n}\n\npub fn torpedo_track() {\n    println!(\"Torpedo track:\")\n}\n\npub fn torpedo_path(sector: Pos) {\n    println!(\"{:<16}{}\", \"\", sector)\n}\n\npub fn torpedo_missed() {\n    println!(\"Torpedo missed!\")\n}\n\npub fn star_absorbed_torpedo(sector: Pos) {\n    println!(\"Star at {sector} absorbed torpedo energy.\")\n}\n\npub fn destroyed_starbase(not_the_last_starbase: bool) {\n    println!(\"*** Starbase destroyed ***\");\n    if not_the_last_starbase {\n        println!(\"\nStarfleet Command reviewing your record to consider\ncourt martial!\")\n    } else {\n        println!(\"\nThat does it, Captain!!  You are hereby relieved of command\nand sentenced to 99 stardates at hard labor on Cygnus 12!!\")\n    }\n}\n\npub fn no_local_starbase() {\n    println!(\"Mr. Spock reports, 'Sensors show no starbases in this quadrant.'\")\n}\n\npub fn starbase_report() {\n    println!(\"From Enterprise to Starbase:'\")\n}\n\npub fn direction_distance(dir: f32, dist: u8) {\n    println!(\n\"Direction = {dir}\nDistance = {dist}\"\n    )\n}\n\npub fn status_report(galaxy: &Galaxy) {\n    let klingon_count = galaxy.remaining_klingons();\n    let star_bases = galaxy.remaining_starbases();\n    let time_remaining = galaxy.final_stardate - galaxy.stardate;\n    let mut plural_starbase = \"\";\n    if star_bases > 1 {\n        plural_starbase = \"s\";\n    }\n\n    println!(\"   Status report:\nKlingons left:  {klingon_count}\nMission must be completed in {time_remaining:.1} stardates.\nThe Federation is maintaining {star_bases} starbase{plural_starbase} in the galaxy.\n\")\n}\n\npub fn direction_dist_intro(enterprise: &Enterprise) {\n    let quadrant = enterprise.quadrant;\n    let sector = enterprise.sector;\n    println!(\"Direction/distance calculator:\nYou are at quadrant {quadrant} sector {sector}\nPlease enter\")\n}\n\npub fn klingon_report(more_than_one: bool) {\n    let mut plural = \"\";\n    if more_than_one {\n        plural = \"s\";\n    }\n    println!(\"From Enterprise to Klingon battle cruiser{}\", plural)\n}"
  },
  {
    "path": "84_Super_Star_Trek/superstartrek.bas",
    "content": "10 REM SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY\n30 REM\n40 REM ****        **** STAR TREK ****        ****\n50 REM **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,\n60 REM **** AS SEEN ON THE STAR TREK TV SHOW.\n70 REM **** ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION\n80 REM **** PUBLISHED IN DEC'S \"101 BASIC GAMES\", BY DAVE AHL.\n90 REM **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB\n100 REM *** LEEDOM - APRIL & DECEMBER 1974,\n110 REM *** WITH A LITTLE HELP FROM HIS FRIENDS . . .\n120 REM *** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --\n130 REM *** SEND TO:  R. C. LEEDOM\n140 REM ***           WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.\n150 REM ***           BOX 746, M.S. 338\n160 REM ***           BALTIMORE, MD  21203\n170 REM ***\n180 REM *** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS\n190 REM *** LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS\n200 REM *** MUCH AS POSSIBLE WHILE USING MULTIPLE STATEMENTS PER LINE\n205 REM *** SOME LINES ARE LONGER THAN 72 CHARACTERS; THIS WAS DONE\n210 REM *** BY USING \"?\" INSTEAD OF \"PRINT\" WHEN ENTERING LINES\n215 REM ***\n220 PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT\n221 PRINT \"                                    ,------*------,\"\n222 PRINT \"                    ,-------------   '---  ------'\"\n223 PRINT \"                     '-------- --'      / /\"\n224 PRINT \"                         ,---' '-------/ /--,\"\n225 PRINT \"                          '----------------'\":PRINT\n226 PRINT \"                    THE USS ENTERPRISE --- NCC-1701\"\n227 PRINT:PRINT:PRINT:PRINT:PRINT\n260 REM CLEAR 600\n270 Z$=\"                         \"\n330 DIM G(8,8),C(9,2),K(3,3),N(3),Z(8,8),D(8)\n370 T=INT(RND(1)*20+20)*100:T0=T:T9=25+INT(RND(1)*10):D0=0:E=3000:E0=E\n440 P=10:P0=P:S9=200:S=0:B9=2:K9=0:X$=\"\":X0$=\" IS \"\n470 DEF FND(D)=SQR((K(I,1)-S1)^2+(K(I,2)-S2)^2)\n475 DEF FNR(R)=INT(RND(R)*7.98+1.01)\n480 REM INITIALIZE ENTERPRIZE'S POSITION\n490 Q1=FNR(1):Q2=FNR(1):S1=FNR(1):S2=FNR(1)\n530 FOR I=1 TO 9:C(I,1)=0:C(I,2)=0:NEXT I\n540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1\n600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1\n670 FOR I=1 TO 8:D(I)=0:NEXT I\n710 A1$=\"NAVSRSLRSPHATORSHEDAMCOMXXX\"\n810 REM SETUP WHAT EXHISTS IN GALAXY . . .\n815 REM K3= # KLINGONS  B3= # STARBASES  S3 = # STARS\n820 FOR I=1 TO 8:FOR J=1 TO 8:K3=0:Z(I,J)=0:R1=RND(1)\n850 IF R1>.98 THEN K3=3:K9=K9+3:GOTO 980\n860 IF R1>.95 THEN K3=2:K9=K9+2:GOTO 980\n870 IF R1>.80 THEN K3=1:K9=K9+1\n980 B3=0:IF RND(1)>.96 THEN B3=1:B9=B9+1\n1040 G(I,J)=K3*100+B3*10+FNR(1):NEXT J:NEXT I:IF K9>T9 THEN T9=K9+1\n1100 IF B9<>0 THEN 1200\n1150 IF G(Q1,Q2)<200 THEN G(Q1,Q2)=G(Q1,Q2)+120:K9=K9+1\n1160 B9=1:G(Q1,Q2)=G(Q1,Q2)+10:Q1=FNR(1):Q2=FNR(1)\n1200 K7=K9:IF B9<>1 THEN X$=\"S\":X0$=\" ARE \"\n1230 PRINT \"YOUR ORDERS ARE AS FOLLOWS:\"\n1240 PRINT \"     DESTROY THE\";K9;\"KLINGON WARSHIPS WHICH HAVE INVADED\"\n1252 PRINT \"   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\"\n1260 PRINT \"   ON STARDATE\";T0+T9;\"  THIS GIVES YOU\";T9;\"DAYS.  THERE\";X0$\n1272 PRINT \"  \";B9;\"STARBASE\";X$;\" IN THE GALAXY FOR RESUPPLYING YOUR SHIP\"\n1280 PRINT:REM PRINT \"HIT ANY KEY EXCEPT RETURN WHEN READY TO ACCEPT COMMAND\"\n1300 I=RND(1):REM IF INP(1)=13 THEN 1300\n1310 REM HERE ANY TIME NEW QUADRANT ENTERED\n1320 Z4=Q1:Z5=Q2:K3=0:B3=0:S3=0:G5=0:D4=.5*RND(1):Z(Q1,Q2)=G(Q1,Q2)\n1390 IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 1600\n1430 GOSUB 9030:PRINT:IF T0<>T THEN 1490\n1460 PRINT \"YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\"\n1470 PRINT \"IN THE GALACTIC QUADRANT, '\";G2$;\"'.\":GOTO 1500\n1490 PRINT \"NOW ENTERING \";G2$;\" QUADRANT . . .\"\n1500 PRINT:K3=INT(G(Q1,Q2)*.01):B3=INT(G(Q1,Q2)*.1)-10*K3\n1540 S3=G(Q1,Q2)-100*K3-10*B3:IF K3=0 THEN 1590\n1560 PRINT \"COMBAT AREA      CONDITION RED\":IF S>200 THEN 1590\n1580 PRINT \"   SHIELDS DANGEROUSLY LOW\"\n1590 FOR I=1 TO 3:K(I,1)=0:K(I,2)=0:NEXT I\n1600 FOR I=1 TO 3:K(I,3)=0:NEXT I:Q$=Z$+Z$+Z$+Z$+Z$+Z$+Z$+LEFT$(Z$,17)\n1660 REM POSITION ENTERPRISE IN QUADRANT, THEN PLACE \"K3\" KLINGONS, &\n1670 REM \"B3\" STARBASES, & \"S3\" STARS ELSEWHERE.\n1680 A$=\"<*>\":Z1=S1:Z2=S2:GOSUB 8670:IF K3<1 THEN 1820\n1720 FOR I=1 TO K3:GOSUB 8590:A$=\"+K+\":Z1=R1:Z2=R2\n1780 GOSUB 8670:K(I,1)=R1:K(I,2)=R2:K(I,3)=S9*(0.5+RND(1)):NEXT I\n1820 IF B3<1 THEN 1910\n1880 GOSUB 8590:A$=\">!<\":Z1=R1:B4=R1:Z2=R2:B5=R2:GOSUB 8670\n1910 FOR I=1 TO S3:GOSUB 8590:A$=\" * \":Z1=R1:Z2=R2:GOSUB 8670:NEXT I\n1980 GOSUB 6430\n1990 IF S+E>10 THEN IF E>10 OR D(7)=0 THEN 2060\n2020 PRINT:PRINT \"** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP IN \"\n2030 PRINT \"SPACE\":PRINT \"YOU HAVE INSUFFICIENT MANEUVERING ENERGY,\";\n2040 PRINT \" AND SHIELD CONTROL\":PRINT \"IS PRESENTLY INCAPABLE OF CROSS\";\n2050 PRINT \"-CIRCUITING TO ENGINE ROOM!!\":GOTO 6220\n2060 INPUT\"COMMAND\";A$\n2080 FOR I=1 TO 9:IF LEFT$(A$,3)<>MID$(A1$,3*I-2,3) THEN 2160\n2140 ON I GOTO 2300,1980,4000,4260,4700,5530,5690,7290,6270\n2160 NEXT I:PRINT \"ENTER ONE OF THE FOLLOWING:\"\n2180 PRINT \"  NAV  (TO SET COURSE)\"\n2190 PRINT \"  SRS  (FOR SHORT RANGE SENSOR SCAN)\"\n2200 PRINT \"  LRS  (FOR LONG RANGE SENSOR SCAN)\"\n2210 PRINT \"  PHA  (TO FIRE PHASERS)\"\n2220 PRINT \"  TOR  (TO FIRE PHOTON TORPEDOES)\"\n2230 PRINT \"  SHE  (TO RAISE OR LOWER SHIELDS)\"\n2240 PRINT \"  DAM  (FOR DAMAGE CONTROL REPORTS)\"\n2250 PRINT \"  COM  (TO CALL ON LIBRARY-COMPUTER)\"\n2260 PRINT \"  XXX  (TO RESIGN YOUR COMMAND)\":PRINT:GOTO 1990\n2290 REM COURSE CONTROL BEGINS HERE\n2300 INPUT\"COURSE (0-9)\";C1:IF C1=9 THEN C1=1\n2310 IF C1>=1 AND C1<9 THEN 2350\n2330 PRINT \"   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'\":GOTO 1990\n2350 X$=\"8\":IF D(1)<0 THEN X$=\"0.2\"\n2360 PRINT \"WARP FACTOR (0-\";X$;\")\";:INPUT W1:IF D(1)<0 AND W1>.2 THEN 2470\n2380 IF W1>0 AND W1<=8 THEN 2490\n2390 IF W1=0 THEN 1990\n2420 PRINT \"   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE\";\n2430 PRINT \" WARP \";W1;\"!'\":GOTO 1990\n2470 PRINT \"WARP ENGINES ARE DAMAGED.  MAXIUM SPEED = WARP 0.2\":GOTO 1990\n2490 N=INT(W1*8+.5):IF E-N>=0 THEN 2590\n2500 PRINT \"ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE\"\n2510 PRINT \"                       FOR MANEUVERING AT WARP\";W1;\"!'\"\n2530 IF S<N-E OR D(7)<0 THEN 1990\n2550 PRINT \"DEFLECTOR CONTROL ROOM ACKNOWLEDGES\";S;\"UNITS OF ENERGY\"\n2560 PRINT \"                         PRESENTLY DEPLOYED TO SHIELDS.\"\n2570 GOTO 1990\n2580 REM KLINGONS MOVE/FIRE ON MOVING STARSHIP . . .\n2590 FOR I=1 TO K3:IF K(I,3)=0 THEN 2700\n2610 A$=\"   \":Z1=K(I,1):Z2=K(I,2):GOSUB 8670:GOSUB 8590\n2660 K(I,1)=Z1:K(I,2)=Z2:A$=\"+K+\":GOSUB 8670\n2700 NEXT I:GOSUB 6000:D1=0:D6=W1:IF W1>=1 THEN D6=1\n2770 FOR I=1 TO 8:IF D(I)>=0 THEN 2880\n2790 D(I)=D(I)+D6:IF D(I)>-.1 AND D(I)<0 THEN D(I)=-.1:GOTO 2880\n2800 IF D(I)<0 THEN 2880\n2810 IF D1<>1 THEN D1=1:PRINT \"DAMAGE CONTROL REPORT:  \";\n2840 PRINT TAB(8);:R1=I:GOSUB 8790:PRINT G2$;\" REPAIR COMPLETED.\"\n2880 NEXT I:IF RND(1)>.2 THEN 3070\n2910 R1=FNR(1):IF RND(1)>=.6 THEN 3000\n2930 D(R1)=D(R1)-(RND(1)*5+1):PRINT \"DAMAGE CONTROL REPORT:  \";\n2960 GOSUB 8790:PRINT G2$;\" DAMAGED\":PRINT:GOTO 3070\n3000 D(R1)=D(R1)+RND(1)*3+1:PRINT \"DAMAGE CONTROL REPORT:  \";\n3030 GOSUB 8790:PRINT G2$;\" STATE OF REPAIR IMPROVED\":PRINT\n3060 REM BEGIN MOVING STARSHIP\n3070 A$=\"   \":Z1=INT(S1):Z2=INT(S2):GOSUB 8670\n3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):X=S1:Y=S2\n3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):Q4=Q1:Q5=Q2\n3170 FOR I=1 TO N:S1=S1+X1:S2=S2+X2:IF S1<1 OR S1>=9 OR S2<1 OR S2>=9 THEN 3500\n3240 S8=INT(S1)*24+INT(S2)*3-26:IF MID$(Q$,S8,2)=\"  \" THEN 3360\n3320 S1=INT(S1-X1):S2=INT(S2-X2):PRINT \"WARP ENGINES SHUT DOWN AT \";\n3350 PRINT \"SECTOR\";S1;\",\";S2;\"DUE TO BAD NAVAGATION\":GOTO 3370\n3360 NEXT I:S1=INT(S1):S2=INT(S2)\n3370 A$=\"<*>\":Z1=INT(S1):Z2=INT(S2):GOSUB 8670:GOSUB 3910:T8=1\n3430 IF W1<1 THEN T8=.1*INT(10*W1)\n3450 T=T+T8:IF T>T0+T9 THEN 6220\n3470 REM SEE IF DOCKED, THEN GET COMMAND\n3480 GOTO 1980\n3490 REM EXCEEDED QUADRANT LIMITS\n3500 X=8*Q1+X+N*X1:Y=8*Q2+Y+N*X2:Q1=INT(X/8):Q2=INT(Y/8):S1=INT(X-Q1*8)\n3550 S2=INT(Y-Q2*8):IF S1=0 THEN Q1=Q1-1:S1=8\n3590 IF S2=0 THEN Q2=Q2-1:S2=8\n3620 X5=0:IF Q1<1 THEN X5=1:Q1=1:S1=1\n3670 IF Q1>8 THEN X5=1:Q1=8:S1=8\n3710 IF Q2<1 THEN X5=1:Q2=1:S2=1\n3750 IF Q2>8 THEN X5=1:Q2=8:S2=8\n3790 IF X5=0 THEN 3860\n3800 PRINT \"LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:\"\n3810 PRINT \"  'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER\"\n3820 PRINT \"  IS HEREBY *DENIED*.  SHUT DOWN YOUR ENGINES.'\"\n3830 PRINT \"CHIEF ENGINEER SCOTT REPORTS  'WARP ENGINES SHUT DOWN\"\n3840 PRINT \"  AT SECTOR\";S1;\",\";S2;\"OF QUADRANT\";Q1;\",\";Q2;\".'\"\n3850 IF T>T0+T9 THEN 6220\n3860 IF 8*Q1+Q2=8*Q4+Q5 THEN 3370\n3870 T=T+1:GOSUB 3910:GOTO 1320\n3900 REM MANEUVER ENERGY S/R **\n3910 E=E-N-10:IF E>=0 THEN RETURN\n3930 PRINT \"SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.\"\n3940 S=S+E:E=0:IF S<=0 THEN S=0\n3980 RETURN\n3990 REM LONG RANGE SENSOR SCAN CODE\n4000 IF D(3)<0 THEN PRINT \"LONG RANGE SENSORS ARE INOPERABLE\":GOTO 1990\n4030 PRINT \"LONG RANGE SCAN FOR QUADRANT\";Q1;\",\";Q2\n4040 O1$=\"-------------------\":PRINT O1$\n4060 FOR I=Q1-1TOQ1+1:N(1)=-1:N(2)=-2:N(3)=-3:FOR J=Q2-1TOQ2+1\n4120 IF I>0 AND I<9 AND J>0 AND J<9 THEN N(J-Q2+2)=G(I,J):Z(I,J)=G(I,J)\n4180 NEXT J:FOR L=1 TO 3:PRINT \": \";:IF N(L)<0 THEN PRINT \"*** \";:GOTO 4230\n4210 PRINT RIGHT$(STR$(N(L)+1000),3);\" \";\n4230 NEXT L:PRINT \":\":PRINT O1$:NEXT I:GOTO 1990\n4250 REM PHASER CONTROL CODE BEGINS HERE\n4260 IF D(4)<0 THEN PRINT \"PHASERS INOPERATIVE\":GOTO 1990\n4265 IF K3>0 THEN 4330\n4270 PRINT \"SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS\"\n4280 PRINT \"                                IN THIS QUADRANT'\":GOTO 1990\n4330 IF D(8)<0 THEN PRINT \"COMPUTER FAILURE HAMPERS ACCURACY\"\n4350 PRINT \"PHASERS LOCKED ON TARGET;  \";\n4360 PRINT \"ENERGY AVAILABLE =\";E;\"UNITS\"\n4370 INPUT\"NUMBER OF UNITS TO FIRE\";X:IF X<=0 THEN 1990\n4400 IF E-X<0 THEN 4360\n4410 E=E-X:IF D(7)<0 THEN X=X*RND(1)\n4450 H1=INT(X/K3):FOR I=1TO3:IF K(I,3)<=0 THEN 4670\n4480 H=INT((H1/FND(0))*(RND(1)+2)):IF H>.15*K(I,3) THEN 4530\n4500 PRINT \"SENSORS SHOW NO DAMAGE TO ENEMY AT \";K(I,1);\",\";K(I,2):GOTO 4670\n4530 K(I,3)=K(I,3)-H:PRINT H;\"UNIT HIT ON KLINGON AT SECTOR\";K(I,1);\",\";\n4550 PRINT K(I,2):IF K(I,3)<=0 THEN PRINT \"*** KLINGON DESTROYED ***\":GOTO 4580\n4560 PRINT \"   (SENSORS SHOW\";K(I,3);\"UNITS REMAINING)\":GOTO 4670\n4580 K3=K3-1:K9=K9-1:Z1=K(I,1):Z2=K(I,2):A$=\"   \":GOSUB 8670\n4650 K(I,3)=0:G(Q1,Q2)=G(Q1,Q2)-100:Z(Q1,Q2)=G(Q1,Q2):IF K9<=0 THEN 6370\n4670 NEXT I:GOSUB 6000:GOTO 1990\n4690 REM PHOTON TORPEDO CODE BEGINS HERE\n4700 IF P<=0 THEN PRINT \"ALL PHOTON TORPEDOES EXPENDED\":GOTO 1990\n4730 IF D(5)<0 THEN PRINT \"PHOTON TUBES ARE NOT OPERATIONAL\":GOTO 1990\n4760 INPUT\"PHOTON TORPEDO COURSE (1-9)\";C1:IF C1=9 THEN C1=1\n4780 IF C1>=1ANDC1<9 THEN 4850\n4790 PRINT \"ENSIGN CHEKOV REPORTS,  'INCORRECT COURSE DATA, SIR!'\"\n4800 GOTO 1990\n4850 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):E=E-2:P=P-1\n4860 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):X=S1:Y=S2\n4910 PRINT \"TORPEDO TRACK:\"\n4920 X=X+X1:Y=Y+X2:X3=INT(X+.5):Y3=INT(Y+.5)\n4960 IF X3<1 OR X3>8 OR Y3<1 OR Y3>8 THEN 5490\n5000 PRINT \"               \";X3;\",\";Y3:A$=\"   \":Z1=X:Z2=Y:GOSUB 8830\n5050 IF Z3<>0 THEN 4920\n5060 A$=\"+K+\":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5210\n5110 PRINT \"*** KLINGON DESTROYED ***\":K3=K3-1:K9=K9-1:IF K9<=0 THEN 6370\n5150 FOR I=1TO3:IF X3=K(I,1) AND Y3=K(I,2) THEN 5190\n5180 NEXT I:I=3\n5190 K(I,3)=0:GOTO 5430\n5210 A$=\" * \":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5280\n5260 PRINT \"STAR AT\";X3;\",\";Y3;\"ABSORBED TORPEDO ENERGY.\":GOSUB 6000:GOTO 1990\n5280 A$=\">!<\":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 4760\n5330 PRINT \"*** STARBASE DESTROYED ***\":B3=B3-1:B9=B9-1\n5360 IF B9>0 OR K9>T-T0-T9 THEN 5400\n5370 PRINT \"THAT DOES IT, CAPTAIN!!  YOU ARE HEREBY RELIEVED OF COMMAND\"\n5380 PRINT \"AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!\"\n5390 GOTO 6270\n5400 PRINT \"STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER\"\n5410 PRINT \"COURT MARTIAL!\":D0=0\n5430 Z1=X:Z2=Y:A$=\"   \":GOSUB 8670\n5470 G(Q1,Q2)=K3*100+B3*10+S3:Z(Q1,Q2)=G(Q1,Q2):GOSUB 6000:GOTO 1990\n5490 PRINT \"TORPEDO MISSED\":GOSUB 6000:GOTO 1990\n5520 REM SHIELD CONTROL\n5530 IF D(7)<0 THEN PRINT \"SHIELD CONTROL INOPERABLE\":GOTO 1990\n5560 PRINT \"ENERGY AVAILABLE =\";E+S;:INPUT\"NUMBER OF UNITS TO SHIELDS\";X\n5580 IF X<0 OR S=X THEN PRINT \"<SHIELDS UNCHANGED>\":GOTO 1990\n5590 IF X<=E+S THEN 5630\n5600 PRINT \"SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION TREASURY.'\"\n5610 PRINT \"<SHIELDS UNCHANGED>\":GOTO 1990\n5630 E=E+S-X:S=X:PRINT \"DEFLECTOR CONTROL ROOM REPORT:\"\n5660 PRINT \"  'SHIELDS NOW AT\";INT(S);\"UNITS PER YOUR COMMAND.'\":GOTO 1990\n5680 REM DAMAGE CONTROL\n5690 IF D(6)>=0 THEN 5910\n5700 PRINT \"DAMAGE CONTROL REPORT NOT AVAILABLE\":IF D0=0 THEN 1990\n5720 D3=0:FOR I=1TO8:IF D(I)<0 THEN D3=D3+.1\n5760 NEXT I:IF D3=0 THEN 1990\n5780 PRINT:D3=D3+D4:IF D3>=1 THEN D3=.9\n5810 PRINT \"TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;\"\n5820 PRINT \"ESTIMATED TIME TO REPAIR:\";.01*INT(100*D3);\"STARDATES\"\n5840 INPUT \"WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)\";A$\n5860 IF A$<>\"Y\" THEN 1990\n5870 FOR I=1TO8:IF D(I)<0 THEN D(I)=0\n5890 NEXT I:T=T+D3+.1\n5910 PRINT:PRINT \"DEVICE             STATE OF REPAIR\":FOR R1=1TO8\n5920 GOSUB 8790:PRINT G2$;LEFT$(Z$,25-LEN(G2$));INT(D(R1)*100)*.01\n5950 NEXT R1:PRINT:IF D0<>0 THEN 5720\n5980 GOTO 1990\n5990 REM KLINGONS SHOOTING\n6000 IF K3<=0 THEN RETURN\n6010 IF D0<>0 THEN PRINT \"STARBASE SHIELDS PROTECT THE ENTERPRISE\":RETURN\n6040 FOR I=1TO3:IF K(I,3)<=0 THEN 6200\n6060 H=INT((K(I,3)/FND(1))*(2+RND(1))):S=S-H:K(I,3)=K(I,3)/(3+RND(0))\n6080 PRINT H;\"UNIT HIT ON ENTERPRISE FROM SECTOR\";K(I,1);\",\";K(I,2)\n6090 IF S<=0 THEN 6240\n6100 PRINT \"      <SHIELDS DOWN TO\";S;\"UNITS>\":IF H<20 THEN 6200\n6120 IF RND(1)>.6 OR H/S<=.02 THEN 6200\n6140 R1=FNR(1):D(R1)=D(R1)-H/S-.5*RND(1):GOSUB 8790\n6170 PRINT \"DAMAGE CONTROL REPORTS \";G2$;\" DAMAGED BY THE HIT'\"\n6200 NEXT I:RETURN\n6210 REM END OF GAME\n6220 PRINT \"IT IS STARDATE\";T:GOTO 6270\n6240 PRINT:PRINT \"THE ENTERPRISE HAS BEEN DESTROYED.  THEN FEDERATION \";\n6250 PRINT \"WILL BE CONQUERED\":GOTO 6220\n6270 PRINT \"THERE WERE\";K9;\"KLINGON BATTLE CRUISERS LEFT AT\"\n6280 PRINT \"THE END OF YOUR MISSION.\"\n6290 PRINT:PRINT:IF B9=0 THEN 6360\n6310 PRINT \"THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER\"\n6320 PRINT \"FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,\"\n6330 INPUT\"LET HIM STEP FORWARD AND ENTER 'AYE'\";A$:IF A$=\"AYE\" THEN 10\n6360 END\n6370 PRINT \"CONGRULATION, CAPTAIN!  THEN LAST KLINGON BATTLE CRUISER\"\n6380 PRINT \"MENACING THE FDERATION HAS BEEN DESTROYED.\":PRINT\n6400 PRINT \"YOUR EFFICIENCY RATING IS\";1000*(K7/(T-T0))^2:GOTO 6290\n6420 REM SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE\n6430 FOR I=S1-1TOS1+1:FOR J=S2-1 TO S2+1\n6450 IF INT(I+.5)<1 OR INT(I+.5)>8 OR INT(J+.5)<1 OR INT(J+.5)>8 THEN 6540\n6490 A$=\">!<\":Z1=I:Z2=J:GOSUB 8830:IF Z3=1 THEN 6580\n6540 NEXT J:NEXT I:D0=0:GOTO 6650\n6580 D0=1:C$=\"DOCKED\":E=E0:P=P0\n6620 PRINT \"SHIELDS DROPPED FOR DOCKING PURPOSES\":S=0:GOTO 6720\n6650 IF K3>0 THEN C$=\"*RED*\":GOTO 6720\n6660 C$=\"GREEN\":IF E<E0*.1 THEN C$=\"YELLOW\"\n6720 IF D(2)>=0 THEN 6770\n6730 PRINT:PRINT \"*** SHORT RANGE SENSORS ARE OUT ***\":PRINT:RETURN\n6770 O1$=\"---------------------------------\":PRINT O1$:FOR I=1 TO 8\n6820 FOR J=(I-1)*24+1 TO (I-1)*24+22STEP3:PRINT \" \";MID$(Q$,J,3);:NEXT J\n6830 ON I GOTO 6850,6900,6960,7020,7070,7120,7180,7240\n6850 PRINT \"        STARDATE          \";INT(T*10)*.1:GOTO 7260\n6900 PRINT \"        CONDITION          \";C$:GOTO 7260\n6960 PRINT \"        QUADRANT          \";Q1;\",\";Q2:GOTO 7260\n7020 PRINT \"        SECTOR            \";S1;\",\";S2:GOTO 7260\n7070 PRINT \"        PHOTON TORPEDOES  \";INT(P):GOTO 7260\n7120 PRINT \"        TOTAL ENERGY      \";INT(E+S):GOTO 7260\n7180 PRINT \"        SHIELDS           \";INT(S):GOTO 7260\n7240 PRINT \"        KLINGONS REMAINING\";INT(K9)\n7260 NEXT I:PRINT O1$:RETURN\n7280 REM LIBRARY COMPUTER CODE\n7290 IF D(8)<0 THEN PRINT \"COMPUTER DISABLED\":GOTO 1990\n7320 INPUT\"COMPUTER ACTIVE AND AWAITING COMMAND\";A:IF A<0 THEN 1990\n7350 PRINT:H8=1:ON A+1 GOTO 7540,7900,8070,8500,8150,7400\n7360 PRINT \"FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\"\n7370 PRINT \"   0 = CUMULATIVE GALACTIC RECORD\"\n7372 PRINT \"   1 = STATUS REPORT\"\n7374 PRINT \"   2 = PHOTON TORPEDO DATA\"\n7376 PRINT \"   3 = STARBASE NAV DATA\"\n7378 PRINT \"   4 = DIRECTION/DISTANCE CALCULATOR\"\n7380 PRINT \"   5 = GALAXY 'REGION NAME' MAP\":PRINT:GOTO 7320\n7390 REM SETUP TO CHANGE CUM GAL RECORD TO GALAXY MAP\n7400 H8=0:G5=1:PRINT \"                        THE GALAXY\":GOTO 7550\n7530 REM CUM GALACTIC RECORD\n7540 REM INPUT\"DO YOU WANT A HARDCOPY? IS THE TTY ON (Y/N)\";A$\n7542 REM IF A$=\"Y\" THEN POKE1229,2:POKE1237,3:NULL1\n7543 PRINT:PRINT \"        \";\n7544 PRINT \"COMPUTER RECORD OF GALAXY FOR QUADRANT\";Q1;\",\";Q2\n7546 PRINT\n7550 PRINT \"       1     2     3     4     5     6     7     8\"\n7560 O1$=\"     ----- ----- ----- ----- ----- ----- ----- -----\"\n7570 PRINT O1$:FOR I=1 TO 8:PRINT I;:IF H8=0 THEN 7740\n7630 FOR J=1 TO 8:PRINT \"   \";:IF Z(I,J)=0 THEN PRINT \"***\";:GOTO 7720\n7700 PRINT RIGHT$(STR$(Z(I,J)+1000),3);\n7720 NEXT J:GOTO 7850\n7740 Z4=I:Z5=1:GOSUB 9030:J0=INT(15-.5*LEN(G2$)):PRINT TAB(J0);G2$;\n7800 Z5=5:GOSUB 9030:J0=INT(39-.5*LEN(G2$)):PRINT TAB(J0);G2$;\n7850 PRINT:PRINT O1$:NEXT I:PRINT:GOTO 1990\n7890 REM STATUS REPORT\n7900 PRINT \"   STATUS REPORT:\":X$=\"\":IF K9>1 THEN X$=\"S\"\n7940 PRINT \"KLINGON\";X$;\" LEFT: \";K9\n7960 PRINT \"MISSION MUST BE COMPLETED IN\";.1*INT((T0+T9-T)*10);\"STARDATES\"\n7970 X$=\"S\":IF B9<2 THEN X$=\"\":IF B9<1 THEN 8010\n7980 PRINT \"THE FEDERATION IS MAINTAINING\";B9;\"STARBASE\";X$;\" IN THE GALAXY\"\n7990 GOTO 5690\n8010 PRINT \"YOUR STUPIDITY HAS LEFT YOU ON YOUR ON IN\"\n8020 PRINT \"  THE GALAXY -- YOU HAVE NO STARBASES LEFT!\":GOTO 5690\n8060 REM TORPEDO, BASE NAV, D/D CALCULATOR\n8070 IF K3<=0 THEN 4270\n8080 X$=\"\":IF K3>1 THEN X$=\"S\"\n8090 PRINT \"FROM ENTERPRISE TO KLINGON BATTLE CRUSER\";X$\n8100 H8=0:FOR I=1 TO 3:IF K(I,3)<=0 THEN 8480\n8110 W1=K(I,1):X=K(I,2)\n8120 C1=S1:A=S2:GOTO 8220\n8150 PRINT \"DIRECTION/DISTANCE CALCULATOR:\"\n8160 PRINT \"YOU ARE AT QUADRANT \";Q1;\",\";Q2;\" SECTOR \";S1;\",\";S2\n8170 PRINT \"PLEASE ENTER\":INPUT\"  INITIAL COORDINATES (X,Y)\";C1,A\n8200 INPUT\"  FINAL COORDINATES (X,Y)\";W1,X\n8220 X=X-A:A=C1-W1:IF X<0 THEN 8350\n8250 IF A<0 THEN 8410\n8260 IF X>0 THEN 8280\n8270 IF A=0 THEN C1=5:GOTO 8290\n8280 C1=1\n8290 IF ABS(A)<=ABS(X) THEN 8330\n8310 PRINT \"DIRECTION =\";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO 8460\n8330 PRINT \"DIRECTION =\";C1+(ABS(A)/ABS(X)):GOTO 8460\n8350 IF A>0 THEN C1=3:GOTO 8420\n8360 IF X<>0 THEN C1=5:GOTO 8290\n8410 C1=7\n8420 IF ABS(A)>=ABS(X) THEN 8450\n8430 PRINT \"DIRECTION =\";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO 8460\n8450 PRINT \"DIRECTION =\";C1+(ABS(X)/ABS(A))\n8460 PRINT \"DISTANCE =\";SQR(X^2+A^2):IF H8=1 THEN 1990\n8480 NEXT I:GOTO 1990\n8500 IF B3<>0 THEN PRINT \"FROM ENTERPRISE TO STARBASE:\":W1=B4:X=B5:GOTO 8120\n8510 PRINT \"MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS\";\n8520 PRINT \" QUADRANT.'\":GOTO 1990\n8580 REM FIND EMPTY PLACE IN QUADRANT (FOR THINGS)\n8590 R1=FNR(1):R2=FNR(1):A$=\"   \":Z1=R1:Z2=R2:GOSUB 8830:IF Z3=0 THEN 8590\n8600 RETURN\n8660 REM INSERT IN STRING ARRAY FOR QUADRANT\n8670 S8=INT(Z2-.5)*3+INT(Z1-.5)*24+1\n8675 IF LEN(A$)<>3 THEN PRINT \"ERROR\":STOP\n8680 IF S8=1 THEN Q$=A$+RIGHT$(Q$,189):RETURN\n8690 IF S8=190 THEN Q$=LEFT$(Q$,189)+A$:RETURN\n8700 Q$=LEFT$(Q$,S8-1)+A$+RIGHT$(Q$,190-S8):RETURN\n8780 REM PRINTS DEVICE NAME\n8790 ON R1 GOTO 8792,8794,8796,8798,8800,8802,8804,8806\n8792 G2$=\"WARP ENGINES\":RETURN\n8794 G2$=\"SHORT RANGE SENSORS\":RETURN\n8796 G2$=\"LONG RANGE SENSORS\":RETURN\n8798 G2$=\"PHASER CONTROL\":RETURN\n8800 G2$=\"PHOTON TUBES\":RETURN\n8802 G2$=\"DAMAGE CONTROL\":RETURN\n8804 G2$=\"SHIELD CONTROL\":RETURN\n8806 G2$=\"LIBRARY-COMPUTER\":RETURN\n8820 REM STRING COMPARISON IN QUADRANT ARRAY\n8830 Z1=INT(Z1+.5):Z2=INT(Z2+.5):S8=(Z2-1)*3+(Z1-1)*24+1:Z3=0\n8890 IF MID$(Q$,S8,3)<>A$ THEN RETURN\n8900 Z3=1:RETURN\n9010 REM QUADRANT NAME IN G2$ FROM Z4,Z5 (=Q1,Q2)\n9020 REM CALL WITH G5=1 TO GET REGION NAME ONLY\n9030 IF Z5<=4 THEN ON Z4 GOTO 9040,9050,9060,9070,9080,9090,9100,9110\n9035 GOTO 9120\n9040 G2$=\"ANTARES\":GOTO 9210\n9050 G2$=\"RIGEL\":GOTO 9210\n9060 G2$=\"PROCYON\":GOTO 9210\n9070 G2$=\"VEGA\":GOTO 9210\n9080 G2$=\"CANOPUS\":GOTO 9210\n9090 G2$=\"ALTAIR\":GOTO 9210\n9100 G2$=\"SAGITTARIUS\":GOTO 9210\n9110 G2$=\"POLLUX\":GOTO 9210\n9120 ON Z4 GOTO 9130,9140,9150,9160,9170,9180,9190,9200\n9130 G2$=\"SIRIUS\":GOTO 9210\n9140 G2$=\"DENEB\":GOTO 9210\n9150 G2$=\"CAPELLA\":GOTO 9210\n9160 G2$=\"BETELGEUSE\":GOTO 9210\n9170 G2$=\"ALDEBARAN\":GOTO 9210\n9180 G2$=\"REGULUS\":GOTO 9210\n9190 G2$=\"ARCTURUS\":GOTO 9210\n9200 G2$=\"SPICA\"\n9210 IF G5<>1 THEN ON Z5 GOTO 9230,9240,9250,9260,9230,9240,9250,9260\n9220 RETURN\n9230 G2$=G2$+\" I\":RETURN\n9240 G2$=G2$+\" II\":RETURN\n9250 G2$=G2$+\" III\":RETURN\n9260 G2$=G2$+\" IV\":RETURN\n"
  },
  {
    "path": "84_Super_Star_Trek/superstartrekins.bas",
    "content": "10 REM INSTRUCTIONS FOR \"SUPER STARTREK\"  MAR 5, 1978\n20 FOR I=1 TO 12:PRINT:NEXT I\n21 PRINT TAB(10);\"*************************************\"\n22 PRINT TAB(10);\"*                                   *\"\n23 PRINT TAB(10);\"*                                   *\"\n30 PRINT TAB(10);\"*      * * SUPER STAR TREK * *      *\"\n31 PRINT TAB(10);\"*                                   *\"\n32 PRINT TAB(10);\"*                                   *\"\n35 PRINT TAB(10);\"*************************************\"\n36 FOR I=1 TO 8:PRINT:NEXT I\n40 INPUT \"DO YOU NEED INSTRUCTIONS (Y/N)\";K$:IF K$=\"N\" THEN 2000\n44 PRINT\n45 REM PRINT \"TURN THE TTY ON-LINE AND HIT ANY KEY EXCEPT RETURN\"\n46 REM IF INP(1)=13 THEN 46\n50 REM POKE 1229,2:POKE 1237,3:NULL 1\n90 PRINT\"      INSTRUCTIONS FOR 'SUPER STAR TREK'\"\n100 PRINT\n110 PRINT\"1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL\"\n120 PRINT\"     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).\"\n130 PRINT\"2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT\"\n140 PRINT\"     LIST OF THE LEGAL COMMANDS PRINTED OUT.\"\n150 PRINT\"3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE\"\n160 PRINT\"     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU\"\n170 PRINT\"     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND\"\n180 PRINT\"     WILL BE ABORTED\"\n190 PRINT\n270 PRINT\"     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,\"\n280 PRINT\"AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.\"\n290 PRINT\n300 PRINT\"     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE\"\n310 PRINT\"GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP\"\n320 PRINT\"\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF\"\n330 PRINT\"KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF\"\n340 PRINT\"PLANETS.\"\n360 PRINT\n370 PRINT\"     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN\"\n380 PRINT\"OF THE STARSHIP ENTERPRISE:\"\n385 PRINT\n390 PRINT\"\\NAV\\ COMMAND = WARP ENGINE CONTROL --\"\n400 PRINT\"     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2\"\n410 PRINT\"     VECTOR ARRANGEMENT AS SHOWN             . . .\"\n420 PRINT\"     INTEGER AND REAL VALUES MAY BE           ...\"\n430 PRINT\"     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1\"\n440 PRINT\"     WAY BETWEEN 1 AND 2                      ...\"\n450 PRINT\"                                             . . .\"\n460 PRINT\"     VALUES MAY APPROACH 9.0, WHICH         6  7  8\"\n470 PRINT\"     ITSELF IS EQUIVALENT TO 1.0\"\n480 PRINT\"                                            COURSE\"\n490 PRINT\"     ONE WARP FACTOR IS THE SIZE OF \"\n500 PRINT\"     ONE QUADTANT.  THEREFORE, TO GET\"\n510 PRINT\"     FROM QUADRANT 6,5 TO 5,5, YOU WOULD\"\n520 PRINT\"     USE COURSE 3, WARP FACTOR 1.\"\n530 PRINT\n540 PRINT\"\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN\"\n550 PRINT\"     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.\"\n555 PRINT\n560 PRINT\"     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:\"\n570 PRINT\"        <*> = YOUR STARSHIP'S POSITION\"\n580 PRINT\"        +K+ = KLINGON BATTLE CRUISER\"\n590 PRINT\"        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)\"\n600 PRINT\"         *  = STAR\"\n605 PRINT\n610 PRINT\"     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.\"\n620 PRINT\n640 PRINT\"\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN\"\n650 PRINT\"     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE\"\n660 PRINT\"     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)\"\n670 PRINT\"     THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT\"\n680 PRINT\"     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF\"\n690 PRINT\"     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF\"\n700 PRINT\"     KLINGONS.\"\n705 PRINT\n706 PRINT\"     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.\"\n710 PRINT\n720 PRINT\"\\PHA\\ COMMAND = PHASER CONTROL.\"\n730 PRINT\"     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY \"\n740 PRINT\"     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO\"\n750 PRINT\"     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE\"\n760 PRINT\"     PHASERS TOO!)\"\n770 PRINT\n780 PRINT\"\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL\"\n790 PRINT\"     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL\"\n800 PRINT\"     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND\"\n810 PRINT\"     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO\"\n820 PRINT\"     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO \"\n825 PRINT\"     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.\"\n830 PRINT\n835 PRINT\"     THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO \"\n840 PRINT\"     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)\"\n850 PRINT\n860 PRINT\"\\SHE\\ COMMAND = SHIELD CONTROL\"\n870 PRINT\"     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE\"\n880 PRINT\"     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE\"\n890 PRINT\"     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY\"\n900 PRINT\n910 PRINT\"\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT\"\n920 PRINT\"     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE\"\n930 PRINT\"     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY\"\n940 PRINT\"     DAMAGED.\"\n950 PRINT\n960 PRINT\"\\COM\\ COMMAND = LIBRARY-COMPUTER\"\n970 PRINT\"     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:\"\n980 PRINT\"     OPTION 0 = CUMULATIVE GALACTIC RECORD\"\n990 PRINT\"        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL\"\n1000 PRINT\"        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS\"\n1010 PRINT\"     OPTION 1 = STATUS REPORT\"\n1020 PRINT\"        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,\"\n1030 PRINT\"        AND STARBASES REMAINING IN THE GAME.\"\n1040 PRINT\"     OPTION 2 = PHOTON TORPEDO DATA\"\n1050 PRINT\"        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE\"\n1060 PRINT\"        TO ALL KLINGONS IN YOUR QUADRANT\"\n1070 PRINT\"     OPTION 3 = STARBASE NAV DATA\"\n1080 PRINT\"        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY \"\n1090 PRINT\"        STARBASE WITHIN YOUR QUADRANT\"\n1100 PRINT\"     OPTION 4 = DIRECTION/DISTANCE CALCULATOR\"\n1110 PRINT\"        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR\"\n1120 PRINT\"        DIRECTION/DISTANCE CALCULATIONS\"\n1130 PRINT\"     OPTION 5 = GALACTIC /REGION NAME/ MAP\"\n1140 PRINT\"        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR \"\n1150 PRINT\"        GALACTIC REGIONS REFERRED TO IN THE GAME.\"\n1990 REM POKE 1229,0:POKE 1237,1:NULL 0\n2000 REM PRINT:PRINT:PRINT\n2010 REM PRINT \"TURN CASSETTE PLAYER ON AND HIT ANY KEY EXCEPT RETURN\"\n2020 REM IF INP(1)=13 THEN 2020\n2030 REM PRINT\n2040 REM PRINT \"TURN CASSETTE PLAYER OFF AND \"\n2050 REM PRINT \"TYPE 'RUN' WHEN COMPUTER PRINTS 'OK'\"\n"
  },
  {
    "path": "84_Super_Star_Trek/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "84_Super_Star_Trek/vbnet/SuperStarTrek.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"SuperStarTrek\", \"SuperStarTrek.vbproj\", \"{92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "84_Super_Star_Trek/vbnet/SuperStarTrek.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>SuperStarTrek</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "85_Synonym/README.md",
    "content": "### Synonym\n\nA synonym of a word is another word (in the English language) which has the same, or very nearly the same, meaning. This program tests your knowledge of synonyms of a few common words.\n\nThe computer chooses a word and asks you for a synonym. The computer then tells you whether you’re right or wrong. If you can’t think of a synonym, type “HELP” which causes a synonym to be printed.\n\nYou may put in words of your choice in the data statements. The number following DATA in Statement 500 is the total number of data statements. In each data statement, the first number is the number of words in that statement.\n\nCan you think of a way to make this into a more general kind of CAI program for any subject?\n\nWalt Koetke of Lexington High School, Massachusetts created this program.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=164)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=179)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n - Each time the player asks for HELP, one of the synonyms is shown\n   and discarded. There is no protection against the player using up\n   all of the help.\n\n - The player can ask for HELP and then submit that answer. Is it\n   meant to be a clue, or just giving a correct answer to the player?\n"
  },
  {
    "path": "85_Synonym/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "85_Synonym/csharp/Synonym.cs",
    "content": "﻿using System.Text;\n\nnamespace Synonym\n{\n    class Synonym\n    {\n        Random rand = new Random();\n\n        // Initialize list of corrent responses\n        private string[] Affirmations = { \"Right\", \"Correct\", \"Fine\", \"Good!\", \"Check\" };\n\n        // Initialize list of words and their synonyms\n        private string[][] Words =\n        {\n                new string[] {\"first\", \"start\", \"beginning\", \"onset\", \"initial\"},\n                new string[] {\"similar\", \"alike\", \"same\", \"like\", \"resembling\"},\n                new string[] {\"model\", \"pattern\", \"prototype\", \"standard\", \"criterion\"},\n                new string[] {\"small\", \"insignificant\", \"little\", \"tiny\", \"minute\"},\n                new string[] {\"stop\", \"halt\", \"stay\", \"arrest\", \"check\", \"standstill\"},\n                new string[] {\"house\", \"dwelling\", \"residence\", \"domicile\", \"lodging\", \"habitation\"},\n                new string[] {\"pit\", \"hole\", \"hollow\", \"well\", \"gulf\", \"chasm\", \"abyss\"},\n                new string[] {\"push\", \"shove\", \"thrust\", \"prod\", \"poke\", \"butt\", \"press\"},\n                new string[] {\"red\", \"rouge\", \"scarlet\", \"crimson\", \"flame\", \"ruby\"},\n                new string[] {\"pain\", \"suffering\", \"hurt\", \"misery\", \"distress\", \"ache\", \"discomfort\"}\n         };\n\n        private void DisplayIntro()\n        {\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"SYNONYM\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"A synonym of a word means another word in the English\");\n            Console.WriteLine(\"language which has the same or very nearly the same meaning.\");\n            Console.WriteLine(\"I choose a word -- you type a synonym.\");\n            Console.WriteLine(\"If you can't think of a synonym, type the word 'help'\");\n            Console.WriteLine(\"and I will tell you a synonym.\");\n            Console.WriteLine(\"\");\n        }\n\n        private void DisplayOutro()\n        {\n            Console.WriteLine(\"Synonym drill completed.\");\n        }\n\n        private void RandomizeTheList()\n        {\n            // Randomize the list of Words to pick from\n            int[] Order = new int[Words.Length];\n            foreach (int i in Order)\n            {\n                Order[i] = rand.Next();\n            }\n            Array.Sort(Order, Words);\n        }\n\n        private string GetAnAffirmation()\n        {\n            return Affirmations[rand.Next(Affirmations.Length)];\n        }\n\n        private bool CheckTheResponse(string WordName, int WordIndex, string LineInput, string[] WordList)\n        {\n            if (LineInput.Equals(\"help\"))\n            {\n                // Choose a random correct synonym response that doesn't equal the current word given\n                int HelpIndex = rand.Next(WordList.Length);\n                while (HelpIndex == WordIndex)\n                {\n                    HelpIndex = rand.Next(0, WordList.Length);\n                }\n                Console.WriteLine(\"**** A synonym of {0} is {1}.\", WordName, WordList[HelpIndex]);\n\n                return false;\n            }\n            else\n            {\n                // Check to see if the response is one of the listed synonyms and not the current word prompt\n                if (WordList.Contains(LineInput) && LineInput != WordName)\n                {\n                    // Randomly display one of the five correct answer exclamations\n                    Console.WriteLine(GetAnAffirmation());\n\n                    return true;\n                }\n                else\n                {\n                    // Incorrect response.  Try again.\n                    Console.WriteLine(\"     Try again.\".PadLeft(5));\n\n                    return false;\n                }\n            }\n        }\n\n        private string PromptForSynonym(string WordName)\n        {\n            Console.Write(\"     What is a synonym of {0}? \", WordName);\n            string LineInput = Console.ReadLine().Trim().ToLower();\n\n            return LineInput;\n        }\n\n        private void AskForSynonyms()\n        {\n            Random rand = new Random();\n\n            // Loop through the now randomized list of Words and display a random word from each to prompt for a synonym\n            foreach (string[] WordList in Words)\n            {\n                int WordIndex = rand.Next(WordList.Length);  // random word position in the current list of words\n                string WordName = WordList[WordIndex];       // what is that actual word\n                bool Success = false;\n\n                while (!Success)\n                {\n                    // Ask for the synonym of the current word\n                    string LineInput = PromptForSynonym(WordName);\n\n                    // Check the response\n                    Success = CheckTheResponse(WordName, WordIndex, LineInput, WordList);\n\n                    // Add extra line space for formatting\n                    Console.WriteLine(\"\");\n                }\n            }\n        }\n\n        public void PlayTheGame()\n        {\n            RandomizeTheList();\n\n            DisplayIntro();\n\n            AskForSynonyms();\n\n            DisplayOutro();\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Synonym().PlayTheGame();\n\n        }\n    }\n}\n"
  },
  {
    "path": "85_Synonym/csharp/Synonym.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <StartupObject>Synonym.Program</StartupObject>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "85_Synonym/csharp/Synonym.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Synonym\", \"Synonym.csproj\", \"{9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "85_Synonym/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "85_Synonym/java/src/Synonym.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Synonym\n * <p>\n * Based on the Basic game of Synonym here\n * https://github.com/coding-horror/basic-computer-games/blob/main/85%20Synonym/synonym.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Synonym {\n\n    public static final String[] RANDOM_ANSWERS = {\"RIGHT\", \"CORRECT\", \"FINE\", \"GOOD!\", \"CHECK\"};\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // List of words and synonyms\n    private final ArrayList<SynonymList> synonyms;\n\n    private enum GAME_STATE {\n        INIT,\n        PLAY,\n        GAME_OVER\n    }\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    private int currentQuestion;\n\n    public Synonym() {\n\n        kbScanner = new Scanner(System.in);\n        synonyms = new ArrayList<>();\n\n        gameState = GAME_STATE.INIT;\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                case INIT:\n                    intro();\n                    currentQuestion = 0;\n\n                    // Load data\n                    synonyms.add(new SynonymList(\"FIRST\", new String[]{\"START\", \"BEGINNING\", \"ONSET\", \"INITIAL\"}));\n                    synonyms.add(new SynonymList(\"SIMILAR\", new String[]{\"SAME\", \"LIKE\", \"RESEMBLING\"}));\n                    synonyms.add(new SynonymList(\"MODEL\", new String[]{\"PATTERN\", \"PROTOTYPE\", \"STANDARD\", \"CRITERION\"}));\n                    synonyms.add(new SynonymList(\"SMALL\", new String[]{\"INSIGNIFICANT\", \"LITTLE\", \"TINY\", \"MINUTE\"}));\n                    synonyms.add(new SynonymList(\"STOP\", new String[]{\"HALT\", \"STAY\", \"ARREST\", \"CHECK\", \"STANDSTILL\"}));\n                    synonyms.add(new SynonymList(\"HOUSE\", new String[]{\"DWELLING\", \"RESIDENCE\", \"DOMICILE\", \"LODGING\", \"HABITATION\"}));\n                    synonyms.add(new SynonymList(\"PIT\", new String[]{\"HOLE\", \"HOLLOW\", \"WELL\", \"GULF\", \"CHASM\", \"ABYSS\"}));\n                    synonyms.add(new SynonymList(\"PUSH\", new String[]{\"SHOVE\", \"THRUST\", \"PROD\", \"POKE\", \"BUTT\", \"PRESS\"}));\n                    synonyms.add(new SynonymList(\"RED\", new String[]{\"ROUGE\", \"SCARLET\", \"CRIMSON\", \"FLAME\", \"RUBY\"}));\n                    synonyms.add(new SynonymList(\"PAIN\", new String[]{\"SUFFERING\", \"HURT\", \"MISERY\", \"DISTRESS\", \"ACHE\", \"DISCOMFORT\"}));\n\n                    gameState = GAME_STATE.PLAY;\n                    break;\n\n                case PLAY:\n\n                    // Get the word and synonyms to ask a question about\n                    SynonymList synonym = synonyms.get(currentQuestion);\n                    String getAnswer = displayTextAndGetInput(\"     WHAT IS A SYNONYM OF \" + synonym.getWord() + \" ? \");\n\n                    // HELP is used to give a random synonym for the current word\n                    if (getAnswer.equals(\"HELP\")) {\n                        int randomSynonym = (int) (Math.random() * synonym.size());\n                        System.out.println(\"**** A SYNONYM OF \" + synonym.getWord() + \" IS \" + synonym.getSynonyms()[randomSynonym] + \".\");\n                    } else {\n                        // Check if the entered word is in the synonym list\n                        if (synonym.exists(getAnswer)) {\n                            // If it is, give a random \"correct\" response\n                            System.out.println(RANDOM_ANSWERS[(int) (Math.random() * RANDOM_ANSWERS.length)]);\n                            currentQuestion++;\n                            // Have we reached the final word/synonyms on file?\n                            if (currentQuestion == synonyms.size()) {\n                                // We have so end game.\n                                System.out.println(\"SYNONYM DRILL COMPLETED.\");\n                                gameState = GAME_STATE.GAME_OVER;\n                            }\n                        } else {\n                            // Word does not exist in the synonym list\n                            System.out.println(\"TRY AGAIN.\");\n                        }\n                    }\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    private void intro() {\n        System.out.println(simulateTabs(33) + \"SYNONYM\");\n        System.out.println(simulateTabs(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\");\n        System.out.println(\"LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME\");\n        System.out.println(\" MEANING.\");\n        System.out.println(\"I CHOOSE A WORD -- YOU TYPE A SYNONYM.\");\n        System.out.println(\"IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\");\n        System.out.println(\"AND I WILL TELL YOU A SYNONYM.\");\n        System.out.println();\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     * Converts input to uppercase.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next().toUpperCase();\n    }\n\n    /**\n     * Simulate the old basic tab(xx) command which indented text by xx spaces.\n     *\n     * @param spaces number of spaces required\n     * @return String with number of spaces\n     */\n    private String simulateTabs(int spaces) {\n        char[] spacesTemp = new char[spaces];\n        Arrays.fill(spacesTemp, ' ');\n        return new String(spacesTemp);\n    }\n}\n"
  },
  {
    "path": "85_Synonym/java/src/SynonymGame.java",
    "content": "public class SynonymGame {\n    public static void main(String[] args) {\n        Synonym synonym = new Synonym();\n        synonym.play();\n    }\n}\n"
  },
  {
    "path": "85_Synonym/java/src/SynonymList.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\n\n/**\n * Stores a word and a list of synonyms for that word\n */\npublic class SynonymList {\n\n    private final String word;\n\n    private final ArrayList<String> synonyms;\n\n    public SynonymList(String word, String[] synonyms) {\n        this.word = word;\n        this.synonyms = new ArrayList<>(Arrays.asList(synonyms));\n    }\n\n    /**\n     * Check if the word passed to this method exists in the list of synonyms\n     * N.B. Case insensitive\n     *\n     * @param word word to search for\n     * @return true if found, otherwise false\n     */\n    public boolean exists(String word) {\n        return synonyms.stream().anyMatch(str -> str.equalsIgnoreCase(word));\n    }\n\n    public String getWord() {\n        return word;\n    }\n\n    public int size() {\n        return synonyms.size();\n    }\n\n    /**\n     * Returns all synonyms for this word in string array format\n     *\n     * @return\n     */\n    public String[] getSynonyms() {\n        // Parameter to toArray method determines type of the resultant array\n        return synonyms.toArray(new String[0]);\n    }\n}\n"
  },
  {
    "path": "85_Synonym/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "85_Synonym/javascript/synonym.html",
    "content": "<html>\n<head>\n<title>SYNONYM</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"synonym.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "85_Synonym/javascript/synonym.js",
    "content": "// SYNONYM\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar ra = [, \"RIGHT\", \"CORRECT\", \"FINE\", \"GOOD!\", \"CHECK\"];\nvar la = [];\nvar tried = [];\n\nvar synonym = [[5,\"FIRST\",\"START\",\"BEGINNING\",\"ONSET\",\"INITIAL\"],\n               [5,\"SIMILAR\",\"ALIKE\",\"SAME\",\"LIKE\",\"RESEMBLING\"],\n               [5,\"MODEL\",\"PATTERN\",\"PROTOTYPE\",\"STANDARD\",\"CRITERION\"],\n               [5,\"SMALL\",\"INSIGNIFICANT\",\"LITTLE\",\"TINY\",\"MINUTE\"],\n               [6,\"STOP\",\"HALT\",\"STAY\",\"ARREST\",\"CHECK\",\"STANDSTILL\"],\n               [6,\"HOUSE\",\"DWELLING\",\"RESIDENCE\",\"DOMICILE\",\"LODGING\",\"HABITATION\"],\n               [7,\"PIT\",\"HOLE\",\"HOLLOW\",\"WELL\",\"GULF\",\"CHASM\",\"ABYSS\"],\n               [7,\"PUSH\",\"SHOVE\",\"THRUST\",\"PROD\",\"POKE\",\"BUTT\",\"PRESS\"],\n               [6,\"RED\",\"ROUGE\",\"SCARLET\",\"CRIMSON\",\"FLAME\",\"RUBY\"],\n               [7,\"PAIN\",\"SUFFERING\",\"HURT\",\"MISERY\",\"DISTRESS\",\"ACHE\",\"DISCOMFORT\"]\n               ];\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"SYNONYM\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (c = 0; c <= synonym.length; c++)\n        tried[c] = false;\n    print(\"A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\\n\");\n    print(\"LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME\");\n    print(\" MEANING.\\n\");\n    print(\"I CHOOSE A WORD -- YOU TYPE A SYNONYM.\\n\");\n    print(\"IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\\n\");\n    print(\"AND I WILL TELL YOU A SYNONYM.\\n\");\n    print(\"\\n\");\n    c = 0;\n    while (c < synonym.length) {\n        c++;\n        do {\n            n1 = Math.floor(Math.random() * synonym.length + 1);\n        } while (tried[n1]) ;\n        tried[n1] = true;\n        n2 = synonym[n1][0];    // Length of synonym list\n        // This array keeps a list of words not shown\n        for (j = 1; j <= n2; j++)\n            la[j] = j;\n        la[0] = n2;\n        g = 1;  // Always show first word\n        print(\"\\n\");\n        la[g] = la[la[0]];  // Replace first word with last word\n        la[0] = n2 - 1; // Reduce size of list by one.\n        print(\"\\n\");\n        while (1) {\n            print(\"     WHAT IS A SYNONYM OF \" + synonym[n1][g]);\n            str = await input();\n            if (str == \"HELP\") {\n                g1 = Math.floor(Math.random() * la[0] + 1);\n                print(\"**** A SYNONYM OF \" + synonym[n1][g] + \" IS \" + synonym[n1][la[g1]] + \".\\n\");\n                print(\"\\n\");\n                la[g1] = la[la[0]];\n                la[0]--;\n                continue;\n            }\n            for (k = 1; k <= n2; k++) {\n                if (g == k)\n                    continue;\n                if (str == synonym[n1][k])\n                    break;\n            }\n            if (k > n2) {\n                print(\"     TRY AGAIN.\\n\");\n            } else {\n                print(synonym[n1][Math.floor(Math.random() * 5 + 1)] + \"\\n\");\n                break;\n            }\n        }\n    }\n    print(\"\\n\");\n    print(\"SYNONYM DRILL COMPLETED.\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "85_Synonym/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "85_Synonym/kotlin/Synonym.kt",
    "content": "/**\n * Game of Synonym\n *\n *\n * Based on the Basic game of Synonym here\n * https://github.com/coding-horror/basic-computer-games/blob/main/85%20Synonym/synonym.bas\n *\n *\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\n\nfun main() {\n    println(introText)\n    synonyms.forEach {\n        it.testUser()\n    }\n    println(\"SYNONYM DRILL COMPLETED.\")\n}\n// We could put this inside of SynonymList, but this keeps the core implementation\n// right here at the top\nprivate fun SynonymList.testUser() {\n    do {\n        val answer = ask(\"     WHAT IS A SYNONYM OF $word ? \")\n        when {\n            answer == \"HELP\" ->\n                println(\"\"\"**** A SYNONYM OF $word IS ${synonyms.random()}.\"\"\")\n            synonyms.contains(answer) ->\n                println(AFFIRMATIONS.random())\n            else ->\n                println(\"TRY AGAIN.\")\n        }\n    } while (!synonyms.contains(answer))\n}\n\nval introText = \"\"\"\n${tab(33)}SYNONYM\n${tab(15)}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\nA SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\nLANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME\n MEANING.\nI CHOOSE A WORD -- YOU TYPE A SYNONYM.\nIF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\nAND I WILL TELL YOU A SYNONYM.\n\n    \"\"\"\n\n// prints a question and reads a string (and converts to uppercase)\nprivate fun ask(text: String): String {\n    print(text)\n    return readln().uppercase()\n}\n\n// Just like TAB in BASIC\nprivate fun tab(spaces: Int): String = \" \".repeat(spaces)\n\nval AFFIRMATIONS = arrayOf(\"RIGHT\", \"CORRECT\", \"FINE\", \"GOOD!\", \"CHECK\")\n\n// List of words and synonyms\nprivate val synonyms = listOf(\n    SynonymList(\"FIRST\", listOf(\"START\", \"BEGINNING\", \"ONSET\", \"INITIAL\")),\n    SynonymList(\"SIMILAR\", listOf(\"SAME\", \"LIKE\", \"RESEMBLING\")),\n    SynonymList(\"MODEL\", listOf(\"PATTERN\", \"PROTOTYPE\", \"STANDARD\", \"CRITERION\")),\n    SynonymList(\"SMALL\", listOf(\"INSIGNIFICANT\", \"LITTLE\", \"TINY\", \"MINUTE\")),\n    SynonymList(\"STOP\", listOf(\"HALT\", \"STAY\", \"ARREST\", \"CHECK\", \"STANDSTILL\")),\n    SynonymList(\"HOUSE\", listOf(\"DWELLING\", \"RESIDENCE\", \"DOMICILE\", \"LODGING\", \"HABITATION\")),\n    SynonymList(\"PIT\", listOf(\"HOLE\", \"HOLLOW\", \"WELL\", \"GULF\", \"CHASM\", \"ABYSS\")),\n    SynonymList(\"PUSH\", listOf(\"SHOVE\", \"THRUST\", \"PROD\", \"POKE\", \"BUTT\", \"PRESS\")),\n    SynonymList(\"RED\", listOf(\"ROUGE\", \"SCARLET\", \"CRIMSON\", \"FLAME\", \"RUBY\")),\n    SynonymList(\"PAIN\", listOf(\"SUFFERING\", \"HURT\", \"MISERY\", \"DISTRESS\", \"ACHE\", \"DISCOMFORT\"))\n)\n\nclass SynonymList(val word: String, val synonyms: List<String>)\n"
  },
  {
    "path": "85_Synonym/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "85_Synonym/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nI used List::Util to do all the heavy work to show that perl can handle all the various\narray functions.  It would be interesting to see a version that handled all of this\nmanually as there ended up being very little code left in this program.\n"
  },
  {
    "path": "85_Synonym/perl/synonym.pl",
    "content": "#!/usr/bin/perl\n\nuse v5.32; # for sample from List::Util, also includes 'use strict'\nuse warnings; # always a good idea\n\nuse List::Util qw/ any sample shuffle /; # Rather than write our own utilities, use the built in ones\n\nmy @correct = qw/ Right Correct Fine Good! Check /;\n\n# lowercase all words here\nmy @synonyms = (\n  [ qw/ first start beginning onset initial / ],\n  [ qw/ similar alike same like resembling / ],\n  [ qw/ model pattern prototype standard criterion /],\n  [ qw/ small insignificant little tiny minute /],\n  [ qw/ stop halt stay arrest check standstill /],\n  [ qw/ house dwelling residense domicile lodging habitation /],\n  [ qw/ pit hole hollow well gulf chasm abyss /],\n  [ qw/ push shove thrust prod poke butt press /],\n  [ qw/ red rouge scarlet crimson flame ruby /],\n  [ qw/ pain suffering hurt misery distress ache discomfort /],\n);\n\nprint <<__END_OF_INTRO;\n                                 Synonym\n                Creative Computing  Morristown, New Jersey\n\n\n\nA synonym of a word means another word in the English\nlanguage which has the same or very nearly the same meaning\nI choose a word -- you type a synonym.\nIf you can't think of a synonym, type the word 'HELP'\nand I will tell you a synonym.\n\n__END_OF_INTRO\n\nforeach my $drill ( shuffle @synonyms ) {\n  my $word = $drill->[0];\n  my @answers = $drill->@[1 .. $drill->$#*];\n  print \"     What is a synonym of $word? \";\n  my $response = <>;\n  chomp $response;\n  $response = lc $response;\n\n  if ( $response eq 'help' ) {\n    say \"**** A synonym of $word is \", sample(1, @answers);\n    redo;\n  } elsif ( not any { $response eq $_ } @answers ) {\n    say '     Try again.';\n    redo;\n  } else {\n    say sample 1, @correct;\n  }\n}\n\nsay \"\\nSynonym drill completed.\";\n"
  },
  {
    "path": "85_Synonym/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "85_Synonym/python/synonym.py",
    "content": "\"\"\"\nSYNONYM\n\nVocabulary quiz\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport random\n\nPAGE_WIDTH = 64\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n\ndef print_instructions() -> None:\n    print(\"A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\")\n    print(\"LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.\")\n    print(\"I CHOOSE A WORD -- YOU TYPE A SYNONYM.\")\n    print(\"IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\")\n    print(\"AND I WILL TELL YOU A SYNONYM.\")\n    print()\n\n\nright_words = [\"RIGHT\", \"CORRECT\", \"FINE\", \"GOOD!\", \"CHECK\"]\n\nsynonym_words = [\n    [\"FIRST\", \"START\", \"BEGINNING\", \"ONSET\", \"INITIAL\"],\n    [\"SIMILAR\", \"ALIKE\", \"SAME\", \"LIKE\", \"RESEMBLING\"],\n    [\"MODEL\", \"PATTERN\", \"PROTOTYPE\", \"STANDARD\", \"CRITERION\"],\n    [\"SMALL\", \"INSIGNIFICANT\", \"LITTLE\", \"TINY\", \"MINUTE\"],\n    [\"STOP\", \"HALT\", \"STAY\", \"ARREST\", \"CHECK\", \"STANDSTILL\"],\n    [\"HOUSE\", \"DWELLING\", \"RESIDENCE\", \"DOMICILE\", \"LODGING\", \"HABITATION\"],\n    [\"PIT\", \"HOLE\", \"HOLLOW\", \"WELL\", \"GULF\", \"CHASM\", \"ABYSS\"],\n    [\"PUSH\", \"SHOVE\", \"THRUST\", \"PROD\", \"POKE\", \"BUTT\", \"PRESS\"],\n    [\"RED\", \"ROUGE\", \"SCARLET\", \"CRIMSON\", \"FLAME\", \"RUBY\"],\n    [\"PAIN\", \"SUFFERING\", \"HURT\", \"MISERY\", \"DISTRESS\", \"ACHE\", \"DISCOMFORT\"],\n]\n\n\ndef print_right() -> None:\n    print(random.choice(right_words))\n\n\ndef ask_question(question_number: int) -> None:\n    words = synonym_words[question_number]\n    clues = words[:]\n    base_word = clues.pop(0)\n\n    while True:\n        question = f\"     WHAT IS A SYNONYM OF {base_word}? \"\n        response = input(question).upper()\n\n        if response == \"HELP\":\n            clue = random.choice(clues)\n            print(f\"**** A SYNONYM OF {base_word} IS {clue}.\")\n            print()\n\n            # remove the clue from available clues\n            clues.remove(clue)\n            continue\n\n        if (response != base_word) and (response in words):\n            print_right()\n            return\n\n\ndef finish() -> None:\n    print()\n    print(\"SYNONYM DRILL COMPLETED.\")\n\n\ndef main() -> None:\n    print_header(\"SYNONYM\")\n    print_instructions()\n\n    num_questions = len(synonym_words)\n    word_indices = list(range(num_questions))\n    random.shuffle(word_indices)\n\n    for word_number in word_indices:\n        ask_question(word_number)\n\n    finish()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "85_Synonym/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "85_Synonym/ruby/synonim.rb",
    "content": "########################################################\n#\n# Synonym\n#\n# From Basic Computer Games (1978)\n#\n# A synonym of a word is another word (in the English language) which has the same,\n# or very nearly the same, meaning. This program tests your knowledge of synonyms\n# of a few common words.\n#\n# The computer chooses a word and asks you for a synonym. The computer then tells\n# you whether you’re right or wrong. If you can’t think of a synonym, type “HELP”\n# which causes a synonym to be printed.\n# You may put in words of your choice in the data statements.\n# The number following DATA in Statement 500 is the total number of data statements.\n# In each data statement, the first number is the number of words in that statement.\n#\n# Can you think of a way to make this into a more general kind of CAI program for any subject?\n# Walt Koetke of Lexington High School, Massachusetts created this program.\n#\n#\n########################################################\n\nputs <<~INSTRUCTIONS\n                                 SYNONYM\n                 CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\nA SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\nLANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.\nI CHOOSE A WORD -- YOU TYPE A SYNONYM.\nIF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\nAND I WILL TELL YOU A SYNONYM.\n\n\nINSTRUCTIONS\n\nright_words = [\"RIGHT\", \"CORRECT\", \"FINE\", \"GOOD!\", \"CHECK\"]\n\nsynonym_words = [\n    [\"FIRST\", \"START\", \"BEGINNING\", \"ONSET\", \"INITIAL\"],\n    [\"SIMILAR\", \"ALIKE\", \"SAME\", \"LIKE\", \"RESEMBLING\"],\n    [\"MODEL\", \"PATTERN\", \"PROTOTYPE\", \"STANDARD\", \"CRITERION\"],\n    [\"SMALL\", \"INSIGNIFICANT\", \"LITTLE\", \"TINY\", \"MINUTE\"],\n    [\"STOP\", \"HALT\", \"STAY\", \"ARREST\", \"CHECK\", \"STANDSTILL\"],\n    [\"HOUSE\", \"DWELLING\", \"RESIDENCE\", \"DOMICILE\", \"LODGING\", \"HABITATION\"],\n    [\"PIT\", \"HOLE\", \"HOLLOW\", \"WELL\", \"GULF\", \"CHASM\", \"ABYSS\"],\n    [\"PUSH\", \"SHOVE\", \"THRUST\", \"PROD\", \"POKE\", \"BUTT\", \"PRESS\"],\n    [\"RED\", \"ROUGE\", \"SCARLET\", \"CRIMSON\", \"FLAME\", \"RUBY\"],\n    [\"PAIN\", \"SUFFERING\", \"HURT\", \"MISERY\", \"DISTRESS\", \"ACHE\", \"DISCOMFORT\"],\n]\n\nsynonym_words.shuffle.each {|words_ar|\n\n}\n\n\nsynonym_words.each {|words_ar|\n    answer = false\n    keyword = words_ar.shift\n\n    while not answer and words_ar.length != 0\n        puts \"     WHAT IS A SYNONYM OF #{keyword}? \"\n        inp = gets.chomp.upcase\n\n        if inp  == \"HELP\"\n            clue = words_ar.sample\n            puts \"**** A SYNONYM OF #{keyword} IS #{clue}.\"\n            words_ar.delete(clue)\n        elsif words_ar.include? inp\n            puts right_words.sample\n            answer = true\n        else\n            puts \"TRY AGAIN.\"\n        end\n\n    end\n\n}\n\nputs \"SYNONYM DRILL COMPLETED\"\n\n\n######################################################################\n#\n# Porting notes\n#\n#  There is a bug in the original program where if you keep asking for\n# synoyms of a given word it ends up running out of synonyms\n# in the array and the program crashes.\n#  The bug has been fixed in this version and now when\n# it runs out of words it continues with the next\n# array.\n#\n######################################################################\n"
  },
  {
    "path": "85_Synonym/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "85_Synonym/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by [Jadi](https://github.com/jadijadi)\n"
  },
  {
    "path": "85_Synonym/rust/src/main.rs",
    "content": "use rand::seq::SliceRandom;\nuse rand::thread_rng;\nuse rand::Rng;\nuse std::io::{self, Write};\n\nfn print_centered(text: &str, width: usize) {\n    let pad_size: usize = if width > text.len() {\n        (width - text.len()) / 2\n    } else {\n        0\n    };\n    println!(\"{}{}\", \" \".repeat(pad_size), text);\n}\n\nfn print_instructions() {\n    println!(\"A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\");\n    println!(\"LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.\");\n    println!(\"I CHOOSE A WORD -- YOU TYPE A SYNONYM.\");\n    println!(\"IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\");\n    println!(\"AND I WILL TELL YOU A SYNONYM.\\n\");\n}\n\nfn ask_question(mut this_question: Vec<&str>) {\n    let right_words = [\"RIGHT\", \"CORRECT\", \"FINE\", \"GOOD!\", \"CHECK\"];\n\n    // use the first one in the main question\n    let base_word = this_question.remove(0);\n\n    loop {\n        print!(\"     WHAT IS A SYNONYM OF {base_word}? \");\n        io::stdout().flush().unwrap();\n        let mut answer: String = String::new();\n        io::stdin()\n            .read_line(&mut answer)\n            .expect(\"Failed to read the line\");\n        let answer = answer.trim();\n        if answer == \"HELP\" {\n            // remove one random from the answers and show it\n            let random_index = thread_rng().gen_range(0..this_question.len());\n            println!(\n                \"**** A SYNONYM OF {base_word} IS {}.\",\n                this_question.remove(random_index)\n            );\n        } else if this_question.contains(&answer) {\n            println!(\"{}\", right_words.choose(&mut rand::thread_rng()).unwrap());\n            break;\n        }\n    }\n}\n\nfn main() {\n    const PAGE_WIDTH: usize = 64;\n\n    let mut synonyms = vec![\n        vec![\"FIRST\", \"START\", \"BEGINNING\", \"ONSET\", \"INITIAL\"],\n        vec![\"SIMILAR\", \"ALIKE\", \"SAME\", \"LIKE\", \"RESEMBLING\"],\n        vec![\"MODEL\", \"PATTERN\", \"PROTOTYPE\", \"STANDARD\", \"CRITERION\"],\n        vec![\"SMALL\", \"INSIGNIFICANT\", \"LITTLE\", \"TINY\", \"MINUTE\"],\n        vec![\"STOP\", \"HALT\", \"STAY\", \"ARREST\", \"CHECK\", \"STANDSTILL\"],\n        vec![\n            \"HOUSE\",\n            \"DWELLING\",\n            \"RESIDENCE\",\n            \"DOMICILE\",\n            \"LODGING\",\n            \"HABITATION\",\n        ],\n        vec![\"PIT\", \"HOLE\", \"HOLLOW\", \"WELL\", \"GULF\", \"CHASM\", \"ABYSS\"],\n        vec![\"PUSH\", \"SHOVE\", \"THRUST\", \"PROD\", \"POKE\", \"BUTT\", \"PRESS\"],\n        vec![\"RED\", \"ROUGE\", \"SCARLET\", \"CRIMSON\", \"FLAME\", \"RUBY\"],\n        vec![\n            \"PAIN\",\n            \"SUFFERING\",\n            \"HURT\",\n            \"MISERY\",\n            \"DISTRESS\",\n            \"ACHE\",\n            \"DISCOMFORT\",\n        ],\n    ];\n\n    synonyms.shuffle(&mut thread_rng());\n\n    print_centered(\"SYNONYM\", PAGE_WIDTH);\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\", PAGE_WIDTH);\n    println!(\"\\n\\n\\n\");\n\n    print_instructions();\n\n    for this_question in synonyms {\n        ask_question(this_question)\n    }\n    println!(\"SYNONYM DRILL COMPLETED.\");\n}\n\n////////////////////////////////////////////////////////////\n// Poring Notes\n// Poring Note: The \"HELP\" function .removes a variable\n// from lists and shows it. This can lead to errors when\n// the list becomes empty. But since the same issue happens\n// on the original BASIC program, kept it intact\n////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "85_Synonym/synonym.bas",
    "content": "2 PRINT TAB(33);\"SYNONYM\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT: PRINT: PRINT\n10 DIM R$(5),W$(10),L(30),R(30)\n20 R$(1)=\"RIGHT\": R$(2)=\"CORRECT\": R$(3)=\"FINE\": R$(4)=\"GOOD!\"\n30 R$(5)=\"CHECK\"\n70 C=0\n90 PRINT \"A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\"\n100 PRINT \"LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME\";\n110 PRINT \" MEANING.\"\n130 PRINT \"I CHOOSE A WORD -- YOU TYPE A SYNONYM.\"\n140 PRINT \"IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\"\n145 PRINT \"AND I WILL TELL YOU A SYNONYM.\": PRINT\n150 RESTORE: C=C+1: READ N\n160 IF C>N THEN 420\n170 N1=INT(RND(1)*N+1)\n174 IF R(N1)=1 THEN 170\n176 R(N1)=1\n180 FOR I=1 TO N1\n190 READ N2\n200 FOR J=1 TO N2\n210 READ W$(J)\n220 NEXT J\n230 NEXT I\n232 FOR J=1 TO N2: L(J)=J: NEXT J\n235 L(0)=N2: G=1: PRINT\n237 L(G)=L(L(0)): L(0)=N2-1: PRINT\n240 PRINT \"     WHAT IS A SYNONYM OF \";W$(G);: INPUT A$\n250 IF A$=\"HELP\" THEN 340\n260 FOR K=1 TO N2\n270 IF G=K THEN 290\n280 IF A$=W$(K) THEN 320\n290 NEXT K\n300 PRINT \"     TRY AGAIN.\": GOTO 240\n320 PRINT R$(INT(RND(1)*5+1)): GOTO 150\n340 G1=INT(RND(1)*L(0)+1)\n360 PRINT \"**** A SYNONYM OF \";W$(G);\" IS \";W$(L(G1));\".\": PRINT\n370 L(G1)=L(L(0)): L(0)=L(0)-1: GOTO 240\n420 PRINT: PRINT \"SYNONYM DRILL COMPLETED.\": GOTO 999\n500 DATA 10\n510 DATA 5,\"FIRST\",\"START\",\"BEGINNING\",\"ONSET\",\"INITIAL\"\n520 DATA 5,\"SIMILAR\",\"ALIKE\",\"SAME\",\"LIKE\",\"RESEMBLING\"\n530 DATA 5,\"MODEL\",\"PATTERN\",\"PROTOTYPE\",\"STANDARD\",\"CRITERION\"\n540 DATA 5,\"SMALL\",\"INSIGNIFICANT\",\"LITTLE\",\"TINY\",\"MINUTE\"\n550 DATA 6,\"STOP\",\"HALT\",\"STAY\",\"ARREST\",\"CHECK\",\"STANDSTILL\"\n560 DATA 6,\"HOUSE\",\"DWELLING\",\"RESIDENCE\",\"DOMICILE\",\"LODGING\"\n565 DATA \"HABITATION\"\n570 DATA 7,\"PIT\",\"HOLE\",\"HOLLOW\",\"WELL\",\"GULF\",\"CHASM\",\"ABYSS\"\n580 DATA 7,\"PUSH\",\"SHOVE\",\"THRUST\",\"PROD\",\"POKE\",\"BUTT\",\"PRESS\"\n590 DATA 6,\"RED\",\"ROUGE\",\"SCARLET\",\"CRIMSON\",\"FLAME\",\"RUBY\"\n600 DATA 7,\"PAIN\",\"SUFFERING\",\"HURT\",\"MISERY\",\"DISTRESS\",\"ACHE\"\n605 DATA \"DISCOMFORT\"\n999 END\n"
  },
  {
    "path": "85_Synonym/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "85_Synonym/vbnet/Synonym.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Synonym\", \"Synonym.vbproj\", \"{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "85_Synonym/vbnet/Synonym.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Synonym</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "86_Target/README.md",
    "content": "### Target\n\nIn this program, you are firing a weapon from a spaceship in 3-dimensional space. Your ship, the Starship Enterprise, is located at the origin (0,0,0) of a set of x,y,z coordinates. You will be told the approximate location of the target in 3-dimensional rectangular coordinates, the approximate angular deviation from the x and z axes in both radians and degrees, and the approximate distance to the target.\n\nGiven this information, you then proceed to shoot at the target. A shot within 20 kilometers of the target destroys it. After each shot, you are given information as to the position of the explosion of your shot and a somewhat improved estimate of the location of the target. Fortunately, this is just practice and the target doesn’t shoot back. After you have attained proficiency, you ought to be able to destroy a target in 3 or 4 shots. However, attaining proficiency might take a while!\n\nThe author is H. David Crockett of Fort Worth, Texas.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=165)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=180)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "86_Target/csharp/Angle.cs",
    "content": "namespace Target\n{\n    internal class Angle\n    {\n        // Use same precision for constants as original code\n        private const float PI = 3.14159f;\n        private const float DegreesPerRadian = 57.296f;\n\n        private readonly float _radians;\n\n        private Angle(float radians) => _radians = radians;\n\n        public static Angle InDegrees(float degrees) => new (degrees / DegreesPerRadian);\n        public static Angle InRotations(float rotations) => new (2 * PI * rotations);\n\n        public static implicit operator float(Angle angle) => angle._radians;\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/Explosion.cs",
    "content": "namespace Target\n{\n    internal class Explosion\n    {\n        private readonly Point _position;\n\n        public Explosion(Point position, Offset targetOffset)\n        {\n            _position = position;\n            FromTarget = targetOffset;\n            DistanceToTarget = targetOffset.Distance;\n        }\n\n        public Point Position => _position;\n        public Offset FromTarget { get; }\n        public float DistanceToTarget { get; }\n        public string GetBearing() => _position.GetBearing();\n\n        public bool IsHit => DistanceToTarget <= 20;\n        public bool IsTooClose => _position.Distance < 20;\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/FiringRange.cs",
    "content": "using Games.Common.Randomness;\n\nnamespace Target\n{\n    internal class FiringRange\n    {\n        private readonly IRandom _random;\n        private Point _targetPosition;\n\n        public FiringRange(IRandom random)\n        {\n            _random = random;\n        }\n\n        public Point NextTarget() =>  _targetPosition = _random.NextPosition();\n\n        public Explosion Fire(Angle angleFromX, Angle angleFromZ, float distance)\n        {\n            var explosionPosition = new Point(angleFromX, angleFromZ, distance);\n            var targetOffset = explosionPosition - _targetPosition;\n            return new (explosionPosition, targetOffset);\n        }\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/Game.cs",
    "content": "using System;\nusing Games.Common.IO;\n\nnamespace Target\n{\n    internal class Game\n    {\n        private readonly IReadWrite _io;\n        private readonly FiringRange _firingRange;\n        private int _shotCount;\n\n        public Game(IReadWrite io, FiringRange firingRange)\n        {\n            _io = io;\n            _firingRange = firingRange;\n        }\n\n        public void Play()\n        {\n            _shotCount = 0;\n            var target = _firingRange.NextTarget();\n            _io.WriteLine(target.GetBearing());\n            _io.WriteLine($\"Target sighted: approximate coordinates:  {target}\");\n\n            while (true)\n            {\n                _io.WriteLine($\"     Estimated distance: {target.EstimateDistance()}\");\n                _io.WriteLine();\n\n                var explosion = Shoot();\n\n                if (explosion.IsTooClose)\n                {\n                    _io.WriteLine(\"You blew yourself up!!\");\n                    return;\n                }\n\n                _io.WriteLine(explosion.GetBearing());\n\n                if (explosion.IsHit)\n                {\n                    ReportHit(explosion.DistanceToTarget);\n                    return;\n                }\n\n                ReportMiss(explosion);\n            }\n        }\n\n        private Explosion Shoot()\n        {\n            var (xDeviation, zDeviation, distance) = _io.Read3Numbers(\n                \"Input angle deviation from X, angle deviation from Z, distance\");\n            _shotCount++;\n            _io.WriteLine();\n\n            return _firingRange.Fire(Angle.InDegrees(xDeviation), Angle.InDegrees(zDeviation), distance);\n        }\n\n        private void ReportHit(float distance)\n        {\n            _io.WriteLine();\n            _io.WriteLine($\" * * * HIT * * *   Target is non-functional\");\n            _io.WriteLine();\n            _io.WriteLine($\"Distance of explosion from target was {distance} kilometers.\");\n            _io.WriteLine();\n            _io.WriteLine($\"Mission accomplished in {_shotCount} shots.\");\n        }\n\n        private void ReportMiss(Explosion explosion)\n        {\n            ReportMiss(explosion.FromTarget);\n            _io.WriteLine($\"Approx position of explosion:  {explosion.Position}\");\n            _io.WriteLine($\"     Distance from target = {explosion.DistanceToTarget}\");\n            _io.WriteLine();\n            _io.WriteLine();\n            _io.WriteLine();\n        }\n\n        private void ReportMiss(Offset targetOffset)\n        {\n            ReportMiss(targetOffset.DeltaX, \"in front of\", \"behind\");\n            ReportMiss(targetOffset.DeltaY, \"to left of\", \"to right of\");\n            ReportMiss(targetOffset.DeltaZ, \"above\", \"below\");\n        }\n\n        private void ReportMiss(float delta, string positiveText, string negativeText) =>\n            _io.WriteLine(delta >= 0 ? GetOffsetText(positiveText, delta) : GetOffsetText(negativeText, -delta));\n\n        private static string GetOffsetText(string text, float distance) => $\"Shot {text} target {distance} kilometers.\";\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/Offset.cs",
    "content": "using System;\n\nnamespace Target\n{\n    internal class Offset\n    {\n        public Offset(float deltaX, float deltaY, float deltaZ)\n        {\n            DeltaX = deltaX;\n            DeltaY = deltaY;\n            DeltaZ = deltaZ;\n\n            Distance = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ + deltaZ);\n        }\n\n        public float DeltaX { get; }\n        public float DeltaY { get; }\n        public float DeltaZ { get; }\n        public float Distance { get; }\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/Point.cs",
    "content": "using System;\n\nnamespace Target\n{\n    internal class Point\n    {\n        private readonly float _angleFromX;\n        private readonly float _angleFromZ;\n\n        private readonly float _x;\n        private readonly float _y;\n        private readonly float _z;\n\n        private int _estimateCount;\n\n        public Point(Angle angleFromX, Angle angleFromZ, float distance)\n        {\n            _angleFromX = angleFromX;\n            _angleFromZ = angleFromZ;\n            Distance = distance;\n\n            _x = distance * (float)Math.Sin(_angleFromZ) * (float)Math.Cos(_angleFromX);\n            _y = distance * (float)Math.Sin(_angleFromZ) * (float)Math.Sin(_angleFromX);\n            _z = distance * (float)Math.Cos(_angleFromZ);\n        }\n\n        public float Distance { get; }\n\n        public float EstimateDistance() =>\n            ++_estimateCount switch\n            {\n                1 => EstimateDistance(20),\n                2 => EstimateDistance(10),\n                3 => EstimateDistance(5),\n                4 => EstimateDistance(1),\n                _ => Distance\n            };\n\n        public float EstimateDistance(int precision) => (float)Math.Floor(Distance / precision) * precision;\n\n        public string GetBearing() => $\"Radians from X axis = {_angleFromX}   from Z axis = {_angleFromZ}\";\n\n        public override string ToString() => $\"X= {_x}   Y = {_y}   Z= {_z}\";\n\n        public static Offset operator -(Point p1, Point p2) => new (p1._x - p2._x, p1._y - p2._y, p1._z - p2._z);\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing Games.Common.IO;\nusing Games.Common.Randomness;\n\nnamespace Target\n{\n    class Program\n    {\n        static void Main()\n        {\n            var io = new ConsoleIO();\n            var game = new Game(io, new FiringRange(new RandomNumberGenerator()));\n\n            Play(game, io, () => true);\n        }\n\n        public static void Play(Game game, TextIO io, Func<bool> playAgain)\n        {\n            DisplayTitleAndInstructions(io);\n\n            while (playAgain())\n            {\n                game.Play();\n\n                io.WriteLine();\n                io.WriteLine();\n                io.WriteLine();\n                io.WriteLine();\n                io.WriteLine();\n                io.WriteLine(\"Next target...\");\n                io.WriteLine();\n            }\n        }\n\n        private static void DisplayTitleAndInstructions(TextIO io)\n        {\n            using var stream = Assembly.GetExecutingAssembly()\n                .GetManifestResourceStream(\"Target.Strings.TitleAndInstructions.txt\");\n            io.Write(stream);\n        }\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "86_Target/csharp/RandomExtensions.cs",
    "content": "using Games.Common.Randomness;\n\nnamespace Target\n{\n    internal static class RandomExtensions\n    {\n        public static Point NextPosition(this IRandom rnd) => new (\n            Angle.InRotations(rnd.NextFloat()),\n            Angle.InRotations(rnd.NextFloat()),\n            100000 * rnd.NextFloat() + rnd.NextFloat());\n    }\n}\n"
  },
  {
    "path": "86_Target/csharp/Strings/TitleAndInstructions.txt",
    "content": "                                 Target\n               Creative Computing  Morristown, New Jersey\n\n\n\nYou are the weapons officer on the Starship Enterprise\nand this is a test to see how accurate a shot you\nare in a three-dimensional range.  You will be told\nthe radian offset for the X and Z axes, the location\nof the target in three dimensional rectangular coordinates,\nthe approximate number of degrees from the X and Z\naxes, and the approximate distance to the target.\nYou will then proceed to shoot at the target until it is\ndestroyed!\n\nGood luck!!\n"
  },
  {
    "path": "86_Target/csharp/Target.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Strings\\TitleAndInstructions.txt\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\00_Common\\dotnet\\Games.Common\\Games.Common.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "86_Target/csharp/Target.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Target\", \"Target.csproj\", \"{DF03CFDB-2857-4416-A07A-80D84874F46E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DF03CFDB-2857-4416-A07A-80D84874F46E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DF03CFDB-2857-4416-A07A-80D84874F46E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DF03CFDB-2857-4416-A07A-80D84874F46E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DF03CFDB-2857-4416-A07A-80D84874F46E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {B49DF932-4DF9-44C3-B63F-FD9443B4DDD2}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "86_Target/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "86_Target/java/Target.java",
    "content": "import java.util.Scanner;\n\n/**\n * TARGET\n * <p>\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n */\npublic class Target {\n\n\tprivate static final double RADIAN = 180 / Math.PI;\n\n\tpublic static void main(String[] args) {\n\t\tScanner scan = new Scanner(System.in);\n\n\t\tprintIntro();\n\n\t\t//continue till the user aborts\n\t\twhile (true) {\n\t\t\tint numberShots = 0;\n\n\t\t\tfinal double xAxisInRadians = Math.random() * 2 * Math.PI;\n\t\t\tfinal double yAxisInRadians = Math.random() * 2 * Math.PI;\n\t\t\tSystem.out.printf(\"RADIANS FROM X AXIS = %.7f     FROM Z AXIS = %.7f\\n\", xAxisInRadians, yAxisInRadians);\n\n\t\t\tfinal double p1 = 100000 * Math.random() + Math.random();\n\t\t\tfinal double x = Math.sin(yAxisInRadians) * Math.cos(xAxisInRadians) * p1;\n\t\t\tfinal double y = Math.sin(yAxisInRadians) * Math.sin(xAxisInRadians) * p1;\n\t\t\tfinal double z = Math.cos(yAxisInRadians) * p1;\n\t\t\tSystem.out.printf(\"TARGET SIGHTED: APPROXIMATE COORDINATES:  X=%.3f  Y=%.3f  Z=%.3f\\n\", x, y, z);\n\t\t\tboolean targetOrSelfDestroyed = false;\n\t\t\twhile (!targetOrSelfDestroyed) {\n\t\t\t\tnumberShots++;\n\t\t\t\tint estimatedDistance = 0;\n\t\t\t\tswitch (numberShots) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\testimatedDistance = (int) (p1 * .05) * 20;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\testimatedDistance = (int) (p1 * .1) * 10;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\testimatedDistance = (int) (p1 * .5) * 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\testimatedDistance = (int) (p1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tSystem.out.printf(\"     ESTIMATED DISTANCE: %s\\n\\n\", estimatedDistance);\n\n\t\t\t\tfinal TargetAttempt targetAttempt = readInput(scan);\n\t\t\t\tif (targetAttempt.distance < 20) {\n\t\t\t\t\tSystem.out.println(\"YOU BLEW YOURSELF UP!!\");\n\t\t\t\t\ttargetOrSelfDestroyed = true;\n\t\t\t\t} else {\n\t\t\t\t\tfinal double a1 = targetAttempt.xDeviation / RADIAN;\n\t\t\t\t\tfinal double b1 = targetAttempt.zDeviation / RADIAN;\n\t\t\t\t\tSystem.out.printf(\"RADIANS FROM X AXIS = %.7f  FROM Z AXIS = %.7f\\n\", a1, b1);\n\n\t\t\t\t\tfinal double x1 = targetAttempt.distance * Math.sin(b1) * Math.cos(a1);\n\t\t\t\t\tfinal double y1 = targetAttempt.distance * Math.sin(b1) * Math.sin(a1);\n\t\t\t\t\tfinal double z1 = targetAttempt.distance * Math.cos(b1);\n\n\t\t\t\t\tdouble distance = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y) + (z1 - z) * (z1 - z));\n\t\t\t\t\tif (distance > 20) {\n\t\t\t\t\t\tdouble X2 = x1 - x;\n\t\t\t\t\t\tdouble Y2 = y1 - y;\n\t\t\t\t\t\tdouble Z2 = z1 - z;\n\t\t\t\t\t\tif (X2 < 0) {\n\t\t\t\t\t\t\tSystem.out.printf(\"SHOT BEHIND TARGET %.7f KILOMETERS.\\n\", -X2);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSystem.out.printf(\"SHOT IN FRONT OF TARGET %.7f KILOMETERS.\\n\", X2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Y2 < 0) {\n\t\t\t\t\t\t\tSystem.out.printf(\"SHOT TO RIGHT OF TARGET %.7f KILOMETERS.\\n\", -Y2);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSystem.out.printf(\"SHOT TO LEFT OF TARGET %.7f KILOMETERS.\\n\", Y2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Z2 < 0) {\n\t\t\t\t\t\t\tSystem.out.printf(\"SHOT BELOW TARGET %.7f KILOMETERS.\\n\", -Z2);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSystem.out.printf(\"SHOT ABOVE TARGET %.7f KILOMETERS.\\n\", Z2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tSystem.out.printf(\"APPROX POSITION OF EXPLOSION:  X=%.7f   Y=%.7f   Z=%.7f\\n\", x1, y1, z1);\n\t\t\t\t\t\tSystem.out.printf(\"     DISTANCE FROM TARGET =%.7f\\n\\n\\n\\n\", distance);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSystem.out.println(\" * * * HIT * * *   TARGET IS NON-FUNCTIONAL\");\n\t\t\t\t\t\tSystem.out.printf(\"DISTANCE OF EXPLOSION FROM TARGET WAS %.5f KILOMETERS.\\n\", distance);\n\t\t\t\t\t\tSystem.out.printf(\"MISSION ACCOMPLISHED IN %s SHOTS.\\n\", numberShots);\n\t\t\t\t\t\ttargetOrSelfDestroyed = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(\"\\n\\n\\n\\n\\nNEXT TARGET...\\n\");\n\t\t}\n\t}\n\n\tprivate static TargetAttempt readInput(Scanner scan) {\n\t\tSystem.out.println(\"INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE \");\n\t\tboolean validInput = false;\n\t\tTargetAttempt targetAttempt = new TargetAttempt();\n\t\twhile (!validInput) {\n\t\t\tString input = scan.nextLine();\n\t\t\tfinal String[] split = input.split(\",\");\n\t\t\ttry {\n\t\t\t\ttargetAttempt.xDeviation = Float.parseFloat(split[0]);\n\t\t\t\ttargetAttempt.zDeviation = Float.parseFloat(split[1]);\n\t\t\t\ttargetAttempt.distance = Float.parseFloat(split[2]);\n\t\t\t\tvalidInput = true;\n\t\t\t} catch (NumberFormatException nfe) {\n\t\t\t\tSystem.out.println(\"!NUMBER EXPECTED - RETRY INPUT LINE\\n? \");\n\t\t\t}\n\n\t\t}\n\t\treturn targetAttempt;\n\t}\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                TARGET\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\");\n\t\tSystem.out.println(\"YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\");\n\t\tSystem.out.println(\"AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\");\n\t\tSystem.out.println(\"ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\");\n\t\tSystem.out.println(\"THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\");\n\t\tSystem.out.println(\"OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\");\n\t\tSystem.out.println(\"THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\");\n\t\tSystem.out.println(\"AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\");\n\t\tSystem.out.println(\"YOU WILL THEN PROCEED TO SHOOT AT THE TARGET UNTIL IT IS\");\n\t\tSystem.out.println(\"DESTROYED!\");\n\t\tSystem.out.println(\"\\nGOOD LUCK!!\\n\\n\");\n\t}\n\n\t/**\n\t * Represents the user input\n\t */\n\tprivate static class TargetAttempt {\n\n\t\tdouble xDeviation;\n\t\tdouble zDeviation;\n\t\tdouble distance;\n\t}\n}\n"
  },
  {
    "path": "86_Target/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "86_Target/javascript/target.html",
    "content": "<html>\n<head>\n<title>TARGET</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"target.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "86_Target/javascript/target.js",
    "content": "// TARGET\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main program\nasync function main()\n{\n    print(tab(33) + \"TARGET\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    r = 0;  // 1 in original\n    r1 = 57.296;\n    p = Math.PI;\n    print(\"YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\\n\");\n    print(\"AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\\n\");\n    print(\"ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\\n\");\n    print(\"THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\\n\");\n    print(\"OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\\n\");\n    print(\"THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\\n\");\n    print(\"AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\\n\");\n    print(\"YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\\n\");\n    print(\"DESTROYED!\\n\");\n    print(\"\\n\");\n    print(\"GOOD LUCK!!\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        a = Math.random() * 2 * p;\n        b = Math.random() * 2 * p;\n        q = Math.floor(a * r1);\n        w = Math.floor(b * r1);\n        print(\"RADIANS FROM X AXIS = \" + a + \"   FROM Z AXIS = \" + b + \"\\n\");\n        p1 = 100000 * Math.random() + Math.random();\n        x = Math.sin(b) * Math.cos(a) * p1;\n        y = Math.sin(b) * Math.sin(a) * p1;\n        z = Math.cos(b) * p1;\n        print(\"TARGET SIGHTED: APPROXIMATE COORDINATES:  X=\" + x + \"  Y=\" + y + \"  Z=\" + z + \"\\n\");\n        while (1) {\n            r++;\n            switch (r) {\n                case 1:\n                    p3 = Math.floor(p1 * 0.05) * 20;\n                    break;\n                case 2:\n                    p3 = Math.floor(p1 * 0.1) * 10;\n                    break;\n                case 3:\n                    p3 = Math.floor(p1 * 0.5) * 2;\n                    break;\n                case 4:\n                    p3 = Math.floor(p1);\n                    break;\n                case 5:\n                    p3 = p1;\n                    break;\n            }\n            print(\"     ESTIMATED DISTANCE: \" + p3 + \"\\n\");\n            print(\"\\n\");\n            print(\"INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE\");\n            str = await input();\n            a1 = parseInt(str);\n            b1 = parseInt(str.substr(str.indexOf(\",\") + 1));\n            p2 = parseInt(str.substr(str.lastIndexOf(\",\") + 1));\n            print(\"\\n\");\n            if (p2 < 20) {\n                print(\"YOU BLEW YOURSELF UP!!\\n\");\n                break;\n            }\n            a1 /= r1;\n            b1 /= r1;\n            print(\"RADIANS FROM X AXIS = \" + a1 + \"  \");\n            print(\"FROM Z AXIS = \" + b1 + \"\\n\");\n            x1 = p2 * Math.sin(b1) * Math.cos(a1);\n            y1 = p2 * Math.sin(b1) * Math.sin(a1);\n            z1 = p2 * Math.cos(b1);\n            d = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y) + (z1 - z) * (z1 - z));\n            if (d <= 20) {\n                print(\"\\n\");\n                print(\" * * * HIT * * *   TARGET IS NON-FUNCTIONAL\\n\");\n                print(\"\\n\");\n                print(\"DISTANCE OF EXPLOSION FROM TARGET WAS \" + d + \" KILOMETERS.\");\n                print(\"\\n\");\n                print(\"MISSION ACCOMPLISHED IN \" + r + \" SHOTS.\\n\");\n                r = 0;\n                for (i = 1; i <= 5; i++)\n                    print(\"\\n\");\n                print(\"NEXT TARGET...\\n\");\n                print(\"\\n\");\n                break;\n            }\n            x2 = x1 - x;\n            y2 = y1 - y;\n            z2 = z1 - z;\n            if (x2 >= 0)\n                print(\"SHOT IN FRONT OF TARGET \" + x2 + \" KILOMETERS.\\n\");\n            else\n                print(\"SHOT BEHIND TARGET \" + -x2 + \" KILOMETERS.\\n\");\n            if (y2 >= 0)\n                print(\"SHOT TO LEFT OF TARGET \" + y2 + \" KILOMETERS.\\n\");\n            else\n                print(\"SHOT TO RIGHT OF TARGET \" + -y2 + \" KILOMETERS.\\n\");\n            if (z2 >= 0)\n                print(\"SHOT ABOVE TARGET \" + z2 + \" KILOMETERS.\\n\");\n            else\n                print(\"SHOT BELOW TARGET \" + -z2 + \" KILOMETERS.\\n\");\n            print(\"APPROX POSITION OF EXPLOSION:  X=\" + x1 + \"   Y=\" + y1 + \"   Z=\" + z1 + \"\\n\");\n            print(\"     DISTANCE FROM TARGET = \" + d + \"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n        }\n    }\n}\n\nmain();\n"
  },
  {
    "path": "86_Target/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "86_Target/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "86_Target/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nModified so that if the user enters \"quit\" or \"stop\" for the input, the program will exit.\nThis way the user doesn't have to enter Contorl-C to quit.\n\nTarget values can be space and/or comma separated, so \"1 2 3\" is valid, as is \"1,2,3\" or even \"1, 2, 3\".\nI believe the original Basic program wanted \"1,2,3\" or else each on a separate line.\n"
  },
  {
    "path": "86_Target/perl/target.pl",
    "content": "#!/usr/bin/perl\n\n# Target program in Perl\n#   Modified so that if the user enters \"quit\" or \"stop\" for the input, the program will exit.\n#   Values can be space and/or comma separated.\n# Translated by Kevin Brannen (kbrannen)\n\nuse strict;\nuse warnings;\n\n# globals\nmy $R = 1;\nmy $R1 = 57.296;\nmy $Pi = 3.14159;\n\nprint \"\\n\";\nprint \" \" x 33, \"TARGET\\n\";\nprint \" \" x 15, \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\nprint \"YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\\n\";\nprint \"AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\\n\";\nprint \"ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\\n\";\nprint \"THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\\n\";\nprint \"OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\\n\";\nprint \"THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\\n\";\nprint \"AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\\n\";\nprint \"YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\\n\";\nprint \"DESTROYED!\\n\\n\";\nprint \"GOOD LUCK!!\\n\\n\";\n\nwhile (1)\n{\n    my $A = rand(1) * 2 * $Pi;\n    my $B = rand(1) * 2 * $Pi;\n    my $P1 = 100000 * rand(1) + rand(1);\n    my $X = sin($B) * cos($A) * $P1;\n    my $Y = sin($B) * sin($A) * $P1;\n    my $Z = cos($B) * $P1;\n    print \"RADIANS FROM X AXIS = $A   FROM Z AXIS = $B\\n\";\n    print \"TARGET SIGHTED: APPROXIMATE COORDINATES:  X=$X  Y=$Y  Z=$Z\\n\";\n\n    while (1)\n    {\n        my $P3;\n        $R++;\n\n        if    ($R == 1) { $P3 = int($P1 * .05) * 20; }\n        elsif ($R == 2) { $P3 = int($P1 * .1) * 10; }\n        elsif ($R == 3) { $P3 = int($P1 * .5) * 2; }\n        elsif ($R == 4) { $P3 = int($P1); }\n        else            { $P3 = $P1; }\n\n        print \"     ESTIMATED DISTANCE: $P3\\n\\n\";\n        print \"INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE: \";\n        chomp(my $ans = lc(<>));\n        exit(0) if ($ans eq \"quit\" || $ans eq \"stop\");\n\n        my ($A1, $B1, $P2) = split(/[,\\s]+/, $ans);\n        print \"\\n\";\n\n        if ($P2 >= 20)\n        {\n            $A1 /= $R1;\n            $B1 /= $R1;\n            print \"RADIANS FROM X AXIS = $A1  FROM Z AXIS = $B1\\n\";\n            my $X1 = $P2 * sin($B1) * cos($A1);\n            my $Y1 = $P2 * sin($B1) * sin($A1);\n            my $Z1 = $P2 * cos($B1);\n            my $D = (($X1 - $X) ** 2 + ($Y1 - $Y) ** 2 + ($Z1 - $Z) ** 2) ** (0.5);\n\n            if ($D <= 20)\n            {\n                print \"\\n * * * HIT * * *   TARGET IS NON-FUNCTIONAL\\n\";\n                print \"\\nDISTANCE OF EXPLOSION FROM TARGET WAS $D KILOMETERS.\\n\";\n                print \"\\nMISSION ACCOMPLISHED IN $R SHOTS.\\n\";\n                last;\n            }\n            else\n            {\n                my $X2 = $X1 - $X;\n                my $Y2 = $Y1 - $Y;\n                my $Z2 = $Z1 - $Z;\n\n                if ($X2 < 0) { print \"SHOT BEHIND TARGET \", -$X2, \" KILOMETERS.\\n\"; }\n                else         { print \"SHOT IN FRONT OF TARGET $X2 KILOMETERS.\\n\"; }\n\n                if ($Y2 < 0) { print \"SHOT TO RIGHT OF TARGET \", -$Y2, \" KILOMETERS.\\n\"; }\n                else         { print \"SHOT TO LEFT OF TARGET $Y2 KILOMETERS.\\n\"; }\n\n                if ($Z2 < 0) { print \"SHOT BELOW TARGET \", -$Z2, \" KILOMETERS.\\n\"; }\n                else         { print \"SHOT ABOVE TARGET $Z2 KILOMETERS.\\n\"; }\n\n                print \"APPROX POSITION OF EXPLOSION:  X=$X1   Y=$Y1   Z=$Z1\\n\";\n                print \"     DISTANCE FROM TARGET = $D\\n\\n\\n\";\n                next;\n            }\n        }\n        else\n        {\n            print \"YOU BLEW YOURSELF UP!!\\n\";\n            last;\n        }\n    }\n\n    $R = 0;\n    print \"\\n\\n\\n\\n\\nNEXT TARGET...\\n\\n\";\n}\n"
  },
  {
    "path": "86_Target/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "86_Target/python/target.py",
    "content": "\"\"\"\nTARGET\n\nWeapon targeting simulation / 3d trigonometry practice\n\nPorted by Dave LeCompte\n\"\"\"\n\nimport math\nimport random\nfrom typing import List\n\nPAGE_WIDTH = 64\n\n\ndef print_centered(msg: str) -> None:\n    spaces = \" \" * ((PAGE_WIDTH - len(msg)) // 2)\n    print(spaces + msg)\n\n\ndef print_header(title: str) -> None:\n    print_centered(title)\n    print_centered(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print()\n    print()\n    print()\n\n\ndef print_instructions() -> None:\n    print(\"YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\")\n    print(\"AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\")\n    print(\"ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\")\n    print(\"THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\")\n    print(\"OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\")\n    print(\"THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\")\n    print(\"AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\")\n    print(\"YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\")\n    print(\"DESTROYED!\")\n    print()\n    print(\"GOOD LUCK!!\")\n    print()\n    print()\n\n\ndef prompt() -> List[float]:\n    while True:\n        response = input(\"INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE? \")\n        if \",\" not in response:\n            continue\n\n        terms = response.split(\",\")\n        if len(terms) != 3:\n            continue\n\n        return [float(t) for t in terms]\n\n\ndef next_target() -> None:\n    for _ in range(5):\n        print()\n    print(\"NEXT TARGET...\")\n    print()\n\n\ndef describe_miss(x, y, z, x1, y1, z1, d) -> None:\n    x2 = x1 - x\n    y2 = y1 - y\n    z2 = z1 - z\n\n    if x2 < 0:\n        print(f\"SHOT BEHIND TARGET {-x2:.2f} KILOMETERS.\")\n    else:\n        print(f\"SHOT IN FRONT OF TARGET {x2:.2f} KILOMETERS.\")\n\n    if y2 < 0:\n        print(f\"SHOT TO RIGHT OF TARGET {-y2:.2f} KILOMETERS.\")\n    else:\n        print(f\"SHOT TO LEFT OF TARGET {y2:.2f} KILOMETERS.\")\n\n    if z2 < 0:\n        print(f\"SHOT BELOW TARGET {-z2:.2f} KILOMETERS.\")\n    else:\n        print(f\"SHOT ABOVE TARGET {z2:.2f} KILOMETERS.\")\n\n    print(f\"APPROX POSITION OF EXPLOSION:  X={x1:.4f}   Y={y1:.4f}   Z={z1:.4f}\")\n    print(f\"     DISTANCE FROM TARGET = {d:.2f}\")\n    print()\n    print()\n    print()\n\n\ndef do_shot_loop(p1, x, y, z) -> None:\n    shot_count = 0\n    while True:\n        shot_count += 1\n        if shot_count == 1:\n            p3 = int(p1 * 0.05) * 20\n        elif shot_count == 2:\n            p3 = int(p1 * 0.1) * 10\n        elif shot_count == 3:\n            p3 = int(p1 * 0.5) * 2\n        elif shot_count == 4:\n            p3 = int(p1)\n        else:\n            p3 = p1\n\n        if p3 == int(p3):\n            print(f\"     ESTIMATED DISTANCE: {p3}\")\n        else:\n            print(f\"     ESTIMATED DISTANCE: {p3:.2f}\")\n        print()\n        a1, b1, p2 = prompt()\n\n        if p2 < 20:\n            print(\"YOU BLEW YOURSELF UP!!\")\n            return\n\n        a1 = math.radians(a1)\n        b1 = math.radians(b1)\n        show_radians(a1, b1)\n\n        x1 = p2 * math.sin(b1) * math.cos(a1)\n        y1 = p2 * math.sin(b1) * math.sin(a1)\n        z1 = p2 * math.cos(b1)\n\n        distance = math.sqrt((x1 - x) ** 2 + (y1 - y) ** 2 + (z1 - z) ** 2)\n\n        if distance <= 20:\n            print()\n            print(\" * * * HIT * * *   TARGET IS NON FUNCTIONAL\")\n            print()\n            print(f\"DISTANCE OF EXPLOSION FROM TARGET WAS {distance:.4f} KILOMETERS\")\n            print()\n            print(f\"MISSION ACCOMPLISHED IN {shot_count} SHOTS.\")\n\n            return\n        else:\n            describe_miss(x, y, z, x1, y1, z1, distance)\n\n\ndef show_radians(a, b) -> None:\n    print(f\"RADIANS FROM X AXIS = {a:.4f}   FROM Z AXIS = {b:.4f}\")\n\n\ndef play_game() -> None:\n    while True:\n        a = random.uniform(0, 2 * math.pi)  # random angle\n        b = random.uniform(0, 2 * math.pi)  # random angle\n\n        show_radians(a, b)\n\n        p1 = random.uniform(0, 100000) + random.uniform(0, 1)\n        x = math.sin(b) * math.cos(a) * p1\n        y = math.sin(b) * math.sin(a) * p1\n        z = math.cos(b) * p1\n        print(\n            f\"TARGET SIGHTED: APPROXIMATE COORDINATES:  X={x:.1f}  Y={y:.1f}  Z={z:.1f}\"\n        )\n\n        do_shot_loop(p1, x, y, z)\n        next_target()\n\n\ndef main() -> None:\n    print_header(\"TARGET\")\n    print_instructions()\n\n    play_game()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "86_Target/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "86_Target/target.bas",
    "content": "10 PRINT TAB(33);\"TARGET\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 R=1: R1=57.296: P=3.14159\n110 PRINT \"YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\"\n120 PRINT \"AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\"\n130 PRINT \"ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\"\n140 PRINT \"THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\"\n150 PRINT \"OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\"\n160 PRINT \"THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\"\n170 PRINT \"AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\"\n180 PRINT \"YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\"\n190 PRINT \"DESTROYED!\": PRINT: PRINT \"GOOD LUCK!!\":PRINT: PRINT\n220 A=RND(1)*2*P: B=RND(1)*2*P: Q=INT(A*R1): W=INT(B*R1)\n260 PRINT \"RADIANS FROM X AXIS =\";A;\"   FROM Z AXIS =\";B\n280 P1=100000*RND(1)+RND(1): X=SIN(B)*COS(A)*P1: Y=SIN(B)*SIN(A)*P1\n290 Z=COS(B)*P1\n340 PRINT \"TARGET SIGHTED: APPROXIMATE COORDINATES:  X=\";X;\"  Y=\";Y;\"  Z=\";Z\n345 R=R+1: IF R>5 THEN 390\n350 ON R GOTO 355,360,365,370,375\n355 P3=INT(P1*.05)*20: GOTO 390\n360 P3=INT(P1*.1)*10: GOTO 390\n365 P3=INT(P1*.5)*2: GOTO 390\n370 P3=INT(P1): GOTO 390\n375 P3=P1\n390 PRINT \"     ESTIMATED DISTANCE:\";P3\n400 PRINT:PRINT \"INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE\";\n405 INPUT A1,B1,P2\n410 PRINT: IF P2<20 THEN PRINT \"YOU BLEW YOURSELF UP!!\": GOTO 580\n420 A1=A1/R1: B1=B1/R1: PRINT \"RADIANS FROM X AXIS =\";A1;\"  \";\n425 PRINT \"FROM Z AXIS =\";B1\n480 X1=P2*SIN(B1)*COS(A1): Y1=P2*SIN(B1)*SIN(A1): Z1=P2*COS(B1)\n510 D=((X1-X)^2+(Y1-Y)^2+(Z1-Z)^2)^(1/2)\n520 IF D>20 THEN 670\n530 PRINT: PRINT \" * * * HIT * * *   TARGET IS NON-FUNCTIONAL\": PRINT\n550 PRINT \"DISTANCE OF EXPLOSION FROM TARGET WAS\";D;\"KILOMETERS.\"\n570 PRINT: PRINT \"MISSION ACCOMPLISHED IN \";R;\" SHOTS.\"\n580 R=0: FOR I=1 TO 5: PRINT: NEXT I: PRINT \"NEXT TARGET...\": PRINT\n590 GOTO 220\n670 X2=X1-X: Y2=Y1-Y: Z2=Z1-Z: IF X2<0 THEN 730\n710 PRINT \"SHOT IN FRONT OF TARGET\";X2;\"KILOMETERS.\": GOTO 740\n730 PRINT \"SHOT BEHIND TARGET\";-X2;\"KILOMETERS.\"\n740 IF Y2<0 THEN 770\n750 PRINT \"SHOT TO LEFT OF TARGET\";Y2;\"KILOMETERS.\": GOTO 780\n770 PRINT \"SHOT TO RIGHT OF TARGET\";-Y2;\"KILOMETERS.\"\n780 IF Z2<0 THEN 810\n790 PRINT \"SHOT ABOVE TARGET\";Z2;\"KILOMETERS.\": GOTO 820\n810 PRINT \"SHOT BELOW TARGET\";-Z2;\"KILOMETERS.\"\n820 PRINT \"APPROX POSITION OF EXPLOSION:  X=\";X1;\"   Y=\";Y1;\"   Z=\";Z1\n830 PRINT \"     DISTANCE FROM TARGET =\";D: PRINT: PRINT: PRINT: GOTO 345\n999 END\n"
  },
  {
    "path": "86_Target/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "86_Target/vbnet/Target.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Target\", \"Target.vbproj\", \"{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "86_Target/vbnet/Target.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Target</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "87_3-D_Plot/3dplot.bas",
    "content": "1 PRINT TAB(32);\"3D PLOT\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n5 DEF FNA(Z)=30*EXP(-Z*Z/100)\n100 PRINT\n110 FOR X=-30 TO 30 STEP 1.5\n120 L=0\n130 Y1=5*INT(SQR(900-X*X)/5)\n140 FOR Y=Y1 TO -Y1 STEP -5\n150 Z=INT(25+FNA(SQR(X*X+Y*Y))-.7*Y)\n160 IF Z<=L THEN 190\n170 L=Z\n180 PRINT TAB(Z);\"*\";\n190 NEXT Y\n200 PRINT\n210 NEXT X\n300 END\n"
  },
  {
    "path": "87_3-D_Plot/README.md",
    "content": "### 3-D Plot\n\n3-D PLOT will plot the family of curves of any function. The function Z is plotted as “rising” out of the x-y plane with x and y inside a circle of radius 30. The resultant plot looks almost 3-dimensional.\n\nYou set the function you want plotted in line 5. As with any mathematical plot, some functions come out “prettier” than others.\n\nThe author of this amazingly clever program is Mark Bramhall of DEC.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=167)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=182)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "87_3-D_Plot/csharp/Function.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Plot\n{\n    internal static class Function\n    {\n        internal static IEnumerable<IEnumerable<int>> GetRows()\n        {\n            for (var x = -30f; x <= 30f; x += 1.5f)\n            {\n                yield return GetValues(x);\n            }\n        }\n\n        private static IEnumerable<int> GetValues(float x)\n        {\n            var zPrevious = 0;\n            var yLimit = 5 * (int)(Math.Sqrt(900 - x * x) / 5);\n\n            for (var y = yLimit; y >= -yLimit; y -= 5)\n            {\n                var z = GetValue(x, y);\n\n                if (z > zPrevious)\n                {\n                    zPrevious = z;\n                    yield return z;\n                }\n            }\n        }\n\n        private static int GetValue(float x, float y)\n        {\n            var r = (float)Math.Sqrt(x * x + y * y);\n            return (int)(25 + 30 * Math.Exp(-r * r / 100) - 0.7f * y);\n        }\n    }\n}\n"
  },
  {
    "path": "87_3-D_Plot/csharp/Plot.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "87_3-D_Plot/csharp/Plot.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Plot\", \"Plot.csproj\", \"{8000A3CF-612D-4FB7-B53D-885BB6E5492B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {5DE8E572-67C9-4DE3-B851-447B78FE983A}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "87_3-D_Plot/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace Plot\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            PrintTitle();\n\n            foreach (var row in Function.GetRows())\n            {\n                foreach (var z in row)\n                {\n                    Plot(z);\n                }\n                Console.WriteLine();\n            }\n        }\n\n        private static void PrintTitle()\n        {\n            Console.WriteLine(\"                                3D Plot\");\n            Console.WriteLine(\"               Creative Computing  Morristown, New Jersey\");\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        private static void Plot(int z)\n        {\n            var x = Console.GetCursorPosition().Top;\n            Console.SetCursorPosition(z, x);\n            Console.Write(\"*\");\n        }\n    }\n}\n"
  },
  {
    "path": "87_3-D_Plot/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "87_3-D_Plot/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "87_3-D_Plot/d/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -dip1000 -run threedeeplot.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n\n## On rounding floating point values to integer values\n\nThe D equivalent of Basic `INT` is [`floor`](https://dlang.org/phobos/std_math_rounding.html#.floor),\nwhich rounds towards negative infinity. If you change occurrences of `floor` to\n[`lrint`](https://dlang.org/phobos/std_math_rounding.html#.lrint), you'll see that the plots show a bit more detail,\nas is done in the bonus below.\n\n## Bonus: Self-writing programs\n\nWith a small modification to the source, the program can be extended to **plot a random function**, and **print its formula**.\n\n```shell\nrdmd -dip1000 threedeeplot_random.d\n```\n(`rdmd` caches the executable, which results in speedy execution when the source does not change.)\n\n### Example output\n```\n                                    3D Plot\n              (After Creative Computing  Morristown, New Jersey)\n\n\n                           f(z) = 30 * sin(z / 10.0)\n\n                             *\n                      *      *    * *\n                *         *      *    * *\n                    *         *      *    * *\n            *           *        *       *   *  *\n               *           *         *      *   *  *\n                  *           *         *     *    * **\n       *             *           *        *      *   *  *\n         *              *           *       *     *   *  **\n            *              *          *       *    *   *  * *\n              *              *          *      *   *   *  *  *\n                *              *          *     *  *  *   *   **\n                  *              *         *    * *  *   *    * *\n   *                *             *        *    ** *    *     * *\n    *                *             *        *  **     *      *   *\n     *                 *            *       * *     *       *    *\n      *                 *            *      * *   *         *    *\n       *                *             *     ** *           *     **\n        *                *            *     **            *      **\n        *                *            *     *            *       **\n        *                *            *     *            *       **\n        *                *            *     *            *       **\n        *                *            *     **            *      **\n       *                *             *     ** *           *     **\n      *                 *            *      * *   *         *    *\n     *                 *            *       * *     *       *    *\n    *                *             *        *  **     *      *   *\n   *                *             *        *    ** *    *     * *\n                  *              *         *    * *  *   *    * *\n                *              *          *     *  *  *   *   **\n              *              *          *      *   *   *  *  *\n            *              *          *       *    *   *  * *\n         *              *           *       *     *   *  **\n       *             *           *        *      *   *  *\n                  *           *         *     *    * **\n               *           *         *      *   *  *\n            *           *        *       *   *  *\n                    *         *      *    * *\n                *         *      *    * *\n                      *      *    * *\n                             *\n```\n\n### Breakdown of differences\n\nHave a look at the relevant differences between `threedeeplot.d` and `threedeeplot_random.d`.\nThis is the original function with the single expression that is evaluated for the plot:\n```d\n    static float fna(float z)\n    {\n        return 30.0 * exp(-z * z / 100.0);\n    }\n```\nHere `static` means that the nested function does not need acces to its enclosing scope.\n\nNow, by inserting the following:\n```d\n    enum functions = [\"30.0 * exp(-z * z / 100.0)\",\n                      \"sqrt(900.01 - z * z) * .9 - 2\",\n                      \"30 * (cos(z / 16.0) + .5)\",\n                      \"30 - 30 * sin(z / 18.0)\",\n                      \"30 * exp(-cos(z / 16.0)) - 30\",\n                      \"30 * sin(z / 10.0)\"];\n\n    size_t index = uniform(0, functions.length);\n    writeln(center(\"f(z) = \" ~ functions[index], width), \"\\n\");\n```\nand changing the implementation of `fna` to\n```d\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            static foreach (i, f; functions)\n                case i:\n                    mixin(\"return \" ~ f ~ \";\");\n        }\n    }\n```\nwe unlock some very special abilities of D. Let's break it down:\n\n```d\n    enum functions = [\"30.0 * exp(-z * z / 100.0)\", /*...*/];\n```\nThis defines an array of strings, each containing a mathematical expression. Due to the `enum` keyword, this is an\narray that really only exists at compile-time.\n\n```d\n    size_t index = uniform(0, functions.length);\n```\nThis defines a random index into the array. `functions.length` is evaluated at compile-time, due to D's compile-time\nfunction evaluation (CTFE).\n\n```d\n    writeln(center(\"f(z) = \" ~ functions[index], width), \"\\n\");\n```\nUnmistakenly, this prints the formula centered on a line. What happens behind the scenes is that `functions` (which\nonly existed at compile-time before now) is pasted in, so that an instance of that array actually exists at run-time\nat this spot, and is instantly indexed.\n\n```d\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            // ...\n        }\n    }\n```\n`static` has been dropped from the nested function because we want to evaluate `index` inside it. The function contains\nan ordinary `switch`, with `final` providing some extra robustness. It disallows a `default` case and produces an error\nwhen the switch doesn't handle all cases. The `switch` body is where the magic happens and consists of these three\nlines:\n```d\n            static foreach (i, f; functions)\n                case i:\n                    mixin(\"return \" ~ f ~ \";\");\n```\nThe `static foreach` iterates over `functions` at compile-time, producing one `case` for every element in `functions`.\n`mixin` takes a string, which is constructed at compile-time, and pastes it right into the source.\n\nIn effect, the implementation of `float fna(float z)` unrolls itself into\n```d\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            case 0:\n                return 30.0 * exp(-z * z / 100.0);\n            case 1:\n                return sqrt(900.01 - z * z) * .9 - 2;\n            case 2:\n                return 30 * (cos(z / 16.0) + .5);\n            case 3:\n                return 30 - 30 * sin(z / 18.0);\n            case 4:\n                return 30 * exp(-cos(z / 16.0)) - 30;\n            case 5:\n                return 30 * sin(z / 10.0)\";\n        }\n    }\n```\n\nSo if you feel like adding another function, all you need to do is append it to the `functions` array, and the rest of\nthe program *rewrites itself...*\n"
  },
  {
    "path": "87_3-D_Plot/d/threedeeplot.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std.stdio, std.string, std.math, std.range, std.conv, std.algorithm;\n\nvoid main()\n{\n    enum width = 80;\n    writeln(center(\"3D Plot\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\\n\", width));\n\n    static float fna(float z)\n    {\n        return 30.0 * exp(-z * z / 100.0);\n    }\n\n    char[] row;\n\n    for (float x = -30.0; x <= 30.0; x += 1.5)\n    {\n        size_t max_z = 0L;\n        auto y1 = 5 * floor((sqrt(900 - x * x)) / 5.0);\n        for (float y = y1; y >= -y1; y -= 5)\n        {\n            auto z = to!size_t(max(0, floor(25 + fna(sqrt(x * x + y * y)) - .7 * y)));\n            if (z > max_z) // Visible\n            {\n                max_z = z;\n                if (z + 1 > row.length) // row needs to grow\n                    row ~= ' '.repeat(z + 1 - row.length).array;\n                row[z] = '*';\n            }\n        }\n        writeln(row);\n        row = null;\n    }\n}\n"
  },
  {
    "path": "87_3-D_Plot/d/threedeeplot_random.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std.stdio, std.string, std.math, std.range, std.conv, std.random, std.algorithm;\n\nvoid main()\n{\n    enum width = 80;\n    writeln(center(\"3D Plot\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\", width));\n\n    enum functions = [\"30.0 * exp(-z * z / 100.0)\",\n                      \"sqrt(900.01 - z * z) * .9 - 2\",\n                      \"30 * (cos(z / 16.0) + .5)\",\n                      \"30 - 30 * sin(z / 18.0)\",\n                      \"30 * exp(-cos(z / 16.0)) - 30\",\n                      \"30 * sin(z / 10.0)\"];\n\n    size_t index = uniform(0, functions.length);\n    writeln(center(\"f(z) = \" ~ functions[index], width), \"\\n\");\n\n    float fna(float z)\n    {\n        final switch (index)\n        {\n            static foreach (i, f; functions)\n                case i:\n                    mixin(\"return \" ~ f ~ \";\");\n        }\n    }\n\n    char[] row;\n\n    for (float x = -30.0; x <= 30.0; x += 1.5)\n    {\n        size_t max_z = 0L;\n        auto y1 = 5 * lrint((sqrt(900 - x * x)) / 5.0);\n        for (float y = y1; y >= -y1; y -= 5)\n        {\n            auto z = to!size_t(max(0, lrint(25 + fna(sqrt(x * x + y * y)) - .7 * y)));\n            if (z > max_z) // Visible\n            {\n                max_z = z;\n                if (z + 1 > row.length) // row needs to grow\n                    row ~= ' '.repeat(z + 1 - row.length).array;\n                row[z] = '*';\n            }\n        }\n        writeln(row);\n        row = null;\n    }\n}\n"
  },
  {
    "path": "87_3-D_Plot/java/Plot3D.java",
    "content": "import java.lang.Math;\n\n/**\n * Game of 3-D Plot\n * <p>\n * Based on the BASIC game of 3-D Plot here\n * https://github.com/coding-horror/basic-computer-games/blob/main/87%203-D%20Plot/3dplot.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\n// Java class names cannot begin with a letter, so class name 3dplot cannot be used\npublic class Plot3D {\n\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n\n  private void showIntro() {\n\n    System.out.println(\" \".repeat(31) + \"3D PLOT\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\\n\");\n\n  }  // End of method showIntro\n\n\n  private void startGame() {\n\n    float row = 0;\n    int column = 0;\n    int limit = 0;\n    int plotVal = 0;\n    int root = 0;\n\n    String lineContent = \"\";\n\n    // Begin loop through all rows\n    for (row = -30; row <= 30; row += 1.5) {\n\n      limit = 0;\n\n      root = 5 * (int) Math.floor((Math.sqrt(900 - row * row) / 5));\n\n      // Begin loop through all columns\n      for (column = root; column >= -root; column += -5) {\n\n        plotVal = 25 + (int) Math.floor(func(Math.sqrt(row * row + column * column)) - 0.7 * column);\n\n        if (plotVal > limit) {\n\n          limit = plotVal;\n\n          // Add whitespace\n          while (lineContent.length() < (plotVal-1)) {\n            lineContent += \" \";\n          }\n\n          lineContent += \"*\";\n\n        }\n\n      }  // End loop through all columns\n\n      System.out.println(lineContent);\n\n      lineContent = \"\";\n\n    }  // End loop through all rows\n\n  }  // End of method startGame\n\n\n  // Function to be plotted\n  public double func(double inputVal) {\n\n    return (30 * Math.exp(-inputVal * inputVal / 100));\n\n  }\n\n\n  public static void main(String[] args) {\n\n    Plot3D plot = new Plot3D();\n    plot.play();\n\n  }  // End of method main\n\n}  // End of class Plot3D\n"
  },
  {
    "path": "87_3-D_Plot/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "87_3-D_Plot/javascript/3dplot.html",
    "content": "<html>\n<head>\n<title>3D PLOT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\" style=\"font-size: 8pt;\"></pre>\n<script src=\"3dplot.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "87_3-D_Plot/javascript/3dplot.js",
    "content": "// 3D PLOT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\nfunction print(str)\n{\n\tdocument.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction tab(space)\n{\n\tvar str = \"\";\n\twhile (space-- > 0)\n\t\tstr += \" \";\n\treturn str;\n}\n\nfunction equation(input)\n{\n\treturn 30 * Math.exp(-input * input / 100);\n}\n\nprint(tab(32) + \"3D PLOT\\n\");\nprint(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n\nfor (x = -30; x <= 30; x += 1.5) {\n\tl = 0;\n\ty1 = 5 * Math.floor(Math.sqrt(900 - x * x) / 5);\n\tstr = \"\";\n\tfor (y = y1; y >= -y1; y -= 5) {\n\t\tz = Math.floor(25 + equation(Math.sqrt(x * x + y * y)) - .7 * y);\n\t\tif (z > l) {\n\t\t\tl = z;\n\t\t\twhile (str.length < z)\n\t\t\t\tstr += \" \";\n\t\t\tstr += \"*\";\n\t\t}\n\t}\n\tprint(str + \"\\n\");\n}\n"
  },
  {
    "path": "87_3-D_Plot/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "87_3-D_Plot/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "87_3-D_Plot/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "87_3-D_Plot/perl/3dplot.pl",
    "content": "#!/usr/bin/perl\nuse strict;\nuse warnings;\n\nprint ' 'x32 .\"3D PLOT\\n\";\nprint ' 'x15 .\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nsub FNA {\n\tmy ($Z)= @_;\n\treturn 30*exp(-$Z*$Z/100);\n\t}\n\nprint \"\\n\";\n\nfor (my $X=-30; $X<=30; $X+=1.5) {\n\tmy $L=0;\n\tmy $Line=\" \"x80; #Empty buffer string;\n\tmy $Y1=5*int(sqrt(900-$X*$X)/5);\n\tfor (my $Y=$Y1; $Y>=-$Y1; $Y-=5) {\n\t\tmy $Z=int(25+&FNA(sqrt($X*$X+$Y*$Y))-.7*$Y);\n\t\tif ($Z<=$L) { next; }\n\t\t$L= $Z;\n\t\tsubstr $Line, $Z, 1, \"*\"; #Plot on the line by sustitution.\n\t\t}\n\tprint \"$Line\\n\"; #Now print the line.\n\t}\n"
  },
  {
    "path": "87_3-D_Plot/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "87_3-D_Plot/python/3dplot.py",
    "content": "#!/usr/bin/env python3\n\n# 3D PLOT\n#\n# Converted from BASIC to Python by Trevor Hobson\n\nfrom math import exp, floor, sqrt\n\n\ndef equation(x: float) -> float:\n    return 30 * exp(-x * x / 100)\n\n\ndef main() -> None:\n    print(\" \" * 32 + \"3D PLOT\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\\n\")\n\n    for x in range(-300, 315, 15):\n        x1 = x / 10\n        max_column = 0\n        y1 = 5 * floor(sqrt(900 - x1 * x1) / 5)\n        y_plot = [\" \"] * 80\n\n        for y in range(y1, -(y1 + 5), -5):\n            column = floor(25 + equation(sqrt(x1 * x1 + y * y)) - 0.7 * y)\n            if column > max_column:\n                max_column = column\n                y_plot[column] = \"*\"\n        print(\"\".join(y_plot))\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "87_3-D_Plot/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "87_3-D_Plot/ruby/3dplot.rb",
    "content": "def intro\n  puts \"                                3D PLOT\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\\n\\n\"\nend\n\ndef fna(z) = 30 * Math.exp(-z * z / 100)\n\ndef render\n  (-30..30).step(1.5).each do |x|\n    l = 0\n    y1 = 5 * (Math.sqrt(900 - x * x) / 5).to_i\n    y_plot = \" \" * 80\n    (y1..-y1).step(-5).each do |y|\n      z = (25 + fna(Math.sqrt(x * x + y * y)) - 0.7 * y).to_i\n      next if z <= l\n      l = z\n      y_plot[z] = '*'\n    end\n    puts y_plot\n  end\nend\n\ndef main\n  intro\n  render\nend\n\nmain\n"
  },
  {
    "path": "87_3-D_Plot/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "87_3-D_Plot/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n"
  },
  {
    "path": "87_3-D_Plot/rust/src/main.rs",
    "content": "/** 3D Plot GAME \n * https://github.com/coding-horror/basic-computer-games/blob/main/87_3-D_Plot/3dplot.bas\n * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs).\n * No additional features or improvements were added. As a faithful translation, \n * many of the code here are done in an unrecommended way by today's standards.\n * 03/03/25\n*/\n\nfn main() {\n    //1 PRINT TAB(32);\"3D PLOT\"\n    //2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n    //3 PRINT:PRINT:PRINT\n    print!(\"{}\",\n        format!(\"{}{}\\n{}{}\\n\\n\\n\\n\",\n            \" \".repeat(31),\n            \"3D PLOT\",\n            \" \".repeat(14),\n            \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n        )\n    );\n\n    //5 DEF FNA(Z)=30*EXP(-Z*Z/100)\n    let fna = |z: f32| {30.0 * f32::exp(-z*z/100.0)};\n\n    //100 PRINT\n    println!();\n    \n    let mut line_content = String::new();\n    //110 FOR X=-30 TO 30 STEP 1.5\n    let mut x = -30.0;\n    while x <= 30.0 {\n        //120 L=0\n        let mut l = 0;\n        \n        //130 Y1=5*INT(SQR(900-X*X)/5)\n        let y1 = 5.0 * (f32::sqrt(900.0-x*x)/5.0).floor();\n\n        //140 FOR Y=Y1 TO -Y1 STEP -5\n        let mut y = y1;\n        while y >= -y1 {\n            //150 Z=INT(25+FNA(SQR(X*X+Y*Y))-.7*Y)\n            let z = (25.0 + fna(f32::sqrt(x*x+y*y))-0.7*y) as i32;\n\n            //160 IF Z<=L THEN 190\n            if z <= l {\n                y = y - 5.0;\n                continue;\n            }\n            //170 L=Z\n            l = z;\n            //180 PRINT TAB(Z);\"*\";\n            while (line_content.len() as i32) < (z-1) {\n                line_content += \" \";\n            }\n            line_content += \"*\";\n            //190 NEXT Y\n            y = y - 5.0;\n        }\n        print!(\"{}\", line_content);\n        line_content.clear();\n\n        //200 PRINT\n        println!();\n        //210 NEXT X\n        x = x + 1.5;\n    }\n    //300 END\n}"
  },
  {
    "path": "87_3-D_Plot/vbnet/Plot.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{778DAE3C-4631-46EA-AA77-85C1314464D9}\") = \"Plot\", \"Plot.vbproj\", \"{534355CC-A2C1-4138-9EB5-09D658DD4504}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{534355CC-A2C1-4138-9EB5-09D658DD4504}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{534355CC-A2C1-4138-9EB5-09D658DD4504}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{534355CC-A2C1-4138-9EB5-09D658DD4504}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{534355CC-A2C1-4138-9EB5-09D658DD4504}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {CAD09CCC-4522-438E-A8C6-514A866D90DE}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "87_3-D_Plot/vbnet/Plot.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Plot</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "87_3-D_Plot/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/README.md",
    "content": "### 3-D Tic-Tac-Toe\n\n3-D TIC-TAC-TOE is a game of tic-tac-toe in a 4x4x4 cube. You must get 4 markers in a row or diagonal along any 3-dimensional plane in order to win.\n\nEach move is indicated by a 3-digit number (digits not separated by commas), with each digit between 1 and 4 inclusive. The digits indicate the level, column, and row, respectively, of the move. You can win if you play correctly; although, it is considerably more difficult than standard, two-dimensional 3x3 tic-tac-toe.\n\nThis version of 3-D TIC-TAC-TOE is from Dartmouth College.\n\n### Conversion notes\n\nThe AI code for TicTacToe2 depends quite heavily on the non-structured GOTO (I can almost hear Dijkstra now) and translation is quite challenging. This code relies very heavily on GOTOs that bind the code tightly together. Comments explain where that happens in the original.\n\nThere are at least two bugs from the original BASIC:\n\n1. Code should only allow player to input valid 3D coordinates where every digit is between 1 and 4, but the original code allows any value between 111 and 444 (such as 297, for instance).\n2. If the player moves first and the game ends in a draw, the original program will still prompt the player for a move instead of calling for a draw.\n\nAlso note that while the file is called qubit.bas (with a \"T\"), the title shown in the program listing is \"QUBIC\" (with \"C\")... and the sample output shows \"TIC TAC TOE\" instead of either of these.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=168)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=183)\n\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/csharp/Program.cs",
    "content": "﻿namespace ThreeDTicTacToe\r\n{\r\n    class Program\r\n    {\r\n        static void Main()\r\n        {\r\n            new Qubic().Run();\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/csharp/Qubic.cs",
    "content": "﻿using System.Text;\r\n\r\nnamespace ThreeDTicTacToe\r\n{\r\n    /// <summary>\r\n    /// Qubic is a 3D Tic-Tac-Toe game played on a 4x4x4 cube. This code allows\r\n    ///  a player to compete against a deterministic AI that is surprisingly\r\n    ///  difficult to beat.\r\n    /// </summary>\r\n    internal class Qubic\r\n    {\r\n        // The Y variable in the original BASIC.\r\n        private static readonly int[] CornersAndCenters = QubicData.CornersAndCenters;\r\n        // The M variable in the original BASIC.\r\n        private static readonly int[,] RowsByPlane = QubicData.RowsByPlane;\r\n\r\n        // Board spaces are filled in with numeric values. A space could be:\r\n        //\r\n        //  - EMPTY: no one has moved here yet.\r\n        //  - PLAYER: the player moved here.\r\n        //  - MACHINE: the machine moved here.\r\n        //  - POTENTIAL: the machine, in the middle of its move,\r\n        //      might fill a space with a potential move marker, which\r\n        //      prioritizes the space once it finally chooses where to move.\r\n        //\r\n        // The numeric values allow the program to determine what moves have\r\n        //  been made in a row by summing the values in a row. In theory, the\r\n        //  individual values could be any positive numbers that satisfy the\r\n        //  following:\r\n        //\r\n        //  - EMPTY = 0\r\n        //  - POTENTIAL * 4 < PLAYER\r\n        //  - PLAYER * 4 < MACHINE\r\n        private const double PLAYER = 1.0;\r\n        private const double MACHINE = 5.0;\r\n        private const double POTENTIAL = 0.125;\r\n        private const double EMPTY = 0.0;\r\n\r\n        // The X variable in the original BASIC. This is the Qubic board,\r\n        //  flattened into a 1D array.\r\n        private readonly double[] Board = new double[64];\r\n\r\n        // The L variable in the original BASIC. There are 76 unique winning rows\r\n        //  in the board, so each gets an entry in RowSums. A row sum can be used\r\n        //  to check what moves have been made to that row in the board.\r\n        //\r\n        // Example: if RowSums[i] == PLAYER * 4, the player won with row i!\r\n        private readonly double[] RowSums = new double[76];\r\n\r\n        public Qubic() { }\r\n\r\n        /// <summary>\r\n        /// Run the Qubic game.\r\n        ///\r\n        /// Show the title, prompt for instructions, then begin the game loop.\r\n        /// </summary>\r\n        public void Run()\r\n        {\r\n            Title();\r\n            Instructions();\r\n            Loop();\r\n        }\r\n\r\n        /***********************************************************************\r\n        /* Terminal Text/Prompts\r\n        /**********************************************************************/\r\n        #region TerminalText\r\n\r\n        /// <summary>\r\n        /// Display title and attribution.\r\n        ///\r\n        /// Original BASIC: 50-120\r\n        /// </summary>\r\n        private static void Title()\r\n        {\r\n            Console.WriteLine(\r\n                \"\\n\" +\r\n                \"                                 QUBIC\\n\\n\" +\r\n                \"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\"\r\n            );\r\n        }\r\n\r\n        /// <summary>\r\n        /// Prompt user for game instructions.\r\n        ///\r\n        /// Original BASIC: 210-313\r\n        /// </summary>\r\n        private static void Instructions()\r\n        {\r\n            Console.Write(\"DO YOU WANT INSTRUCTIONS? \");\r\n            var yes = ReadYesNo();\r\n\r\n            if (yes)\r\n            {\r\n                Console.WriteLine(\r\n                    \"\\n\" +\r\n                    \"THE GAME IS TIC-TAC-TOE IN A 4 X 4 X 4 CUBE.\\n\" +\r\n                    \"EACH MOVE IS INDICATED BY A 3 DIGIT NUMBER, WITH EACH\\n\" +\r\n                    \"DIGIT BETWEEN 1 AND 4 INCLUSIVE.  THE DIGITS INDICATE THE\\n\" +\r\n                    \"LEVEL, ROW, AND COLUMN, RESPECTIVELY, OF THE OCCUPIED\\n\" +\r\n                    \"PLACE.\\n\" +\r\n                    \"\\n\" +\r\n                    \"TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE.\\n\" +\r\n                    \"THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-\\n\" +\r\n                    \"CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND\\n\" +\r\n                    \"UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER.\\n\" +\r\n                    \"\\n\" +\r\n                    \"TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE.\\n\\n\"\r\n                );\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Prompt player for whether they would like to move first, or allow\r\n        ///  the machine to make the first move.\r\n        ///\r\n        /// Original BASIC: 440-490\r\n        /// </summary>\r\n        /// <returns>true if the player wants to move first</returns>\r\n        private static bool PlayerMovePreference()\r\n        {\r\n            Console.Write(\"DO YOU WANT TO MOVE FIRST? \");\r\n            var result = ReadYesNo();\r\n            Console.WriteLine();\r\n            return result;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Run the Qubic program loop.\r\n        /// </summary>\r\n        private void Loop()\r\n        {\r\n            // The \"retry\" loop; ends if player quits or chooses not to retry\r\n            // after game ends.\r\n            while (true)\r\n            {\r\n                ClearBoard();\r\n                var playerNext = PlayerMovePreference();\r\n\r\n                // The \"game\" loop; ends if player quits, player/machine wins,\r\n                // or game ends in draw.\r\n                while (true)\r\n                {\r\n                    if (playerNext)\r\n                    {\r\n                        // Player makes a move.\r\n                        var playerAction = PlayerMove();\r\n                        if (playerAction == PlayerAction.Move)\r\n                        {\r\n                            playerNext = !playerNext;\r\n                        }\r\n                        else\r\n                        {\r\n                            return;\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        // Check for wins, if any.\r\n                        RefreshRowSums();\r\n                        if (CheckPlayerWin() || CheckMachineWin())\r\n                        {\r\n                            break;\r\n                        }\r\n\r\n                        // Machine makes a move.\r\n                        var machineAction = MachineMove();\r\n                        if (machineAction == MachineAction.Move)\r\n                        {\r\n                            playerNext = !playerNext;\r\n                        }\r\n                        else if (machineAction == MachineAction.End)\r\n                        {\r\n                            break;\r\n                        }\r\n                        else\r\n                        {\r\n                            throw new Exception(\"unreachable; machine should always move or end game in game loop\");\r\n                        }\r\n                    }\r\n                }\r\n\r\n                var retry = RetryPrompt();\r\n\r\n                if (!retry)\r\n                {\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Prompt the user to try another game.\r\n        ///\r\n        /// Original BASIC: 1490-1560\r\n        /// </summary>\r\n        /// <returns>true if the user wants to play again</returns>\r\n        private static bool RetryPrompt()\r\n        {\r\n            Console.Write(\"DO YOU WANT TO TRY ANOTHER GAME? \");\r\n            return ReadYesNo();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Read a yes/no from the terminal. This method accepts anything that\r\n        ///  starts with N/n as no and Y/y as yes.\r\n        /// </summary>\r\n        /// <returns>true if the player answered yes</returns>\r\n        private static bool ReadYesNo()\r\n        {\r\n            while (true)\r\n            {\r\n                var response = Console.ReadLine() ?? \" \";\r\n                if (response.ToLower().StartsWith(\"y\"))\r\n                {\r\n                    return true;\r\n                }\r\n                else if (response.ToLower().StartsWith(\"n\"))\r\n                {\r\n                    return false;\r\n                }\r\n                else\r\n                {\r\n                    Console.Write(\"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'. \");\r\n                }\r\n            }\r\n        }\r\n\r\n        #endregion\r\n\r\n        /***********************************************************************\r\n        /* Player Move\r\n        /**********************************************************************/\r\n        #region PlayerMove\r\n\r\n        /// <summary>\r\n        /// Possible actions player has taken after ending their move. This\r\n        ///  replaces the `GOTO` logic that allowed the player to jump out of\r\n        ///  the game loop and quit.\r\n        /// </summary>\r\n        private enum PlayerAction\r\n        {\r\n            /// <summary>\r\n            /// The player ends the game prematurely.\r\n            /// </summary>\r\n            Quit,\r\n            /// <summary>\r\n            /// The player makes a move on the board.\r\n            /// </summary>\r\n            Move,\r\n        }\r\n\r\n        /// <summary>\r\n        /// Make the player's move based on their input.\r\n        ///\r\n        /// Original BASIC: 500-620\r\n        /// </summary>\r\n        /// <returns>Whether the player moved or quit the program.</returns>\r\n        private PlayerAction PlayerMove()\r\n        {\r\n            // Loop until a valid move is inputted.\r\n            while (true)\r\n            {\r\n                var move = ReadMove();\r\n                if (move == 1)\r\n                {\r\n                    return PlayerAction.Quit;\r\n                }\r\n                else if (move == 0)\r\n                {\r\n                    ShowBoard();\r\n                }\r\n                else\r\n                {\r\n                    ClearPotentialMoves();\r\n                    if (TryCoordToIndex(move, out int moveIndex))\r\n                    {\r\n                        if (Board[moveIndex] == EMPTY)\r\n                        {\r\n                            Board[moveIndex] = PLAYER;\r\n                            return PlayerAction.Move;\r\n                        }\r\n                        else\r\n                        {\r\n                            Console.WriteLine(\"THAT SQUARE IS USED, TRY AGAIN.\");\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        Console.WriteLine(\"INCORRECT MOVE, TRY AGAIN.\");\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Read a player move from the terminal. Move can be any integer.\r\n        ///\r\n        /// Original BASIC: 510-520\r\n        /// </summary>\r\n        /// <returns>the move inputted</returns>\r\n        private static int ReadMove()\r\n        {\r\n            Console.Write(\"YOUR MOVE? \");\r\n            return ReadInteger();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Read an integer from the terminal.\r\n        ///\r\n        /// Original BASIC: 520\r\n        ///\r\n        /// Unlike the basic, this code will not accept any string that starts\r\n        ///  with a number; only full number strings are allowed.\r\n        /// </summary>\r\n        /// <returns>the integer inputted</returns>\r\n        private static int ReadInteger()\r\n        {\r\n            while (true)\r\n            {\r\n                var response = Console.ReadLine() ?? \" \";\r\n\r\n                if (int.TryParse(response, out var move))\r\n                {\r\n                    return move;\r\n\r\n                }\r\n                else\r\n                {\r\n                    Console.Write(\"!NUMBER EXPECTED - RETRY INPUT LINE--? \");\r\n                }\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Display the board to the player. Spaces taken by the player are\r\n        ///  marked with \"Y\", while machine spaces are marked with \"M\".\r\n        ///\r\n        /// Original BASIC: 2550-2740\r\n        /// </summary>\r\n        private void ShowBoard()\r\n        {\r\n            var s = new StringBuilder(new string('\\n', 9));\r\n\r\n            for (int i = 1; i <= 4; i++)\r\n            {\r\n                for (int j = 1; j <= 4; j++)\r\n                {\r\n                    s.Append(' ', 3 * (j + 1));\r\n                    for (int k = 1; k <= 4; k++)\r\n                    {\r\n                        int q = (16 * i) + (4 * j) + k - 21;\r\n                        s.Append(Board[q] switch\r\n                        {\r\n                            EMPTY or POTENTIAL => \"( )      \",\r\n                            PLAYER => \"(Y)      \",\r\n                            MACHINE => \"(M)      \",\r\n                            _ => throw new Exception($\"invalid space value {Board[q]}\"),\r\n                        });\r\n                    }\r\n                    s.Append(\"\\n\\n\");\r\n                }\r\n                s.Append(\"\\n\\n\");\r\n            }\r\n\r\n            Console.WriteLine(s.ToString());\r\n        }\r\n\r\n        #endregion\r\n\r\n        /***********************************************************************\r\n        /* Machine Move\r\n        /**********************************************************************/\r\n        #region MachineMove\r\n\r\n        /// <summary>\r\n        /// Check all rows for a player win.\r\n        ///\r\n        /// A row indicates a player win if its sum = PLAYER * 4.\r\n        ///\r\n        /// Original BASIC: 720-780\r\n        /// </summary>\r\n        /// <returns>whether the player won in any row</returns>\r\n        private bool CheckPlayerWin()\r\n        {\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                if (RowSums[row] == (PLAYER * 4))\r\n                {\r\n                    // Found player win!\r\n                    Console.WriteLine(\"YOU WIN AS FOLLOWS\");\r\n                    DisplayRow(row);\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            // No player win found.\r\n            return false;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Check all rows for a row that the machine could move to to win\r\n        ///  immediately.\r\n        ///\r\n        /// A row indicates a player could win immediately if it has three\r\n        ///  machine moves already; that is, sum = MACHINE * 3.\r\n        ///\r\n        /// Original Basic: 790-920\r\n        /// </summary>\r\n        /// <returns></returns>\r\n        private bool CheckMachineWin()\r\n        {\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                if (RowSums[row] == (MACHINE * 3))\r\n                {\r\n                    // Found a winning row!\r\n                    for (int space = 0; space < 4; space++)\r\n                    {\r\n                        int move = RowsByPlane[row, space];\r\n                        if (Board[move] == EMPTY)\r\n                        {\r\n                            // Found empty space in winning row; move there.\r\n                            Board[move] = MACHINE;\r\n                            Console.WriteLine($\"MACHINE MOVES TO {IndexToCoord(move)} , AND WINS AS FOLLOWS\");\r\n                            DisplayRow(row);\r\n                            return true;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            // No winning row available.\r\n            return false;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Display the coordinates of a winning row.\r\n        /// </summary>\r\n        /// <param name=\"row\">index into RowsByPlane data</param>\r\n        private void DisplayRow(int row)\r\n        {\r\n            for (int space = 0; space < 4; space++)\r\n            {\r\n                Console.Write($\" {IndexToCoord(RowsByPlane[row, space])} \");\r\n            }\r\n            Console.WriteLine();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Possible actions machine can take in a move. This helps replace the\r\n        ///  complex GOTO logic from the original BASIC, which allowed the\r\n        ///  program to jump from the machine's action to the end of the game.\r\n        /// </summary>\r\n        private enum MachineAction\r\n        {\r\n            /// <summary>\r\n            /// Machine did not take any action.\r\n            /// </summary>\r\n            None,\r\n            /// <summary>\r\n            /// Machine made a move.\r\n            /// </summary>\r\n            Move,\r\n            /// <summary>\r\n            /// Machine either won, conceded, or found a draw.\r\n            /// </summary>\r\n            End,\r\n        }\r\n\r\n        /// <summary>\r\n        /// Machine decides where to move on the board, and ends the game if\r\n        ///  appropriate.\r\n        ///\r\n        /// The machine's AI tries to take the following actions (in order):\r\n        ///\r\n        ///  1. If the player has a row that will get them the win on their\r\n        ///     next turn, block that row.\r\n        ///  2. If the machine can trap the player (create two different rows\r\n        ///     with three machine moves each that cannot be blocked by only a\r\n        ///     single player move, create such a trap.\r\n        ///  3. If the player can create a similar trap for the machine on\r\n        ///     their next move, block the space where that trap would be\r\n        ///     created.\r\n        ///  4. Find a plane in the board that is well-populated by player\r\n        ///     moves, and take a space in the first such plane.\r\n        ///  5. Find the first open corner or center and move there.\r\n        ///  6. Find the first open space and move there.\r\n        ///\r\n        /// If none of these actions are possible, then the board is entirely\r\n        ///  full, and the game results in a draw.\r\n        ///\r\n        /// Original BASIC: start at 930\r\n        /// </summary>\r\n        /// <returns>the action the machine took</returns>\r\n        private MachineAction MachineMove()\r\n        {\r\n            // The actions the machine attempts to take, in order.\r\n            var actions = new Func<MachineAction>[]\r\n            {\r\n                BlockPlayer,\r\n                MakePlayerTrap,\r\n                BlockMachineTrap,\r\n                MoveByPlane,\r\n                MoveCornerOrCenter,\r\n                MoveAnyOpenSpace,\r\n            };\r\n\r\n            foreach (var action in actions)\r\n            {\r\n                // Try each action, moving to the next if nothing happens.\r\n                var actionResult = action();\r\n                if (actionResult != MachineAction.None)\r\n                {\r\n                    // Not in original BASIC: check for draw after each machine\r\n                    // move.\r\n                    if (CheckDraw())\r\n                    {\r\n                        return DrawGame();\r\n                    }\r\n                    return actionResult;\r\n                }\r\n            }\r\n\r\n            // If we got here, all spaces are taken. Draw the game.\r\n            return DrawGame();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Block a row with three spaces already taken by the player.\r\n        ///\r\n        /// Original BASIC: 930-1010\r\n        /// </summary>\r\n        /// <returns>\r\n        /// Move if the machine blocked,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction BlockPlayer()\r\n        {\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                if (RowSums[row] == (PLAYER * 3))\r\n                {\r\n                    // Found a row to block on!\r\n                    for (int space = 0; space < 4; space++)\r\n                    {\r\n                        if (Board[RowsByPlane[row, space]] == EMPTY)\r\n                        {\r\n                            // Take the remaining empty space.\r\n                            Board[RowsByPlane[row, space]] = MACHINE;\r\n                            Console.WriteLine($\"NICE TRY. MACHINE MOVES TO {IndexToCoord(RowsByPlane[row, space])}\");\r\n                            return MachineAction.Move;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            // Didn't find a row to block on.\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Create a trap for the player if possible. A trap can be created if\r\n        ///  moving to a space on the board results in two different rows having\r\n        ///  three MACHINE spaces, with the remaining space not shared between\r\n        ///  the two rows. The player can only block one of these traps, so the\r\n        ///  machine will win.\r\n        ///\r\n        /// If a player trap is not possible, but a row is found that is\r\n        ///  particularly advantageous for the machine to move to, the machine\r\n        ///  will try and move to a plane edge in that row.\r\n        ///\r\n        /// Original BASIC: 1300-1480\r\n        ///\r\n        /// Lines 1440/50 of the BASIC call 2360 (MovePlaneEdge). Because it\r\n        ///  goes to this code only after it has found an open space marked as\r\n        ///  potential, it cannot reach line 2440 of that code, as that is only\r\n        ///  reached if an open space failed to be found in the row on which\r\n        ///  that code was called.\r\n        /// </summary>\r\n        /// <returns>\r\n        /// Move if a trap was created,\r\n        /// End if the machine conceded,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction MakePlayerTrap()\r\n        {\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                // Refresh row sum, since new POTENTIALs might have changed it.\r\n                var rowSum = RefreshRowSum(row);\r\n\r\n                // Machine has moved in this row twice, and player has not moved\r\n                // in this row.\r\n                if (rowSum >= (MACHINE * 2) && rowSum < (MACHINE * 2) + 1)\r\n                {\r\n                    // Machine has no potential moves yet in this row.\r\n                    if (rowSum == (MACHINE * 2))\r\n                    {\r\n                        for (int space = 0; space < 4; space++)\r\n                        {\r\n                            // Empty space can potentially be used to create a\r\n                            // trap.\r\n                            if (Board[RowsByPlane[row, space]] == EMPTY)\r\n                            {\r\n                                Board[RowsByPlane[row, space]] = POTENTIAL;\r\n                            }\r\n                        }\r\n                    }\r\n                    // Machine has already found a potential move in this row,\r\n                    // so a trap can be created with another row.\r\n                    else\r\n                    {\r\n                        return MakeOrBlockTrap(row);\r\n                    }\r\n                }\r\n            }\r\n\r\n            // No player traps can be made.\r\n            RefreshRowSums();\r\n\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                // A row may be particularly advantageous for the machine to\r\n                // move to at this point; this is the case if a row is entirely\r\n                // filled with POTENTIAL or has one MACHINE and others\r\n                // POTENTIAL. Such rows may help set up trapping opportunities.\r\n                if (RowSums[row] == (POTENTIAL * 4) || RowSums[row] == MACHINE + (POTENTIAL * 3))\r\n                {\r\n                    // Try moving to a plane edge in an advantageous row.\r\n                    return MovePlaneEdge(row, POTENTIAL);\r\n                }\r\n            }\r\n\r\n            // No spaces found that are particularly advantageous to machine.\r\n            ClearPotentialMoves();\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Block a trap that the player could create for the machine on their\r\n        ///  next turn.\r\n        ///\r\n        /// If there are no player traps to block, but a row is found that is\r\n        ///  particularly advantageous for the player to move to, the machine\r\n        ///  will try and move to a plane edge in that row.\r\n        ///\r\n        /// Original BASIC: 1030-1190\r\n        ///\r\n        /// Lines 1160/1170 of the BASIC call 2360 (MovePlaneEdge). As with\r\n        ///  MakePlayerTrap, because it goes to this code only after it has\r\n        ///  found an open space marked as potential, it cannot reach line 2440\r\n        ///  of that code, as that is only reached if an open space failed to be\r\n        ///  found in the row on which that code was called.\r\n        /// </summary>\r\n        /// <returns>\r\n        /// Move if a trap was created,\r\n        /// End if the machine conceded,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction BlockMachineTrap()\r\n        {\r\n            for (int i = 0; i < 76; i++)\r\n            {\r\n                // Refresh row sum, since new POTENTIALs might have changed it.\r\n                var rowSum = RefreshRowSum(i);\r\n\r\n                // Player has moved in this row twice, and machine has not moved\r\n                // in this row.\r\n                if (rowSum >= (PLAYER * 2) && rowSum < (PLAYER * 2) + 1)\r\n                {\r\n                    // Machine has no potential moves yet in this row.\r\n                    if (rowSum == (PLAYER * 2))\r\n                    {\r\n                        for (int j = 0; j < 4; j++)\r\n                        {\r\n                            if (Board[RowsByPlane[i, j]] == EMPTY)\r\n                            {\r\n                                Board[RowsByPlane[i, j]] = POTENTIAL;\r\n                            }\r\n                        }\r\n                    }\r\n                    // Machine has already found a potential move in this row,\r\n                    // so a trap can be created with another row by the player.\r\n                    // Move to block.\r\n                    else\r\n                    {\r\n                        return MakeOrBlockTrap(i);\r\n                    }\r\n                }\r\n            }\r\n\r\n            // No player traps to block found.\r\n            RefreshRowSums();\r\n\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                // A row may be particularly advantageous for the player to move\r\n                // to at this point, indicated by a row containing all POTENTIAL\r\n                // moves or one PLAYER and rest POTENTIAL. Such rows may aid in\r\n                // in the later creation of traps.\r\n                if (RowSums[row] == (POTENTIAL * 4) || RowSums[row] == PLAYER + (POTENTIAL * 3))\r\n                {\r\n                    // Try moving to a plane edge in an advantageous row.\r\n                    return MovePlaneEdge(row, POTENTIAL);\r\n                }\r\n            }\r\n\r\n            // No spaces found that are particularly advantageous to the player.\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Either make a trap for the player or block a trap the player could\r\n        ///  create on their next turn.\r\n        ///\r\n        /// Unclear how this method could possibly end with a concession; it\r\n        ///  seems it can only be called if the row contains a potential move.\r\n        ///\r\n        /// Original BASIC: 2230-2350\r\n        /// </summary>\r\n        /// <param name=\"row\">the row containing the space to move to</param>\r\n        /// <returns>\r\n        /// Move if the machine moved,\r\n        /// End if the machine conceded\r\n        /// </returns>\r\n        private MachineAction MakeOrBlockTrap(int row)\r\n        {\r\n            for (int space = 0; space < 4; space++)\r\n            {\r\n                if (Board[RowsByPlane[row, space]] == POTENTIAL)\r\n                {\r\n                    Board[RowsByPlane[row, space]] = MACHINE;\r\n\r\n                    // Row sum indicates we're blocking a player trap.\r\n                    if (RowSums[row] < MACHINE)\r\n                    {\r\n                        Console.Write(\"YOU FOX.  JUST IN THE NICK OF TIME, \");\r\n                    }\r\n                    // Row sum indicates we're completing a machine trap.\r\n                    else\r\n                    {\r\n                        Console.Write(\"LET'S SEE YOU GET OUT OF THIS:  \");\r\n                    }\r\n\r\n                    Console.WriteLine($\"MACHINE MOVES TO {IndexToCoord(RowsByPlane[row, space])}\");\r\n\r\n                    return MachineAction.Move;\r\n                }\r\n            }\r\n\r\n            // Unclear how this can be reached.\r\n            Console.WriteLine(\"MACHINE CONCEDES THIS GAME.\");\r\n            return MachineAction.End;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Find a satisfactory plane on the board and move to one if that\r\n        ///  plane's plane edges.\r\n        ///\r\n        /// A plane on the board is satisfactory if it meets the following\r\n        ///  conditions:\r\n        ///     1. Player has made exactly 4 moves on the plane.\r\n        ///     2. Machine has made either 0 or one moves on the plane.\r\n        ///  Such a plane is one that the player could likely use to form traps.\r\n        ///\r\n        /// Original BASIC: 1830-2020\r\n        ///\r\n        /// Line 1990 of the original basic calls 2370 (MovePlaneEdge). Only on\r\n        ///  this call to MovePlaneEdge can line 2440 of that method be reached,\r\n        ///  which surves to help this method iterate through the rows of a\r\n        ///  plane.\r\n        /// </summary>\r\n        /// <returns>\r\n        /// Move if a move in a plane was found,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction MoveByPlane()\r\n        {\r\n            // For each plane in the cube...\r\n            for (int plane = 1; plane <= 18; plane++)\r\n            {\r\n                double planeSum = PlaneSum(plane);\r\n\r\n                // Check that plane sum satisfies condition.\r\n                const double P4 = PLAYER * 4;\r\n                const double P4_M1 = (PLAYER * 4) + MACHINE;\r\n                if (\r\n                    (planeSum >= P4 && planeSum < P4 + 1) ||\r\n                    (planeSum >= P4_M1 && planeSum < P4_M1 + 1)\r\n                )\r\n                {\r\n                    // Try to move to plane edges in each row of plane\r\n                    // First, check for plane edges marked as POTENTIAL.\r\n                    for (int row = (4 * plane) - 4; row < (4 * plane); row++)\r\n                    {\r\n                        var moveResult = MovePlaneEdge(row, POTENTIAL);\r\n                        if (moveResult != MachineAction.None)\r\n                        {\r\n                            return moveResult;\r\n                        }\r\n                    }\r\n\r\n                    // If no POTENTIAL plane edge found, look for an EMPTY one.\r\n                    for (int row = (4 * plane) - 4; row < (4 * plane); row++)\r\n                    {\r\n                        var moveResult = MovePlaneEdge(row, EMPTY);\r\n                        if (moveResult != MachineAction.None)\r\n                        {\r\n                            return moveResult;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            // No satisfactory planes with open plane edges found.\r\n            ClearPotentialMoves();\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Given a row, move to the first space in that row that:\r\n        ///  1. is a plane edge, and\r\n        ///  2. has the given value in Board\r\n        ///\r\n        /// Plane edges are any spaces on a plane with one face exposed. The AI\r\n        ///  prefers to move to these spaces before others, presumably\r\n        ///  because they are powerful moves: a plane edge is contained on 3-4\r\n        ///  winning rows of the cube.\r\n        ///\r\n        /// Original BASIC: 2360-2490\r\n        ///\r\n        /// In the original BASIC, this code is pointed to from three different\r\n        ///  locations by GOTOs:\r\n        ///  - 1440/50, or MakePlayerTrap;\r\n        ///  - 1160/70, or BlockMachineTrap; and\r\n        ///  - 1990, or MoveByPlane.\r\n        /// At line 2440, this code jumps back to line 2000, which is in\r\n        ///  MoveByPlane. This makes it appear as though calling MakePlayerTrap\r\n        ///  or BlockPlayerTrap in the BASIC could jump into the middle of the\r\n        ///  MoveByPlane method; were this to happen, not all of MoveByPlane's\r\n        ///  variables would be defined! However, the program logic prevents\r\n        ///  this from ever occurring; see each method's description for why\r\n        ///  this is the case.\r\n        /// </summary>\r\n        /// <param name=\"row\">the row to try to move to</param>\r\n        /// <param name=\"spaceValue\">\r\n        /// what value the space to move to should have in Board\r\n        /// </param>\r\n        /// <returns>\r\n        /// Move if a plane edge piece in the row with the given spaceValue was\r\n        /// found,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction MovePlaneEdge(int row, double spaceValue)\r\n        {\r\n            // Given a row, we want to find the plane edge pieces in that row.\r\n            // We know that each row is part of a plane, and that the first\r\n            // and last rows of the plane are on the plane edge, while the\r\n            // other two rows are in the middle. If we know whether a row is an\r\n            // edge or middle, we can determine which spaces in that row are\r\n            // plane edges.\r\n            //\r\n            // Below is a birds-eye view of a plane in the cube, with rows\r\n            // oriented horizontally:\r\n            //\r\n            //   row 0: ( ) (1) (2) ( )\r\n            //   row 1: (0) ( ) ( ) (3)\r\n            //   row 2: (0) ( ) ( ) (3)\r\n            //   row 3: ( ) (1) (2) ( )\r\n            //\r\n            // The plane edge pieces have their row indices marked. The pattern\r\n            // above shows that:\r\n            //\r\n            //  if row == 0 | 3, plane edge spaces = [1, 2]\r\n            //  if row == 1 | 2, plane edge spaces = [0, 3]\r\n\r\n            // The below condition replaces the following BASIC code (2370):\r\n            //\r\n            //  I-(INT(I/4)*4)>1\r\n            //\r\n            // which in C# would be:\r\n            //\r\n            //\r\n            // int a = i - (i / 4) * 4 <= 1)\r\n            //     ? 1\r\n            //     : 2;\r\n            //\r\n            // In the above, i is the one-indexed row in RowsByPlane.\r\n            //\r\n            // This condition selects a different a value based on whether the\r\n            // given row is on the edge or middle of its plane.\r\n            int a = (row % 4) switch\r\n            {\r\n                0 or 3 => 1,  // row is on edge of plane\r\n                1 or 2 => 2,  // row is in middle of plane\r\n                _ => throw new Exception($\"unreachable ({row % 4})\"),\r\n            };\r\n\r\n            // Iterate through plane edge pieces of the row.\r\n            //\r\n            //  if a = 1 (row is edge), iterate through [0, 3]\r\n            //  if a = 2 (row is middle), iterate through [1, 2]\r\n            for (int space = a - 1; space <= 4 - a; space += 5 - (2 * a))\r\n            {\r\n                if (Board[RowsByPlane[row, space]] == spaceValue)\r\n                {\r\n                    // Found a plane edge to take!\r\n                    Board[RowsByPlane[row, space]] = MACHINE;\r\n                    Console.WriteLine($\"MACHINE TAKES {IndexToCoord(RowsByPlane[row, space])}\");\r\n                    return MachineAction.Move;\r\n                }\r\n            }\r\n\r\n            // No valid corner edge to take.\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Find the first open corner or center in the board and move there.\r\n        ///\r\n        /// Original BASIC: 1200-1290\r\n        ///\r\n        /// This is the only place where the Z variable from the BASIC code is\r\n        ///  used; here it is implied in the for loop.\r\n        /// </summary>\r\n        /// <returns>\r\n        /// Move if an open corner/center was found and moved to,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction MoveCornerOrCenter()\r\n        {\r\n            foreach (int space in CornersAndCenters)\r\n            {\r\n                if (Board[space] == EMPTY)\r\n                {\r\n                    Board[space] = MACHINE;\r\n                    Console.WriteLine($\"MACHINE MOVES TO {IndexToCoord(space)}\");\r\n                    return MachineAction.Move;\r\n                }\r\n            }\r\n\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Find the first open space in the board and move there.\r\n        ///\r\n        /// Original BASIC: 1720-1800\r\n        /// </summary>\r\n        /// <returns>\r\n        /// Move if an open space was found and moved to,\r\n        /// None otherwise\r\n        /// </returns>\r\n        private MachineAction MoveAnyOpenSpace()\r\n        {\r\n            for (int row = 0; row < 64; row++)\r\n            {\r\n                if (Board[row] == EMPTY)\r\n                {\r\n                    Board[row] = MACHINE;\r\n                    Console.WriteLine($\"MACHINE LIKES {IndexToCoord(row)}\");\r\n                    return MachineAction.Move;\r\n                }\r\n            }\r\n            return MachineAction.None;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Draw the game in the event that there are no open spaces.\r\n        ///\r\n        /// Original BASIC: 1810-1820\r\n        /// </summary>\r\n        /// <returns>End</returns>\r\n        private MachineAction DrawGame()\r\n        {\r\n            Console.WriteLine(\"THIS GAME IS A DRAW.\");\r\n            return MachineAction.End;\r\n        }\r\n\r\n        #endregion\r\n\r\n        /***********************************************************************\r\n        /* Helpers\r\n        /**********************************************************************/\r\n        #region Helpers\r\n\r\n        /// <summary>\r\n        /// Attempt to transform a cube coordinate to an index into Board.\r\n        ///\r\n        /// A valid cube coordinate is a three-digit number, where each digit\r\n        ///  of the number X satisfies 1 <= X <= 4.\r\n        ///\r\n        /// Examples:\r\n        ///  111 -> 0\r\n        ///  444 -> 63\r\n        ///  232 -> 35\r\n        ///\r\n        /// If the coord provided is not valid, the transformation fails.\r\n        ///\r\n        /// The conversion from coordinate to index is essentially a conversion\r\n        ///  between base 4 and base 10.\r\n        ///\r\n        /// Original BASIC: 525-580\r\n        ///\r\n        /// This method fixes a bug in the original BASIC (525-526), which only\r\n        ///  checked whether the given coord satisfied 111 <= coord <= 444. This\r\n        ///  allows invalid coordinates such as 199 and 437, whose individual\r\n        ///  digits are out of range.\r\n        /// </summary>\r\n        /// <param name=\"coord\">cube coordinate (e.g. \"111\", \"342\")</param>\r\n        /// <param name=\"index\">trasnformation output</param>\r\n        /// <returns>\r\n        /// true if the transformation was successful, false otherwise\r\n        /// </returns>\r\n        private static bool TryCoordToIndex(int coord, out int index)\r\n        {\r\n            // parse individual digits, subtract 1 to get base 4 number\r\n            var hundreds = (coord / 100) - 1;\r\n            var tens = ((coord % 100) / 10) - 1;\r\n            var ones = (coord % 10) - 1;\r\n\r\n            // bounds check for each digit\r\n            foreach (int digit in new int[] { hundreds, tens, ones })\r\n            {\r\n                if (digit < 0 || digit > 3)\r\n                {\r\n                    index = -1;\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            // conversion from base 4 to base 10\r\n            index = (16 * hundreds) + (4 * tens) + ones;\r\n            return true;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Transform a Board index into a valid cube coordinate.\r\n        ///\r\n        /// Examples:\r\n        ///  0 -> 111\r\n        ///  63 -> 444\r\n        ///  35 -> 232\r\n        ///\r\n        /// The conversion from index to coordinate is essentially a conversion\r\n        ///  between base 10 and base 4.\r\n        ///\r\n        /// Original BASIC: 1570-1610\r\n        /// </summary>\r\n        /// <param name=\"index\">Board index</param>\r\n        /// <returns>the corresponding cube coordinate</returns>\r\n        private static int IndexToCoord(int index)\r\n        {\r\n            // check that index is valid\r\n            if (index < 0 || index > 63)\r\n            {\r\n                // runtime exception; all uses of this method are with\r\n                // indices provided by the program, so this should never fail\r\n                throw new Exception($\"index {index} is out of range\");\r\n            }\r\n\r\n            // convert to base 4, add 1 to get cube coordinate\r\n            var hundreds = (index / 16) + 1;\r\n            var tens = ((index % 16) / 4) + 1;\r\n            var ones = (index % 4) + 1;\r\n\r\n            // concatenate digits\r\n            int coord = (hundreds * 100) + (tens * 10) + ones;\r\n            return coord;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Refresh the values in RowSums to account for any changes.\r\n        ///\r\n        /// Original BASIC: 1640-1710\r\n        /// </summary>\r\n        private void RefreshRowSums()\r\n        {\r\n            for (var row = 0; row < 76; row++)\r\n            {\r\n                RefreshRowSum(row);\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Refresh a row in RowSums to reflect changes.\r\n        /// </summary>\r\n        /// <param name=\"row\">row in RowSums to refresh</param>\r\n        /// <returns>row sum after refresh</returns>\r\n        private double RefreshRowSum(int row)\r\n        {\r\n            double rowSum = 0;\r\n            for (int space = 0; space < 4; space++)\r\n            {\r\n                rowSum += Board[RowsByPlane[row, space]];\r\n            }\r\n            RowSums[row] = rowSum;\r\n            return rowSum;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Calculate the sum of spaces in one of the 18 cube planes in RowSums.\r\n        ///\r\n        /// Original BASIC: 1840-1890\r\n        /// </summary>\r\n        /// <param name=\"plane\">the desired plane</param>\r\n        /// <returns>sum of spaces in plane</returns>\r\n        private double PlaneSum(int plane)\r\n        {\r\n            double planeSum = 0;\r\n            for (int row = (4 * (plane - 1)); row < (4 * plane); row++)\r\n            {\r\n                for (int space = 0; space < 4; space++)\r\n                {\r\n                    planeSum += Board[RowsByPlane[row, space]];\r\n                }\r\n            }\r\n            return planeSum;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Check whether the board is in a draw state, that is all spaces are\r\n        ///  full and neither the player nor the machine has won.\r\n        ///\r\n        /// The original BASIC contains a bug that if the player moves first, a\r\n        ///  draw will go undetected. An example series of player inputs\r\n        ///  resulting in such a draw (assuming player goes first):\r\n        ///\r\n        ///  114, 414, 144, 444, 122, 221, 112, 121,\r\n        ///  424, 332, 324, 421, 231, 232, 244, 311,\r\n        ///  333, 423, 331, 134, 241, 243, 143, 413,\r\n        ///  142, 212, 314, 341, 432, 412, 431, 442\r\n        /// </summary>\r\n        /// <returns>whether the game is a draw</returns>\r\n        private bool CheckDraw()\r\n        {\r\n            for (var i = 0; i < 64; i++)\r\n            {\r\n                if (Board[i] != PLAYER && Board[i] != MACHINE)\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            RefreshRowSums();\r\n\r\n            for (int row = 0; row < 76; row++)\r\n            {\r\n                var rowSum = RowSums[row];\r\n                if (rowSum == PLAYER * 4 || rowSum == MACHINE * 4)\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n\r\n            return true;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Reset POTENTIAL spaces in Board to EMPTY.\r\n        ///\r\n        /// Original BASIC: 2500-2540\r\n        /// </summary>\r\n        private void ClearPotentialMoves()\r\n        {\r\n            for (var i = 0; i < 64; i++)\r\n            {\r\n                if (Board[i] == POTENTIAL)\r\n                {\r\n                    Board[i] = EMPTY;\r\n                }\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Reset all spaces in Board to EMPTY.\r\n        ///\r\n        /// Original BASIC: 400-420\r\n        /// </summary>\r\n        private void ClearBoard()\r\n        {\r\n            for (var i = 0; i < 64; i++)\r\n            {\r\n                Board[i] = EMPTY;\r\n            }\r\n        }\r\n\r\n        #endregion\r\n    }\r\n}\r\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/csharp/QubicData.cs",
    "content": "﻿namespace ThreeDTicTacToe\r\n{\r\n    /// <summary>\r\n    /// Data in this class was originally given by the following DATA section in\r\n    /// the BASIC program:\r\n    ///\r\n    /// 2030 DATA 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43\r\n    /// 2040 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20\r\n    /// 2050 DATA 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38\r\n    /// 2060 DATA 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56\r\n    /// 2070 DATA 57,58,59,60,61,62,63,64\r\n    /// 2080 DATA 1,17,33,49,5,21,37,53,9,25,41,57,13,29,45,61\r\n    /// 2090 DATA 2,18,34,50,6,22,38,54,10,26,42,58,14,30,46,62\r\n    /// 2100 DATA 3,19,35,51,7,23,39,55,11,27,43,59,15,31,47,63\r\n    /// 2110 DATA 4,20,36,52,8,24,40,56,12,28,44,60,16,32,48,64\r\n    /// 2120 DATA 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61\r\n    /// 2130 DATA 2,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62\r\n    /// 2140 DATA 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63\r\n    /// 2150 DATA 4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64\r\n    /// 2160 DATA 1,6,11,16,17,22,27,32,33,38,43,48,49,54,59,64\r\n    /// 2170 DATA 13,10,7,4,29,26,23,20,45,42,39,36,61,58,55,52\r\n    /// 2180 DATA 1,21,41,61,2,22,42,62,3,23,43,63,4,24,44,64\r\n    /// 2190 DATA 49,37,25,13,50,38,26,14,51,39,27,15,52,40,28,16\r\n    /// 2200 DATA 1,18,35,52,5,22,39,56,9,26,43,60,13,30,47,64\r\n    /// 2210 DATA 49,34,19,4,53,38,23,8,57,42,27,12,61,46,31,16\r\n    /// 2220 DATA 1,22,43,64,16,27,38,49,4,23,42,61,13,26,39,52\r\n    ///\r\n    /// In short, each number is an index into the board. The data in this class\r\n    /// is zero-indexed, as opposed to the original data which was one-indexed.\r\n    /// </summary>\r\n    internal static class QubicData\r\n    {\r\n        /// <summary>\r\n        /// The corners and centers of the Qubic board. They correspond to the\r\n        ///  following coordinates:\r\n        ///\r\n        /// [\r\n        ///     111, 411, 414, 114, 141, 441, 444, 144,\r\n        ///     222, 323, 223, 322, 232, 332, 233, 333\r\n        /// ]\r\n        /// </summary>\r\n        public static readonly int[] CornersAndCenters = new int[16]\r\n        {\r\n           //     (X)      ( )      ( )      (X)\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 (X)      ( )      ( )      (X)\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      (X)      (X)      ( )\r\n           //             ( )      (X)      (X)      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      (X)      (X)      ( )\r\n           //             ( )      (X)      (X)      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     (X)      ( )      ( )      (X)\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 (X)      ( )      ( )      (X)\r\n\r\n            0,48,51,3,12,60,63,15,21,38,22,37,25,41,26,42\r\n        };\r\n\r\n        /// <summary>\r\n        /// A list of all \"winning\" rows in the Qubic board; that is, sets of\r\n        ///  four spaces that, if filled entirely by the player (or machine),\r\n        ///  would result in a win.\r\n        ///\r\n        /// Each group of four rows in the list corresponds to a plane in the\r\n        ///  cube, and each plane is organized so that the first and last rows\r\n        ///  are on the plane's edges, while the second and third rows are in\r\n        ///  the middle of the plane. The only exception is the last group of\r\n        ///  rows, which contains the corners and centers rather than a plane.\r\n        ///\r\n        /// The order of the rows in this list is key to how the Qubic AI\r\n        ///  decides its next move.\r\n        /// </summary>\r\n        public static readonly int[,] RowsByPlane = new int[76, 4]\r\n        {\r\n           //     (1)      (1)      (1)      (1)\r\n           //         (2)      (2)      (2)      (2)\r\n           //             (3)      (3)      (3)      (3)\r\n           //                 (4)      (4)      (4)      (4)\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           { 0, 1, 2, 3,  },\r\n           { 4, 5, 6, 7,  },\r\n           { 8, 9, 10,11, },\r\n           { 12,13,14,15, },\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     (1)      (1)      (1)      (1)\r\n           //         (2)      (2)      (2)      (2)\r\n           //             (3)      (3)      (3)      (3)\r\n           //                 (4)      (4)      (4)      (4)\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           { 16,17,18,19, },\r\n           { 20,21,22,23, },\r\n           { 24,25,26,27, },\r\n           { 28,29,30,31, },\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     (1)      (1)      (1)      (1)\r\n           //         (2)      (2)      (2)      (2)\r\n           //             (3)      (3)      (3)      (3)\r\n           //                 (4)      (4)      (4)      (4)\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           { 32,33,34,35, },\r\n           { 36,37,38,39, },\r\n           { 40,41,42,43, },\r\n           { 44,45,46,47, },\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     (1)      (1)      (1)      (1)\r\n           //         (2)      (2)      (2)      (2)\r\n           //             (3)      (3)      (3)      (3)\r\n           //                 (4)      (4)      (4)      (4)\r\n\r\n           { 48,49,50,51, },\r\n           { 52,53,54,55, },\r\n           { 56,57,58,59, },\r\n           { 60,61,62,63, },\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           { 0, 16,32,48, },\r\n           { 4, 20,36,52, },\r\n           { 8, 24,40,56, },\r\n           { 12,28,44,60, },\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           { 1, 17,33,49, },\r\n           { 5, 21,37,53, },\r\n           { 9, 25,41,57, },\r\n           { 13,29,45,61, },\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           { 2, 18,34,50, },\r\n           { 6, 22,38,54, },\r\n           { 10,26,42,58, },\r\n           { 14,30,46,62, },\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           { 3, 19,35,51, },\r\n           { 7, 23,39,55, },\r\n           { 11,27,43,59, },\r\n           { 15,31,47,63, },\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (1)      ( )      ( )      ( )\r\n           //             (1)      ( )      ( )      ( )\r\n           //                 (1)      ( )      ( )      ( )\r\n\r\n           //     (2)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (2)      ( )      ( )      ( )\r\n           //                 (2)      ( )      ( )      ( )\r\n\r\n           //     (3)      ( )      ( )      ( )\r\n           //         (3)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (3)      ( )      ( )      ( )\r\n\r\n           //     (4)      ( )      ( )      ( )\r\n           //         (4)      ( )      ( )      ( )\r\n           //             (4)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           { 0, 4, 8, 12, },\r\n           { 16,20,24,28, },\r\n           { 32,36,40,44, },\r\n           { 48,52,56,60, },\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (1)      ( )      ( )\r\n           //             ( )      (1)      ( )      ( )\r\n           //                 ( )      (1)      ( )      ( )\r\n\r\n           //     ( )      (2)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (2)      ( )      ( )\r\n           //                 ( )      (2)      ( )      ( )\r\n\r\n           //     ( )      (3)      ( )      ( )\r\n           //         ( )      (3)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (3)      ( )      ( )\r\n\r\n           //     ( )      (4)      ( )      ( )\r\n           //         ( )      (4)      ( )      ( )\r\n           //             ( )      (4)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           { 1, 5, 9, 13, },\r\n           { 17,21,25,29, },\r\n           { 33,37,41,45, },\r\n           { 49,53,57,61, },\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (1)      ( )\r\n           //             ( )      ( )      (1)      ( )\r\n           //                 ( )      ( )      (1)      ( )\r\n\r\n           //     ( )      ( )      (2)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (2)      ( )\r\n           //                 ( )      ( )      (2)      ( )\r\n\r\n           //     ( )      ( )      (3)      ( )\r\n           //         ( )      ( )      (3)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (3)      ( )\r\n\r\n           //     ( )      ( )      (4)      ( )\r\n           //         ( )      ( )      (4)      ( )\r\n           //             ( )      ( )      (4)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           { 2, 6, 10,14, },\r\n           { 18,22,26,30, },\r\n           { 34,38,42,46, },\r\n           { 50,54,58,62, },\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (1)\r\n           //             ( )      ( )      ( )      (1)\r\n           //                 ( )      ( )      ( )      (1)\r\n\r\n           //     ( )      ( )      ( )      (2)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (2)\r\n           //                 ( )      ( )      ( )      (2)\r\n\r\n           //     ( )      ( )      ( )      (3)\r\n           //         ( )      ( )      ( )      (3)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (3)\r\n\r\n           //     ( )      ( )      ( )      (4)\r\n           //         ( )      ( )      ( )      (4)\r\n           //             ( )      ( )      ( )      (4)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           { 3, 7, 11,15, },\r\n           { 19,23,27,31, },\r\n           { 35,39,43,47, },\r\n           { 51,55,59,63, },\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         ( )      (1)      ( )      ( )\r\n           //             ( )      ( )      (1)      ( )\r\n           //                 ( )      ( )      ( )      (1)\r\n\r\n           //     (2)      ( )      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      ( )      (2)      ( )\r\n           //                 ( )      ( )      ( )      (2)\r\n\r\n           //     (3)      ( )      ( )      ( )\r\n           //         ( )      (3)      ( )      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      ( )      (3)\r\n\r\n           //     (4)      ( )      ( )      ( )\r\n           //         ( )      (4)      ( )      ( )\r\n           //             ( )      ( )      (4)      ( )\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           { 0, 5, 10,15, },\r\n           { 16,21,26,31, },\r\n           { 32,37,42,47, },\r\n           { 48,53,58,63, },\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      (1)      ( )\r\n           //             ( )      (1)      ( )      ( )\r\n           //                 (1)      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      (2)\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      (2)      ( )      ( )\r\n           //                 (2)      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      (3)\r\n           //         ( )      ( )      (3)      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 (3)      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      (4)\r\n           //         ( )      ( )      (4)      ( )\r\n           //             ( )      (4)      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           { 12,9, 6, 3,  },\r\n           { 28,25,22,19, },\r\n           { 44,41,38,35, },\r\n           { 60,57,54,51, },\r\n\r\n           //     (1)      (2)      (3)      (4)\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         (1)      (2)      (3)      (4)\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             (1)      (2)      (3)      (4)\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 (1)      (2)      (3)      (4)\r\n\r\n           { 0, 20,40,60, },\r\n           { 1, 21,41,61, },\r\n           { 2, 22,42,62, },\r\n           { 3, 23,43,63, },\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 (1)      (2)      (3)      (4)\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      ( )      ( )      ( )\r\n           //             (1)      (2)      (3)      (4)\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         (1)      (2)      (3)      (4)\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     (1)      (2)      (3)      (4)\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           { 48,36,24,12, },\r\n           { 49,37,25,13, },\r\n           { 50,38,26,14, },\r\n           { 51,39,27,15, },\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           { 0, 17,34,51, },\r\n           { 4, 21,38,55, },\r\n           { 8, 25,42,59, },\r\n           { 12,29,46,63, },\r\n\r\n           //     ( )      ( )      ( )      (1)\r\n           //         ( )      ( )      ( )      (2)\r\n           //             ( )      ( )      ( )      (3)\r\n           //                 ( )      ( )      ( )      (4)\r\n\r\n           //     ( )      ( )      (1)      ( )\r\n           //         ( )      ( )      (2)      ( )\r\n           //             ( )      ( )      (3)      ( )\r\n           //                 ( )      ( )      (4)      ( )\r\n\r\n           //     ( )      (1)      ( )      ( )\r\n           //         ( )      (2)      ( )      ( )\r\n           //             ( )      (3)      ( )      ( )\r\n           //                 ( )      (4)      ( )      ( )\r\n\r\n           //     (1)      ( )      ( )      ( )\r\n           //         (2)      ( )      ( )      ( )\r\n           //             (3)      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      ( )\r\n\r\n           { 48,33,18,3,  },\r\n           { 52,37,22,7,  },\r\n           { 56,41,26,11, },\r\n           { 60,45,30,15, },\r\n\r\n           //     (1)      ( )      ( )      (3)\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 (4)      ( )      ( )      (2)\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      (1)      (3)      ( )\r\n           //             ( )      (4)      (2)      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     ( )      ( )      ( )      ( )\r\n           //         ( )      (2)      (4)      ( )\r\n           //             ( )      (3)      (1)      ( )\r\n           //                 ( )      ( )      ( )      ( )\r\n\r\n           //     (2)      ( )      ( )      (4)\r\n           //         ( )      ( )      ( )      ( )\r\n           //             ( )      ( )      ( )      ( )\r\n           //                 (3)      ( )      ( )      (1)\r\n\r\n           { 0, 21,42,63, },\r\n           { 15,26,37,48, },\r\n           { 3, 22,41,60, },\r\n           { 12,25,38,51, },\r\n        };\r\n    }\r\n}\r\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ThreeDTicTacToe\", \"ThreeDTicTacToe.csproj\", \"{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/javascript/qubit.html",
    "content": "<html>\n<head>\n<title>QUBIT</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"qubit.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/javascript/qubit.js",
    "content": "// QUBIT\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar xa = [];\nvar la = [];\nvar ma = [[],\n          [,1,2,3,4],    // 1\n          [,5,6,7,8],    // 2\n          [,9,10,11,12], // 3\n          [,13,14,15,16],    // 4\n          [,17,18,19,20],    // 5\n          [,21,22,23,24],    // 6\n          [,25,26,27,28],    // 7\n          [,29,30,31,32],    // 8\n          [,33,34,35,36],    // 9\n          [,37,38,39,40],    // 10\n          [,41,42,43,44],    // 11\n          [,45,46,47,48],    // 12\n          [,49,50,51,52],    // 13\n          [,53,54,55,56],    // 14\n          [,57,58,59,60],    // 15\n          [,61,62,63,64],    // 16\n          [,1,17,33,49], // 17\n          [,5,21,37,53],    // 18\n          [,9,25,41,57],   // 19\n          [,13,29,45,61], // 20\n          [,2,18,34,50], // 21\n          [,6,22,38,54],    // 22\n          [,10,26,42,58],  // 23\n          [,14,30,46,62],   // 24\n          [,3,19,35,51], // 25\n          [,7,23,39,55],    // 26\n          [,11,27,43,59],  // 27\n          [,15,31,47,63], // 28\n          [,4,20,36,52], // 29\n          [,8,24,40,56], // 30\n          [,12,28,44,60],    // 31\n          [,16,32,48,64],    // 32\n          [,1,5,9,13],   // 33\n          [,17,21,25,29],    // 34\n          [,33,37,41,45],    // 35\n          [,49,53,57,61],    // 36\n          [,2,6,10,14],  // 37\n          [,18,22,26,30],    // 38\n          [,34,38,42,46],    // 39\n          [,50,54,58,62],    // 40\n          [,3,7,11,15],  // 41\n          [,19,23,27,31],    // 42\n          [,35,39,43,47],    // 43\n          [,51,55,59,63],    // 44\n          [,4,8,12,16],  // 45\n          [,20,24,28,32],    // 46\n          [,36,40,44,48],    // 47\n          [,52,56,60,64],    // 48\n          [,1,6,11,16],  // 49\n          [,17,22,27,32],    // 50\n          [,33,38,43,48],    // 51\n          [,49,54,59,64],    // 52\n          [,13,10,7,4],  // 53\n          [,29,26,23,20],    // 54\n          [,45,42,39,36],    // 55\n          [,61,58,55,52],    // 56\n          [,1,21,41,61], // 57\n          [,2,22,42,62], // 58\n          [,3,23,43,63], // 59\n          [,4,24,44,64], // 60\n          [,49,37,25,13],    // 61\n          [,50,38,26,14],    // 62\n          [,51,39,27,15],    // 63\n          [,52,40,28,16],    // 64\n          [,1,18,35,52], // 65\n          [,5,22,39,56], // 66\n          [,9,26,43,60], // 67\n          [,13,30,47,64],    // 68\n          [,49,34,19,4], // 69\n          [,53,38,23,8], // 70\n          [,57,42,27,12],    // 71\n          [,61,46,31,16],    // 72\n          [,1,22,43,64], // 73\n          [,16,27,38,49],    // 74\n          [,4,23,42,61], // 75\n          [,13,26,39,52] // 76\n          ];\nvar ya = [,1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43];\n\nfunction show_board()\n{\n    for (xx = 1; xx <= 9; xx++)\n        print(\"\\n\");\n    for (i = 1; i <= 4; i++) {\n        for (j = 1; j <= 4; j++) {\n            str = \"\";\n            for (i1 = 1; i1 <= j; i1++)\n                str += \"   \";\n            for (k = 1; k <= 4; k++) {\n                q = 16 * i + 4 * j + k - 20;\n                if (xa[q] == 0)\n                    str += \"( )      \";\n                if (xa[q] == 5)\n                    str += \"(M)      \";\n                if (xa[q] == 1)\n                    str += \"(Y)      \";\n                if (xa[q] == 1 / 8)\n                    str += \"( )      \";\n            }\n            print(str + \"\\n\");\n            print(\"\\n\");\n        }\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n}\n\nfunction process_board()\n{\n    for (i = 1; i <= 64; i++) {\n        if (xa[i] == 1 / 8)\n            xa[i] = 0;\n    }\n}\n\nfunction check_for_lines()\n{\n    for (s = 1; s <= 76; s++) {\n        j1 = ma[s][1];\n        j2 = ma[s][2];\n        j3 = ma[s][3];\n        j4 = ma[s][4];\n        la[s] = xa[j1] + xa[j2] + xa[j3] + xa[j4];\n    }\n}\n\nfunction show_square(m)\n{\n    k1 = Math.floor((m - 1) / 16) + 1;\n    j2 = m - 16 * (k1 - 1);\n    k2 = Math.floor((j2 - 1) / 4) + 1;\n    k3 = m - (k1 - 1) * 16 - (k2 - 1) * 4;\n    m = k1 * 100 + k2 * 10 + k3;\n    print(\" \" + m + \" \");\n}\n\nfunction select_move() {\n    if (i % 4 <= 1) {\n        a = 1;\n    } else {\n        a = 2;\n    }\n    for (j = a; j <= 5 - a; j += 5 - 2 * a) {\n        if (xa[ma[i][j]] == s)\n            break;\n    }\n    if (j > 5 - a)\n        return false;\n    xa[ma[i][j]] = 5;\n    m = ma[i][j];\n    print(\"MACHINE TAKES\");\n    show_square(m);\n    return true;\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(33) + \"QUBIC\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"DO YOU WANT INSTRUCTIONS\");\n        str = await input();\n        str = str.substr(0, 1);\n        if (str == \"Y\" || str == \"N\")\n            break;\n        print(\"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'\");\n    }\n    if (str == \"Y\") {\n        print(\"\\n\");\n        print(\"THE GAME IS TIC-TAC-TOE IN A 4 X 4 X 4 CUBE.\\n\");\n        print(\"EACH MOVE IS INDICATED BY A 3 DIGIT NUMBER, WITH EACH\\n\");\n        print(\"DIGIT BETWEEN 1 AND 4 INCLUSIVE.  THE DIGITS INDICATE THE\\n\");\n        print(\"LEVEL, ROW, AND COLUMN, RESPECTIVELY, OF THE OCCUPIED\\n\");\n        print(\"PLACE.  \\n\");\n        print(\"\\n\");\n        print(\"TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE.\\n\");\n        print(\"THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-\\n\");\n        print(\"CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND\\n\");\n        print(\"UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER.\\n\");\n        print(\"\\n\");\n        print(\"TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE.\\n\");\n        print(\"\\n\");\n        print(\"\\n\");\n    }\n    while (1) {\n        for (i = 1; i <= 64; i++)\n            xa[i] = 0;\n        z = 1;\n        print(\"DO YOU WANT TO MOVE FIRST\");\n        while (1) {\n            str = await input();\n            str = str.substr(0, 1);\n            if (str == \"Y\" || str == \"N\")\n                break;\n            print(\"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'\");\n        }\n        while (1) {\n            while (1) {\n                print(\" \\n\");\n                print(\"YOUR MOVE\");\n                j1 = parseInt(await input());\n                if (j1 == 0) {\n                    show_board();\n                    continue;\n                }\n                if (j1 == 1)\n                    return;\n                k1 = Math.floor(j1 / 100);\n                j2 = j1 - k1 * 100;\n                k2 = Math.floor(j2 / 10);\n                k3 = j2 - k2 * 10;\n                m = 16 * k1 + 4 * k2 + k3 - 20;\n                if (k1 < 1 || k2 < 1 || k3 < 1 || k1 > 4 || k2 > 4 || k3 >> 4) {\n                    print(\"INCORRECT MOVE, RETYPE IT--\");\n                } else {\n                    process_board();\n                    if (xa[m] != 0) {\n                        print(\"THAT SQUARE IS USED, TRY AGAIN.\\n\");\n                    } else {\n                        break;\n                    }\n                }\n            }\n            xa[m] = 1;\n            check_for_lines();\n            status = 0;\n            for (j = 1; j <= 3; j++) {\n                for (i = 1; i <= 76; i++) {\n                    if (j == 1) {\n                        if (la[i] != 4)\n                            continue;\n                        print(\"YOU WIN AS FOLLOWS\");\n                        for (j = 1; j <= 4; j++) {\n                            m = ma[i][j];\n                            show_square(m);\n                        }\n                        status = 1;\n                        break;\n                    }\n                    if (j == 2) {\n                        if (la[i] != 15)\n                            continue;\n                        for (j = 1; j <= 4; j++) {\n                            m = ma[i][j];\n                            if (xa[m] != 0)\n                                continue;\n                            xa[m] = 5;\n                            print(\"MACHINE MOVES TO \");\n                            show_square(m);\n                        }\n                        print(\", AND WINS AS FOLLOWS\");\n                        for (j = 1; j <= 4; j++) {\n                            m = ma[i][j];\n                            show_square(m);\n                        }\n                        status = 1;\n                        break;\n                    }\n                    if (j == 3) {\n                        if (la[i] != 3)\n                            continue;\n                        print(\"NICE TRY, MACHINE MOVES TO\");\n                        for (j = 1; j <= 4; j++) {\n                            m = ma[i][j];\n                            if (xa[m] != 0)\n                                continue;\n                            xa[m] = 5;\n                            show_square(m);\n                            status = 2;\n                        }\n                        break;\n                    }\n                }\n                if (i <= 76)\n                    break;\n            }\n            if (status == 2)\n                continue;\n            if (status == 1)\n                break;\n            // x = x; non-useful in original\n            i = 1;\n            do {\n                la[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]];\n                l = la[i];\n                if (l == 10) {\n                    for (j = 1; j <= 4; j++) {\n                        if (xa[ma[i][j]] == 0)\n                            xa[ma[i][j]] = 1 / 8;\n                    }\n                }\n            } while (++i <= 76) ;\n            check_for_lines();\n            i = 1;\n            do {\n                if (la[i] == 0.5) {\n                    s = 1 / 8;\n                    select_move();\n                    break;\n                }\n                if (la[i] == 5 + 3 / 8) {\n                    s = 1 / 8;\n                    select_move();\n                    break;\n                }\n            } while (++i <= 76) ;\n            if (i <= 76)\n                continue;\n\n            process_board();\n\n            i = 1;\n            do {\n                la[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]];\n                l = la[i];\n                if (l == 2) {\n                    for (j = 1; j <= 4; j++) {\n                        if (xa[ma[i][j]] == 0)\n                            xa[ma[i][j]] = 1 / 8;\n                    }\n                }\n            } while (++i <= 76) ;\n            check_for_lines();\n            i = 1;\n            do {\n                if (la[i] == 0.5) {\n                    s = 1 / 8;\n                    select_move();\n                    break;\n                }\n                if (la[i] == 1 + 3 / 8) {\n                    s = 1 / 8;\n                    select_move();\n                    break;\n                }\n            } while (++i <= 76) ;\n            if (i <= 76)\n                continue;\n\n            for (k = 1; k <= 18; k++) {\n                p = 0;\n                for (i = 4 * k - 3; i <= 4 * k; i++) {\n                    for (j = 1; j <= 4; j++)\n                        p += xa[ma[i][j]];\n                }\n                if (p == 4 || p == 9) {\n                    s = 1 / 8;\n                    for (i = 4 * k - 3; i <= 4 * k; i++) {\n                        if (select_move())\n                            break;\n                    }\n                    s = 0;\n                }\n            }\n            if (k <= 18)\n                continue\n            process_board();\n            z = 1;\n            do {\n                if (xa[ya[z]] == 0)\n                    break;\n            } while (++z < 17) ;\n            if (z >= 17) {\n                for (i = 1; i <= 64; i++) {\n                    if (xa[i] == 0) {\n                        xa[i] = 5;\n                        m = i;\n                        print(\"MACHINE LIKES\");\n                        break;\n                    }\n                }\n                if (i > 64) {\n                    print(\"THE GAME IS A DRAW.\\n\");\n                    break;\n                }\n            } else {\n                m = ya[z];\n                xa[m] = 5;\n                print(\"MACHINE MOVES TO\");\n            }\n            show_square(m);\n        }\n        print(\" \\n\");\n        print(\"DO YOU WANT TO TRY ANOTHER GAME\");\n        while (1) {\n            str = await input();\n            str = str.substr(0, 1);\n            if (str == \"Y\" || str == \"N\")\n                break;\n            print(\"INCORRECT ANSWER. PLEASE TYPE 'YES' OR 'NO'\");\n        }\n        if (str == \"N\")\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/python/qubit.py",
    "content": "#!/usr/bin/env python3\n\n# Ported from the BASIC source for 3D Tic Tac Toe\n# in BASIC Computer Games, by David H. Ahl\n# The code originated from Dartmouth College\n\nfrom enum import Enum\nfrom typing import Optional, Tuple, Union\n\n\nclass Move(Enum):\n    \"\"\"Game status and types of machine move\"\"\"\n\n    HUMAN_WIN = 0\n    MACHINE_WIN = 1\n    DRAW = 2\n    MOVES = 3\n    LIKES = 4\n    TAKES = 5\n    GET_OUT = 6\n    YOU_FOX = 7\n    NICE_TRY = 8\n    CONCEDES = 9\n\n\nclass Player(Enum):\n    EMPTY = 0\n    HUMAN = 1\n    MACHINE = 2\n\n\nclass TicTacToe3D:\n    \"\"\"The game logic for 3D Tic Tac Toe and the machine opponent\"\"\"\n\n    def __init__(self) -> None:\n        # 4x4x4 board keeps track of which player occupies each place\n        # and used by machine to work out its strategy\n        self.board = [0] * 64\n\n        # starting move\n        self.corners = [0, 48, 51, 3, 12, 60, 63, 15, 21, 38, 22, 37, 25, 41, 26, 42]\n\n        # lines to check for end game\n        self.lines = [\n            [0, 1, 2, 3],\n            [4, 5, 6, 7],\n            [8, 9, 10, 11],\n            [12, 13, 14, 15],\n            [16, 17, 18, 19],\n            [20, 21, 22, 23],\n            [24, 25, 26, 27],\n            [28, 29, 30, 31],\n            [32, 33, 34, 35],\n            [36, 37, 38, 39],\n            [40, 41, 42, 43],\n            [44, 45, 46, 47],\n            [48, 49, 50, 51],\n            [52, 53, 54, 55],\n            [56, 57, 58, 59],\n            [60, 61, 62, 63],\n            [0, 16, 32, 48],\n            [4, 20, 36, 52],\n            [8, 24, 40, 56],\n            [12, 28, 44, 60],\n            [1, 17, 33, 49],\n            [5, 21, 37, 53],\n            [9, 25, 41, 57],\n            [13, 29, 45, 61],\n            [2, 18, 34, 50],\n            [6, 22, 38, 54],\n            [10, 26, 42, 58],\n            [14, 30, 46, 62],\n            [3, 19, 35, 51],\n            [7, 23, 39, 55],\n            [11, 27, 43, 59],\n            [15, 31, 47, 63],\n            [0, 4, 8, 12],\n            [16, 20, 24, 28],\n            [32, 36, 40, 44],\n            [48, 52, 56, 60],\n            [1, 5, 9, 13],\n            [17, 21, 25, 29],\n            [33, 37, 41, 45],\n            [49, 53, 57, 61],\n            [2, 6, 10, 14],\n            [18, 22, 26, 30],\n            [34, 38, 42, 46],\n            [50, 54, 58, 62],\n            [3, 7, 11, 15],\n            [19, 23, 27, 31],\n            [35, 39, 43, 47],\n            [51, 55, 59, 63],\n            [0, 5, 10, 15],\n            [16, 21, 26, 31],\n            [32, 37, 42, 47],\n            [48, 53, 58, 63],\n            [12, 9, 6, 3],\n            [28, 25, 22, 19],\n            [44, 41, 38, 35],\n            [60, 57, 54, 51],\n            [0, 20, 40, 60],\n            [1, 21, 41, 61],\n            [2, 22, 42, 62],\n            [3, 23, 43, 63],\n            [48, 36, 24, 12],\n            [49, 37, 25, 13],\n            [50, 38, 26, 14],\n            [51, 39, 27, 15],\n            [0, 17, 34, 51],\n            [4, 21, 38, 55],\n            [8, 25, 42, 59],\n            [12, 29, 46, 63],\n            [48, 33, 18, 3],\n            [52, 37, 22, 7],\n            [56, 41, 26, 11],\n            [60, 45, 30, 15],\n            [0, 21, 42, 63],\n            [15, 26, 37, 48],\n            [3, 22, 41, 60],\n            [12, 25, 38, 51],\n        ]\n\n    def get(self, x, y, z) -> Player:\n        m = self.board[4 * (4 * z + y) + x]\n        if m == 40:\n            return Player.MACHINE\n        elif m == 8:\n            return Player.HUMAN\n        else:\n            return Player.EMPTY\n\n    def move_3d(self, x, y, z, player) -> bool:\n        m = 4 * (4 * z + y) + x\n        return self.move(m, player)\n\n    def move(self, m, player) -> bool:\n        if self.board[m] > 1:\n            return False\n\n        self.board[m] = 40 if player == Player.MACHINE else 8\n        return True\n\n    def get_3d_position(self, m) -> Tuple[int, int, int]:\n        x = m % 4\n        y = (m // 4) % 4\n        z = m // 16\n        return x, y, z\n\n    def evaluate_lines(self) -> None:\n        self.lineValues = [0] * 76\n        for j in range(76):\n            value = sum(self.board[self.lines[j][k]] for k in range(4))\n            self.lineValues[j] = value\n\n    def strategy_mark_line(self, i) -> None:\n        for j in range(4):\n            m = self.lines[i][j]\n            if self.board[m] == 0:\n                self.board[m] = 1\n\n    def clear_strategy_marks(self) -> None:\n        for i in range(64):\n            if self.board[i] == 1:\n                self.board[i] = 0\n\n    def mark_and_move(self, vlow, vhigh, vmove) -> Optional[Tuple[Move, int]]:\n        \"\"\"\n        mark lines that can potentially win the game for the human\n        or the machine and choose best place to play\n        \"\"\"\n        for i in range(76):\n            value = sum(self.board[self.lines[i][j]] for j in range(4))\n            self.lineValues[i] = value\n            if vlow <= value < vhigh:\n                if value > vlow:\n                    return self.move_triple(i)\n                self.strategy_mark_line(i)\n        self.evaluate_lines()\n\n        for i in range(76):\n            value = self.lineValues[i]\n            if value in [4, vmove]:\n                return self.move_diagonals(i, 1)\n        return None\n\n    def machine_move(self) -> Union[None, Tuple[Move, int], Tuple[Move, int, int]]:\n        \"\"\"machine works out what move to play\"\"\"\n        self.clear_strategy_marks()\n\n        self.evaluate_lines()\n        for value, event in [\n            (32, self.human_win),\n            (120, self.machine_win),\n            (24, self.block_human_win),\n        ]:\n            for i in range(76):\n                if self.lineValues[i] == value:\n                    return event(i)\n\n        m = self.mark_and_move(80, 88, 43)\n        if m is not None:\n            return m\n\n        self.clear_strategy_marks()\n\n        m = self.mark_and_move(16, 24, 11)\n        if m is not None:\n            return m\n\n        for k in range(18):\n            value = 0\n            for i in range(4 * k, 4 * k + 4):\n                for j in range(4):\n                    value += self.board[self.lines[i][j]]\n            if (32 <= value < 40) or (72 <= value < 80):\n                for s in [1, 0]:\n                    for i in range(4 * k, 4 * k + 4):\n                        m = self.move_diagonals(i, s)\n                        if m is not None:\n                            return m\n\n        self.clear_strategy_marks()\n\n        for y in self.corners:\n            if self.board[y] == 0:\n                return (Move.MOVES, y)\n\n        return next(\n            ((Move.LIKES, i) for i in range(64) if self.board[i] == 0),\n            (Move.DRAW, -1),\n        )\n\n    def human_win(self, i) -> Tuple[Move, int, int]:\n        return (Move.HUMAN_WIN, -1, i)\n\n    def machine_win(self, i) -> Optional[Tuple[Move, int, int]]:\n        for j in range(4):\n            m = self.lines[i][j]\n            if self.board[m] == 0:\n                return (Move.MACHINE_WIN, m, i)\n        return None\n\n    def block_human_win(self, i) -> Optional[Tuple[Move, int]]:\n        for j in range(4):\n            m = self.lines[i][j]\n            if self.board[m] == 0:\n                return (Move.NICE_TRY, m)\n        return None\n\n    def move_triple(self, i) -> Tuple[Move, int]:\n        \"\"\"make two lines-of-3 or prevent human from doing this\"\"\"\n        for j in range(4):\n            m = self.lines[i][j]\n            if self.board[m] == 1:\n                return (Move.YOU_FOX, m) if self.lineValues[i] < 40 else (Move.GET_OUT, m)\n        return (Move.CONCEDES, -1)\n\n    # choose move in corners or center boxes of square 4x4\n    def move_diagonals(self, i, s) -> Optional[Tuple[Move, int]]:\n        jrange = [1, 2] if 0 < (i % 4) < 3 else [0, 3]\n        for j in jrange:\n            m = self.lines[i][j]\n            if self.board[m] == s:\n                return (Move.TAKES, m)\n        return None\n\n\nclass Qubit:\n    def move_code(self, board, m) -> str:\n        x, y, z = board.get_3d_position(m)\n        return f\"{z + 1:d}{y + 1:d}{x + 1:d}\"\n\n    def show_win(self, board, i) -> None:\n        for m in board.lines[i]:\n            print(self.move_code(board, m))\n\n    def show_board(self, board) -> None:\n        c = \" YM\"\n        for z in range(4):\n            for y in range(4):\n                print(\"   \" * y, end=\"\")\n                for x in range(4):\n                    p = board.get(x, y, z)\n                    print(f\"({c[p.value]})      \", end=\"\")\n                print(\"\\n\")\n            print(\"\\n\")\n\n    def human_move(self, board) -> bool:\n        print()\n        c = \"1234\"\n        while True:\n            h = input(\"Your move?\\n\")\n            if h == \"1\":\n                return False\n            if h == \"0\":\n                self.show_board(board)\n                continue\n            if (len(h) == 3) and (h[0] in c) and (h[1] in c) and (h[2] in c):\n                x = c.find(h[2])\n                y = c.find(h[1])\n                z = c.find(h[0])\n                if board.move_3d(x, y, z, Player.HUMAN):\n                    break\n\n                print(\"That square is used. Try again.\")\n            else:\n                print(\"Incorrect move. Retype it--\")\n\n        return True\n\n    def play(self) -> None:\n        print(\"Qubic\\n\")\n        print(\"Create Computing Morristown, New Jersey\\n\\n\\n\")\n        while True:\n            c = input(\"Do you want instructions?\\n\")\n            if len(c) >= 1 and (c[0] in \"ynYN\"):\n                break\n            print(\"Incorrect answer. Please type 'yes' or 'no.\")\n\n        c = c.lower()\n        if c[0] == \"y\":\n            print(\"The game is Tic-Tac-Toe in a 4 x 4 x 4 cube.\")\n            print(\"Each move is indicated by a 3 digit number, with each\")\n            print(\"digit between 1 and 4 inclusive.  The digits indicate the\")\n            print(\"level, row, and column, respectively, of the occupied\")\n            print(\"place.\\n\")\n\n            print(\"To print the playing board, type 0 (zero) as your move.\")\n            print(\"The program will print the board with your moves indicated\")\n            print(\"with a (Y), the machine's moves with an (M), and\")\n            print(\"unused squares with a ( ).\\n\")\n\n            print(\"To stop the program run, type 1 as your move.\\n\\n\")\n\n        play_again = True\n        while play_again:\n            board = TicTacToe3D()\n\n            while True:\n                s = input(\"Do you want to move first?\\n\")\n                if len(s) >= 1 and (s[0] in \"ynYN\"):\n                    break\n                print(\"Incorrect answer. Please type 'yes' or 'no'.\")\n\n            skip_human = s[0] in \"nN\"\n\n            move_text = [\n                \"Machine moves to\",\n                \"Machine likes\",\n                \"Machine takes\",\n                \"Let's see you get out of this:  Machine moves to\",\n                \"You fox.  Just in the nick of time, machine moves to\",\n                \"Nice try. Machine moves to\",\n            ]\n\n            while True:\n                if not skip_human and not self.human_move(board):\n                    break\n                skip_human = False\n\n                m = board.machine_move()\n                assert m is not None\n                if m[0] == Move.HUMAN_WIN:\n                    print(\"You win as follows,\")\n                    self.show_win(board, m[2])  # type: ignore\n                    break\n                elif m[0] == Move.MACHINE_WIN:\n                    print(f\"Machine moves to {self.move_code(board, m[1])}, and wins as follows\")\n                    self.show_win(board, m[2])  # type: ignore\n                    break\n                elif m[0] == Move.DRAW:\n                    print(\"The game is a draw.\")\n                    break\n                elif m[0] == Move.CONCEDES:\n                    print(\"Machine concedes this game.\")\n                    break\n                else:\n                    print(move_text[m[0].value - Move.MOVES.value])\n                    print(self.move_code(board, m[1]))\n                    board.move(m[1], Player.MACHINE)\n\n                self.show_board(board)\n\n            print(\" \")\n            while True:\n                x = input(\"Do you want to try another game\\n\")\n                if len(x) >= 1 and x[0] in \"ynYN\":\n                    break\n                print(\"Incorrect answer. Please Type 'yes' or 'no'.\")\n\n            play_again = x[0] in \"yY\"\n\n\nif __name__ == \"__main__\":\n    game = Qubit()\n    game.play()\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/qubit.bas",
    "content": "50 PRINT CHR$(26):REM WIDTH 80\n100 PRINT TAB(33);\"QUBIC\":PRINT\n110 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n120 PRINT:PRINT:PRINT\n210 PRINT \"DO YOU WANT INSTRUCTIONS\";\n220 INPUT C$\n230 IF LEFT$(C$,1)=\"N\" THEN 315\n240 IF LEFT$(C$,1)=\"Y\" THEN 265\n250 PRINT \"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'\";\n260 GOTO 220\n265 PRINT\n270 PRINT \"THE GAME IS TIC-TAC-TOE IN A 4 X 4 X 4 CUBE.\"\n280 PRINT \"EACH MOVE IS INDICATED BY A 3 DIGIT NUMBER, WITH EACH\"\n290 PRINT \"DIGIT BETWEEN 1 AND 4 INCLUSIVE.  THE DIGITS INDICATE THE\"\n300 PRINT \"LEVEL, ROW, AND COLUMN, RESPECTIVELY, OF THE OCCUPIED\"\n305 PRINT \"PLACE.  \"\n306 PRINT\n307 PRINT \"TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE.\"\n308 PRINT \"THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-\"\n309 PRINT \"CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND\"\n310 PRINT \"UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER.\"\n311 PRINT\n312 PRINT \"TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE.\"\n313 PRINT:PRINT\n315 DIM X(64),L(76),M(76,4),Y(16)\n320 FOR I = 1 TO 16\n330 READ Y(I)\n340 NEXT I\n350 FOR I=1 TO 76\n360 FOR J = 1 TO 4\n370 READ M(I,J)\n380 NEXT J\n390 NEXT I\n400 FOR I = 1 TO 64\n410 LET X (I) =0\n420 NEXT I\n430 LET Z=1\n440 PRINT \"DO YOU WANT TO MOVE FIRST\";\n450 INPUT S$\n460 IF LEFT$(S$,1)=\"N\" THEN 630\n470 IF LEFT$(S$,1)=\"Y\" THEN 500\n480 PRINT \"INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'.\";\n490 GOTO 450\n500 PRINT \" \"\n510 PRINT \"YOUR MOVE\";\n520 INPUT J1\n521 IF J1=1 THEN 2770\n522 IF J1<>0 THEN 525\n523 GOSUB 2550\n524 GOTO 500\n525 IF J1<111 THEN 2750\n526 IF J1>444 THEN 2750\n530 GOSUB 2500\n540 LET K1=INT(J1/100)\n550 LET J2=(J1-K1*100)\n560 LET K2=INT(J2/10)\n570 LET K3= J1 - K1*100 -K2*10\n580 LET M=16*K1+4*K2+K3-20\n590 IF X(M)=0 THEN 620\n600 PRINT \"THAT SQUARE IS USED, TRY AGAIN.\"\n610 GOTO 500\n620 LET X(M)=1\n630 GOSUB 1640\n640 J=1\n650 I=1\n660 IF J=1 THEN 720\n670 IF J=2 THEN 790\n680 IF J=3 THEN 930\n690 I=I+1: IF I<=76 THEN 660\n700 J=J+1: IF J<=3 THEN 650\n710 GOTO 1300\n720 IF L(I)<>4 THEN 690\n730 PRINT \"YOU WIN AS FOLLOWS\";\n740 FOR J=1 TO 4\n750 LET M=M(I,J)\n760 GOSUB 1570\n770 NEXT J\n780 GOTO 1490\n790 IF L(I)<>15 THEN 690\n800 FOR J=1 TO 4\n810 LET M=M(I,J)\n820 IF X(M)<>0 THEN 860\n830 LET X(M)=5\n840 PRINT \"MACHINE MOVES TO\";\n850 GOSUB 1570\n860 NEXT J\n870 PRINT \", AND WINS AS FOLLOWS\"\n880 FOR J=1 TO 4\n890 LET M=M(I,J)\n900 GOSUB 1570\n910 NEXT J\n920 GOTO 1490\n930 IF L(I)<>3 THEN 690\n940 PRINT \"NICE TRY. MACHINE MOVES TO\";\n950 FOR J=1 TO 4\n960 LET M=M(I,J)\n970 IF X(M)<>0 THEN 1010\n980 LET X(M)=5\n990 GOSUB 1570\n1000 GOTO 500\n1010 NEXT J\n1020 GOTO 1300\n1030 I=1\n1040 LET L(I)=X(M(I,1))+X(M(I,2))+X(M(I,3))+X(M(I,4))\n1050 LET L = L(I)\n1060 IF L <2 THEN 1130\n1070 IF L>=3 THEN 1130\n1080 IF L>2 THEN 2230\n1090 FOR J = 1 TO 4\n1100 IF X(M(I,J))<>0 THEN 1120\n1110 LET X(M(I,J))=1/8\n1120 NEXT J\n1130 I=I+1: IF I<=76 THEN 1040\n1140 GOSUB 1640\n1150 I=1\n1160 IF L(I)=1/2 THEN 2360\n1170 IF L(I)=1+3/8 THEN 2360\n1180 I=I+1: IF I<=76 THEN 1160\n1190 GOTO 1830\n1200 LET Z = 1\n1210 IF X(Y(Z))=0 THEN 1250\n1220 LET Z=Z+1\n1230 IF Z<>17 THEN 1210\n1240 GOTO 1720\n1250 LET M=Y(Z)\n1260 LET X(M)=5\n1270 PRINT \"MACHINE MOVES TO\";\n1280 GOSUB 1570\n1290 GOTO 500\n1300 LET X=X\n1310 I=1\n1320 LET L(I)=X(M(I,1))+X(M(I,2))+X(M(I,3))+X(M(I,4))\n1330 LET L=L(I)\n1340 IF L<10 THEN 1410\n1350 IF L>=11 THEN 1410\n1360 IF L>10 THEN 2230\n1370 FOR J=1 TO 4\n1380 IF X(M(I,J))<>0 THEN 1400\n1390 LET X(M(I,J))=1/8\n1400 NEXT J\n1410 I=I+1: IF I<=76 THEN 1320\n1420 GOSUB 1640\n1430 I=1\n1440 IF L(I)=.5 THEN 2360\n1450 IF L(I)=5+3/8 THEN 2360\n1460 I=I+1: IF I<=76 THEN 1440\n1470 GOSUB 2500\n1480 GOTO 1030\n1490 PRINT \" \"\n1500 PRINT \"DO YOU WANT TO TRY ANOTHER GAME\";\n1510 INPUT X$\n1520 IF LEFT$(X$,1)=\"Y\" THEN 400\n1530 IF LEFT$(X$,1)=\"N\" THEN 1560\n1540 PRINT \"INCORRECT ANSWER. PLEASE TYPE 'YES' OR 'NO'\";\n1550 GOTO 1510\n1560 END\n1570 LET K1=INT((M-1)/16)+1\n1580 LET J2=M-16*(K1-1)\n1590 LET K2=INT((J2-1)/4)+1\n1600 LET K3=M-(K1-1)*16-(K2-1)*4\n1610 LET M=K1*100+K2*10+K3\n1620 PRINT M;\n1630 RETURN\n1640 FOR S=1 TO 76\n1650 LET J1 = M(S,1)\n1660 LET J2=M(S,2)\n1670 LET J3=M(S,3)\n1680 LET J4=M(S,4)\n1690 LET L(S)=X(J1)+X(J2)+X(J3)+X(J4)\n1700 NEXT S\n1710 RETURN\n1720 FOR I=1 TO 64\n1730 IF X(I)<>0 THEN 1800\n1740 LET X(I)=5\n1750 LET M=I\n1760 PRINT \"MACHINE LIKES\";\n1770 GOSUB 1570\n1780 PRINT \" \"\n1790 GOTO 500\n1800 NEXT I\n1810 PRINT \"THE GAME IS A DRAW.\"\n1820 GOTO 1490\n1830 FOR K=1 TO 18\n1840 LET P=0\n1850 FOR I=4*K-3 TO 4*K\n1860 FOR J=1 TO 4\n1870 LET P=P+X(M(I,J))\n1880 NEXT J\n1890 NEXT I\n1900 IF P<4 THEN 1940\n1910 IF P<5 THEN 1970\n1920 IF P<9 THEN 1940\n1930 IF P<10 THEN 1970\n1940 NEXT K\n1950 GOSUB 2500\n1960 GOTO 1200\n1970 LET S=1/8\n1980 FOR I=4*K-3 TO 4*K\n1990 GOTO 2370\n2000 NEXT I\n2010 LET S=0\n2020 GOTO 1980\n2030 DATA 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43\n2040 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20\n2050 DATA 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38\n2060 DATA 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56\n2070 DATA 57,58,59,60,61,62,63,64\n2080 DATA 1,17,33,49,5,21,37,53,9,25,41,57,13,29,45,61\n2090 DATA 2,18,34,50,6,22,38,54,10,26,42,58,14,30,46,62\n2100 DATA 3,19,35,51,7,23,39,55,11,27,43,59,15,31,47,63\n2110 DATA 4,20,36,52,8,24,40,56,12,28,44,60,16,32,48,64\n2120 DATA 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61\n2130 DATA 2,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62\n2140 DATA 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63\n2150 DATA 4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64\n2160 DATA 1,6,11,16,17,22,27,32,33,38,43,48,49,54,59,64\n2170 DATA 13,10,7,4,29,26,23,20,45,42,39,36,61,58,55,52\n2180 DATA 1,21,41,61,2,22,42,62,3,23,43,63,4,24,44,64\n2190 DATA 49,37,25,13,50,38,26,14,51,39,27,15,52,40,28,16\n2200 DATA 1,18,35,52,5,22,39,56,9,26,43,60,13,30,47,64\n2210 DATA 49,34,19,4,53,38,23,8,57,42,27,12,61,46,31,16\n2220 DATA 1,22,43,64,16,27,38,49,4,23,42,61,13,26,39,52\n2230 FOR J=1 TO 4\n2240 IF X(M(I,J))<>1/8 THEN 2330\n2250 LET X(M(I,J))=5\n2260 IF L(I)<5 THEN 2290\n2270 PRINT \"LET'S SEE YOU GET OUT OF THIS:  MACHINE MOVES TO\";\n2280 GOTO 2300\n2290 PRINT \"YOU FOX.  JUST IN THE NICK OF TIME, MACHINE MOVES TO\";\n2300 LET M=M(I,J)\n2310 GOSUB 1570\n2320 GOTO 500\n2330 NEXT J\n2340 PRINT \"MACHINE CONCEDES THIS GAME.\"\n2350 GOTO 1490\n2360 LET S=1/8\n2370 IF I-INT(I/4)*4>1 THEN 2400\n2380 LET A=1\n2390 GOTO 2410\n2400 LET A=2\n2410 FOR J=A TO 5-A STEP 5-2*A\n2420 IF X(M(I,J))=S THEN 2450\n2430 NEXT J\n2440 GOTO 2000\n2450 LET X(M(I,J))=5\n2460 LET M=M(I,J)\n2470 PRINT \"MACHINE TAKES\";\n2480 GOSUB 1570\n2490 GOTO 500\n2500 FOR I=1 TO 64\n2510 IF X(I)<>1/8 THEN 2530\n2520 LET X(I)=0\n2530 NEXT I\n2540 RETURN\n2550 FOR XX=1 TO 9:PRINT:NEXT:FOR I=1 TO 4\n2560 FOR J=1 TO 4\n2562 FOR I1=1 TO J\n2564 PRINT\"   \";\n2566 NEXT I1\n2570 FOR K=1 TO 4\n2600 LET Q=16*I+4*J+K-20\n2610 IF X(Q)<>O THEN 2630\n2620 PRINT\"( )      \";\n2630 IF X(Q)<>5 THEN 2650\n2640 PRINT\"(M)      \";\n2650 IF X(Q)<>1 THEN 2660\n2655 PRINT\"(Y)      \";\n2660 IF X(Q)<>1/8 THEN 2670\n2665 PRINT\"( )      \";\n2670 NEXT K\n2680 PRINT\n2690 PRINT\n2700 NEXT J\n2710 PRINT\n2720 PRINT\n2730 NEXT I\n2735 REM PRINT CHR$(12)\n2740 RETURN\n2750 PRINT\"INCORRECT MOVE, RETYPE IT--\";\n2760 GOTO 520\n2770 END\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"ThreeDTicTacToe\", \"ThreeDTicTacToe.vbproj\", \"{AD17E9E0-4795-4533-A215-09DD99F7D696}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AD17E9E0-4795-4533-A215-09DD99F7D696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AD17E9E0-4795-4533-A215-09DD99F7D696}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AD17E9E0-4795-4533-A215-09DD99F7D696}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AD17E9E0-4795-4533-A215-09DD99F7D696}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>ThreeDTicTacToe</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "89_Tic-Tac-Toe/README.md",
    "content": "### Tic-Tac-Toe\n\nThe game of tic-tac-toe hardly needs any introduction. In this one, you play versus the computer. Moves are entered by number:\n```\n1   2   3\n\n4   5   6\n\n7   8   9\n```\n\nIf you make any bad moves, the computer will win; if the computer makes a bad move, you can win; otherwise, the game ends in a tie.\n\nA second version of the game is included which prints out the board after each move. This is ideally suited to a CRT terminal, particularly if you modify it to not print out a new board after each move, but rather use the cursor to make the move.\n\nThe first program was written by Tom Koos while a student researcher at the Oregon Museum of Science and Industry; it was extensively modified by Steve North of Creative Computing. The author of the second game is Curt Flick of Akron, Ohio.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=171)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=186)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/csharp/TicTacToe.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"tictactoe1\", \"tictactoe1\\tictactoe1.csproj\", \"{E0AF55BF-4C2B-41C6-B556-E8EC8C1BE647}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"tictactoe2\", \"tictactoe2\\tictactoe2.csproj\", \"{B98682C9-132E-44F1-B288-8BE04CF53BCF}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E0AF55BF-4C2B-41C6-B556-E8EC8C1BE647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E0AF55BF-4C2B-41C6-B556-E8EC8C1BE647}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E0AF55BF-4C2B-41C6-B556-E8EC8C1BE647}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E0AF55BF-4C2B-41C6-B556-E8EC8C1BE647}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B98682C9-132E-44F1-B288-8BE04CF53BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B98682C9-132E-44F1-B288-8BE04CF53BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B98682C9-132E-44F1-B288-8BE04CF53BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B98682C9-132E-44F1-B288-8BE04CF53BCF}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs",
    "content": "﻿// See https://aka.ms/new-console-template for more information\n// Print text on the screen with 30 spaces before text\nConsole.WriteLine(\"TIC TAC TOE\".PadLeft(30));\n// Print text on screen with 15 spaces before text\nConsole.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".PadLeft(15));\n// Print three blank lines on screen\nConsole.WriteLine(\"\\n\\n\\n\");\n// THIS PROGRAM PLAYS TIC TAC TOE\n// THE MACHINE GOES FIRST\nConsole.WriteLine(\"THE GAME BOARD IS NUMBERED:\\n\");\nConsole.WriteLine(\"1  2  3\");\nConsole.WriteLine(\"8  9  4\");\nConsole.WriteLine(\"7  6  5\");\n\n// Main program\nwhile(true) {\n\tint a, b, c, d, e;\n\tint p, q, r, s;\n\ta = 9;\n\tConsole.WriteLine(\"\\n\\n\");\n\tcomputerMoves(a);\n\tp = readYourMove();\n\tb = move(p + 1);\n\tcomputerMoves(b);\n\tq = readYourMove();\n\tif (q == move(b + 4)) {\n\t\tc = move(b + 2);\n\t\tcomputerMoves(c);\n\t\tr = readYourMove();\n\t\tif (r == move(c + 4)) {\n\t\t\tif (p % 2 != 0) {\n\t\t\t\td = move(c + 3);\n\t\t\t\tcomputerMoves(d);\n\t\t\t\ts = readYourMove();\n\t\t\t\tif (s == move(d + 4)) {\n\t\t\t\t\te = move(d + 6);\n\t\t\t\t\tcomputerMoves(e);\n\t\t\t\t\tConsole.WriteLine(\"THE GAME IS A DRAW.\");\n\t\t\t\t} else {\n\t\t\t\t\te = move(d + 4);\n\t\t\t\t\tcomputerMoves(e);\n\t\t\t\t\tConsole.WriteLine(\"AND WINS ********\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\td = move(c + 7);\n\t\t\t\tcomputerMoves(d);\n\t\t\t\tConsole.WriteLine(\"AND WINS ********\");\n\t\t\t}\n\t\t} else {\n\t\t\td = move(c + 4);\n\t\t\tcomputerMoves(d);\n\t\t\tConsole.WriteLine(\"AND WINS ********\");\n\t\t}\n\t} else {\n\t\tc = move(b + 4);\n\t\tcomputerMoves(c);\n\t\tConsole.WriteLine(\"AND WINS ********\");\n\t}\n}\n\nvoid computerMoves(int move) {\n\t\tConsole.WriteLine(\"COMPUTER MOVES \" + move);\n}\nint readYourMove() {\n\twhile(true) {\n\t\tConsole.Write(\"YOUR MOVE?\");\n\t\tstring input = Console.ReadLine();\n\t\tif (int.TryParse(input, out int number)) {\n\t\t\treturn number;\n\t\t}\n\t}\n}\n\nint move(int number) {\n\treturn number - 8 * (int)((number - 1) / 8);\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "89_Tic-Tac-Toe/csharp/tictactoe2/Program.cs",
    "content": "﻿// See https://aka.ms/new-console-template for more information\nchar[] board = new char[10];\nchar human;\nchar computer;\nint move = 0;\nchar result;\nfor(;;){\n    // Print text on the screen with 30 spaces before text\n    Console.WriteLine(\"TIC TAC TOE\".PadLeft(30));\n    // Print text on screen with 15 spaces before text\n    Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".PadLeft(15));\n    // THIS PROGRAM PLAYS TIC TAC TOE\n    Console.WriteLine(\"THE BOARD IS NUMBERED:\");\n    Console.WriteLine(\"1  2  3\");\n    Console.WriteLine(\"4  5  6\");\n    Console.WriteLine(\"7  8  9\");\n    Console.Write(\"\\n\\nDO YOU WANT 'X' OR 'O'\");\n    var key = Console.ReadKey();\n\tConsole.WriteLine();\n\t// cleanup the board\n\tfor(int i=0; i < 10; i++) {\n\t\tboard[i]=' ';\n\t}\n\t// X GOES FIRST\n    if (key.Key == ConsoleKey.X) {\n\t\thuman = 'X';\n\t\tcomputer = 'O';\n\t\tmove = readYourMove();\n\t\tboard[move] = human;\n\t\tprintBoard();\n    } else {\n\t\thuman = 'O';\n\t\tcomputer = 'X';\n    }\n\tfor(;;){\n\t\tConsole.WriteLine(\"THE COMPUTER MOVES TO...\");\n\t\tmove = computerMove(move);\n\t\tboard[move] = computer;\n\t\tresult = printBoard();\n\t\tprintResult(result);\n\t\tmove = readYourMove();\n\t\tboard[move] = human;\n\t\tresult = printBoard();\n\t\tprintResult(result);\n\t}\n}\n\nvoid printResult(int result) {\n\tif (result == '\\0') {\n\t\tConsole.WriteLine(\"IT'S A DRAW. THANK YOU.\");\n\t\tEnvironment.Exit(0);\n\t} else if (result == computer) {\n\t\tConsole.WriteLine(\"I WIN, TURKEY!!!\");\n\t\tEnvironment.Exit(0);\n\t} else if (result == human) {\n\t\tConsole.WriteLine(\"YOU BEAT ME!! GOOD GAME.\");\n\t\tEnvironment.Exit(0);\n\t}\n}\nchar printBoard() {\n\tfor (int i=1; i < 10; i++){\n\t\tConsole.Write($\" {board[i]} \");\n\t\tif (i % 3 == 0) {\n\t\t\tif (i < 9) {\n\t\t\t\tConsole.Write(\"\\n---+---+---\\n\");\n\t\t\t} else {\n\t\t\t\tConsole.Write(\"\\n\");\n\t\t\t}\n\t\t} else {\n\t\t\tConsole.Write(\"!\");\n\t\t}\n\t}\n\t// horizontal check\n\tfor (int i = 1; i <= 9; i += 3) {\n\t\tif (board[i] != ' ' && (board[i] == board[i+1]) && (board[i+1] == board[i+2])) {\n\t\t\treturn board[i];\n\t\t}\n\t}\n\t// vertical check\n\tfor (int i = 1; i <= 3; i++) {\n\t\tif (board[i] != ' ' && (board[i] == board[i+3]) && (board[i] == board[i+6])) {\n\t\t\treturn board[i];\n\t\t}\n\t}\n\t// cross\n\tif (board[5] != ' ') {\n\t\tif ((board[1] == board[5] && board[9] == board[5]) || (board[3] == board[5] && board[7] == board[5])) {\n\t\t\treturn board[5];\n\t\t}\n\t}\n\t// draw check\n\tfor (int i = 1; i <= 9; i++) {\n\t\tif (board[i] == ' ') {\n\t\t\treturn ' ';\n\t\t}\n\t}\n\treturn '\\0';\n}\n\nint readYourMove()  {\n\tint number = 0;\n    for(;;) {\n\t\tConsole.Write(\"\\n\\nWHERE DO YOU MOVE? \");\n\t\tvar key = Console.ReadKey();\n        Console.WriteLine();\n\t\tif (key.Key == ConsoleKey.D0) {\n\t\t\tConsole.WriteLine(\"THANKS FOR THE GAME.\");\n            Environment.Exit(0);\n        }\n        if (key.Key >= ConsoleKey.D1 && key.Key <= ConsoleKey.D9) {\n            number = key.Key - ConsoleKey.D0;\n            if (number > 9 || board[number] != ' ') {\n                Console.WriteLine(\"THAT SQUARE IS OCCUPIED.\\n\");\n                continue;\n            }\n        }\n\t\treturn number;\n\t}\n}\n\nint getIndex(int number) {\n\treturn ((number - 1) % 8) + 1; //number - 8 * (int)((number - 1) / 8);\n}\nint computerMove(int lastMove) {\n\tint[] boardMap = new int[] {0, 1, 2, 3, 6, 9, 8, 7, 4, 5};\n\tint index = Array.IndexOf(boardMap, lastMove);\n\tif (lastMove == 0 || board[5] == ' '){\n\t\treturn 5;\n\t}\n\tif (lastMove == 5) {\n\t\treturn 1;\n\t}\n\tif (board[5] == human) {\n\t\t// check possible win\n\t\tif (board[1] == computer && board[2] == ' ' && board[3] == computer) {\n\t\t\treturn 2;\n\t\t}\n\t\tif (board[7] == computer && board[8] == ' ' && board[9] == computer) {\n\t\t\treturn 8;\n\t\t}\n\t\tif (board[1] == computer && board[4] == ' ' && board[7] == computer) {\n\t\t\treturn 4;\n\t\t}\n\t\tif (board[3] == computer && board[6] == ' ' && board[7] == computer) {\n\t\t\treturn 6;\n\t\t}\n\t\t// check cross\n\t\tint crossIndex = boardMap[getIndex(index + 4)];\n\t\tif (board[crossIndex] == ' ') {\n\t\t\treturn crossIndex;\n\t\t}\n\t\tint stepForward2 = boardMap[getIndex(index + 2)];\n\t\tif (board[stepForward2] == ' ') {\n\t\t\treturn stepForward2;\n\t\t}\n\t\tint stepBackward2 = boardMap[getIndex(index + 6)];\n\t\tif (board[stepBackward2] == ' ') {\n\t\t\treturn stepBackward2;\n\t\t}\n\t\tint stepForward1 = boardMap[getIndex(index + 1)];\n\t\tif (board[stepForward1] == ' ') {\n\t\t\treturn stepForward1;\n\t\t}\n\t\tint stepBackward1 = boardMap[getIndex(index + 7)];\n\t\tif (board[stepBackward1] == ' ') {\n\t\t\treturn stepBackward1;\n\t\t}\n\t\tint stepForward3 = boardMap[getIndex(index + 3)];\n\t\tif (board[stepForward3] == ' ') {\n\t\t\treturn stepForward3;\n\t\t}\n\t\tint stepBackward3 = boardMap[getIndex(index + 5)];\n\t\tif (board[stepBackward3] == ' ') {\n\t\t\treturn stepBackward3;\n\t\t}\n\t} else {\n\t\t// check possible win\n\t\tif (board[1] == computer && board[9] == ' ') {\n\t\t\treturn 9;\n\t\t}\n\t\tif (board[9] == computer && board[1] == ' ') {\n\t\t\treturn 1;\n\t\t}\n\t\tif (board[3] == computer && board[7] == ' ') {\n\t\t\treturn 7;\n\t\t}\n\t\tif (board[7] == computer && board[3] == ' ') {\n\t\t\treturn 3;\n\t\t}\n\t\t// if corner\n\t\tif (index % 2 == 1) {\n\t\t\tint stepForward2 = boardMap[getIndex(index + 2)];\n\t\t\tif (board[stepForward2] == ' ') {\n\t\t\t\treturn stepForward2;\n\t\t\t}\n\t\t\tint stepBackward2 = boardMap[getIndex(index + 6)];\n\t\t\tif (board[stepBackward2] == ' ') {\n\t\t\t\treturn stepBackward2;\n\t\t\t}\n\t\t} else {\n\t\t\tint stepForward1 = boardMap[getIndex(index + 1)];\n\t\t\tif (board[stepForward1] == ' ') {\n\t\t\t\treturn stepForward1;\n\t\t\t}\n\t\t\tint stepBackward1 = boardMap[getIndex(index + 7)];\n\t\t\tif (board[stepBackward1] == ' ') {\n\t\t\t\treturn stepBackward1;\n\t\t\t}\n\t\t\tint stepForward3 = boardMap[getIndex(index + 3)];\n\t\t\tif (board[stepForward3] == ' ') {\n\t\t\t\treturn stepForward3;\n\t\t\t}\n\t\t\tint stepBackward3 = boardMap[getIndex(index + 5)];\n\t\t\tif (board[stepBackward3] == ' ') {\n\t\t\t\treturn stepBackward3;\n\t\t\t}\n\t\t\t\t\tint crossIndex = boardMap[getIndex(index + 4)];\n\t\t\tif (board[crossIndex] == ' ') {\n\t\t\t\treturn crossIndex;\n\t\t\t}\n\t\t\tint stepForward2 = boardMap[getIndex(index + 2)];\n\t\t\tif (board[stepForward2] == ' ') {\n\t\t\t\treturn stepForward2;\n\t\t\t}\n\t\t\tint stepBackward2 = boardMap[getIndex(index + 6)];\n\t\t\tif (board[stepBackward2] == ' ') {\n\t\t\t\treturn stepBackward2;\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/csharp/tictactoe2/tictactoe2.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "89_Tic-Tac-Toe/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/java/src/Board.java",
    "content": "/**\n * @author Ollie Hensman-Crook\n */\npublic class Board {\n    private char arr[];\n\n    public Board() {\n        this.arr = new char[9];\n        for (int x = 1; x <= 9; x++) {\n            this.arr[x - 1] = ' ';\n        }\n    }\n\n\n    /**\n     * Place 'X' or 'O' on the board position passed\n     * @param position\n     * @param player\n     */\n    public void setArr(int position, char player) {\n        if (player == 'X') {\n            this.arr[position-1] = 'X';\n        } else {\n            this.arr[position -1] = 'O';\n        }\n    }\n\n    public void printBoard() {\n        System.out.format(\"%-3c ! %-3c ! %-3c\\n----+----+----\\n%-3c ! %-3c ! %-3c\\n----+----+----\\n%-3c ! %-3c ! %-3c\\n\",\n        this.arr[0], this.arr[1], this.arr[2], this.arr[3], this.arr[4], this.arr[5], this.arr[6], this.arr[7], this.arr[8]\n        );\n    }\n\n\n    /**\n     * @param x\n     * @return the value of the char at a given position\n     */\n    public char getBoardValue(int x) {\n        return arr[x-1];\n    }\n\n\n    /**\n     * Go through the board and check for win (horizontal, diagonal, vertical)\n     * @param player\n     * @return whether a win has occured\n     */\n    public boolean checkWin(char player) {\n        if(this.arr[0] == player && this.arr[1] == player && this.arr[2] == player)\n            return true;\n\n\n        if(this.arr[3] == player && this.arr[4] == player && this.arr[5] == player)\n            return true;\n\n\n        if(this.arr[6] == player && this.arr[7] == player && this.arr[8] == player)\n            return true;\n\n        if(this.arr[0] == player && this.arr[4] == player && this.arr[8] == player)\n            return true;\n\n        if(this.arr[2] == player && this.arr[4] == player && this.arr[6] == player)\n            return true;\n\n        if(this.arr[0] == player && this.arr[3] == player && this.arr[6] == player)\n            return true;\n\n        if(this.arr[1] == player && this.arr[4] == player && this.arr[7] == player)\n            return true;\n\n        if(this.arr[2] == player && this.arr[5] == player && this.arr[8] == player)\n            return true;\n\n        return false;\n    }\n    public boolean checkDraw() {\n        if(this.checkWin('X') == false && this.checkWin('O') == false) {\n            if(this.getBoardValue(1) != ' ' && this.getBoardValue(2) != ' ' && this.getBoardValue(3) != ' ' && this.getBoardValue(4) != ' ' && this.getBoardValue(5) != ' ' && this.getBoardValue(6) != ' ' && this.getBoardValue(7) != ' ' && this.getBoardValue(8) != ' ' && this.getBoardValue(9) != ' ' ) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n    /**\n     * Reset the board\n     */\n    public void clear() {\n        for (int x = 1; x <= 9; x++) {\n            this.arr[x - 1] = ' ';\n        }\n    }\n\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/java/src/TicTacToe2.java",
    "content": "import java.util.Scanner;\nimport java.util.Random;\n\n/**\n * @author Ollie Hensman-Crook\n */\npublic class TicTacToe2 {\n    public static void main(String[] args) {\n        Board gameBoard = new Board();\n        Random compChoice = new Random();\n        char yourChar;\n        char compChar;\n        Scanner in = new Scanner(System.in);\n\n        System.out.println(\"              TIC-TAC-TOE\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println(\"\\nTHE BOARD IS NUMBERED: \");\n        System.out.println(\" 1  2  3\\n 4  5  6\\n 7  8  9\\n\");\n\n        while (true) {\n            // ask if the player wants to be X or O and if their input is valid set their\n            // play piece as such\n            System.out.println(\"DO YOU WANT 'X' OR 'O'\");\n            while (true) {\n                try {\n                    char input;\n                    input = in.next().charAt(0);\n\n                    if (input == 'X' || input == 'x') {\n                        yourChar = 'X';\n                        compChar = 'O';\n                        break;\n                    } else if (input == 'O' || input == 'o') {\n                        yourChar = 'O';\n                        compChar = 'X';\n                        break;\n                    } else {\n                        System.out.println(\"THATS NOT 'X' OR 'O', TRY AGAIN\");\n                        in.nextLine();\n                    }\n\n                } catch (Exception e) {\n                    System.out.println(\"THATS NOT 'X' OR 'O', TRY AGAIN\");\n                    in.nextLine();\n                }\n            }\n\n            while (true) {\n                System.out.println(\"WHERE DO YOU MOVE\");\n\n                // check the user can move where they want to and if so move them there\n                while (true) {\n                    int input;\n                    try {\n                        input = in.nextInt();\n                        if (gameBoard.getBoardValue(input) == ' ') {\n                            gameBoard.setArr(input, yourChar);\n                            break;\n                        } else {\n                            System.out.println(\"INVALID INPUT, TRY AGAIN\");\n                        }\n                        in.nextLine();\n                    } catch (Exception e) {\n                        System.out.println(\"INVALID INPUT, TRY AGAIN\");\n                        in.nextLine();\n                    }\n                }\n\n                gameBoard.printBoard();\n                System.out.println(\"THE COMPUTER MOVES TO\");\n\n                while (true) {\n                    int position = 1 + compChoice.nextInt(9);\n                    if (gameBoard.getBoardValue(position) == ' ') {\n                        gameBoard.setArr(position, compChar);\n                        break;\n                    }\n                }\n\n                gameBoard.printBoard();\n\n                // if there is a win print if player won or the computer won and ask if they\n                // want to play again\n                if (gameBoard.checkWin(yourChar)) {\n                    System.out.println(\"YOU WIN, PLAY AGAIN? (Y/N)\");\n                    gameBoard.clear();\n                    while (true) {\n                        try {\n                            char input;\n                            input = in.next().charAt(0);\n\n                            if (input == 'Y' || input == 'y') {\n                                break;\n                            } else if (input == 'N' || input == 'n') {\n                                System.exit(0);\n                            } else {\n                                System.out.println(\"THATS NOT 'Y' OR 'N', TRY AGAIN\");\n                                in.nextLine();\n                            }\n\n                        } catch (Exception e) {\n                            System.out.println(\"THATS NOT 'Y' OR 'N', TRY AGAIN\");\n                            in.nextLine();\n                        }\n                    }\n                    break;\n                } else if (gameBoard.checkWin(compChar)) {\n                    System.out.println(\"YOU LOSE, PLAY AGAIN? (Y/N)\");\n                    gameBoard.clear();\n                    while (true) {\n                        try {\n                            char input;\n                            input = in.next().charAt(0);\n\n                            if (input == 'Y' || input == 'y') {\n                                break;\n                            } else if (input == 'N' || input == 'n') {\n                                System.exit(0);\n                            } else {\n                                System.out.println(\"THATS NOT 'Y' OR 'N', TRY AGAIN\");\n                                in.nextLine();\n                            }\n\n                        } catch (Exception e) {\n                            System.out.println(\"THATS NOT 'Y' OR 'N', TRY AGAIN\");\n                            in.nextLine();\n                        }\n                    }\n                    break;\n                } else if (gameBoard.checkDraw()) {\n                    System.out.println(\"DRAW, PLAY AGAIN? (Y/N)\");\n                    gameBoard.clear();\n                    while (true) {\n                        try {\n                            char input;\n                            input = in.next().charAt(0);\n\n                            if (input == 'Y' || input == 'y') {\n                                break;\n                            } else if (input == 'N' || input == 'n') {\n                                System.exit(0);\n                            } else {\n                                System.out.println(\"THATS NOT 'Y' OR 'N', TRY AGAIN\");\n                                in.nextLine();\n                            }\n\n                        } catch (Exception e) {\n                            System.out.println(\"THATS NOT 'Y' OR 'N', TRY AGAIN\");\n                            in.nextLine();\n                        }\n                    }\n                    break;\n                }\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/javascript/tictactoe1.html",
    "content": "<html>\n<head>\n<title>TIC TAC TOE 1</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"tictactoe1.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "89_Tic-Tac-Toe/javascript/tictactoe1.js",
    "content": "// TIC TAC TOE 1\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nfunction mf(x)\n{\n    return x - 8 * Math.floor((x - 1) / 8);\n}\n\nfunction computer_moves()\n{\n    print(\"COMPUTER MOVES \" + m + \"\\n\");\n}\n\nvar m;\n\n// Main control section\nasync function main()\n{\n    print(tab(30) + \"TIC TAC TOE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    //\n    // This program plays Tic Tac Toe\n    // The machine goes first\n    print(\"THE GAME BOARD IS NUMBERED:\\n\");\n    print(\"\\n\");\n    print(\"1  2  3\\n\");\n    print(\"8  9  4\\n\");\n    print(\"7  6  5\\n\");\n    print(\"\\n\");\n    //\n    // Main program\n    while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        a = 9;\n        m = a;\n\n        computer_moves();\n        print(\"YOUR MOVE\");\n        m = parseInt(await input());\n\n        p = m;\n        b = mf(p + 1);\n        m = b;\n\n        computer_moves();\n        print(\"YOUR MOVE\");\n        m = parseInt(await input());\n\n        q = m;\n        if (q != mf(b + 4)) {\n            c = mf(b + 4);\n            m = c;\n            computer_moves();\n            print(\"AND WINS ********\\n\");\n            continue;\n        }\n\n        c = mf(b + 2);\n        m = c;\n\n        computer_moves();\n        print(\"YOUR MOVE\");\n        m = parseInt(await input());\n\n        r = m;\n        if (r != mf(c + 4)) {\n            d = mf(c + 4);\n            m = d;\n            computer_moves();\n            print(\"AND WINS ********\\n\");\n            continue;\n        }\n\n        if (p % 2 == 0) {\n            d = mf(c + 7);\n            m = d;\n            computer_moves();\n            print(\"AND WINS ********\\n\");\n            continue;\n        }\n\n        d = mf(c + 3);\n        m = d;\n\n        computer_moves();\n        print(\"YOUR MOVE\");\n        m = parseInt(await input());\n\n        s = m;\n        if (s != mf(d + 4)) {\n            e = mf(d + 4);\n            m = e;\n            computer_moves();\n        }\n        e = mf(d + 6);\n        m = e;\n        computer_moves();\n        print(\"THE GAME IS A DRAW.\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "89_Tic-Tac-Toe/javascript/tictactoe2.html",
    "content": "<html>\n<head>\n<title>TIC TAC TOE 2</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"tictactoe2.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "89_Tic-Tac-Toe/javascript/tictactoe2.js",
    "content": "// TIC TAC TOE 2\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar s = [];\n\nfunction who_win(piece)\n{\n    if (piece == -1) {\n        print(\"I WIN, TURKEY!!!\\n\");\n    } else if (piece == 1) {\n        print(\"YOU BEAT ME!! GOOD GAME.\\n\");\n    }\n}\n\nfunction show_board()\n{\n    print(\"\\n\");\n    for (i = 1; i <= 9; i++) {\n        print(\" \");\n        if (s[i] == -1) {\n            print(qs + \" \");\n        } else if (s[i] == 0) {\n            print(\"  \");\n        } else {\n            print(ps + \" \");\n        }\n        if (i == 3 || i == 6) {\n            print(\"\\n\");\n            print(\"---+---+---\\n\");\n        } else if (i != 9) {\n            print(\"!\");\n        }\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 1; i <= 7; i += 3) {\n        if (s[i] && s[i] == s[i + 1] && s[i] == s[i + 2]) {\n            who_win(s[i]);\n            return true;\n        }\n    }\n    for (i = 1; i <= 3; i++) {\n        if (s[i] && s[i] == s[i + 3] && s[i] == s[i + 6]) {\n            who_win(s[i]);\n            return true;\n        }\n    }\n    if (s[1] && s[1] == s[5] && s[1] == s[9]) {\n        who_win(s[1]);\n        return true;\n    }\n    if (s[3] && s[3] == s[5] && s[3] == s[7]) {\n        who_win(s[3]);\n        return true;\n    }\n    for (i = 1; i <= 9; i++) {\n        if (s[i] == 0)\n            break;\n    }\n    if (i > 9) {\n        print(\"IT'S A DRAW. THANK YOU.\\n\");\n        return true;\n    }\n    return false;\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(30) + \"TIC-TAC-TOE\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    for (i = 1; i <= 9; i++)\n        s[i] = 0;\n    print(\"THE BOARD IS NUMBERED:\\n\");\n    print(\" 1  2  3\\n\");\n    print(\" 4  5  6\\n\");\n    print(\" 7  8  9\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"DO YOU WANT 'X' OR 'O'\");\n    str = await input();\n    if (str == \"X\") {\n        ps = \"X\";\n        qs = \"O\";\n        first_time = true;\n    } else {\n        ps = \"O\";\n        qs = \"X\";\n        first_time = false;\n    }\n    while (1) {\n        if (!first_time) {\n            g = -1;\n            h = 1;\n            if (s[5] == 0) {\n                s[5] = -1;\n            } else if (s[5] == 1 && s[1] == 0) {\n                s[1] = -1;\n            } else if (s[5] != 1 && s[2] == 1 && s[1] == 0 || s[5] != 1 && s[4] == 1 && s[1] == 0) {\n                s[1] = -1;\n            } else if (s[5] != 1 && s[6] == 1 && s[9] == 0 || s[5] != 1 && s[8] == 1 && s[9] == 0) {\n                s[9] = -1;\n            } else {\n                while (1) {\n                    played = false;\n                    if (g == 1) {\n                        j = 3 * Math.floor((m - 1) / 3) + 1;\n                        if (3 * Math.floor((m - 1) / 3) + 1 == m)\n                            k = 1;\n                        if (3 * Math.floor((m - 1) / 3) + 2 == m)\n                            k = 2;\n                        if (3 * Math.floor((m - 1) / 3) + 3 == m)\n                            k = 3;\n                    } else {\n                        j = 1;\n                        k = 1;\n                    }\n                    while (1) {\n                        if (s[j] == g) {\n                            if (s[j + 2] == g) {\n                                if (s[j + 1] == 0) {\n                                    s[j + 1] = -1;\n                                    played = true;\n                                    break;\n                                }\n                            } else {\n                                if (s[j + 2] == 0 && s[j + 1] == g) {\n                                    s[j + 2] = -1;\n                                    played = true;\n                                    break;\n                                }\n                            }\n                        } else {\n                            if (s[j] != h && s[j + 2] == g && s[j + 1] == g) {\n                                s[j] = -1;\n                                played = true;\n                                break;\n                            }\n                        }\n                        if (s[k] == g) {\n                            if (s[k + 6] == g) {\n                                if (s[k + 3] == 0) {\n                                    s[k + 3] = -1;\n                                    played = true;\n                                    break;\n                                }\n                            } else {\n                                if (s[k + 6] == 0 && s[k + 3] == g) {\n                                    s[k + 6] = -1;\n                                    played = true;\n                                    break;\n                                }\n                            }\n                        } else {\n                            if (s[k] != h && s[k + 6] == g && s[k + 3] == g) {\n                                s[k] = -1;\n                                played = true;\n                                break;\n                            }\n                        }\n                        if (g == 1)\n                            break;\n                        if (j == 7 && k == 3)\n                            break;\n                        k++;\n                        if (k > 3) {\n                            k = 1;\n                            j += 3;\n                            if (j > 7)\n                                break;\n                        }\n                    }\n                    if (!played) {\n                        if (s[5] == g) {\n                            if (s[3] == g && s[7] == 0) {\n                                s[7] = -1;\n                                played = true;\n                            } else if (s[9] == g && s[1] == 0) {\n                                s[1] = -1;\n                                played = true;\n                            } else if (s[7] == g && s[3] == 0) {\n                                s[3] = -1;\n                                played = true;\n                            } else if (s[9] == 0 && s[1] == g) {\n                                s[9] = -1;\n                                played = true;\n                            }\n                        }\n                        if (!played) {\n                            if (g == -1) {\n                                g = 1;\n                                h = -1;\n                            }\n                        }\n                    }\n                    if (played)\n                        break;\n                }\n                if (!played) {\n                    if (s[9] == 1 && s[3] == 0 && s[1] != 1) {\n                        s[3] = -1;\n                    } else {\n                        for (i = 2; i <= 9; i++) {\n                            if (s[i] == 0) {\n                                s[i] = -1;\n                                break;\n                            }\n                        }\n                        if (i > 9) {\n                            s[1] = -1;\n                        }\n                    }\n                }\n            }\n            print(\"\\n\");\n            print(\"THE COMPUTER MOVES TO...\");\n            if (show_board())\n                break;\n        }\n        first_time = false;\n        while (1) {\n            print(\"\\n\");\n            print(\"WHERE DO YOU MOVE\");\n            m = parseInt(await input());\n            if (m == 0) {\n                print(\"THANKS FOR THE GAME.\\n\");\n                break;\n            }\n            if (m >= 1 && m <= 9 && s[m] == 0)\n                break;\n            print(\"THAT SQUARE IS OCCUPIED.\\n\");\n            print(\"\\n\");\n            print(\"\\n\");\n        }\n        g = 1;\n        s[m] = 1;\n        if (show_board())\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "89_Tic-Tac-Toe/kotlin/Board.kt",
    "content": "/**\n * @author John Long based on Java by Ollie Hensman-Crook\n */\n\nenum class Player(val char: Char) {\n    X('X'),\n    O('O')\n}\n\nclass Board {\n    // Initialize an array of size nine with all values set to null\n    private var boxes: Array<Player?> = arrayOfNulls(9)\n\n    /**\n     * Place 'X' or 'O' on the board position passed\n     * @param position\n     * @param player\n     */\n    fun setArr(position: Int, player: Player) {\n        boxes[position - 1] = player\n    }\n\n    fun printBoard() {\n        System.out.format(\n            \"\"\"\n  %c !  %c !  %c\n----+----+----\n  %c !  %c !  %c\n----+----+----\n  %c !  %c !  %c\n\"\"\",\n            // converts each box to a char and then passes them in order to format\n            // If the person is unassigned, use a space ' '\n     *(boxes.map{it?.char ?: ' '}.toTypedArray()))\n    }\n\n    /**\n     * @param x\n     * @return the value of the char at a given position\n     */\n    fun getBoardValue(x: Int): Player? {\n        return boxes[x - 1]\n    }\n\n    private val winningCombos = listOf(\n        // horizontal\n        listOf(0,1,2),\n        listOf(3,4,5),\n        listOf(6,7,8),\n        // diagonal\n        listOf(0,4,8),\n        listOf(2,4,6),\n        // vertical\n        listOf(0,3,6),\n        listOf(1,4,7),\n        listOf(2,5,8)\n    )\n    /**\n     * Go through the board and check for win\n     * @param player\n     * @return whether a win has occurred\n     */\n    fun isWinFor(player: Player): Boolean {\n        // Check if any winningCombos have all their boxes set to player\n        return winningCombos.any{ combo ->\n            combo.all { boxes[it] == player }\n        }\n    }\n\n    fun isDraw(): Boolean {\n        return !isWinFor(Player.X) && !isWinFor(Player.O) && boxes.all { it != null }\n    }\n\n    /**\n     * Reset the board\n     */\n    fun clear() {\n        boxes = arrayOfNulls(9)\n    }\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/kotlin/TicTacToe2.kt",
    "content": "import java.util.Random\nimport kotlin.system.exitProcess\n\n/**\n * @author John Long based on Java from Ollie Hensman-Crook\n */\nprivate val compChoice = Random()\nprivate val gameBoard = Board()\n\nfun main() {\n    println(\"              TIC-TAC-TOE\")\n    println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    println(\"\\nTHE BOARD IS NUMBERED: \")\n    println(\" 1  2  3\\n 4  5  6\\n 7  8  9\\n\")\n    while (true) {\n        // Let the player choose whether to be X or O (Player.X or Player.O)\n        val (human, computer) = readXOrO()\n        while (true) {\n            // Get a valid move from the user and then move there\n            val validMoveIndex = readValidMove()\n            gameBoard.setArr(validMoveIndex, human)\n            gameBoard.printBoard()\n\n            // Computer randomly fills a square (if the game isn't already over)\n            // This uses Kotlin's null handling and will only set the board\n            // if validRandomMove returned a non-null value\n            validRandomMove()?.let {\n                gameBoard.setArr(it, computer)\n                gameBoard.printBoard()\n            }\n\n            // if there is a win print if player won or the computer won and ask if they\n            // want to play again\n            when {\n                gameBoard.isWinFor(human) -> {\n                    checkPlayAgain(\"YOU WIN\")\n                    break\n                }\n                gameBoard.isWinFor(computer) -> {\n                    checkPlayAgain(\"YOU LOSE\")\n                    break\n                }\n                gameBoard.isDraw() -> {\n                    checkPlayAgain(\"DRAW\")\n                    break\n                }\n            }\n        }\n    }\n}\n\nprivate fun checkPlayAgain(result: String) {\n    println(\"$result, PLAY AGAIN? (Y/N)\")\n    gameBoard.clear()\n    if (!readYesOrNo()) exitProcess(0)\n}\n\nprivate fun readYesOrNo(): Boolean {\n    while (true) {\n        when (readLine()?.get(0)?.uppercaseChar()) {\n            'Y' -> return true\n            'N' -> return false\n            else -> println(\"THAT'S NOT 'Y' OR 'N', TRY AGAIN\")\n        }\n    }\n}\n\nprivate fun validRandomMove(): Int? {\n    if (gameBoard.isDraw() || gameBoard.isWinFor(Player.O) || gameBoard.isWinFor(Player.X)) return null\n    println(\"THE COMPUTER MOVES TO\")\n    // keep generating a random value until we find one that is null (unset)\n    return generateSequence { 1 + compChoice.nextInt(9) }.first { gameBoard.getBoardValue(it) == null }\n}\n\nprivate fun readValidMove(): Int {\n    println(\"WHERE DO YOU MOVE\")\n    while (true) {\n        val input = readln().toIntOrNull()\n        if (input != null && gameBoard.getBoardValue(input) == null) {\n            return input\n        } else {\n            println(\"INVALID INPUT, TRY AGAIN\")\n        }\n    }\n}\n\nprivate fun readXOrO(): Pair<Player, Player> {\n    println(\"DO YOU WANT 'X' OR 'O'\")\n    while (true) {\n        when (readln()[0].uppercaseChar()) {\n            'X' -> return Player.X to Player.O\n            'O' -> return Player.O to Player.X\n            else -> println(\"THAT'S NOT 'X' OR 'O', TRY AGAIN\")\n        }\n    }\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/perl/tictactoe2.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\n#GLOBALs\nmy %board = (\n\t1\t=>\t0,\n\t2\t=>\t0,\n\t3\t=>\t0,\n\t4\t=>\t0,\n\t5\t=>\t0,\n\t6\t=>\t0,\n\t7\t=>\t0,\n\t8\t=>\t0,\n\t9\t=>\t0,\n);\n\nmy %winning_combos = (\n\t1\t=> [1,2,3],\n\t2\t=> [4,5,6],\n\t3\t=> [7,8,9],\n\t4\t=> [1,4,7],\n\t5\t=> [2,5,8],\n\t6\t=> [3,6,9],\n\t7\t=> [1,5,9],\n\t8\t=> [7,5,3],\n);\n\nmy $player=100;\nmy $player_goal=0;\nmy $computer=100;\nmy $computer_goal=0;\nmy $count=0;\n\n&main;\n\nsub main {\n\t&print_intro;\n\tprint \"DO YOU WANT 'X' OR 'O'\\n\";\n\tchomp(my $ans = <STDIN>);\n\t&assign_X_and_O($ans);\n\tif ($ans eq \"X\") {\n\t\tuntil ($count >= 9) {\n\t\t\t&player_choice;\n\t\t\t$count++;\n\t\t\t&print_board;\n\t\t\t&check_for_winners;\n\t\t\t&computer_choice;\n\t\t\t$count++;\n\t\t\t&print_board;\n\t\t\t&check_for_winners;\n\t\t}\n\t}\n\telse {\n\t\tuntil ($count >= 9) {\n\t\t\t&computer_choice;\n\t\t\t$count++;\n\t\t\t&print_board;\n\t\t\t&check_for_winners;\n\t\t\tif ($count >= 9) {\n\t\t\t\tprint \"IT'S A DRAW. THANK YOU.\\n\";\n\t\t\t\texit;\n\t\t\t}\n\t\t\t&player_choice;\n\t\t\t$count++;\n\t\t\t&print_board;\n\t\t\t&check_for_winners;\n\t\t}\n\t}\n\tprint \"IT'S A DRAW. THANK YOU.\\n\";\n\texit;\n}\n\n# This will check to see if anyone has won by adding up the various 3-in-a-row lines.\nsub check_for_winners {\n\tmy %tally;\n\tforeach my $key (keys %winning_combos) {\n\t\tforeach my $val (@{$winning_combos{$key}}) {\n\t\t\t$tally{$key}+=$board{$val};\n\t\t}\n\t}\n\tforeach my $key (keys %tally) {\n\t\tif ($tally{$key} == $player_goal) {\n\t\t\tprint \"YOU BEAT ME!! GOOD GAME.\\n\";\n\t\t\texit;\n\t\t}\n\t\tif ($tally{$key} == $computer_goal) {\n\t\t\tprint \"I WIN, TURKEY!!!\\n\";\n\t\t\texit;\n\t\t}\n\t}\n}\n\n#On the computer's turn it will first check to see if it should block the player.  If it finds it isn't going to win or need to block a player, the it will choose a spot to place it's X or O.\n\nsub computer_choice {\n\tmy $move;\n\t$move=&check_for_blocks_or_wins;;\n\tif ($move > 9) {\n\t\t$move=&check_for_corners;\n\t}\n\tprint \"THE COMPUTER MOVES TO...\\n\";\n\t$board{$move}=$computer;\n}\n\nsub check_for_corners {\n\tmy @precedence;\n\tif ($count == 0) {\n\t\t@precedence=(1,9,7,3,5,2,4,6,8);\n\t}\n\telse {\n\t\t@precedence=(5,2,4,6,8,1,9,7,3);\n\t}\n\tforeach my $move (@precedence) {\n\t\tmy $validity=&check_occupation($move);\n\t\tif ($validity eq \"valid\") {\n\t\t\treturn $move;\n\t\t}\n\t}\n}\n\nsub check_for_blocks_or_wins {\n\tmy %tally;\n\tmy $validity = \"invalid\";\n\tmy $move = 10;\n\tforeach my $key (keys %winning_combos) {\n\t\tforeach my $val (@{$winning_combos{$key}}) {\n\t\t\t$tally{$key}+=$board{$val};\n\t\t}\n\t}\n\tforeach my $key (keys %tally) {\n\t\tif (abs($tally{$key}) == 2) {\n\t\t\tuntil ($validity eq \"valid\") {\n\t\t\t\tforeach my $val (@{$winning_combos{$key}}) {\n\t\t\t\t\t$validity=&check_occupation($val);\n\t\t\t\t\tif ($validity eq \"valid\") {\n\t\t\t\t\t\t$move = $val;\n\t\t\t\t\t\tlast;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $move;\n\t\t}\n\t}\n\treturn $move;\n}\n\nsub player_choice {\n\tmy $validity = \"invalid\";\n\tmy $ans = \"\";\n\tuntil ($validity eq \"valid\") {\n\t\tprint \"WHERE DO YOU MOVE? \";\n\t\tchomp($ans = <STDIN>);\n\t\t$validity=&check_occupation($ans);\n\t\tif ($validity eq \"invalid\") {print \"THAT SQUARE IS OCCUPIED.\\n\\n\"}\n\t}\n\t$board{$ans}=$player;\n}\n\nsub check_occupation {\n\tmy $space = shift;\n\tif ($board{$space}==0) { return \"valid\" }\n\telse {return \"invalid\"};\n}\n\nsub print_board {\n\tforeach my $num (1..9) {\n\t\tmy $char = &which_char($board{$num});\n\t\tif ($num == 4 || $num == 7) { print \"\\n---+---+---\\n\";}\n\t\tprint \"$char\";\n\t\tif ($num % 3 > 0) { print \"!\" }\n\t}\n\tprint \"\\n\";\n}\n\nsub which_char {\n\tmy $val=shift;\n\tif ($val == 0) {return \"   \";}\n\telsif ($val == 1) {return \" X \";}\n\telse {return \" O \";}\n}\n\nsub assign_X_and_O {\n\tmy $ans = shift;\n\tif ($ans eq \"X\") {\n\t\t$player = 1;\n\t\t$computer = -1;\n\t\t$player_goal=3;\n\t\t$computer_goal=-3;\n\t}\n\telse {\n\t\t$player = -1;\n\t\t$computer = 1;\n\t\t$player_goal=-3;\n\t\t$computer_goal=3;\n\t}\n}\n\nsub print_intro {\n\tprint ' ' x 30 . \"TIC-TAC-TOE\\n\";\n\tprint ' ' x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\";\n\tprint \"THE BOARD IS NUMBERED:\\n\";\n\tprint \"1  2  3\\n4  5  6\\n7  8  9\\n\\n\\n\";\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/python/TicTacToe_Hard.py",
    "content": "from typing import List, Tuple, Union\n\n\nclass TicTacToe:\n    def __init__(self, pick, sz=3) -> None:\n        self.pick = pick\n        self.dim_sz = sz\n        self.board = self.clear_board()\n\n    def clear_board(self) -> List[List[str]]:\n        return [[\"blur\" for _ in range(self.dim_sz)] for _ in range(self.dim_sz)]\n\n    def move_record(self, r, c) -> Union[str, bool]:\n        if r > self.dim_sz or c > self.dim_sz:\n            return \"Out of Bounds\"\n        if self.board[r][c] != \"blur\":\n            return \"Spot Pre-Occupied\"\n        self.board[r][c] = self.pick\n        return True\n\n    def check_win(self) -> int:  # 1 you won, 0 computer won, -1 tie\n        # Flag syntax -> first player no. ,\n        # User is Player#1 ;\n        # Check set 1 -> row and '\\' diagonal & Check set 2 -> col and '/' diagonal\n\n        for i in range(0, self.dim_sz):  # Rows\n            flag11 = True\n            flag21 = True\n\n            flag12 = True\n            flag22 = True\n            for j in range(0, self.dim_sz):\n\n                ch2 = self.board[i][j]\n                ch1 = self.board[j][i]\n                # Row\n                if ch1 == self.pick:  # if it's mine, computer didn't make it\n                    flag21 = False\n                elif ch1 == \"blur\":  # if it's blank no one made it\n                    flag11 = False\n                    flag21 = False\n                else:\n                    flag11 = False  # else i didn't make it\n\n                if ch2 == self.pick:  # Same but for Col\n                    flag22 = False\n                elif ch2 == \"blur\":\n                    flag12 = False\n                    flag22 = False\n                else:\n                    flag12 = False\n\n            if flag11 is True or flag12 is True:  # I won\n                return 1\n            if flag21 is True or flag22 is True:  # Computer Won\n                return 0\n\n        # Diagonals#\n        flag11 = True\n        flag21 = True\n\n        flag12 = True\n        flag22 = True\n        for i in range(0, self.dim_sz):\n\n            ch2 = self.board[i][i]\n            ch1 = self.board[i][self.dim_sz - 1 - i]\n\n            if ch1 == self.pick:\n                flag21 = False\n            elif ch1 == \"blur\":\n                flag11 = False\n                flag21 = False\n            else:\n                flag11 = False\n\n            if ch2 == self.pick:\n                flag22 = False\n            elif ch2 == \"blur\":\n                flag12 = False\n                flag22 = False\n            else:\n                flag12 = False\n\n        if flag11 or flag12:\n            return 1\n        return 0 if flag21 or flag22 else -1\n\n    def next_move(self) -> Union[Tuple[int, int], Tuple[List[int], List[int]]]:\n        available_moves = []  # will carry all available moves\n        player_win_spot = []  # if player (user Wins)\n        comp_pick = \"X\" if self.pick == \"O\" else \"O\"\n        for i in range(0, self.dim_sz):\n            for j in range(0, self.dim_sz):\n\n                if self.board[i][j] == \"blur\":  # BLANK\n                    t = (i, j)\n                    available_moves.append(t)  # add it to available moves\n                    self.board[i][j] = comp_pick  # Check if I (Computer can win)\n                    if self.check_win() == 0:  # Best Case I(Computer) win!\n                        return i, j\n                    self.board[i][j] = self.pick\n                    if (\n                        self.check_win() == 1\n                    ):  # Second Best Case, he (player) didn't won\n                        player_win_spot.append(t)\n                    self.board[i][j] = \"blur\"\n\n        if player_win_spot:\n            self.board[player_win_spot[0][0]][player_win_spot[0][1]] = comp_pick\n            return player_win_spot[0][0], player_win_spot[0][1]\n        if len(available_moves) == 1:\n            self.board[available_moves[0][0]][available_moves[0][1]] = comp_pick\n            return [available_moves[0][0]], [available_moves[0][1]]\n        if not available_moves:\n            return -1, -1\n\n        c1, c2 = self.dim_sz // 2, self.dim_sz // 2\n        if (c1, c2) in available_moves:  # CENTER\n            self.board[c1][c2] = comp_pick\n            return c1, c2\n        for i in range(c1 - 1, -1, -1):  # IN TO OUT\n            gap = c1 - i\n            # checking  - 4 possibilities at max\n            # EDGES\n            if (c1 - gap, c2 - gap) in available_moves:\n                self.board[c1 - gap][c2 - gap] = comp_pick\n                return c1 - gap, c2 - gap\n            if (c1 - gap, c2 + gap) in available_moves:\n                self.board[c1 - gap][c2 + gap] = comp_pick\n                return c1 - gap, c2 + gap\n            if (c1 + gap, c2 - gap) in available_moves:\n                self.board[c1 + gap][c2 - gap] = comp_pick\n                return c1 + gap, c2 - gap\n            if (c1 + gap, c2 + gap) in available_moves:\n                self.board[c1 + gap][c2 + gap] = comp_pick\n                return c1 + gap, c2 + gap\n\n            # Four Lines\n\n            for i in range(0, gap):\n                if (c1 - gap, c2 - gap + i) in available_moves:  # TOP LEFT TO TOP RIGHT\n                    self.board[c1 - gap][c2 - gap + i] = comp_pick\n                    return c1 - gap, c2 - gap + i\n                if (\n                    c1 + gap,\n                    c2 - gap + i,\n                ) in available_moves:  # BOTTOM LEFT TO BOTTOM RIGHT\n                    self.board[c1 + gap][c2 - gap + i] = comp_pick\n                    return c1 + gap, c2 - gap + i\n                if (c1 - gap, c2 - gap) in available_moves:  # LEFT TOP TO LEFT BOTTOM\n                    self.board[c1 - gap + i][c2 - gap] = comp_pick\n                    return c1 - gap + i, c2 - gap\n                if (\n                    c1 - gap + i,\n                    c2 + gap,\n                ) in available_moves:  # RIGHT TOP TO RIGHT BOTTOM\n                    self.board[c1 - gap + i][c2 + gap] = comp_pick\n                    return c1 - gap + i, c2 + gap\n        raise RuntimeError(\"No moves available\")\n\n\ndef display(game: TicTacToe) -> None:\n    line1 = \"\"\n    for i in range(0, game.dim_sz):\n        for j in range(0, game.dim_sz - 1):\n            if game.board[i][j] == \"blur\":\n                line1 = f\"{line1}    |\"\n            else:\n                line1 = f\"{line1}  {game.board[i][j]} |\"\n        if game.board[i][game.dim_sz - 1] == \"blur\":\n            line1 = line1 + \"    \\n\"\n        else:\n            line1 = f\"{line1}  {game.board[i][game.dim_sz - 1]} \\n\"\n    print(line1, \"\\n\\n\")\n\n\ndef main() -> None:\n    pick = input(\"Pick 'X' or 'O' \").strip().upper()\n    game = TicTacToe(\"O\") if pick == \"O\" else TicTacToe(\"X\")\n    display(game=game)\n    while True:\n        temp: Union[bool, str] = False\n        while not temp:\n            move = list(\n                map(\n                    int,\n                    input(\"Make A Move in Grid System from (0,0) to (2,2) \").split(),\n                )\n            )\n            temp = game.move_record(move[0], move[1])\n            if not temp:\n                print(temp)\n\n        if game.check_win() == 1:\n            print(\"You Won!\")\n            break\n        print(\"Your Move:- \")\n        display(game)\n        C1, C2 = game.next_move()\n        if C1 == -1 and C2 == -1:\n            print(\"Game Tie!\")\n            break\n        if game.check_win() == 0:\n            print(\"You lost!\")\n            break\n        print(\"Computer's Move :-\")\n        display(game)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "89_Tic-Tac-Toe/python/tictactoe2.py",
    "content": "#!/usr/bin/env python3\nfrom enum import Enum\n\n\nclass OccupiedBy(Enum):\n    COMPUTER = -1\n    EMPTY = 0\n    PLAYER = 1\n\n\nclass Winner(Enum):\n    NONE = 0\n    COMPUTER = 1\n    PLAYER = 2\n    DRAW = 3\n\n\nclass Space(Enum):\n    TOP_LEFT = 0\n    TOP_CENTER = 1\n    TOP_RIGHT = 2\n    MID_LEFT = 3\n    MID_CENTER = 4\n    MID_RIGHT = 5\n    BOT_LEFT = 6\n    BOT_CENTER = 7\n    BOT_RIGHT = 8\n\n\ndef line_170(board, g, h, j, k):\n    if g == OccupiedBy.Player and board[Space.MID_CENTER] == g:\n        if (\n            board[Space.TOP_RIGHT] == g and board[Space.BOTTOM_LEFT] is OccupiedBy.EMPTY\n        ):  # Line 171\n            return Space.BOTTOM_LEFT  # Line 187\n        elif (\n            board[Space.BOTTOM_RIGHT] == g and board[Space.TOP_LEFT] is OccupiedBy.EMPTY\n        ):  # Line 172\n            return Space.TOP_LEFT  # Line 181\n        elif (\n            board[Space.BOTTOM_LEFT] == g and board[Space.TOP_RIGHT] is OccupiedBy.EMPTY\n        ) or (\n            board[Space.BOTTOM_RIGHT] is OccupiedBy.PLAYER\n            and board[Space.TOP_RIGHT] is OccupiedBy.EMPTY\n        ):  # Line 173 and 174\n            return Space.TOP_RIGHT  # Line 183 and Line 189\n        elif g is OccupiedBy.COMPUTER:\n            g = OccupiedBy.PLAYER\n            h = OccupiedBy.COMPUTER\n            return line_118(board, g, h, j, k)\n\n\ndef line_150(board, g, h, j, k):\n    if board[k] != g:  # line 150\n        return (\n            -1\n            if (\n                board[k] == h  # line 160\n                or board[k + 6] != g  # line 161\n                or board[k + 3] != g\n            )\n            else k + 3\n        )\n    elif board[k + 6] != g:  # line 152\n        if board[k + 6] != 0 or board[k + 3] != g:  # line 165\n            return -1  # Goto 170\n    elif board[k + 3]:  # line 156\n        return -1\n\n    return k + 6\n\n\ndef line_120(board, g, h, j, k):\n    pass\n\n\ndef line_118(board, g, h):\n    for j in range(7):\n        for k in range(3):\n            return line_120(board, g, h, j, k)\n\n\ndef think(board, g, h, moves):\n\n    if board[Space.MID_CENTER] is OccupiedBy.EMPTY:\n        return Space.MID_CENTER\n\n    if board[Space.MID_CENTER] is OccupiedBy.PLAYER:\n        if (\n            board[Space.TOP_CENTER] is OccupiedBy.PLAYER\n            and board[Space.TOP_LEFT] is OccupiedBy.EMPTY\n            or board[Space.MID_LEFT] is OccupiedBy.PLAYER\n            and board[Space.TOP_LEFT] is OccupiedBy.EMPTY\n        ):\n            return Space.BOT_LEFT\n        elif (\n            board[Space.MID_RIGHT] is OccupiedBy.PLAYER\n            and board[Space.BOT_RIGHT] is OccupiedBy.EMPTY\n            or board[Space.BOT_CENTER] is OccupiedBy.PLAYER\n            and board[Space.BOT_RIGHT] is OccupiedBy.EMPTY\n        ):\n            return Space.BOT_RIGHT\n\n    if g == OccupiedBy.PLAYER:\n        j = 3 * int((moves - 1) / 3)\n        if move == j + 1:  # noqa: This definitely is a bug!\n            k = 1\n        if move == j + 2:  # noqa: This definitely is a bug!\n            k = 2\n        if move == j + 3:  # noqa: This definitely is a bug!\n            k = 3\n        return subthink(g, h, j, k)  # noqa: This definitely is a bug!\n\n\ndef render_board(board, space_mapping):\n    vertical_divider = \"!\"\n    horizontal_divider = \"---+---+---\"\n    lines = [\n        vertical_divider.join(space_mapping[space] for space in board[:3]),\n        horizontal_divider,\n        vertical_divider.join((space_mapping[space] for space in board[3:6])),\n        horizontal_divider,\n        vertical_divider.join((space_mapping[space] for space in board[6:9])),\n    ]\n    return \"\\n\".join(lines)\n\n\ndef determine_winner(board, g):\n    # Check for matching horizontal lines\n    for i in range(Space.TOP_LEFT.value, Space.BOT_LEFT.value + 1, 3):  # Line 1095\n        if board[i] != board[i + 1] or board[i] != board[i + 2]:  # Lines 1100 and 1105\n            continue  # First third of Line 1115\n        elif board[i] == OccupiedBy.COMPUTER:  #\n            return Winner.COMPUTER\n        elif board[i] == OccupiedBy.PLAYER:\n            return Winner.PLAYER\n\n    # Check for matching vertical lines\n    for i in range(\n        Space.TOP_LEFT.value, Space.TOP_RIGHT.value + 1, 1\n    ):  # Second third of Line 1115\n        if (\n            board[i] != board[i + 3] or board[i] != board[i + 6]\n        ):  # Last third of Line 1115\n            continue  # First third of 1150\n        elif board[i] == OccupiedBy.COMPUTER:  # Line 1135\n            return Winner.COMPUTER\n        elif board[i] == OccupiedBy.PLAYER:  # Line 1137\n            return Winner.PLAYER\n\n    # Check diagonals\n    if any(space is OccupiedBy.EMPTY for space in board):\n        if board[Space.MID_CENTER.value] != g:\n            return Winner.NONE\n        elif (\n            board[Space.TOP_LEFT.value] == g and board[Space.BOT_RIGHT.value] == g\n        ) or (board[Space.BOT_LEFT.value] == g and board[Space.TOP_RIGHT.value] == g):\n            return Winner.COMPUTER if g is OccupiedBy.COMPUTER else Winner.PLAYER\n        else:\n            return Winner.NONE\n\n    return Winner.DRAW\n\n\ndef computer_think(board):\n    empty_indices = [\n        index for index, space in enumerate(board) if space is OccupiedBy.EMPTY\n    ]\n\n    return empty_indices[0]\n\n\ndef prompt_player(board):\n    while True:\n        move = int(input(\"\\nWHERE DO YOU MOVE? \"))\n\n        if move == 0:\n            return 0\n\n        if move > 9 or board[move - 1] is not OccupiedBy.EMPTY:\n            print(\"THAT SQUARE IS OCCUPIED.\\n\\n\")\n            continue\n\n        return move\n\n\ndef main() -> None:\n    print(\" \" * 30 + \"TIC-TAC-TOE\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    print(\"\\n\\n\")\n\n    print(\"THE BOARD IS NUMBERED:\")\n    print(\" 1  2  3\")\n    print(\" 4  5  6\")\n    print(\" 7  8  9\")\n    print(\"\\n\\n\")\n\n    # Default state\n    board = [OccupiedBy.EMPTY] * 9\n    current_player = OccupiedBy.PLAYER\n    space_mapping = {\n        OccupiedBy.EMPTY: \"   \",\n        OccupiedBy.PLAYER: \" X \",\n        OccupiedBy.COMPUTER: \" O \",\n    }\n\n    symbol = input(\"DO YOU WANT 'X' OR 'O'? \").upper()\n\n    # If the player doesn't choose X, then assume you want O\n    # and the computer goes first.\n    if symbol != \"X\":\n        space_mapping[OccupiedBy.PLAYER] = \" O \"\n        space_mapping[OccupiedBy.COMPUTER] = \" X \"\n        current_player = OccupiedBy.COMPUTER\n\n    while True:\n        if current_player is OccupiedBy.PLAYER:\n            move = prompt_player(board)\n            if move == 0:\n                print(\"THANKS FOR THE GAME.\")\n                break\n            board[move - 1] = current_player\n\n        elif current_player is OccupiedBy.COMPUTER:\n            print(\"\\nTHE COMPUTER MOVES TO...\")\n            board[computer_think(board)] = current_player\n\n        print(render_board(board, space_mapping))\n\n        winner = determine_winner(board, current_player)\n\n        if winner is not Winner.NONE:\n            print(winner)\n            break\n\n        if current_player is OccupiedBy.COMPUTER:\n            current_player = OccupiedBy.PLAYER\n        elif current_player is OccupiedBy.PLAYER:\n            current_player = OccupiedBy.COMPUTER\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "89_Tic-Tac-Toe/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\n[dependencies]\n"
  },
  {
    "path": "89_Tic-Tac-Toe/rust/README.md",
    "content": "README.md\n\nOriginal source downloaded from Vintage Basic\n\nConversion to Rust\n"
  },
  {
    "path": "89_Tic-Tac-Toe/rust/src/main.rs",
    "content": "use std::fmt::{self, Display};\nuse std::io::{stdin, stdout, Write};\n\nconst WIN: [(usize, usize, usize); 8] = [\n    (0, 1, 2),\n    (3, 4, 5),\n    (6, 7, 8),\n    (0, 4, 8),\n    (2, 4, 6),\n    (0, 3, 6),\n    (1, 4, 7),\n    (2, 5, 8),\n];\n\ntype Board = [Sign; 9];\n\nfn main() {\n    let mut board: Board = [Sign::E; 9];\n    let mut sign = Sign::X;\n    loop {\n        clear();\n        render(&board, &sign);\n        let (win, winner) = check_board(board);\n        if win {\n            match winner {\n                Sign::X => break println!(\"Looks like X own this one!\"),\n                Sign::O => break println!(\"O is the winner!!\"),\n                Sign::C => break println!(\"Cat got this one!\"),\n                Sign::E => {}\n            }\n        }\n        let num = input(\"Pick a number 1 - 9:> \");\n        if let Some(Sign::E) = board.get(num) {\n            board.get_mut(num).map(|s| *s = sign);\n            sign = if sign == Sign::X { Sign::O } else { Sign::X };\n        }\n    }\n}\n\n#[derive(Debug, Copy, Clone, PartialEq)]\nenum Sign {\n    X,\n    O,\n    C,\n    E,\n}\n\nimpl Display for Sign {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        let sign = match self {\n            Self::X => 'X',\n            Self::O => 'O',\n            Self::C => 'C',\n            Self::E => ' ',\n        };\n        write!(f, \"{}\", sign)\n    }\n}\n\nfn check_board(board: Board) -> (bool, Sign) {\n    for &(a, b, c) in WIN.iter() {\n        if board[a] == board[b] && board[a] == board[c] {\n            return (true, board[a]);\n        }\n    }\n    if !board.contains(&Sign::E) {\n        return (true, Sign::C);\n    }\n    (false, Sign::E)\n}\n\nfn clear() {\n    println!(\"\\x1b[2J\\x1b[0;0H\");\n}\n\nfn input(message: &str) -> usize {\n    let mut out = String::new();\n    loop {\n        print!(\"{}\", message);\n        stdout().flush().expect(\"Failed to flush to stdout.\");\n        stdin().read_line(&mut out).expect(\"Failed to read line\");\n        let num = out.trim().parse::<usize>();\n        match num {\n            Ok(n) => match n {\n                1..=9 => return n - 1,\n                _ => println!(\"The number needs to be between 1 - 9.\"),\n            },\n            Err(_) => println!(\"'{}' is not a number.\", out.trim()),\n        }\n        out.clear();\n    }\n}\n\nfn render(spots: &Board, sign: &Sign) {\n    println!(\"                    The board is numbered\");\n    println!(\n        \" {} │ {} │ {}  [{}: Turn]    1 │ 2 │ 3\",\n        spots[0], spots[1], spots[2], sign\n    );\n    println!(\"⎼⎼⎼╄⎼⎼⎼╄⎼⎼⎼             ⎼⎼⎼╄⎼⎼⎼╄⎼⎼⎼\");\n    println!(\n        \" {} │ {} │ {}               4 │ 5 │ 6 \",\n        spots[3], spots[4], spots[5]\n    );\n    println!(\"⎼⎼⎼╄⎼⎼⎼╄⎼⎼⎼             ⎼⎼⎼╄⎼⎼⎼╄⎼⎼⎼\");\n    println!(\n        \" {} │ {} │ {}               7 │ 8 │ 9 \",\n        spots[6], spots[7], spots[8]\n    );\n}\n"
  },
  {
    "path": "89_Tic-Tac-Toe/tictactoe1.bas",
    "content": "10 PRINT TAB(30);\"TIC TAC TOE\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n50 REM\n100 REM   THIS PROGRAM PLAYS TIC TAC TOE\n110 REM   THE MACHINE GOES FIRST\n120 PRINT \"THE GAME BOARD IS NUMBERED:\": PRINT\n130 PRINT \"1  2  3\": PRINT \"8  9  4\": PRINT \"7  6  5\"\n140 PRINT\n150 REM\n160 REM\n170 REM\n180 DEF FNM(X)=X-8*INT((X-1)/8)\n190 REM\n200 REM  MAIN PROGRAM\n210 PRINT\n220 PRINT\n230 A=9\n240 M=A\n250 GOSUB 650\n260 P=M\n270 B=FNM(P+1)\n280 M=B\n290 GOSUB 650\n300 Q=M\n310 IF Q=FNM(B+4) THEN 360\n320 C=FNM(B+4)\n330 M=C\n340 GOSUB 700\n350 GOTO 730\n360 C=FNM(B+2)\n370 M=C\n380 GOSUB 650\n390 R=M\n400 IF R=FNM(C+4) THEN 450\n410 D=FNM(C+4)\n420 M=D\n430 GOSUB 700\n440 GOTO 730\n450 IF P/2<>INT(P/2) THEN 500\n460 D=FNM(C+7)\n470 M=D\n480 GOSUB 700\n490 GOTO 730\n500 D=FNM(C+3)\n510 M=D\n520 GOSUB 650\n530 S=M\n540 IF S=FNM(D+4) THEN 590\n550 E=FNM(D+4)\n560 M=E\n570 GOSUB 700\n580 REM\n590 E=FNM(D+6)\n600 M=E\n610 GOSUB 700\n620 PRINT \"THE GAME IS A DRAW.\"\n630 GOTO 210\n640 REM\n650 GOSUB 700\n660 PRINT \"YOUR MOVE\";\n670 INPUT M\n680 RETURN\n700 PRINT \"COMPUTER MOVES\";M\n710 RETURN\n720 REM\n730 PRINT \"AND WINS ********\"\n740 GOTO 210\n750 END\n"
  },
  {
    "path": "89_Tic-Tac-Toe/tictactoe2.bas",
    "content": "2 PRINT TAB(30);\"TIC-TAC-TOE\"\n4 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n6 PRINT:PRINT:PRINT\n8 PRINT \"THE BOARD IS NUMBERED:\"\n10 PRINT \" 1  2  3\"\n12 PRINT \" 4  5  6\"\n14 PRINT \" 7  8  9\"\n16 PRINT:PRINT:PRINT\n20 DIM S(9)\n50 INPUT\"DO YOU WANT 'X' OR 'O'\";C$\n55 IF C$=\"X\"THEN 475\n60 P$=\"O\":Q$=\"X\"\n100 G=-1:H=1:IF S(5)<>0 THEN 103\n102 S(5)=-1:GOTO 195\n103 IF S(5)<>1 THEN 106\n104 IF S(1)<>0 THEN 110\n105 S(1)=-1:GOTO 195\n106 IF S(2)=1 AND S(1)=0 THEN 181\n107 IF S(4)=1 AND S(1)=0 THEN 181\n108 IF S(6)=1 AND S(9)=0 THEN 189\n109 IF S(8)=1 AND S(9)=0 THEN 189\n110 IF G=1 THEN 112\n111 GOTO 118\n112 J=3*INT((M-1)/3)+1\n113 IF 3*INT((M-1)/3)+1=M THEN K=1\n114 IF 3*INT((M-1)/3)+2=M THEN K=2\n115 IF 3*INT((M-1)/3)+3=M THEN K=3\n116 GOTO 120\n118 FOR J=1 TO 7 STEP 3:FOR K=1 TO 3\n120 IF S(J)<>G THEN 130\n122 IF S(J+2)<>G THEN 135\n126 IF S(J+1)<>0 THEN 150\n128 S(J+1)=-1:GOTO 195\n130 IF S(J)=H THEN 150\n131 IF S(J+2)<>G THEN 150\n132 IF S(J+1)<>G THEN 150\n133 S(J)=-1:GOTO 195\n135 IF S(J+2)<>0 THEN 150\n136 IF S(J+1)<>G THEN 150\n138 S(J+2)=-1:GOTO 195\n150 IF S(K)<>G THEN 160\n152 IF S(K+6)<>G THEN 165\n156 IF S(K+3)<>0 THEN 170\n158 S(K+3)=-1:GOTO 195\n160 IF S(K)=H THEN 170\n161 IF S(K+6)<>G THEN 170\n162 IF S(K+3)<>G THEN 170\n163 S(K)=-1:GOTO 195\n165 IF S(K+6)<>0 THEN 170\n166 IF S(K+3)<>G THEN 170\n168 S(K+6)=-1:GOTO 195\n170 GOTO 450\n171 IF S(3)=G AND S(7)=0 THEN 187\n172 IF S(9)=G AND S(1)=0 THEN 181\n173 IF S(7)=G AND S(3)=0 THEN 183\n174 IF S(9)=0 AND S(1)=G THEN 189\n175 IF G=-1 THEN G=1:H=-1:GOTO 110\n176 IF S(9)=1 AND S(3)=0 THEN 182\n177 FOR I=2 TO 9:IF S(I)<>0 THEN 179\n178 S(I)=-1:GOTO 195\n179 NEXT I\n181 S(1)=-1:GOTO 195\n182 IF S(1)=1 THEN 177\n183 S(3)=-1:GOTO 195\n187 S(7)=-1:GOTO 195\n189 S(9)=-1\n195 PRINT:PRINT\"THE COMPUTER MOVES TO...\"\n202 GOSUB 1000\n205 GOTO 500\n450 IF G=1 THEN 465\n455 IF J=7 AND K=3 THEN 465\n460 NEXT K,J\n465 IF S(5)=G THEN 171\n467 GOTO 175\n475 P$=\"X\":Q$=\"O\"\n500 PRINT:INPUT\"WHERE DO YOU MOVE\";M\n502 IF M=0 THEN PRINT\"THANKS FOR THE GAME.\":GOTO 2000\n503 IF M>9 THEN 506\n505 IF S(M)=0 THEN 510\n506 PRINT\"THAT SQUARE IS OCCUPIED.\":PRINT:PRINT:GOTO 500\n510 G=1:S(M)=1\n520 GOSUB 1000\n530 GOTO 100\n1000 PRINT:FOR I=1 TO 9:PRINT\" \";:IF S(I)<>-1 THEN 1014\n1012 PRINT Q$\" \";:GOTO 1020\n1014 IF S(I)<>0 THEN 1018\n1016 PRINT\"  \";:GOTO 1020\n1018 PRINT P$\" \";\n1020 IF I<>3 AND I<>6 THEN 1050\n1030 PRINT:PRINT\"---+---+---\"\n1040 GOTO 1080\n1050 IF I=9 THEN 1080\n1060 PRINT\"!\";\n1080 NEXT I:PRINT:PRINT:PRINT\n1095 FOR I=1 TO 7 STEP 3\n1100 IF S(I)<>S(I+1)THEN 1115\n1105 IF S(I)<>S(I+2)THEN 1115\n1110 IF S(I)=-1 THEN 1350\n1112 IF S(I)=1 THEN 1200\n1115 NEXT I:FOR I=1 TO 3:IF S(I)<>S(I+3)THEN 1150\n1130 IF S(I)<>S(I+6)THEN 1150\n1135 IF S(I)=-1 THEN 1350\n1137 IF S(I)=1 THEN 1200\n1150 NEXT I:FOR I=1 TO 9:IF S(I)=0 THEN 1155\n1152 NEXT I:GOTO 1400\n1155 IF S(5)<>G THEN 1170\n1160 IF S(1)=G AND S(9)=G THEN 1180\n1165 IF S(3)=G AND S(7)=G THEN 1180\n1170 RETURN\n1180 IF G=-1 THEN 1350\n1200 PRINT\"YOU BEAT ME!! GOOD GAME.\":GOTO 2000\n1350 PRINT\"I WIN, TURKEY!!!\":GOTO 2000\n1400 PRINT\"IT'S A DRAW. THANK YOU.\"\n2000 END\n"
  },
  {
    "path": "89_Tic-Tac-Toe/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "89_Tic-Tac-Toe/vbnet/TicTacToe.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"TicTacToe\", \"TicTacToe.vbproj\", \"{5B43817F-EEF6-4298-BADF-69203BE7D088}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{5B43817F-EEF6-4298-BADF-69203BE7D088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B43817F-EEF6-4298-BADF-69203BE7D088}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B43817F-EEF6-4298-BADF-69203BE7D088}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5B43817F-EEF6-4298-BADF-69203BE7D088}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "89_Tic-Tac-Toe/vbnet/TicTacToe.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>TicTacToe</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "90_Tower/README.md",
    "content": "### Tower\n\nThis is a simulation of a game of logic that originated in the middle East. It is sometimes called Pharaoh's Needles, but its most common name is the Towers of Hanoi.\n\nLegend has it that a secret society of monks live beneath the city of Hanoi. They possess three large towers or needles on which different size gold disks may be placed. Moving one at a time and never placing a large on a smaller disk, the monks endeavor to move the tower of disks from the left needle to the right needle. Legend says when they have finished moving this 64-disk tower, the world will end. How many moves will they have to make to accomplish this? If they can move 1 disk per minute and work 24 hours per day, how many years will it take?\n\nIn the computer puzzle you are faced with three upright needles. On the leftmost needle are placed from two to seven graduated disks, the largest being on bottom and smallest on top. Your object is to move the entire stack of disks to the rightmost needle. However, you many only move one disk at a time and you may never place a larger disk on top of a smaller one.\n\nIn this computer game, the disks are referred to by their size — i.e., the smallest is 3, next 5, 7, 9, 11, 13, and 15. If you play with fewer than 7 disks always use the largest, i.e. with 2 disks you would use nos. 13 and 15. The program instructions are self-explanatory. Good luck!\n\nCharles Lund wrote this program while at the American School in the Hague, Netherlands.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=173)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=188)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "90_Tower/csharp/Game.cs",
    "content": "using System;\nusing Tower.Models;\nusing Tower.Resources;\nusing Tower.UI;\n\nnamespace Tower\n{\n    internal class Game\n    {\n        private readonly Towers _towers;\n        private readonly TowerDisplay _display;\n        private readonly int _optimalMoveCount;\n        private int _moveCount;\n\n        public Game(int diskCount)\n        {\n            _towers = new Towers(diskCount);\n            _display = new TowerDisplay(_towers);\n            _optimalMoveCount = (1 << diskCount) - 1;\n        }\n\n        public bool Play()\n        {\n            Console.Write(Strings.Instructions);\n\n            Console.Write(_display);\n\n            while (true)\n            {\n                if (!Input.TryReadNumber(Prompt.Disk, out int disk)) { return false; }\n\n                if (!_towers.TryFindDisk(disk, out var from, out var message))\n                {\n                    Console.WriteLine(message);\n                    continue;\n                }\n\n                if (!Input.TryReadNumber(Prompt.Needle, out var to)) { return false; }\n\n                if (!_towers.TryMoveDisk(from, to))\n                {\n                    Console.Write(Strings.IllegalMove);\n                    continue;\n                }\n\n                Console.Write(_display);\n\n                var result = CheckProgress();\n                if (result.HasValue) { return result.Value; }\n            }\n        }\n\n        private bool? CheckProgress()\n        {\n            _moveCount++;\n\n            if (_moveCount == 128)\n            {\n                Console.Write(Strings.TooManyMoves);\n                return false;\n            }\n\n            if (_towers.Finished)\n            {\n                if (_moveCount == _optimalMoveCount)\n                {\n                    Console.Write(Strings.Congratulations);\n                }\n\n                Console.WriteLine(Strings.TaskFinished, _moveCount);\n\n                return true;\n            }\n\n            return default;\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/Models/Needle.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Tower.Models\n{\n    internal class Needle : IEnumerable<int>\n    {\n        private readonly Stack<int> _disks = new Stack<int>();\n\n        public bool IsEmpty => _disks.Count == 0;\n\n        public int Top => _disks.TryPeek(out var disk) ? disk : default;\n\n        public bool TryPut(int disk)\n        {\n            if (_disks.Count == 0 || disk < _disks.Peek())\n            {\n                _disks.Push(disk);\n                return true;\n            }\n\n            return false;\n        }\n\n        public bool TryGetTopDisk(out int disk) => _disks.TryPop(out disk);\n\n        public IEnumerator<int> GetEnumerator() =>\n            Enumerable.Repeat(0, 7 - _disks.Count).Concat(_disks).GetEnumerator();\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/Models/Towers.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Tower.Resources;\n\nnamespace Tower.Models\n{\n    internal class Towers : IEnumerable<(int, int, int)>\n    {\n        private static int[] _availableDisks = new[] { 15, 13, 11, 9, 7, 5, 3 };\n\n        private readonly Needle[] _needles = new[] { new Needle(), new Needle(), new Needle() };\n        private readonly int _smallestDisk;\n\n        public Towers(int diskCount)\n        {\n            foreach (int disk in _availableDisks.Take(diskCount))\n            {\n                this[1].TryPut(disk);\n                _smallestDisk = disk;\n            }\n        }\n\n        private Needle this[int i] => _needles[i-1];\n\n        public bool Finished => this[1].IsEmpty && this[2].IsEmpty;\n\n        public bool TryFindDisk(int disk, out int needle, out string message)\n        {\n            needle = default;\n            message = default;\n\n            if (disk < _smallestDisk)\n            {\n                message = Strings.DiskNotInPlay;\n                return false;\n            }\n\n            for (needle = 1; needle <= 3; needle++)\n            {\n                if (this[needle].Top == disk) { return true; }\n            }\n\n            message = Strings.DiskUnavailable;\n            return false;\n        }\n\n        public bool TryMoveDisk(int from, int to)\n        {\n            if (!this[from].TryGetTopDisk(out var disk))\n            {\n                throw new InvalidOperationException($\"Needle {from} is empty\");\n            }\n\n            if (this[to].TryPut(disk)) { return true; }\n\n            this[from].TryPut(disk);\n            return false;\n        }\n\n        public IEnumerator<(int, int, int)> GetEnumerator() => new TowersEnumerator(_needles);\n\n        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n\n        private class TowersEnumerator : IEnumerator<(int, int, int)>\n        {\n            private readonly List<IEnumerator<int>> _enumerators;\n\n            public TowersEnumerator(Needle[] needles)\n            {\n                _enumerators = needles.Select(n => n.GetEnumerator()).ToList();\n            }\n\n            public (int, int, int) Current =>\n                (_enumerators[0].Current, _enumerators[1].Current, _enumerators[2].Current);\n\n            object IEnumerator.Current => Current;\n\n            public void Dispose() => _enumerators.ForEach(e => e.Dispose());\n\n            public bool MoveNext() => _enumerators.All(e => e.MoveNext());\n\n            public void Reset() => _enumerators.ForEach(e => e.Reset());\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/Program.cs",
    "content": "﻿using System;\nusing Tower.Resources;\nusing Tower.UI;\n\nnamespace Tower\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            Console.Write(Strings.Title);\n\n            do\n            {\n                Console.Write(Strings.Intro);\n\n                if (!Input.TryReadNumber(Prompt.DiskCount, out var diskCount)) { return; }\n\n                var game = new Game(diskCount);\n\n                if (!game.Play()) { return; }\n            } while (Input.ReadYesNo(Strings.PlayAgainPrompt, Strings.YesNoPrompt));\n\n            Console.Write(Strings.Thanks);\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "90_Tower/csharp/Resources/Congratulations.txt",
    "content": "\nCongratulations!!\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskCountPrompt.txt",
    "content": "How many disks do you want to move (7 is max)\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskCountQuit.txt",
    "content": "All right, wise guy, if you can't play the game right, I'll\njust take my puzzle and go home.  So long.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskCountRetry.txt",
    "content": "Sorry, but i can't do that job for you.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskNotInPlay.txt",
    "content": "That disk is not in play.  Make another choice.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskPrompt.txt",
    "content": "Which disk would you like to move\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskQuit.txt",
    "content": "Stop wasting my time.  Go bother someone else.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskRetry.txt",
    "content": "Illegal entry... You may only type 3, 5, 7, 9, 11, 13, or 15.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/DiskUnavailable.txt",
    "content": "That disk is below another one.  Make another choice.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/IllegalMove.txt",
    "content": "You can't place a larger disk on top of a smaller one,\nit might crush it!\nNow then,\n"
  },
  {
    "path": "90_Tower/csharp/Resources/Instructions.txt",
    "content": "In this program, we shall refer to disks by numerical code.\n3 will represent the smallest disk, 5 the next size,\n7 the next, and so on, up to 15.  If you do the puzzle with\n2 disks, their code names would be 13 and 15.  With 3 disks\nthe code names would be 11, 13 and 15, etc.  The needles\nare numbered from left to right, 1 to 3.  We will\nstartup with the disks on needle 1, and attempt to move them\nto needle 3.\n\nGood luck!\n"
  },
  {
    "path": "90_Tower/csharp/Resources/Intro.txt",
    "content": "\nTowers of Hanoi puzzle.\n\nYou must transfer the disks from the left to the right\ntower, one at a time, never putting a larger dish on a\nsmaller disk.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/NeedlePrompt.txt",
    "content": "Place disk on which needle\n"
  },
  {
    "path": "90_Tower/csharp/Resources/NeedleQuit.txt",
    "content": "I tried to warn you, but you wouldn't listen,\nBye bye, big shot.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/NeedleRetry.txt",
    "content": "I'll assume you hit the wrong key this time.  But watch it,\nI only allow one mistake\n"
  },
  {
    "path": "90_Tower/csharp/Resources/PlayAgainPrompt.txt",
    "content": "\nTry again (Yes or No)\n"
  },
  {
    "path": "90_Tower/csharp/Resources/Strings.cs",
    "content": "﻿using System.IO;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\nnamespace Tower.Resources\n{\n    internal static class Strings\n    {\n        internal static string Congratulations => GetResource();\n        internal static string DiskCountPrompt => GetResource();\n        internal static string DiskCountQuit => GetResource();\n        internal static string DiskCountRetry => GetResource();\n        internal static string DiskNotInPlay => GetResource();\n        internal static string DiskPrompt => GetResource();\n        internal static string DiskQuit => GetResource();\n        internal static string DiskRetry => GetResource();\n        internal static string DiskUnavailable => GetResource();\n        internal static string IllegalMove => GetResource();\n        internal static string Instructions => GetResource();\n        internal static string Intro => GetResource();\n        internal static string NeedlePrompt => GetResource();\n        internal static string NeedleQuit => GetResource();\n        internal static string NeedleRetry => GetResource();\n        internal static string PlayAgainPrompt => GetResource();\n        internal static string TaskFinished => GetResource();\n        internal static string Thanks => GetResource();\n        internal static string Title => GetResource();\n        internal static string TooManyMoves => GetResource();\n        internal static string YesNoPrompt => GetResource();\n\n        private static string GetResource([CallerMemberName] string name = \"\")\n        {\n            var streamName = $\"Tower.Resources.{name}.txt\";\n            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(streamName);\n            using var reader = new StreamReader(stream);\n\n            return reader.ReadToEnd();\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/Resources/TaskFinished.txt",
    "content": "\nYou have performed the task in {0} moves.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/Thanks.txt",
    "content": "\nThanks for the game!\n"
  },
  {
    "path": "90_Tower/csharp/Resources/Title.txt",
    "content": "                                 Towers\n               Creative Computing  Morristown, New Jersey\n"
  },
  {
    "path": "90_Tower/csharp/Resources/TooManyMoves.txt",
    "content": "Sorry, but I have orders to stop if you make more than\n128 moves.\n"
  },
  {
    "path": "90_Tower/csharp/Resources/YesNoPrompt.txt",
    "content": "\n'Yes' or 'No' please\n"
  },
  {
    "path": "90_Tower/csharp/Tower.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"Resources\\*.txt\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "90_Tower/csharp/Tower.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 15.0.26124.0\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Tower\", \"Tower.csproj\", \"{EEED33AD-3DE2-49AA-8AF1-2174C510E128}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {BDCB8278-62ED-46E3-92C2-FF572E0E3ED3}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "90_Tower/csharp/UI/Input.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Tower.UI\n{\n    // Provides input methods which emulate the BASIC interpreter's keyboard input routines\n    internal static class Input\n    {\n        private static void Prompt(string text = \"\") => Console.Write($\"{text}? \");\n\n        internal static bool ReadYesNo(string prompt, string retryPrompt)\n        {\n            var response = ReadString(prompt);\n\n            while (true)\n            {\n                if (response.Equals(\"No\", StringComparison.InvariantCultureIgnoreCase)) { return false; }\n                if (response.Equals(\"Yes\", StringComparison.InvariantCultureIgnoreCase)) { return true; }\n                response = ReadString(retryPrompt);\n            }\n        }\n\n        internal static bool TryReadNumber(Prompt prompt, out int number)\n        {\n            var message = prompt.Message;\n\n            for (int retryCount = 0; retryCount <= prompt.RetriesAllowed; retryCount++)\n            {\n                if (retryCount > 0) { Console.WriteLine(prompt.RetryMessage); }\n\n                if (prompt.TryValidateResponse(ReadNumber(message), out number)) { return true; }\n\n                if (!prompt.RepeatPrompt) { message = \"\"; }\n            }\n\n            Console.WriteLine(prompt.QuitMessage);\n\n            number = 0;\n            return false;\n        }\n\n        private static float ReadNumber(string prompt)\n        {\n            Prompt(prompt);\n\n            while (true)\n            {\n                var inputValues = ReadStrings();\n\n                if (TryParseNumber(inputValues[0], out var number))\n                {\n                    if (inputValues.Length > 1)\n                    {\n                        Console.WriteLine(\"!Extra input ingored\");\n                    }\n\n                    return number;\n                }\n            }\n        }\n\n        private static string ReadString(string prompt)\n        {\n            Prompt(prompt);\n\n            var inputValues = ReadStrings();\n            if (inputValues.Length > 1)\n            {\n                Console.WriteLine(\"!Extra input ingored\");\n            }\n            return inputValues[0];\n        }\n\n        private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries);\n\n        private static bool TryParseNumber(string text, out float number)\n        {\n            if (float.TryParse(text, out number)) { return true; }\n\n            Console.WriteLine(\"!Number expected - retry input line\");\n            number = default;\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/UI/Prompt.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing static Tower.Resources.Strings;\n\nnamespace Tower.UI\n{\n    internal class Prompt\n    {\n        public static Prompt DiskCount =\n            new(DiskCountPrompt, DiskCountRetry, DiskCountQuit, 1, 2, 3, 4, 5, 6, 7) { RetriesAllowed = 2 };\n\n        public static Prompt Disk =\n            new(DiskPrompt, DiskRetry, DiskQuit, 3, 5, 7, 9, 11, 13, 15) { RepeatPrompt = false };\n\n        public static Prompt Needle = new(NeedlePrompt, NeedleRetry, NeedleQuit, 1, 2, 3);\n\n        private readonly HashSet<int> _validValues;\n\n        private Prompt(string prompt, string retryMessage, string quitMessage, params int[] validValues)\n        {\n            Message = prompt;\n            RetryMessage = retryMessage;\n            QuitMessage = quitMessage;\n            _validValues = validValues.ToHashSet();\n            RetriesAllowed = 1;\n            RepeatPrompt = true;\n        }\n\n        public string Message { get; }\n        public string RetryMessage { get; }\n        public string QuitMessage { get; }\n        public int RetriesAllowed { get; private set; }\n        public bool RepeatPrompt { get; private set; }\n\n        public bool TryValidateResponse(float number, out int integer)\n        {\n            integer = (int)number;\n            return integer == number && _validValues.Contains(integer);\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/csharp/UI/TowerDisplay.cs",
    "content": "using System;\nusing System.Text;\nusing Tower.Models;\n\nnamespace Tower.UI\n{\n    internal class TowerDisplay\n    {\n        private readonly Towers _towers;\n\n        public TowerDisplay(Towers towers)\n        {\n            _towers = towers;\n        }\n\n        public override string ToString()\n        {\n            var builder = new StringBuilder();\n\n            foreach (var row in _towers)\n            {\n                AppendTower(row.Item1);\n                AppendTower(row.Item2);\n                AppendTower(row.Item3);\n                builder.AppendLine();\n            }\n\n            return builder.ToString();\n\n            void AppendTower(int size)\n            {\n                var padding = 10 - size / 2;\n                builder.Append(' ', padding).Append('*', Math.Max(1, size)).Append(' ', padding);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "90_Tower/java/Tower.java",
    "content": "import java.lang.Math;\nimport java.util.Scanner;\n\n/**\n * Game of Tower\n * <p>\n * Based on the BASIC game of Tower here\n * https://github.com/coding-horror/basic-computer-games/blob/main/90%20Tower/tower.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Tower {\n\n  private final static int MAX_DISK_SIZE = 15;\n\n  private final static int MAX_NUM_COLUMNS = 3;\n\n  private final static int MAX_NUM_MOVES = 128;\n\n  private final static int MAX_NUM_ROWS = 7;\n\n  private final Scanner scan;  // For user input\n\n  // Represent all possible disk positions\n  private int[][] positions;\n\n  private enum Step {\n    INITIALIZE, SELECT_TOTAL_DISKS, SELECT_DISK_MOVE, SELECT_NEEDLE, CHECK_SOLUTION\n  }\n\n\n  public Tower() {\n\n    scan = new Scanner(System.in);\n\n    // Row 0 and column 0 are not used\n    positions = new int[MAX_NUM_ROWS + 1][MAX_NUM_COLUMNS + 1];\n\n  }  // End of constructor Tower\n\n\n  public class Position {\n\n    public int row;\n    public int column;\n\n    public Position(int row, int column) {\n      this.row = row;\n      this.column = column;\n\n    }  // End of constructor Position\n\n  }  // End of inner class Position\n\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n\n  private void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"TOWERS\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n  }  // End of method showIntro\n\n\n  private void startGame() {\n\n    boolean diskMoved = false;\n\n    int column = 0;\n    int disk = 0;\n    int needle = 0;\n    int numDisks = 0;\n    int numErrors = 0;\n    int numMoves = 0;\n    int row = 0;\n\n    Step nextStep = Step.INITIALIZE;\n\n    String userResponse = \"\";\n\n    Position diskPosition = new Position(0, 0);\n\n    // Begin outer while loop\n    while (true) {\n\n      switch (nextStep) {\n\n\n        case INITIALIZE:\n\n          // Initialize error count\n          numErrors = 0;\n\n          // Initialize positions\n          for (row = 1; row <= MAX_NUM_ROWS; row++) {\n            for (column = 1; column <= MAX_NUM_COLUMNS; column++) {\n              positions[row][column] = 0;\n            }\n          }\n\n          // Display description\n          System.out.println(\"\");\n          System.out.println(\"TOWERS OF HANOI PUZZLE.\\n\");\n          System.out.println(\"YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT\");\n          System.out.println(\"TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A\");\n          System.out.println(\"SMALLER DISK.\\n\");\n\n          nextStep = Step.SELECT_TOTAL_DISKS;\n          break;\n\n\n        case SELECT_TOTAL_DISKS:\n\n          while (numErrors <= 2) {\n\n            // Get user input\n            System.out.print(\"HOW MANY DISKS DO YOU WANT TO MOVE (\" + MAX_NUM_ROWS + \" IS MAX)? \");\n            numDisks = scan.nextInt();\n            System.out.println(\"\");\n\n            numMoves = 0;\n\n            // Ensure the number of disks is valid\n            if ((numDisks < 1) || (numDisks > MAX_NUM_ROWS)) {\n\n              numErrors++;\n\n              // Handle user input errors\n              if (numErrors < 3) {\n                System.out.println(\"SORRY, BUT I CAN'T DO THAT JOB FOR YOU.\");\n              }\n\n            }\n            else {\n              break;  // Leave the while loop\n            }\n          }\n\n          // Too many user input errors\n          if (numErrors > 2) {\n            System.out.println(\"ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL\");\n            System.out.println(\"JUST TAKE MY PUZZLE AND GO HOME.  SO LONG.\");\n            return;\n          }\n\n          // Display detailed instructions\n          System.out.println(\"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\");\n          System.out.println(\"3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\");\n          System.out.println(\"7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\");\n          System.out.println(\"2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\");\n          System.out.println(\"THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\");\n          System.out.println(\"ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\");\n          System.out.println(\"START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\");\n          System.out.println(\"TO NEEDLE 3.\\n\");\n          System.out.println(\"GOOD LUCK!\\n\");\n\n          disk = MAX_DISK_SIZE;\n\n          // Set disk starting positions\n          for (row = MAX_NUM_ROWS; row > (MAX_NUM_ROWS - numDisks); row--) {\n            positions[row][1] = disk;\n            disk = disk - 2;\n          }\n\n          printPositions();\n\n          nextStep = Step.SELECT_DISK_MOVE;\n          break;\n\n\n        case SELECT_DISK_MOVE:\n\n          System.out.print(\"WHICH DISK WOULD YOU LIKE TO MOVE? \");\n\n          numErrors = 0;\n\n          while (numErrors < 2) {\n            disk = scan.nextInt();\n\n            // Validate disk numbers\n            if ((disk - 3) * (disk - 5) * (disk - 7) * (disk - 9) * (disk - 11) * (disk - 13) * (disk - 15) == 0) {\n\n              // Check if disk exists\n              diskPosition = getDiskPosition(disk);\n\n              // Disk found\n              if ((diskPosition.row > 0) && (diskPosition.column > 0))\n              {\n                // Disk can be moved\n                if (isDiskMovable(disk, diskPosition.row, diskPosition.column) == true) {\n\n                  break;\n\n                }\n                // Disk cannot be moved\n                else {\n\n                  System.out.println(\"THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\");\n                  System.out.print(\"WHICH DISK WOULD YOU LIKE TO MOVE? \");\n\n                }\n              }\n              // Mimic legacy handling of valid disk number but disk not found\n              else {\n\n                System.out.println(\"THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\");\n                System.out.print(\"WHICH DISK WOULD YOU LIKE TO MOVE? \");\n                numErrors = 0;\n                continue;\n\n              }\n\n            }\n            // Invalid disk number\n            else {\n\n              System.out.println(\"ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\");\n              numErrors++;\n\n              if (numErrors > 1) {\n                break;\n              }\n\n              System.out.print(\"? \");\n\n            }\n          }\n\n          if (numErrors > 1) {\n\n            System.out.println(\"STOP WASTING MY TIME.  GO BOTHER SOMEONE ELSE.\");\n            return;\n          }\n\n          nextStep = Step.SELECT_NEEDLE;\n          break;\n\n\n        case SELECT_NEEDLE:\n\n          numErrors = 0;\n\n          while (true) {\n\n            System.out.print(\"PLACE DISK ON WHICH NEEDLE? \");\n            needle = scan.nextInt();\n\n            // Handle valid needle numbers\n            if ((needle - 1) * (needle - 2) * (needle - 3) == 0) {\n\n              // Ensure needle is safe for disk move\n              if (isNeedleSafe(needle, disk, row) == false) {\n\n                System.out.println(\"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,\");\n                System.out.println(\"IT MIGHT CRUSH IT!\");\n                System.out.print(\"NOW THEN, \");\n\n                nextStep = Step.SELECT_DISK_MOVE;\n                break;\n              }\n\n              diskPosition = getDiskPosition(disk);\n\n              // Attempt to move the disk on a non-empty needle\n              diskMoved = false;\n              for (row = 1; row <= MAX_NUM_ROWS; row++) {\n                if (positions[row][needle] != 0) {\n                  row--;\n\n                  positions[row][needle] = positions[diskPosition.row][diskPosition.column];\n                  positions[diskPosition.row][diskPosition.column] = 0;\n\n                  diskMoved = true;\n                  break;\n                }\n              }\n\n              // Needle was empty, so move disk to the bottom\n              if (diskMoved == false) {\n                positions[MAX_NUM_ROWS][needle] = positions[diskPosition.row][diskPosition.column];\n                positions[diskPosition.row][diskPosition.column] = 0;\n              }\n\n              nextStep = Step.CHECK_SOLUTION;\n              break;\n\n            }\n            // Handle invalid needle numbers\n            else {\n\n              numErrors++;\n\n              if (numErrors > 1) {\n                System.out.println(\"I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\");\n                System.out.println(\"BYE BYE, BIG SHOT.\");\n                return;\n              }\n              else {\n                System.out.println(\"I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME.  BUT WATCH IT,\");\n                System.out.println(\"I ONLY ALLOW ONE MISTAKE.\");\n              }\n            }\n\n          }\n\n          break;\n\n\n        case CHECK_SOLUTION:\n\n          printPositions();\n\n          numMoves++;\n\n          // Puzzle is solved\n          if (isPuzzleSolved() == true) {\n\n            // Check for optimal solution\n            if (numMoves == (Math.pow(2, numDisks) - 1)) {\n              System.out.println(\"\");\n              System.out.println(\"CONGRATULATIONS!!\\n\");\n            }\n\n            System.out.println(\"YOU HAVE PERFORMED THE TASK IN \" + numMoves + \" MOVES.\\n\");\n            System.out.print(\"TRY AGAIN (YES OR NO)? \");\n\n            // Prompt for retries\n            while (true) {\n              userResponse = scan.next();\n\n              if (userResponse.toUpperCase().equals(\"YES\")) {\n                nextStep = Step.INITIALIZE;\n                break;\n              }\n              else if (userResponse.toUpperCase().equals(\"NO\")) {\n                System.out.println(\"\");\n                System.out.println(\"THANKS FOR THE GAME!\\n\");\n                return;\n              }\n              else {\n                System.out.print(\"'YES' OR 'NO' PLEASE? \");\n              }\n            }\n          }\n          // Puzzle is not solved\n          else {\n\n            // Exceeded maximum number of moves\n            if (numMoves > MAX_NUM_MOVES) {\n              System.out.println(\"SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN\");\n              System.out.println(\"128 MOVES.\");\n              return;\n            }\n\n            nextStep = Step.SELECT_DISK_MOVE;\n            break;\n          }\n\n          break;\n\n        default:\n          System.out.println(\"INVALID STEP\");\n          break;\n\n      }\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n\n  private boolean isPuzzleSolved() {\n\n    int column = 0;\n    int row = 0;\n\n    // Puzzle is solved if first 2 needles are empty\n    for (row = 1; row <= MAX_NUM_ROWS; row++) {\n      for (column = 1; column <= 2; column++) {\n        if (positions[row][column] != 0) {\n          return false;\n        }\n      }\n    }\n\n    return true;\n\n  }  // End of method isPuzzleSolved\n\n\n  private Position getDiskPosition(int disk) {\n\n    int column = 0;\n    int row = 0;\n\n    Position pos = new Position(0, 0);\n\n    // Begin loop through all rows\n    for (row = 1; row <= MAX_NUM_ROWS; row++) {\n\n      // Begin loop through all columns\n      for (column = 1; column <= MAX_NUM_COLUMNS; column++) {\n\n        // Found the disk\n        if (positions[row][column] == disk) {\n\n          pos.row = row;\n          pos.column = column;\n          return pos;\n\n        }\n\n      }  // End loop through all columns\n\n    }  // End loop through all rows\n\n    return pos;\n\n  }  // End of method getDiskPosition\n\n\n  private boolean isDiskMovable(int disk, int row, int column) {\n\n    int ii = 0;  // Loop iterator\n\n    // Begin loop through all rows above disk\n    for (ii = row; ii >= 1; ii--) {\n\n      // Disk can be moved\n      if (positions[ii][column] == 0) {\n        continue;\n      }\n\n      // Disk cannot be moved\n      if (positions[ii][column] < disk) {\n        return false;\n      }\n\n    }  // End loop through all rows above disk\n\n    return true;\n\n  }  // End of method isDiskMovable\n\n\n  private boolean isNeedleSafe(int needle, int disk, int row) {\n\n    for (row = 1; row <= MAX_NUM_ROWS; row++) {\n\n      // Needle is not empty\n      if (positions[row][needle] != 0) {\n\n        // Disk crush condition\n        if (disk >= positions[row][needle]) {\n          return false;\n        }\n      }\n    }\n\n    return true;\n\n  }  // End of method isNeedleSafe\n\n\n  private void printPositions() {\n\n    int column = 1;\n    int ii = 0;  // Loop iterator\n    int numSpaces = 0;\n    int row = 1;\n\n    // Begin loop through all rows\n    for (row = 1; row <= MAX_NUM_ROWS; row++) {\n\n      numSpaces = 9;\n\n      // Begin loop through all columns\n      for (column = 1; column <= MAX_NUM_COLUMNS; column++) {\n\n        // No disk at the current position\n        if (positions[row][column] == 0) {\n\n          System.out.print(\" \".repeat(numSpaces) + \"*\");\n          numSpaces = 20;\n        }\n\n        // Draw a disk at the current position\n        else {\n\n          System.out.print(\" \".repeat(numSpaces - ((int) (positions[row][column] / 2))));\n\n          for (ii = 1; ii <= positions[row][column]; ii++) {\n            System.out.print(\"*\");\n          }\n\n          numSpaces = 20 - ((int) (positions[row][column] / 2));\n        }\n\n      }  // End loop through all columns\n\n      System.out.println(\"\");\n\n    }  // End loop through all rows\n\n  }  // End of method printPositions\n\n\n  public static void main(String[] args) {\n\n    Tower tower = new Tower();\n    tower.play();\n\n  }  // End of method main\n\n}  // End of class Tower\n"
  },
  {
    "path": "90_Tower/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "90_Tower/javascript/tower.html",
    "content": "<html>\n<head>\n<title>TOWER</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"tower.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "90_Tower/javascript/tower.js",
    "content": "// TOWER\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\nvar ta = [];\n\n// Print subroutine\nfunction show_towers()\n{\n    var z;\n\n    for (var k = 1; k <= 7; k++) {\n        z = 10;\n        str = \"\";\n        for (var j = 1; j <= 3; j++) {\n            if (ta[k][j] != 0) {\n                while (str.length < z - Math.floor(ta[k][j] / 2))\n                    str += \" \";\n                for (v = 1; v <= ta[k][j]; v++)\n                    str += \"*\";\n            } else {\n                while (str.length < z)\n                    str += \" \";\n                str += \"*\";\n            }\n            z += 21;\n        }\n        print(str + \"\\n\");\n    }\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(33) + \"TOWERS\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    while (1) {\n        print(\"\\n\");\n        // Initialize\n        e = 0;\n        for (d = 1; d <= 7; d++) {\n            ta[d] = [];\n            for (n = 1; n <= 3; n++)\n                ta[d][n] = 0;\n        }\n        print(\"TOWERS OF HANOI PUZZLE.\\n\");\n        print(\"\\n\");\n        print(\"YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT\\n\");\n        print(\"TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A\\n\");\n        print(\"SMALLER DISK.\\n\");\n        print(\"\\n\");\n        while (1) {\n            print(\"HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)\");\n            s = parseInt(await input());\n            print(\"\\n\");\n            m = 0;\n            if (s >= 1 && s <= 7)\n                break;\n            e++;\n            if (e < 2) {\n                print(\"SORRY, BUT I CAN'T DO THAT JOB FOR YOU.\\n\");\n                continue;\n            }\n            print(\"ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL\\n\");\n            print(\"JUST TAKE MY PUZZLE AND GO HOME.  SO LONG.\\n\");\n            return;\n        }\n        // Store disks from smallest to largest\n        print(\"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\\n\");\n        print(\"3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\\n\");\n        print(\"7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\\n\");\n        print(\"2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\\n\");\n        print(\"THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\\n\");\n        print(\"ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\\n\");\n        print(\"START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\\n\");\n        print(\"TO NEEDLE 3.\\n\");\n        print(\"\\n\");\n        print(\"GOOD LUCK!\\n\");\n        print(\"\\n\");\n        y = 7;\n        d = 15;\n        for (x = s; x >= 1; x--) {\n            ta[y][1] = d;\n            d -= 2;\n            y--;\n        }\n        show_towers();\n        while (1) {\n            print(\"WHICH DISK WOULD YOU LIKE TO MOVE\");\n            e = 0;\n            while (1) {\n                d = parseInt(await input());\n                if (d % 2 == 0 || d < 3 || d > 15) {\n                    print(\"ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\\n\");\n                    e++;\n                    if (e <= 1)\n                        continue;\n                    print(\"STOP WASTING MY TIME.  GO BOTHER SOMEONE ELSE.\\n\");\n                    return;\n                } else {\n                    break;\n                }\n            }\n            // Check if requested disk is below another\n            for (r = 1; r <= 7; r++) {\n                for (c = 1; c <= 3; c++) {\n                    if (ta[r][c] == d)\n                        break;\n                }\n                if (c <= 3)\n                    break;\n            }\n            for (q = r; q >= 1; q--) {\n                if (ta[q][c] != 0 && ta[q][c] < d)\n                    break;\n            }\n            if (q >= 1) {\n                print(\"THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\\n\");\n                continue;\n            }\n            e = 0;\n            while (1) {\n                print(\"PLACE DISK ON WHICH NEEDLE\");\n                n = parseInt(await input());\n                if (n >= 1 && n <= 3)\n                    break;\n                e++;\n                if (e <= 1) {\n                    print(\"I'LL ASSUME YOU HIT THE WRONG KEY THI TIME.  BUT WATCH IT,\\n\");\n                    print(\"I ONLY ALLOW ONE MISTAKE.\\n\");\n                    continue;\n                } else {\n                    print(\"I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\\n\");\n                    print(\"BYE BYE, BIG SHOT.\\n\");\n                    return;\n                }\n            }\n            // Check if requested disk is below another\n            for (r = 1; r <= 7; r++) {\n                if (ta[r][n] != 0)\n                    break;\n            }\n            if (r <= 7) {\n                // Check if disk to be placed on a larger one\n                if (d >= ta[r][n]) {\n                    print(\"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,\\n\");\n                    print(\"IT MIGHT CRUSH IT!\\n\");\n                    print(\"NOW THEN, \");\n                    continue;\n                }\n            }\n            // Move relocated disk\n            for (v = 1; v <= 7; v++) {\n                for (w = 1; w <= 3; w++) {\n                    if (ta[v][w] == d)\n                        break;\n                }\n                if (w <= 3)\n                    break;\n            }\n            // Locate empty space on needle n\n            for (u = 1; u <= 7; u++) {\n                if (ta[u][n] != 0)\n                    break;\n            }\n            ta[--u][n] = ta[v][w];\n            ta[v][w] = 0;\n            // Print out current status\n            show_towers();\n            // Check if done\n            m++;\n            for (r = 1; r <= 7; r++) {\n                for (c = 1; c <= 2; c++) {\n                    if (ta[r][c] != 0)\n                        break;\n                }\n                if (c <= 2)\n                    break;\n            }\n            if (r > 7)\n                break;\n            if (m > 128) {\n                print(\"SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN\\n\");\n                print(\"128 MOVES.\\n\");\n                return;\n            }\n        }\n        if (m == Math.pow(2, s) - 1) {\n            print(\"\\n\");\n            print(\"CONGRATULATIONS!!\\n\");\n            print(\"\\n\");\n        }\n        print(\"YOU HAVE PERFORMED THE TASK IN \" + m + \" MOVES.\\n\");\n        print(\"\\n\");\n        print(\"TRY AGAIN (YES OR NO)\");\n        while (1) {\n            str = await input();\n            if (str == \"YES\" || str == \"NO\")\n                break;\n            print(\"\\n\");\n            print(\"'YES' OR 'NO' PLEASE\");\n        }\n        if (str == \"NO\")\n            break;\n    }\n    print(\"\\n\");\n    print(\"THANKS FOR THE GAME!\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "90_Tower/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "90_Tower/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "90_Tower/lua/tower.lua",
    "content": "print [[\n            \n            TOWERS\nCREATIVE COMPUTING  MORRISTOWN, NEW JERSY\n\n\n]]\n\nlocal MAX_DISKS <const> = 7\nlocal MAX_DISK_SIZE <const> = 15\nlocal MAX_MOVES <const> = 128\nlocal NUM_TOWERS <const> = 3\n\nlocal towers = {\n    { size = 0, elem = {} },\n    { size = 0, elem = {} },\n    { size = 0, elem = {} },\n}\n\nlocal total_disks\nfunction ask_how_many_disks()\n\n    local keep_asking = true\n    local input\n    local errors = 0\n\n    while keep_asking do\n\n        io.write(string.format(\"HOW MANY DISKS DO YOU WANT TO MOVE (%d IS MAX)? \", MAX_DISKS) )\n        input = io.read(\"*number\")\n        io.read() --get rid of the remaining newline character\n\n        if input ~= nil and input>0 and input<=MAX_DISKS then\n            keep_asking = false\n\n        else\n            errors = errors + 1\n            if errors > 2 then\n                print \"ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL\"\n                print \"JUST TAKE MY PUZZLE AND GO HOME. SO LONG.\"\n                os.exit()\n            end\n\n            print \"SORRY, BUT I CAN'T DO THAT JOB FOR YOU.\"\n        end\n    end\n    total_disks = input\nend\n\nfunction init_game()\n    print(\"TOWERS OF HANOIR PUZZLE\\n\") --'\\n' indicates a new line\n\n    print \"YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT TOWER,\"\n    print \"ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A SMALLER DISK.\\n\"\n\n    ask_how_many_disks()\n\n    print() -- print() already creates a new line at the end, so an empty print leaves an empty line\n    print \"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\"\n    print \"3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE, 7 THE\"\n    print \"NEXT, AND SO ON, UP TO 15. IF YOU DO THE PUZZLE WITH 2 DISKS,\"\n    print \"THEIR CODE NAMES WOULD BE 13 AND 15, ETC. THE NEEDLES ARE\"\n    print \"NUMBERED FROM LEFT TO RIGHT, 1 TO 3. WE WILL START WITH THE\"\n    print \"DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM TO NEEDLE 3.\\n\"\n    \n    print \"GOOD LUCK!\\n\"\n\n    local i = 1\n    local max = MAX_DISK_SIZE\n    while i<= total_disks do\n        towers[1].elem[i] = max\n        max = max-2\n        i = i+1\n    end\n\n    towers[1].size = total_disks\n\n    local idx = 2\n    while idx <= NUM_TOWERS do\n        towers[idx].size = 0\n    end\nend\n\nfunction print_towers()\n    local line = MAX_DISKS\n    \n    while line > 0 do\n        local twr = 1\n        \n        while twr <=3 do\n            local rpt = 10\n            local offset = 0\n            if line <= towers[twr].size then\n                offset = (towers[twr].elem[line] - 1) / 2\n                rpt = rpt - offset\n            end\n            io.write( string.rep(' ', rpt) )\n            io.write( string.rep('*', offset) )\n            io.write '*'\n            io.write( string.rep('*', offset) )\n            io.write( string.rep(' ', rpt) )\n            twr = twr + 1\n        end\n        print ''\n        line = line - 1\n    end\n    \nend\n\nfunction ask_which_disk()\n\n    local keep_asking = true\n    local input\n    local errors = 0\n    while keep_asking do\n\n        io.write(\"WHICH DISK WOULD YOU LIKE TO MOVE? \")\n        input = io.read(\"*number\")\n        io.read() --get rid of the remaining newline character\n\n        if input==nil or input > MAX_DISK_SIZE or input%2==0 or input <= MAX_DISK_SIZE-(total_disks*2) then\n            print \"ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13 or 15.\"\n            errors = errors + 1\n            if errors > 1 then\n                print \"STOP WASTING MY TIME. GO BOTHER SOMEONE ELSE.\"\n                os.exit()\n            end\n\n        --[[\n        Since there are only 3 towers, it's easier to do an 'if' with three\n        conditions than to do a loop\n        ]]\n        elseif towers[1].elem[ towers[1].size ] ~= input and\n                towers[2].elem[ towers[2].size ] ~= input and\n                towers[3].elem[ towers[3].size ] ~= input then\n\n            print \"THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE.\"\n        else\n            keep_asking = false \n        end\n    end\n    \n    return input\nend\n\nfunction ask_which_needle(dsk)\n\n    local keep_asking = true\n    local input\n    local errors = 0\n\n    while keep_asking do\n\n        io.write(\"PLACE DISK ON WHICH NEEDLE? \")\n        input = io.read(\"*number\")\n        io.read() --get rid of the remaining newline character\n\n        if input~=nil and towers[input].size > 0 and towers[input].elem[ towers[input].size ] < dsk then\n            print \"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,\"\n            print \"IT MIGHT CRUSH IT!\"\n            return 0\n\n        elseif input~=nil and input>=1 and input<=3 then\n                keep_asking = false\n\n        else\n            errors = errors + 1\n            if errors > 1 then\n                print \"I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\"\n                print \"BYE BYE, BIG SHOT.\"\n                os.exit() --Stop program\n            else\n                print \"I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME. BUT WATCH IT,\"\n                print \"I ONLY ALLOW ONE MISTAKE.\"\n            end\n        end\n    end\n    return input\nend\n\nfunction is_game_over()\n    if towers[1].size == 0 and towers[2].size == 0 then\n        return true\n    else\n        return false\n    end\nend\n\nfunction game_loop()\n    local moves = 0\n    local dsk \n    local twr_to\n    local twr_fr\n\n    while not is_game_over() do\n        moves = moves + 1\n\n        if moves > MAX_MOVES then\n            print(string.format(\"SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN %d MOVES.\", MAX_MOVES))\n            os.exit()\n        end\n\n\n        repeat\n            dsk = ask_which_disk()\n            twr_to = ask_which_needle(dsk)\n        until twr_to ~= 0\n\n\n        if towers[1].elem[ towers[1].size ] == dsk then\n            twr_fr = 1\n        elseif towers[2].elem[ towers[2].size ] == dsk then\n            twr_fr = 2\n        else\n            twr_fr = 3\n        end\n\n        towers[twr_fr].size = towers[twr_fr].size - 1\n\n        towers[twr_to].size = towers[twr_to].size + 1\n        towers[twr_to].elem[ towers[twr_to].size ] = dsk\n\n        print_towers()\n    end\n\n    return moves\nend\n\nfunction keep_playing()\n    \n    while true do\n        io.write(\"TRY AGAIN (YES OR NO)? \")\n        local input = io.read(\"*line\")\n\n        if input == \"YES\" or input == \"yes\" then\n            return true\n        elseif input == \"NO\" or input == \"no\" then\n            return false\n        else\n            print \"'YES' OR 'NO' PLEASE\"\n        end\n    end\nend\n\nfunction start_loop()\n\n    while true do\n        init_game()\n        print_towers()\n\n        local moves = game_loop()\n\n        --check ideal solution\n        if moves == (2^total_disks) - 1 then\n            print \"CONGRATULATIONS!!\"\n        end\n\n        print ( string.format(\"YOU HAVE PERFORMED THE TASK IN %d MOVES.\\n\", moves) )\n\n        if not keep_playing() then\n            break\n        end\n    end\n\n    print \"\\nTHANKS FOR THE GAME!\"\nend\n\nstart_loop()\n"
  },
  {
    "path": "90_Tower/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "90_Tower/perl/tower.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\n# Manifest constant representing the maximum number of disks. We can\n# change this within limits. It needs to be at least 3 or the\n# explanatory text will contain negative numbers. There is no known\n# upper limit, though if it is more than 10 the output lines can be more\n# than 80 columns, and if it is more than 49 the disk numbers will be\n# more than two digits, which will cause output lines not to align\n# properly.\nuse constant MAX_DISKS  => 7;\n\nprint <<'EOD';\n                                 TOWERS\n               Creative Computing  Morristown, New Jersey\n\n\nEOD\n\nwhile ( 1 ) {   # Iterate until something makes us stop.\n\n    print <<'EOD';\nTowers of Hanoi Puzzle.\n\nYou must transfer the disks from the left to the right\nTower, one at a time, never putting a larger disk on a\nsmaller disk.\n\nEOD\n\n    # Get the desired number of disks to work with.\n    my $size = get_input(\n\n        # Manifest constants do not interpolate into strings. This can\n        # be worked around using the @{[ ... ]} construction, which\n        # interpolates any expression.\n        \"How many disks do you want to move (@{[ MAX_DISKS ]} is max)? \",\n\n        sub {\n\n            # Accept any response which is an integer greater than zero\n            # and less than or equal to the maximum number of disks.\n            # NOTE that 'and' performs the same operation as &&, but\n            # binds much more loosely.\n            return m/ \\A [0-9]+ \\z /smx &&\n                $ARG > 0 &&\n                $ARG <= MAX_DISKS;\n        },\n\n        3,\n        \"Sorry, but I can't do that job for you.\\n\",    # Warning\n        <<'EOD',\nAll right, wise guy, if you can't play the game right, I'll\njust take my puzzle and go home.  So long.\nEOD\n    );\n\n    # Expressions can be interpolated using @{[ ... ]}\n    print <<\"EOD\";\nIn this program, we shall refer to disks by numerical code.\n3 will represent the smallest disk, 5 the next size,\n7 the next, and so on, up to @{[ MAX_DISKS * 2 + 1 ]}.  If you do the puzzle with\n2 disks, their code names would be @{[ MAX_DISKS * 2 - 1 ]} and @{[ MAX_DISKS * 2 + 1 ]}.  With 3 disks\nthe code names would be @{[ MAX_DISKS * 2 - 3 ]}, @{[ MAX_DISKS * 2 - 1 ]} and @{[ MAX_DISKS * 2 + 1 ]}, etc.  The needles\nare numbered from left to right, 1 to 3.  We will\nstart with the disks on needle 1, and attempt to move them\nto needle 3.\n\n\nGood luck!\n\nEOD\n\n    # Compute the legal disk numbers for this puzzle. The expression\n    # reads right to left thus:\n    #   * The .. operator generates the integers between and including\n    #     its end points, that is, from MAX_DISKS + 1 - $size to\n    #     MAX_DISKS, inclusive.\n    #   * map { .. } calls the block once for each of its arguments.\n    #     The value of the argument appears in the topic variable $ARG,\n    #     and the result of the block is returned.\n    #   * The list generated by the map {} is assigned to array\n    #     @legal_disks.\n    my @legal_disks = map { $ARG * 2 + 1 }\n        MAX_DISKS + 1 - $size ..  MAX_DISKS;\n\n    # Generate the board. This is an array of needles, indexed from\n    # zero. Each needle is represented by a reference to an array\n    # containing the disks on that needle, bottom to top.\n    my @board = (\n        [ reverse @legal_disks ],\n        [],\n        []\n    );\n\n    display( \\@board ); # Display the initial board.\n\n    my $moves = 0;  # Move counter.\n\n    while ( 1 ) {   # Iterate until something makes us stop.\n        my $disk = get_input(\n            'Which disk would you like to move? ',\n            sub {\n                # Accept any odd integer in the required range.\n                # NOTE that 'and' performs the same operation as &&, but\n                # binds much more loosely.\n                return m/ \\A [0-9]+ \\z /smx &&\n                    $ARG % 2 &&\n                    $ARG >= ( MAX_DISKS + 1 - $size ) * 2 + 1 &&\n                    $ARG <= MAX_DISKS * 2 + 1;\n            },\n            3,\n            do {    # Compound statement and scope for 'local'\n\n                # We want to interpolate @legal_disks into our warning.\n                # Interpolation of an array places $LIST_SEPARATOR\n                # between the elements of the array. The default is ' ',\n                # but we want ', '. We use 'local' to restrict the\n                # change to the current block and code called by it.\n                # Failure to localize the change can cause Spooky Action\n                # at a Distance.\n                local $LIST_SEPARATOR = ', ';\n\n                \"Illegal entry... You may only type @legal_disks\\n\";\n            },\n            \"Stop wasting my time.  Go bother someone else.\\n\",\n        );\n\n        # Return the number (from zero) of the needle which has the\n        # desired disk on top. If the desired disk is not found, we got\n        # undef back. In this case we redo the innermost loop.\n        redo unless defined( my $from = find_disk( $disk, \\@board ) );\n\n        # Find out where the chosen disk goes.\n        # NOTE that unlike the BASIC implementation, we require the\n        # needle to be moved.\n        my $to = get_input(\n            'Place disk on which needle? ',\n            sub {\n                # Accept integers 1 through 3, but not the current\n                # location of the disk\n                return m/ \\A [0-9]+ \\z /smx &&\n                    $ARG > 0 &&\n                    $ARG <= 3 &&\n                    $ARG != $from + 1;\n            },\n            2,\n            <<'EOD',\nI'll assume you hit the wrong key this time.  But watch it,\nI only allow one mistake.\nEOD\n            <<'EOD',\nI tried to warn you, but you wouldn't listen.\nBye bye, big shot.\nEOD\n        ) - 1;\n\n        # Check for placing a larger disk on a smaller one. The check is\n        # that the destination needle has something on it (an empty\n        # array is false in Boolean context) and that the destination\n        # needle's top disk ([-1] selects the last element of an array)\n        # is smaller than the source needle's disk.\n        if ( @{ $board[$to] } && $board[$to][-1] < $board[$from][-1] ) {\n            warn <<'EOD';\nYou can't place a larger disk on top of a smaller one,\nIt might crush it!\nEOD\n            redo;\n        }\n\n        # Remove the selected disk from its needle, and place it on the\n        # destination needle.\n        push @{ $board[$to] }, pop @{ $board[$from] };\n\n        $moves++;   # Count another move.\n\n        display( \\@board ); # Display the current board.\n\n        # If all the disks are on the last needle, we are done.\n        if ( @{ $board[2] } == $size ) {\n\n            # Print a success message\n            print <<\"EOD\";\nCongratulations!\n\nYou have performed the task in $moves moves.\n\nEOD\n            last;   # Exit the innermost loop.\n\n        # If the maximum allowed moves have been exceeded\n        } elsif ( $moves >= 2 ** MAX_DISKS ) {\n\n            # Warn\n            warn <<\"EOD\";\nSorry, but I have orders to stop if you make more than\n$moves moves.\nEOD\n\n            last;   # Exit the innermost loop.\n        }\n    }\n\n    say '';\n    get_input(\n        'Try again? [y/N]: ',\n        sub {\n            exit if $ARG eq '' || m/ \\A n /smxi;\n            return m/ \\A y /smxi;\n        },\n        ~0, # The 1's complement of 0 = largest possible integer\n        \"Please respond 'y' or 'n'\\n\",\n    );\n}\n\n# Display the board, which is passed in as a reference.\nsub display {\n    my ( $board ) = @_;\n    say '';\n\n    # Use a manifest constant for an empty needle. This is global\n    # despite its appearing to be nested in the subroutine. Perl uses\n    # 'x' as its string replication operator. The initial 4 blanks\n    # accommodate the disk number and spacing between needles.\n    use constant EMPTY_NEEDLE   => ' ' x 4 . ' ' x MAX_DISKS . '|' .\n        ' ' x MAX_DISKS;\n\n    # Iterate over the rows to be printed.\n    foreach my $inx ( reverse 0 .. MAX_DISKS ) {\n\n        my $line;   # Line buffer.\n\n        # Iterate over needles.\n        foreach my $col ( 0 .. 2 ) {\n\n            # If this position on the needle is occupied\n            if ( my $disk_num = $board->[$col][$inx] ) {\n\n                # Compute the width of a half disk\n                my $half_width = ( $disk_num - 1 ) / 2;\n\n                # Compute the graphic for the half disk. Perl uses 'x'\n                # as its string replication operator.\n                my $half_disk = '*' x $half_width;\n\n                # Append the disk to the line. The inner sprintf() does\n                # most of the work; the outer simply pads the graphic to\n                # the required total width.\n                $line .= sprintf( '%*s', -( MAX_DISKS * 2 + 5 ),\n                    sprintf( '%*d %s|%s', MAX_DISKS + 3 - $half_width,\n                        $disk_num, $half_disk, $half_disk ) );\n\n            # Else this position is not occupied\n            } else {\n\n                # So just append the empty needle.\n                $line .= EMPTY_NEEDLE;\n            }\n        }\n\n        # Remove white space at the end of the line\n        $line =~ s/ \\s+ \\z //smx;\n\n        # Display the line\n        say $line;\n    }\n    {   # Display the needle numbers\n        my $line;\n        foreach my $col ( 0 .. 2 ) {\n            $line .= sprintf '%*d%*s', MAX_DISKS + 5, $col + 1,\n            MAX_DISKS, ' ';\n        }\n        $line =~ s/ \\s+ \\z //smx;\n        say $line;\n    }\n\n    say ''; # Empty line\n\n    return;\n}\n\n# Find the named disk. The arguments are the disk number (which is\n# assumed valid) and a reference to the board. If the disk is found on\n# the top of a needle, the needle's index (from zero) is returned.\n# Otherwise a warning is issued and undef is returned.\nsub find_disk {\n    my ( $disk, $board ) = @_;\n    foreach my $inx ( 0 .. 2 ) {\n        @{ $board->[$inx] }                 # If the needle is occupied\n            and $disk == $board->[$inx][-1] # and we want its topmost\n            and return $inx;                # return needle index\n    }\n\n    # Since we assume the disk number is valid but we did not find it,\n    # it must not be the topmost disk.\n    warn \"That disk is below another one.  Make another choice.\\n\";\n\n    return undef;\n}\n\n# Input subroutine. The arguments are:\n# * The prompt.\n# * Validation code. This recieves the input in the topic variable $ARG,\n#   and returns a true value if the validation passed, and a false value\n#   if it failed.\n# * The maximum number of tries before dying.\n# * The warning message for a validation failure, with trailing \"\\n\".\n# * The error message when the number of tries is exceeded, with\n#   trailing \"\\n\".\n# The return is the valid input. We exit if end-of-file is reached,\nsub get_input {\n    my ( $prompt, $validate, $tries, $warning, $error ) = @_;\n\n    # Instantiate the readline object. A state variable is only\n    # initialized once.\n    state $term = Term::ReadLine->new( 'tower' );\n\n    while ( 1 ) {   # Iterate until something makes us stop.\n\n        # The input gets read into the localized topic variable. If it\n        # is undefined, it signals end-of-file, so we exit.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Call the validation code. If it returns a true value, we\n        # return our input.\n        return $ARG if $validate->();\n\n        # Die if we are out of retries. In Perl, 0 is false and all\n        # other integers are true.\n        die $error unless --$tries;\n\n        # Warn.\n        warn $warning;\n    }\n}\n\n__END__\n\n=head1 TITLE\n\ntower.pl - Play the game 'tower' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n tower.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of C<tower>, which is the 90th entry in Basic\nComputer Games.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "90_Tower/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "90_Tower/python/tower.py",
    "content": "import sys\nfrom typing import List, Optional\n\n\nclass Disk:\n    def __init__(self, size: int) -> None:\n        self.__size = size\n\n    def size(self) -> int:\n        return self.__size\n\n    def print(self) -> None:\n        print(f\"[ {self.size()} ]\")\n\n\nclass Tower:\n    def __init__(self) -> None:\n        self.__disks: List[Disk] = []\n\n    def empty(self) -> bool:\n        return len(self.__disks) == 0\n\n    def top(self) -> Optional[Disk]:\n        return None if self.empty() else self.__disks[-1]\n\n    def add(self, disk: Disk) -> None:\n        if not self.empty():\n            t = self.top()\n            assert t is not None  # cannot happen as it's not empty\n            if disk.size() > t.size():\n                raise Exception(\n                    \"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!\"\n                )\n        self.__disks.append(disk)\n\n    def pop(self) -> Disk:\n        if self.empty():\n            raise Exception(\"empty pop\")\n        return self.__disks.pop()\n\n    def print(self) -> None:\n        r = f'Needle: [{\", \".join([str(x.size()) for x in self.__disks])}]'\n        print(r)\n\n\nclass Game:\n    def __init__(self) -> None:\n        # use fewer sizes to make debugging easier\n        # self.__sizes = [3, 5, 7]  # ,9,11,13,15]\n        self.__sizes = [3, 5, 7, 9, 11, 13, 15]\n\n        self.__sizes.sort()\n\n        self.__towers = []\n        self.__moves = 0\n        self.__towers = [Tower(), Tower(), Tower()]\n        self.__sizes.reverse()\n        for size in self.__sizes:\n            disk = Disk(size)\n            self.__towers[0].add(disk)\n\n    def winner(self) -> bool:\n        return self.__towers[0].empty() and self.__towers[1].empty()\n\n    def print(self) -> None:\n        for t in self.__towers:\n            t.print()\n\n    def moves(self) -> int:\n        return self.__moves\n\n    def which_disk(self) -> int:\n        w = int(input(\"WHICH DISK WOULD YOU LIKE TO MOVE\\n\"))\n        if w in self.__sizes:\n            return w\n        raise Exception()\n\n    def pick_disk(self) -> Optional[Tower]:\n        which = None\n        while which is None:\n            try:\n                which = self.which_disk()\n            except Exception:\n                print(\"ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\\n\")\n\n        valids = [t for t in self.__towers if t.top() and t.top().size() == which]\n        assert len(valids) in {0, 1}\n        if not valids:\n            print(\"THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\\n\")\n            return None\n        else:\n            assert valids[0].top().size() == which\n            return valids[0]\n\n    def which_tower(self) -> Optional[Tower]:\n        try:\n            needle = int(input(\"PLACE DISK ON WHICH NEEDLE\\n\"))\n            tower = self.__towers[needle - 1]\n        except Exception:\n            print(\n                \"I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME.  BUT WATCH IT,\\nI ONLY ALLOW ONE MISTAKE.\\n\"\n            )\n            return None\n        else:\n            return tower\n\n    def take_turn(self) -> None:\n        from_tower = None\n        while from_tower is None:\n            from_tower = self.pick_disk()\n\n        to_tower = self.which_tower()\n        if not to_tower:\n            to_tower = self.which_tower()\n\n        if not to_tower:\n            print(\"I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\\nBYE BYE, BIG SHOT.\\n\")\n            sys.exit(0)\n\n        disk = from_tower.pop()\n        try:\n            to_tower.add(disk)\n            self.__moves += 1\n        except Exception as err:\n            print(err)\n            from_tower.add(disk)\n\n\ndef main() -> None:\n    print(\n        \"\"\"\n    IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\n    3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\n    7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\n    2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\n    THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\n    ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\n    START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\n    TO NEEDLE 3.\n\n    GOOD LUCK!\n\n    \"\"\"\n    )\n\n    game = Game()\n    while True:\n        game.print()\n\n        game.take_turn()\n\n        if game.winner():\n            print(\n                \"CONGRATULATIONS!!\\nYOU HAVE PERFORMED THE TASK IN %s MOVES.\\n\"\n                % game.moves()\n            )\n            while True:\n                yesno = input(\"TRY AGAIN (YES OR NO)\\n\")\n                if yesno.upper() == \"YES\":\n                    game = Game()\n                    break\n                elif yesno.upper() == \"NO\":\n                    print(\"THANKS FOR THE GAME!\\n\")\n                    sys.exit(0)\n                else:\n                    print(\"'YES' OR 'NO' PLEASE\\n\")\n        elif game.moves() > 128:\n            print(\"SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN 128 MOVES.\")\n            sys.exit(0)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "90_Tower/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "90_Tower/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "90_Tower/rust/src/disk.rs",
    "content": "pub struct Disk {\n    pub size: u8,\n}\n\nimpl Disk {\n    pub fn new(size: u8) -> Self {\n        Disk { size }\n    }\n\n    pub fn draw(&self) {\n        let draw_space = || {\n            let space_amount = (15 - self.size) / 2;\n\n            if space_amount > 0 {\n                for _ in 0..space_amount {\n                    print!(\" \");\n                }\n            }\n        };\n\n        draw_space();\n        for _ in 0..self.size {\n            print!(\"*\");\n        }\n        draw_space();\n        print!(\"   \");\n    }\n}\n"
  },
  {
    "path": "90_Tower/rust/src/game.rs",
    "content": "use crate::{\n    disk::Disk,\n    needle::Needle,\n    util::{self, prompt, PromptResult},\n};\n\npub struct Game {\n    pub needles: Vec<Needle>,\n    disk_count: u8,\n    moves: usize,\n}\n\nimpl Game {\n    pub fn new() -> Self {\n        let mut needles = Vec::new();\n        let disk_count = util::get_disk_count();\n\n        for i in 1..=3 {\n            let disks = match i {\n                1 => {\n                    let mut disks = Vec::new();\n\n                    let mut half_size = 7;\n                    for _ in (1..=disk_count).rev() {\n                        disks.push(Disk::new(half_size * 2 + 1));\n                        half_size -= 1;\n                    }\n\n                    disks\n                }\n                2 | 3 => Vec::new(),\n                _ => panic!(\"THERE MUST BE EXACTLY THREE NEEDLES!\"),\n            };\n\n            needles.push(Needle { disks, number: i });\n        }\n\n        Game {\n            needles,\n            disk_count,\n            moves: 0,\n        }\n    }\n\n    pub fn update(&mut self) -> bool {\n        self.draw();\n\n        loop {\n            let (disk_index, from_needle_index) = self.get_disk_to_move();\n            let to_needle_index = self.ask_which_needle();\n\n            if from_needle_index == to_needle_index {\n                println!(\"DISK IS ALREADY AT THAT NEEDLE!\");\n                break;\n            }\n\n            let to_needle = &self.needles[to_needle_index];\n\n            if to_needle.disks.len() == 0\n                || to_needle.disks[0].size > self.needles[from_needle_index].disks[disk_index].size\n            {\n                self.move_disk(disk_index, from_needle_index, to_needle_index);\n                break;\n            } else {\n                println!(\"CAN'T PLACE ON A SMALLER DISK!\");\n            }\n        }\n\n        if self.needles[2].disks.len() == self.disk_count as usize {\n            self.draw();\n            println!(\"CONGRATULATIONS!!\");\n            println!(\"YOU HAVE PERFORMED THE TASK IN {} MOVES.\", self.moves);\n            return true;\n        }\n\n        false\n    }\n\n    pub fn draw(&self) {\n        println!(\"\");\n        for r in (1..=7).rev() {\n            for n in &self.needles {\n                n.draw(r)\n            }\n            println!(\"\");\n        }\n        println!(\"\");\n    }\n\n    fn get_disk_to_move(&self) -> (usize, usize) {\n        loop {\n            if let PromptResult::Number(n) = prompt(true, \"WHICH DISK WOULD YOU LIKE TO MOVE?\") {\n                let smallest_disk = 15 - ((self.disk_count - 1) * 2);\n\n                if n < smallest_disk as i32 || n > 15 || (n % 2) == 0 {\n                    println!(\"PLEASE ENTER A VALID DISK!\")\n                } else {\n                    for (n_i, needle) in self.needles.iter().enumerate() {\n                        if let Some((i, _)) = needle\n                            .disks\n                            .iter()\n                            .enumerate()\n                            .find(|(_, disk)| disk.size == n as u8)\n                        {\n                            if i == (needle.disks.len() - 1) {\n                                return (i, n_i);\n                            }\n\n                            println!(\"THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE.\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    fn ask_which_needle(&self) -> usize {\n        loop {\n            if let PromptResult::Number(n) = prompt(true, \"PLACE DISK ON WHICH NEEDLE?\") {\n                if n <= 0 || n > 3 {\n                    println!(\"PLEASE ENTER A VALID NEEDLE.\");\n                } else {\n                    return (n - 1) as usize;\n                }\n            }\n        }\n    }\n\n    fn move_disk(&mut self, disk: usize, from: usize, to: usize) {\n        let from = &mut self.needles[from];\n        let size = from.disks[disk].size;\n\n        from.disks.remove(disk);\n        self.needles[to].add(size);\n\n        self.moves += 1;\n    }\n}\n"
  },
  {
    "path": "90_Tower/rust/src/main.rs",
    "content": "use game::Game;\nuse util::PromptResult;\n\nmod disk;\nmod game;\nmod needle;\nmod util;\n\nfn main() {\n    println!(\"\\n\\n\\t\\tTOWERS\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n\n    println!(\"TOWERS OF HANOI PUZZLE\\n\");\n\n    println!(\"YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT\");\n    println!(\"TOWER, ON AT A TIME, NEVER PUTTING A LARGER DISK ON A\");\n    println!(\"SMALLER DISK.\\n\");\n\n    let mut quit = false;\n\n    while !quit {\n        let mut game = Game::new();\n\n        println!(\"\");\n        println!(\n            r#\"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\n3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\n7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\n2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\nTHE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\nARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\nSTART WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\nTO NEEDLE 3.\n\nGOOD LUCK!\"#\n        );\n\n        loop {\n            if game.update() {\n                break;\n            }\n        }\n\n        if let PromptResult::YesNo(r) = util::prompt(false, \"TRY AGAIN (YES OR NO)?\") {\n            quit = !r;\n        }\n    }\n\n    println!(\"THANKS FOR THE GAME!\");\n}\n"
  },
  {
    "path": "90_Tower/rust/src/needle.rs",
    "content": "use crate::disk::Disk;\n\npub struct Needle {\n    pub disks: Vec<Disk>,\n    pub number: u8,\n}\n\nimpl Needle {\n    pub fn draw(&self, row: u8) {\n        let row = row as usize;\n\n        if self.disks.len() >= row {\n            self.disks[row - 1].draw();\n        } else {\n            let offset = \"       \";\n\n            print!(\"{offset}\");\n            print!(\"*\");\n            print!(\"{offset}   \");\n        }\n    }\n\n    pub fn add(&mut self, size: u8) {\n        self.disks.push(Disk { size });\n    }\n}\n"
  },
  {
    "path": "90_Tower/rust/src/util.rs",
    "content": "use std::io;\n\npub enum PromptResult {\n    Number(i32),\n    YesNo(bool),\n}\n\npub fn prompt(numeric: bool, msg: &str) -> PromptResult {\n    use PromptResult::*;\n    loop {\n        println!(\"{}\", msg);\n\n        let mut input = String::new();\n\n        io::stdin()\n            .read_line(&mut input)\n            .expect(\"Failed to read line.\");\n\n        let input = input.trim().to_string();\n\n        if numeric {\n            if let Ok(n) = input.parse::<i32>() {\n                return Number(n);\n            }\n\n            println!(\"PLEASE ENTER A NUMBER.\")\n        } else {\n            match input.to_uppercase().as_str() {\n                \"YES\" | \"Y\" => return YesNo(true),\n                \"NO\" | \"N\" => return YesNo(false),\n                _ => println!(\"PLEASE ENTER (Y)ES OR (N)O.\"),\n            }\n        }\n    }\n}\n\npub fn get_disk_count() -> u8 {\n    loop {\n        if let PromptResult::Number(n) =\n            prompt(true, \"HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)?\")\n        {\n            if n <= 2 {\n                println!(\"THERE MUST BE AT LEAST 3 DISKS!\")\n            } else if n > 7 {\n                println!(\"THERE CAN'T BE MORE THAN 7 DISKS!\")\n            } else {\n                return n as u8;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "90_Tower/tower.bas",
    "content": "10 PRINT TAB(33);\"TOWERS\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n90 PRINT\n100 REM*** INITIALIZE\n110 DIM T(7,3)\n120 E=0\n130 FOR D=1 TO 7\n140 FOR N=1 TO 3\n150 T(D,N)=0\n160 NEXT N\n170 NEXT D\n180 PRINT \"TOWERS OF HANOI PUZZLE.\": PRINT\n200 PRINT \"YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT\"\n205 PRINT \"TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A\"\n210 PRINT \"SMALLER DISK.\": PRINT\n215 INPUT \"HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)\";S\n220 PRINT\n230 M=0\n240 FOR Q=1 TO 7\n250 IF Q=S THEN 350\n260 NEXT Q\n270 E=E+1\n280 IF E>2 THEN 310\n290 PRINT \"SORRY, BUT I CAN'T DO THAT JOB FOR YOU.\": GOTO 215\n310 PRINT \"ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL\"\n320 PRINT \"JUST TAKE MY PUZZLE AND GO HOME.  SO LONG.\": STOP\n340 REM *** STORE DISKS FROM SMALLEST TO LARGEST\n350 PRINT \"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\"\n355 PRINT \"3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\"\n360 PRINT \"7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\"\n365 PRINT \"2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\"\n370 PRINT \"THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\"\n375 PRINT \"ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\"\n380 PRINT \"START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\"\n385 PRINT \"TO NEEDLE 3.\"\n390 PRINT: PRINT \"GOOD LUCK!\": PRINT\n400 Y=7: D=15\n420 FOR X=S TO 1 STEP -1\n430 T(Y,1)=D: D=D-2: Y=Y-1\n460 NEXT X\n470 GOSUB 1230\n480 PRINT \"WHICH DISK WOULD YOU LIKE TO MOVE\";:E=0\n500 INPUT D\n510 IF (D-3)*(D-5)*(D-7)*(D-9)*(D-11)*(D-13)*(D-15)=0 THEN 580\n520 PRINT \"ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\"\n530 E=E+1: IF E>1 THEN 560\n550 GOTO 500\n560 PRINT \"STOP WASTING MY TIME.  GO BOTHER SOMEONE ELSE.\": STOP\n580 REM *** CHECK IF REQUESTED DISK IS BELOW ANOTHER\n590 FOR R=1 TO 7\n600 FOR C=1 TO 3\n610 IF T(R,C)=D THEN 640\n620 NEXT C: NEXT R\n640 FOR Q=R TO 1 STEP -1\n645 IF T(Q,C)=0 THEN 660\n650 IF T(Q,C)<D THEN 680\n660 NEXT Q\n670 GOTO 700\n680 PRINT \"THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\"\n690 GOTO 480\n700 E=0\n705 INPUT \"PLACE DISK ON WHICH NEEDLE\";N\n730 IF (N-1)*(N-2)*(N-3)=0 THEN 800\n735 E=E+1\n740 IF E>1 THEN 780\n750 PRINT \"I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME.  BUT WATCH IT,\"\n760 PRINT \"I ONLY ALLOW ONE MISTAKE.\": GOTO 705\n780 PRINT \"I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\"\n790 PRINT \"BYE BYE, BIG SHOT.\":STOP\n800 FOR R=1 TO 7\n810 IF T(R,N)<>0 THEN 840\n820 NEXT R\n830 GOTO 880\n835 REM *** CHECK IF DISK TO BE PLACED ON A LARGER ONE\n840 IF D<T(R,N) THEN 880\n850 PRINT \"YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,\"\n860 PRINT \"IT MIGHT CRUSH IT!\": PRINT \"NOW THEN, \";:GOTO 480\n875 REM *** MOVE RELOCATED DISK\n880 FOR V=1 TO 7: FOR W=1 TO 3\n900 IF T(V,W)=D THEN 930\n910 NEXT W: NEXT V\n925 REM *** LOCATE EMPTY SPACE ON NEEDLE N\n930 FOR U=1 TO 7\n940 IF T(U,N)<>0 THEN 970\n950 NEXT U\n960 U=7: GOTO 980\n965 REM *** MOVE DISK AND SET OLD LOCATION TO 0\n970 U=U-1\n980 T(U,N)=T(V,W): T(V,W)=0\n995 REM *** PRINT OUT CURRENT STATUS\n1000 GOSUB 1230\n1018 REM *** CHECK IF DONE\n1020 M=M+1\n1030 FOR R=1 TO 7: FOR C=1 TO 2\n1050 IF T(R,C)<>0 THEN 1090\n1060 NEXT C: NEXT R\n1080 GOTO 1120\n1090 IF M<=128 THEN 480\n1100 PRINT \"SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN\"\n1110 PRINT \"128 MOVES.\": STOP\n1120 IF M<>2^S-1 THEN 1140\n1130 PRINT:PRINT \"CONGRATULATIONS!!\":PRINT\n1140 PRINT \"YOU HAVE PERFORMED THE TASK IN\";M;\"MOVES.\"\n1150 PRINT: PRINT \"TRY AGAIN (YES OR NO)\";: INPUT A$\n1160 IF A$=\"NO\" THEN 1390\n1170 IF A$=\"YES\" THEN 90\n1180 PRINT: PRINT \"'YES' OR 'NO' PLEASE\";: INPUT A$: GOTO 1160\n1230 REM *** PRINT SUBROUTINE\n1240 FOR K=1 TO 7\n1250 Z=10\n1260 FOR J=1 TO 3\n1270 IF T(K,J)=0 THEN 1330\n1280 PRINT TAB(Z-INT(T(K,J)/2));\n1290 FOR V=1 TO T(K,J)\n1300 PRINT \"*\";\n1310 NEXT V\n1320 GOTO 1340\n1330 PRINT TAB(Z);\"*\";\n1340 Z=Z+21\n1350 NEXT J\n1360 PRINT\n1370 NEXT K\n1380 RETURN\n1390 PRINT: PRINT \"THANKS FOR THE GAME!\": PRINT: END\n"
  },
  {
    "path": "90_Tower/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "90_Tower/vbnet/Tower.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Tower\", \"Tower.vbproj\", \"{9B62545A-F076-4390-864B-ABE6FC20CC62}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{9B62545A-F076-4390-864B-ABE6FC20CC62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{9B62545A-F076-4390-864B-ABE6FC20CC62}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{9B62545A-F076-4390-864B-ABE6FC20CC62}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{9B62545A-F076-4390-864B-ABE6FC20CC62}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "90_Tower/vbnet/Tower.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Tower</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "91_Train/README.md",
    "content": "### Train\n\nTRAIN is a program which uses the computer to generate problems with random initial conditions to teach about the time-speed-distance relationship (distance = rate x time). You then input your answer and the computer verifies your response.\n\nTRAIN is merely an example of a student-generated problem. Maximum fun (and benefit) comes more from _writing_ programs like this as opposed to solving the specific problem posed. Exchange your program with others—you solve their problem and let them solve yours.\n\nTRAIN was originally written in FOCAL by one student for use by others in his class. It was submitted to us by Walt Koetke, Lexington High School, Lexington, Mass.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=175)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=190)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "91_Train/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "91_Train/csharp/Train/TrainGame.cs",
    "content": "﻿using System;\nusing System.Linq;\n\nnamespace Train\n{\n    public class TrainGame\n    {\n        private Random Rnd { get; } = new Random();\n        private readonly int ALLOWED_PERCENTAGE_DIFFERENCE = 5;\n\n        static void Main()\n        {\n            TrainGame train = new TrainGame();\n            train.GameLoop();\n        }\n\n        public void GameLoop()\n        {\n            DisplayIntroText();\n\n            do\n            {\n                PlayGame();\n            } while (TryAgain());\n        }\n\n        private void PlayGame()\n        {\n            int carSpeed = (int)GenerateRandomNumber(40, 25);\n            int timeDifference = (int)GenerateRandomNumber(5, 15);\n            int trainSpeed = (int)GenerateRandomNumber(20, 19);\n\n            Console.WriteLine($\"A CAR TRAVELING {carSpeed} MPH CAN MAKE A CERTAIN TRIP IN\");\n            Console.WriteLine($\"{timeDifference} HOURS LESS THAN A TRAIN TRAVELING AT {trainSpeed} MPH\");\n            Console.WriteLine(\"HOW LONG DOES THE TRIP TAKE BY CAR?\");\n\n            double userInputCarJourneyDuration = double.Parse(Console.ReadLine());\n            double actualCarJourneyDuration = CalculateCarJourneyDuration(carSpeed, timeDifference, trainSpeed);\n            int percentageDifference = CalculatePercentageDifference(userInputCarJourneyDuration, actualCarJourneyDuration);\n\n            if (IsWithinAllowedDifference(percentageDifference, ALLOWED_PERCENTAGE_DIFFERENCE))\n            {\n                Console.WriteLine($\"GOOD! ANSWER WITHIN {percentageDifference} PERCENT.\");\n            }\n            else\n            {\n                Console.WriteLine($\"SORRY.  YOU WERE OFF BY {percentageDifference} PERCENT.\");\n            }\n            Console.WriteLine($\"CORRECT ANSWER IS {actualCarJourneyDuration} HOURS.\");\n        }\n\n        public static bool IsWithinAllowedDifference(int percentageDifference, int allowedDifference)\n        {\n            return percentageDifference <= allowedDifference;\n        }\n\n        private static int CalculatePercentageDifference(double userInputCarJourneyDuration, double carJourneyDuration)\n        {\n            return (int)(Math.Abs((carJourneyDuration - userInputCarJourneyDuration) * 100 / userInputCarJourneyDuration) + .5);\n        }\n\n        public static double CalculateCarJourneyDuration(double carSpeed, double timeDifference, double trainSpeed)\n        {\n            return timeDifference * trainSpeed / (carSpeed - trainSpeed);\n        }\n\n        public double GenerateRandomNumber(int baseSpeed, int multiplier)\n        {\n            return multiplier * Rnd.NextDouble() + baseSpeed;\n        }\n\n        private bool TryAgain()\n        {\n            Console.WriteLine(\"ANOTHER PROBLEM (YES OR NO)? \");\n            return IsInputYes(Console.ReadLine());\n        }\n\n        public static bool IsInputYes(string consoleInput)\n        {\n            var options = new string[] { \"Y\", \"YES\" };\n            return options.Any(o => o.Equals(consoleInput, StringComparison.CurrentCultureIgnoreCase));\n        }\n\n        private void DisplayIntroText()\n        {\n            Console.WriteLine(\"TRAIN\");\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n            Console.WriteLine(\"TIME - SPEED DISTANCE EXERCISE\");\n            Console.WriteLine();\n        }\n    }\n}\n"
  },
  {
    "path": "91_Train/csharp/Train/TrainGame.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "91_Train/csharp/Train.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31129.286\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"TrainGame\", \"Train\\TrainGame.csproj\", \"{42617537-4E7C-4082-A17B-7F18DFA04C35}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"TrainTests\", \"TrainTests\\TrainTests.csproj\", \"{B967AA46-78F2-44F8-A30D-85D35F625991}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{42617537-4E7C-4082-A17B-7F18DFA04C35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{42617537-4E7C-4082-A17B-7F18DFA04C35}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{42617537-4E7C-4082-A17B-7F18DFA04C35}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{42617537-4E7C-4082-A17B-7F18DFA04C35}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B967AA46-78F2-44F8-A30D-85D35F625991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B967AA46-78F2-44F8-A30D-85D35F625991}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B967AA46-78F2-44F8-A30D-85D35F625991}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B967AA46-78F2-44F8-A30D-85D35F625991}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {919F73B8-DE34-4992-9B05-E1FEC2D2F7C6}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "91_Train/csharp/TrainTests/TrainGameTests.cs",
    "content": "using Train;\nusing Xunit;\n\nnamespace TrainTests\n{\n    public class TrainGameTests\n    {\n        [Fact]\n        public void MiniumRandomNumber()\n        {\n            TrainGame game = new TrainGame();\n            Assert.True(game.GenerateRandomNumber(10, 10) >= 10);\n        }\n\n        [Fact]\n        public void MaximumRandomNumber()\n        {\n            TrainGame game = new TrainGame();\n            Assert.True(game.GenerateRandomNumber(10, 10) <= 110);\n        }\n\n        [Fact]\n        public void IsInputYesWhenY()\n        {\n            Assert.True(TrainGame.IsInputYes(\"y\"));\n        }\n\n        [Fact]\n        public void IsInputYesWhenNotY()\n        {\n            Assert.False(TrainGame.IsInputYes(\"a\"));\n        }\n\n        [Fact]\n        public void CarDurationTest()\n        {\n            Assert.Equal(1, TrainGame.CalculateCarJourneyDuration(30, 1, 15) );\n        }\n\n        [Fact]\n        public void IsWithinAllowedDifference()\n        {\n            Assert.True(TrainGame.IsWithinAllowedDifference(5,5));\n        }\n\n\n        [Fact]\n        public void IsNotWithinAllowedDifference()\n        {\n            Assert.False(TrainGame.IsWithinAllowedDifference(6, 5));\n        }\n    }\n}\n"
  },
  {
    "path": "91_Train/csharp/TrainTests/TrainTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.7.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.3\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"1.3.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Train\\TrainGame.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "91_Train/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "91_Train/java/src/Train.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Train\n * <p>\n * Based on the Basic program Train here\n * https://github.com/coding-horror/basic-computer-games/blob/main/91%20Train/train.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic program in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Train {\n\n    private final Scanner kbScanner;\n\n    public Train() {\n        kbScanner = new Scanner(System.in);\n    }\n\n    public void process() {\n\n        intro();\n\n        boolean gameOver = false;\n\n        do {\n            double carMph = (int) (25 * Math.random() + 40);\n            double hours = (int) (15 * Math.random() + 5);\n            double train = (int) (19 * Math.random() + 20);\n\n            System.out.println(\" A CAR TRAVELING \" + (int) carMph + \" MPH CAN MAKE A CERTAIN TRIP IN\");\n            System.out.println((int) hours + \" HOURS LESS THAN A TRAIN TRAVELING AT \" + (int) train + \" MPH.\");\n\n            double howLong = Double.parseDouble(displayTextAndGetInput(\"HOW LONG DOES THE TRIP TAKE BY CAR? \"));\n\n            double hoursAnswer = hours * train / (carMph - train);\n            int percentage = (int) (Math.abs((hoursAnswer - howLong) * 100 / howLong) + .5);\n            if (percentage > 5) {\n                System.out.println(\"SORRY.  YOU WERE OFF BY \" + percentage + \" PERCENT.\");\n            } else {\n                System.out.println(\"GOOD! ANSWER WITHIN \" + percentage + \" PERCENT.\");\n            }\n            System.out.println(\"CORRECT ANSWER IS \" + hoursAnswer + \" HOURS.\");\n\n            System.out.println();\n            if (!yesEntered(displayTextAndGetInput(\"ANOTHER PROBLEM (YES OR NO)? \"))) {\n                gameOver = true;\n            }\n\n        } while (!gameOver);\n\n\n    }\n\n    private void intro() {\n        System.out.println(\"TRAIN\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println(\"TIME - SPEED DISTANCE EXERCISE\");\n        System.out.println();\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text));\n\n    }\n\n    /**\n     * Program startup.\n     *\n     * @param args not used (from command line).\n     */\n    public static void main(String[] args) {\n        Train train = new Train();\n        train.process();\n    }\n}\n"
  },
  {
    "path": "91_Train/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "91_Train/javascript/train.html",
    "content": "<html>\n<head>\n<title>TRAIN</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"train.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "91_Train/javascript/train.js",
    "content": "// TRAIN\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(33) + \"TRAIN\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"TIME - SPEED DISTANCE EXERCISE\\n\");\n    print(\"\\n \");\n    while (1) {\n        c = Math.floor(25 * Math.random()) + 40;\n        d = Math.floor(15 * Math.random()) + 5;\n        t = Math.floor(19 * Math.random()) + 20;\n        print(\" A CAR TRAVELING \" + c + \" MPH CAN MAKE A CERTAIN TRIP IN\\n\");\n        print(d + \" HOURS LESS THAN A TRAIN TRAVELING AT \" + t + \" MPH.\\n\");\n        print(\"HOW LONG DOES THE TRIP TAKE BY CAR\");\n        a = parseFloat(await input());\n        v = d * t / (c - t);\n        e = Math.floor(Math.abs((v - a) * 100 / a) + 0.5);\n        if (e > 5) {\n            print(\"SORRY.  YOU WERE OFF BY \" + e + \" PERCENT.\\n\");\n        } else {\n            print(\"GOOD! ANSWER WITHIN \" + e + \" PERCENT.\\n\");\n        }\n        print(\"CORRECT ANSWER IS \" + v + \" HOURS.\\n\");\n        print(\"\\n\");\n        print(\"ANOTHER PROBLEM (YES OR NO)\\n\");\n        str = await input();\n        print(\"\\n\");\n        if (str.substr(0, 1) != \"Y\")\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "91_Train/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "91_Train/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "91_Train/lua/train.lua",
    "content": "print [[\n            TRAIN\n CREATIVE COMPUTING  MORRISTOWN, NEW JERSY\n\n\n\n TIME - SPEED DISTANCE EXERCISE]]\n\nmath.randomseed(os.time())\n\nlocal ERROR_MARGIN <const> = 5.0\n\nfunction play()\n    local car_speed = 25*math.random() + 40--Between 40 and 64\n    local delta_time = 15*math.random() + 5--Between 5 and 19\n    local train_speed = 19*math.random() + 20--Between 20 and 38\n\n    print( string.format(\"\\nA CAR TRAVELING AT %u MPH CAN MAKE A CERTAIN TRIP IN %u HOURS LESS THAN A TRAIN TRAVELING AT %u MPH.\", car_speed, delta_time, train_speed) )\n\n    local try = true\n    local input\n    while try do\n        io.write(\"HOW LONG DOES THE TRIP TAKE BY CAR? \")\n        input = io.read(\"n\")\n        if input == nil then\n            print(\"<!>PLEASE INSERT A NUMBER<!>\")\n        else\n            try = false\n        end\n        io.read()\n    end\n\n    local car_time = delta_time * train_speed / (car_speed - train_speed)\n    local percent = ( math.abs(car_time-input) * 100 / car_time + .5)\n\n    if percent > ERROR_MARGIN then\n        print( string.format(\"SORRY. YOU WERE OFF BY %f PERCENT.\", percent) )\n    else\n        print( string.format(\"GOOD! ANSWER WITHIN %f PERCENT.\", percent) )\n    end\n    \n    print( string.format(\"CORRECT ANSWER IS %f HOURS.\", car_time) )\nend\n\nfunction game_loop()\n    local keep_playing = true\n    while keep_playing do\n        play()\n        io.write(\"\\nANOTHER PROBLEM (YES OR NO)? \")\n        answer = io.read(\"l\")\n        \n        if not (answer == \"YES\" or answer == \"Y\" or answer == \"yes\" or answer == \"y\") then\n            keep_playing = false\n        end\n    end\n\nend\n\ngame_loop()"
  },
  {
    "path": "91_Train/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "91_Train/perl/train.pl",
    "content": "#!/usr/bin/perl\nuse strict;\nuse warnings;\n\nprint ' 'x33 .\"TRAIN\\n\";\nprint ' 'x15 .\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\nprint \"TIME - SPEED DISTANCE EXERCISE\\n\"; print \"\\n\";\n\n\nmy $A= \"\"; #We must declare this before...\ndo {\n\tmy $C= int(25*rand(1))+40;\n\tmy $D= int(15*rand(1))+5;\n\tmy $T= int(19*rand(1))+20;\n\n\tprint \" A CAR TRAVELING $C MPH CAN MAKE A CERTAIN TRIP IN\\n\";\n\tprint \"$D HOURS LESS THAN A TRAIN TRAVELING AT $T MPH.\\n\";\n\tprint \"HOW LONG DOES THE TRIP TAKE BY CAR\\n\";\n\tchomp ($A = <STDIN>);\n\n\tmy $V= $D*$T/($C-$T);\n\tmy $E= int(abs(($V-$A)*100/$A)+.5);\n\tif ($E>5) {\n\t\tprint \"SORRY.  YOU WERE OFF BY $E PERCENT.\\n\";\n\t\t} else {\n\t\tprint \"GOOD! ANSWER WITHIN $E PERCENT.\\n\";\n\t\t}\n\n\tprint \"CORRECT ANSWER IS $V HOURS.\\n\";\n\tprint \"\\n\";\n\tprint \"ANOTHER PROBLEM (YES OR NO)\\n\";\n\tchomp ($A = uc(<STDIN>)); #Uppercased\n\t} until ($A ne \"YES\");\n"
  },
  {
    "path": "91_Train/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "91_Train/python/train.py",
    "content": "#!/usr/bin/env python3\n# TRAIN\n#\n# Converted from BASIC to Python by Trevor Hobson\n\nimport random\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n    car_speed = random.randint(40, 65)\n    time_difference = random.randint(5, 20)\n    train_speed = random.randint(20, 39)\n    print(\"\\nA car travelling\", car_speed, \"MPH can make a certain trip in\")\n    print(time_difference, \"hours less than a train travelling at\", train_speed, \"MPH\")\n    time_answer: float = 0\n    while time_answer == 0:\n        try:\n            time_answer = float(input(\"How long does the trip take by car \"))\n        except ValueError:\n            print(\"Please enter a number.\")\n    car_time = time_difference * train_speed / (car_speed - train_speed)\n    error_percent = int(abs((car_time - time_answer) * 100 / time_answer) + 0.5)\n    if error_percent > 5:\n        print(\"Sorry. You were off by\", error_percent, \"percent.\")\n        print(\"Correct answer is\", round(car_time, 6), \"hours\")\n    else:\n        print(\"Good! Answer within\", error_percent, \"percent.\")\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"TRAIN\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n    print(\"Time - speed distance exercise\")\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nAnother problem (yes or no) \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "91_Train/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "91_Train/ruby/train.rb",
    "content": "def intro\n  puts \"                                 TRAIN\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\nTIME - SPEED DISTANCE EXERCISE\n\n\"\nend\n\ndef get_user_guess\n  while true\n    begin\n      number = Float(gets.chomp)\n      return number\n    rescue ArgumentError\n      # Ignored\n    end\n\n    puts \"!NUMBER EXPECTED - RETRY INPUT LINE\"\n    print \"? \"\n  end\nend\n\ndef main\n  intro\n\n  loop do\n    car_speed = rand(25) + 40\n    car_time = rand(15) + 5\n    train_speed = rand(19) + 20\n\n    print \" A CAR TRAVELING #{car_speed} MPH CAN MAKE A CERTAIN TRIP IN\n #{car_time} HOURS LESS THAN A TRAIN TRAVELING AT #{train_speed} MPH.\nHOW LONG DOES THE TRIP TAKE BY CAR? \"\n    guess = get_user_guess\n\n    answer = ((car_time * train_speed) / (car_speed - train_speed).to_f).round(5)\n    delta = (((answer - guess) * 100 / guess) + 0.5).abs.to_i\n\n    if delta > 5\n      puts \"SORRY.  YOU WERE OFF BY #{delta} PERCENT.\"\n    else\n      puts \"GOOD! ANSWER WITHIN #{delta} PERCENT.\"\n    end\n\n    print \"CORRECT ANSWER IS #{answer == answer.to_i ? answer.to_i : answer} HOURS.\n\nANOTHER PROBLEM (YES OR NO)? \"\n    option = (gets || '').chomp.upcase\n    break unless option == 'YES'\n  end\nend\n\ntrap \"SIGINT\" do puts; exit 130 end\n\nmain\n"
  },
  {
    "path": "91_Train/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nauthors = [\"AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com>\"]\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "91_Train/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "91_Train/rust/src/lib.rs",
    "content": "/*\n lib.rs contains all the logic of the program\n*/\nuse rand::{Rng, prelude::thread_rng}; //rng\nuse std::error::Error; //better errors\nuse std::io::{self, Write}; //io interactions\nuse std::{str::FromStr, fmt::Display}; //traits\n\n//DATA\n\n/// handles setup for the game\npub struct Config {\n}\nimpl Config {\n    /// creates and returns a new Config from user input\n    pub fn new() -> Result<Config, Box<dyn Error>> {\n        //DATA\n        let config: Config = Config { \n        };\n        \n        //return new config\n        return Ok(config);\n    }\n}\n\n/// run the program\npub fn run(_config: &Config) -> Result<(), Box<dyn Error>> {\n    //DATA\n    let mut rng = thread_rng();\n    \n    let mut speed_train_1;\n    let mut time_difference;\n    let mut speed_train_2;\n\n    let mut guess;\n    let mut answer;\n    \n    let mut error:f32; \n\n    //Game loop\n    loop {\n        //initialize variables\n        speed_train_1 =  rng.gen_range(40..65);\n        time_difference = rng.gen_range(5..20); \n        speed_train_2 = rng.gen_range(20..39);\n\n        //print starting message / conditions\n        println!(\"A CAR TRAVELING {} MPH CAN MAKE A CERTAIN TRIP IN\\n{} HOURS LESS THAN A TRAIN TRAVELING AT {} MPH\",speed_train_1,time_difference,speed_train_2);\n        println!();\n\n        //get guess\n        guess = loop {\n            match get_number_from_input(\"HOW LONG DOES THE TRIP TAKE BY CAR?\",0,-1) {\n                Ok(num) => break num,\n                Err(err) => {\n                    eprintln!(\"{}\",err);\n                    continue;\n                },\n            }\n        };\n\n        //calculate answer and error\n        answer = time_difference * speed_train_2 / (speed_train_1 - speed_train_2);\n        error = ((answer - guess) as isize).abs() as f32 * 100.0/(guess as f32) + 0.5;\n\n        //check guess against answer\n        if error > 5.0 {\n            println!(\"SORRY, YOU WERE OFF BY {} PERCENT.\", error);\n            println!(\"CORRECT ANSWER IS {} HOURS.\",answer);\n        } else {\n            println!(\"GOOD! ANSWER WITHIN {} PERCENT.\", error);\n        }\n\n        //ask user if they want to go again\n        match get_string_from_user_input(\"ANOTHER PROBLEM (Y/N)\") {\n            Ok(s) => if !s.to_uppercase().eq(\"Y\") {break;} else {continue;},\n            _ => break,\n        }\n    }\n\n    //return to main\n    Ok(())\n}\n\n/// gets a string from user input\nfn get_string_from_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\", prompt);\n    //make sure it's printed before getting input\n    io::stdout().flush().expect(\"couldn't flush stdout\");\n\n    //read user input from standard input, and store it to raw_input, then return it or an error as needed\n    raw_input.clear(); //clear input\n    match io::stdin().read_line(&mut raw_input) {\n        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),\n        Err(err) => return Err(format!(\"ERROR: CANNOT READ INPUT!: {}\", err).into()),\n    }\n}\n/// generic function to get a number from the passed string (user input)\n/// pass a min lower  than the max to have minimum and maximum bounds\n/// pass a min higher than the max to only have a minimum bound\n/// pass a min equal   to  the max to only have a maximum bound\n/// \n/// Errors:\n/// no number on user input\nfn get_number_from_input<T:Display + PartialOrd + FromStr>(prompt: &str, min:T, max:T) -> Result<T, Box<dyn Error>> {\n    //DATA\n    let raw_input: String;\n    let processed_input: String;\n\n    \n    //input loop\n    raw_input = loop {\n        match get_string_from_user_input(prompt) {\n            Ok(input) => break input,\n            Err(e) => {\n                eprintln!(\"{}\",e);\n                continue;\n            },\n        }\n    };\n\n    //filter out non-numeric characters from user input\n    processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();\n\n    //from input, try to read a number\n    match processed_input.trim().parse() {\n        Ok(i) => {\n            //what bounds must the input fall into\n            if min < max {  //have a min and max bound: [min,max]\n                if i >= min && i <= max {//is input valid, within bounds\n                    return Ok(i); //exit the loop with the value i, returning it\n                } else { //print error message specific to this case\n                    return Err(format!(\"ONLY BETWEEN {} AND {}, PLEASE!\", min, max).into());\n                } \n            } else if min > max { //only a min bound: [min, infinity)\n                if i >= min {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO LESS THAN {}, PLEASE!\", min).into());\n                }\n            } else { //only a max bound: (-infinity, max]\n                if i <= max {\n                    return Ok(i);\n                } else {\n                    return Err(format!(\"NO MORE THAN {}, PLEASE!\", max).into());\n                }\n            }\n        },\n        Err(_e) => return Err(format!(\"Error: couldn't find a valid number in {}\",raw_input).into()),\n    }\n}\n"
  },
  {
    "path": "91_Train/rust/src/main.rs",
    "content": "use std::process;//allows for some better error handling\n\nmod lib; //allows access to lib.rs\nuse lib::Config;\n\n/// main function\n/// responsibilities:\n/// - Calling the command line logic with the argument values\n/// - Setting up any other configuration\n/// - Calling a run function in lib.rs\n/// - Handling the error if run returns an error\nfn main() {\n    //greet user\n    welcome();\n\n    // set up other configuration\n    let mut config = Config::new().unwrap_or_else(|err| {\n        eprintln!(\"Problem configuring program: {}\", err);\n        process::exit(1);\n    });\n\n    // run the program\n    if let Err(e) = lib::run(&mut config) {\n        eprintln!(\"Application Error: {}\", e); //use the eprintln! macro to output to standard error\n        process::exit(1); //exit the program with an error code\n    }\n\n    //end of program\n    println!(\"THANKS FOR PLAYING!\");\n}\n\n/// print the welcome message\nfn welcome() {\n    println!(\"\n                                Train\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\nTIME - SPEED DISTANCE EXERCISE\n    \");\n}\n"
  },
  {
    "path": "91_Train/train.bas",
    "content": "1 PRINT TAB(33);\"TRAIN\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT: PRINT: PRINT\n4 PRINT \"TIME - SPEED DISTANCE EXERCISE\": PRINT\n10 C=INT(25*RND(1))+40\n15 D=INT(15*RND(1))+5\n20 T=INT(19*RND(1))+20\n25 PRINT \" A CAR TRAVELING\";C;\"MPH CAN MAKE A CERTAIN TRIP IN\"\n30 PRINT D;\"HOURS LESS THAN A TRAIN TRAVELING AT\";T;\"MPH.\"\n35 PRINT \"HOW LONG DOES THE TRIP TAKE BY CAR\";\n40 INPUT A\n45 V=D*T/(C-T)\n50 E=INT(ABS((V-A)*100/A)+.5)\n55 IF E>5 THEN 70\n60 PRINT \"GOOD! ANSWER WITHIN\";E;\"PERCENT.\"\n65 GOTO 80\n70 PRINT \"SORRY.  YOU WERE OFF BY\";E;\"PERCENT.\"\n80 PRINT \"CORRECT ANSWER IS\";V;\"HOURS.\"\n90 PRINT\n95 PRINT \"ANOTHER PROBLEM (YES OR NO)\";\n100 INPUT A$\n105 PRINT\n110 IF A$=\"YES\" THEN 10\n999 END\n"
  },
  {
    "path": "91_Train/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "91_Train/vbnet/Train.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Train\", \"Train.vbproj\", \"{05F1229A-9138-4B1D-9781-CE8C4F7A6151}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "91_Train/vbnet/Train.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Train</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "92_Trap/README.md",
    "content": "### Trap\n\nThis is another in the family of “guess the mystery number” games. In TRAP the computer selects a random number between 1 and 100 (or other limit set). Your object is to find the number. On each guess, you enter 2 numbers trying to trap the mystery number between your two trap numbers. The computer will tell you if you have trapped the number.\n\nTo win the game, you must guess the mystery number by entering it as the same value for both of your trap numbers. You get 6 guesses (this should be changed if you change the guessing limit).\n\nAfter you have played GUESS, STARS, and TRAP, compare the guessing strategy you have found best for each game. Do you notice any similarities? What are the differences? Can you write a new guessing game with still another approach?\n\nTRAP was suggested by a 10-year-old when he was playing GUESS. It was originally programmed by Steve Ullman and extensively modified into its final form by Bob Albrecht of People’s Computer Co.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=176)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=191)\n\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "92_Trap/csharp/Program.cs",
    "content": "﻿using System;\n\nnamespace trap_cs\n{\n  class Program\n  {\n    const int maxGuesses = 6;\n    const int maxNumber = 100;\n    static void Main(string[] args)\n    {\n      int lowGuess  = 0;\n      int highGuess = 0;\n\n      Random randomNumberGenerator = new ();\n\n      Print(\"TRAP\");\n      Print(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n      Print();\n      Print();\n      Print();\n\n      PrintInstructions();\n\n      int numberToGuess = randomNumberGenerator.Next(1, maxNumber);\n\n      for (int nGuess = 1; nGuess <= maxGuesses + 1; nGuess++)\n      {\n        if (nGuess > maxGuesses)\n        {\n          Print(string.Format(\"SORRY, THAT'S {0} GUESSES. THE NUMBER WAS {1}\", maxGuesses, numberToGuess));\n          Print();\n          break;\n        }\n\n        GetGuesses(nGuess, ref lowGuess, ref highGuess);\n\n        if(lowGuess == highGuess && lowGuess == numberToGuess)\n        {\n          Print(\"YOU GOT IT!!!\");\n          Print();\n          Print(\"TRY AGAIN.\");\n          Print();\n          break;\n        }\n        if (highGuess < numberToGuess)\n        {\n          Print(\"MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\");\n        }\n        else if (lowGuess > numberToGuess)\n        {\n          Print(\"MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\");\n        }\n        else\n        {\n          Print(\"YOU HAVE TRAPPED MY NUMBER.\");\n        }\n      }\n    }\n\n// TRAP\n// REM - STEVE ULLMAN, 8 - 1 - 72\n    static void PrintInstructions()\n    {\n      Print(\"INSTRUCTIONS ?\");\n\n      char response = Console.ReadKey().KeyChar;\n      if (response == 'Y')\n      {\n        Print(string.Format(\"I AM THINKING OF A NUMBER BETWEEN 1 AND {0}\", maxNumber));\n        Print(\"TRY TO GUESS MY NUMBER. ON EACH GUESS,\");\n        Print(\"YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\");\n        Print(\"MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\");\n        Print(\"TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\");\n        Print(\"NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\");\n        Print(\"MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\");\n        Print(\"IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\");\n        Print(\"YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\");\n        Print(string.Format(\"YOU GET {0} GUESSES TO GET MY NUMBER.\", maxGuesses));\n      }\n    }\n    static void Print(string stringToPrint)\n    {\n      Console.WriteLine(stringToPrint);\n    }\n    static void Print()\n    {\n      Console.WriteLine();\n    }\n    static void GetGuesses(int nGuess, ref int lowGuess, ref int highGuess)\n    {\n      Print();\n      Print(string.Format(\"GUESS #{0}\", nGuess));\n\n      lowGuess  = GetIntFromConsole(\"Type low guess\");\n      highGuess = GetIntFromConsole(\"Type high guess\");\n\n      if(lowGuess > highGuess)\n      {\n        int tempGuess = lowGuess;\n\n        lowGuess = highGuess;\n        highGuess = tempGuess;\n      }\n    }\n    static int GetIntFromConsole(string prompt)\n    {\n\n      Console.Write( prompt + \" > \");\n      string intAsString = Console.ReadLine();\n\n      if(int.TryParse(intAsString, out int intValue) ==false)\n      {\n        intValue = 1;\n      }\n\n      return intValue;\n    }\n  }\n}\n"
  },
  {
    "path": "92_Trap/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "92_Trap/csharp/Trap.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "92_Trap/csharp/Trap.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Trap\", \"Trap.csproj\", \"{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "92_Trap/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "92_Trap/java/src/Trap.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Trap\n * <p>\n * Based on the Basic game of Trap here\n * https://github.com/coding-horror/basic-computer-games/blob/main/92%20Trap/trap.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n */\npublic class Trap {\n\n    public static final int HIGH_NUMBER_RANGE = 100;\n    public static final int MAX_GUESSES = 6;\n\n    private enum GAME_STATE {\n        STARTING,\n        START_GAME,\n        GUESSING,\n        PLAY_AGAIN,\n        GAME_OVER\n    }\n\n    // Used for keyboard input\n    private final Scanner kbScanner;\n\n    // Current game state\n    private GAME_STATE gameState;\n\n    // Players guess count;\n    private int currentPlayersGuess;\n\n    // Computers random number\n    private int computersNumber;\n\n    public Trap() {\n\n        gameState = GAME_STATE.STARTING;\n\n        // Initialise kb scanner\n        kbScanner = new Scanner(System.in);\n    }\n\n    /**\n     * Main game loop\n     */\n    public void play() {\n\n        do {\n            switch (gameState) {\n\n                // Show an introduction and optional instructions the first time the game is played.\n                case STARTING:\n                    intro();\n                    if (yesEntered(displayTextAndGetInput(\"INSTRUCTIONS? \"))) {\n                        instructions();\n                    }\n                    gameState = GAME_STATE.START_GAME;\n                    break;\n\n                // Start new game\n                case START_GAME:\n                    computersNumber = randomNumber();\n                    currentPlayersGuess = 1;\n                    gameState = GAME_STATE.GUESSING;\n                    break;\n\n                // Player guesses the number until they get it or run out of guesses\n                case GUESSING:\n                    System.out.println();\n                    String playerRangeGuess = displayTextAndGetInput(\"GUESS # \" + currentPlayersGuess + \"? \");\n                    int startRange = getDelimitedValue(playerRangeGuess, 0);\n                    int endRange = getDelimitedValue(playerRangeGuess, 1);\n\n                    // Has the player won?\n                    if (startRange == computersNumber && endRange == computersNumber) {\n                        System.out.println(\"YOU GOT IT!!!\");\n                        System.out.println();\n                        gameState = GAME_STATE.PLAY_AGAIN;\n                    } else {\n                        // show where the guess is at\n                        System.out.println(showGuessResult(startRange, endRange));\n                        currentPlayersGuess++;\n                        if (currentPlayersGuess > MAX_GUESSES) {\n                            System.out.println(\"SORRY, THAT'S \" + MAX_GUESSES + \" GUESSES. THE NUMBER WAS \"\n                                    + computersNumber);\n                            gameState = GAME_STATE.PLAY_AGAIN;\n                        }\n                    }\n                    break;\n\n                // Play again, or exit game?\n                case PLAY_AGAIN:\n                    System.out.println(\"TRY AGAIN\");\n                    gameState = GAME_STATE.START_GAME;\n            }\n        } while (gameState != GAME_STATE.GAME_OVER);\n    }\n\n    /**\n     * Show the players guess result\n     *\n     * @param start start range entered by player\n     * @param end   end range\n     * @return text to indicate their progress.\n     */\n    private String showGuessResult(int start, int end) {\n\n        String status;\n        if (start <= computersNumber && computersNumber <= end) {\n            status = \"YOU HAVE TRAPPED MY NUMBER.\";\n        } else if (computersNumber < start) {\n            status = \"MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\";\n        } else {\n            status = \"MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\";\n        }\n\n        return status;\n    }\n\n    private void instructions() {\n        System.out.println(\"I AM THINKING OF A NUMBER BETWEEN 1 AND \" + HIGH_NUMBER_RANGE);\n        System.out.println(\"TRY TO GUESS MY NUMBER. ON EACH GUESS,\");\n        System.out.println(\"YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\");\n        System.out.println(\"MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\");\n        System.out.println(\"TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\");\n        System.out.println(\"NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\");\n        System.out.println(\"MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\");\n        System.out.println(\"IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\");\n        System.out.println(\"YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\");\n        System.out.println(\"YOU GET \" + MAX_GUESSES + \" GUESSES TO GET MY NUMBER.\");\n    }\n\n    private void intro() {\n        System.out.println(\"TRAP\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println();\n        System.out.println();\n    }\n\n    /**\n     * Accepts a string delimited by comma's and returns the nth delimited\n     * value (starting at count 0).\n     *\n     * @param text - text with values separated by comma's\n     * @param pos  - which position to return a value for\n     * @return the int representation of the value\n     */\n    private int getDelimitedValue(String text, int pos) {\n        String[] tokens = text.split(\",\");\n        return Integer.parseInt(tokens[pos]);\n    }\n\n    /**\n     * Checks whether player entered Y or YES to a question.\n     *\n     * @param text player string from kb\n     * @return true of Y or YES was entered, otherwise false\n     */\n    private boolean yesEntered(String text) {\n        return stringIsAnyValue(text, \"Y\", \"YES\");\n    }\n\n    /**\n     * Check whether a string equals one of a variable number of values\n     * Useful to check for Y or YES for example\n     * Comparison is case insensitive.\n     *\n     * @param text   source string\n     * @param values a range of values to compare against the source string\n     * @return true if a comparison was found in one of the variable number of strings passed\n     */\n    private boolean stringIsAnyValue(String text, String... values) {\n\n        return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text));\n    }\n\n    /*\n     * Print a message on the screen, then accept input from Keyboard.\n     *\n     * @param text message to be displayed on screen.\n     * @return what was typed by the player.\n     */\n    private String displayTextAndGetInput(String text) {\n        System.out.print(text);\n        return kbScanner.next();\n    }\n\n    /**\n     * Generate random number\n     * Used as a single digit of the computer player\n     *\n     * @return random number\n     */\n    private int randomNumber() {\n        return (int) (Math.random()\n                * (HIGH_NUMBER_RANGE) + 1);\n    }\n}\n"
  },
  {
    "path": "92_Trap/java/src/TrapGame.java",
    "content": "public class TrapGame {\n\n    public static void main(String[] args) {\n\n        Trap trap = new Trap();\n        trap.play();\n    }\n}\n"
  },
  {
    "path": "92_Trap/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "92_Trap/javascript/trap.html",
    "content": "<html>\n<head>\n<title>TRAP</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"trap.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "92_Trap/javascript/trap.js",
    "content": "// TRAP\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(34) + \"TRAP\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    g = 6;\n    n = 100;\n    // Trap\n    // Steve Ullman, Aug/01/1972\n    print(\"INSTRUCTIONS\");\n    str = await input();\n    if (str.substr(0, 1) == \"Y\") {\n        print(\"I AM THINKING OF A NUMBER BETWEEN 1 AND \" + n + \"\\n\");\n        print(\"TRY TO GUESS MY NUMBER. ON EACH GUESS,\\n\");\n        print(\"YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\\n\");\n        print(\"MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\\n\");\n        print(\"TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\\n\");\n        print(\"NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\\n\");\n        print(\"MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\\n\");\n        print(\"IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\\n\");\n        print(\"YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\\n\");\n        print(\"YOU GET \" + g + \" GUESSES TO GET MY NUMBER.\\n\");\n    }\n    while (1) {\n        x = Math.floor(n * Math.random()) + 1;\n        for (q = 1; q <= g; q++) {\n            print(\"\\n\");\n            print(\"GUESS #\" + q + \" \");\n            str = await input();\n            a = parseInt(str);\n            b = parseInt(str.substr(str.indexOf(\",\") + 1));\n            if (a == b && x == a) {\n                print(\"YOU GOT IT!!!\\n\");\n                break;\n            }\n            if (a > b) {\n                r = a;\n                a = b;\n                b = r;\n            }\n            if (a <= x && x <= b) {\n                print(\"YOU HAVE TRAPPED MY NUMBER.\\n\");\n            } else if (x >= a) {\n                print(\"MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\\n\");\n            } else {\n                print(\"MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\\n\");\n            }\n        }\n        print(\"\\n\");\n        print(\"TRY AGAIN.\\n\");\n        print(\"\\n\");\n    }\n}\n\nmain();\n"
  },
  {
    "path": "92_Trap/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "92_Trap/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "92_Trap/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "92_Trap/perl/trap.pl",
    "content": "#!/usr/bin/perl\nuse strict;\n\nprint ' 'x 34 . \"TRAP\\n\";\nprint ' 'x 15 . \"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\"; print \"\\n\"; print \"\\n\";\nmy $G=6;\nmy $N=100;\n# REM-TRAP;\n# REM-STEVE ULLMAN, 8-1-72;\n\nprint \"INSTRUCTIONS\";\nprint \"? \"; chomp(my $Z = uc(<STDIN>));\nif (substr($Z,0,1) eq \"Y\") {\n\tprint \"I AM THINKING OF A NUMBER BETWEEN 1 AND $N\\n\";\n\tprint \"TRY TO GUESS MY NUMBER. ON EACH GUESS,\\n\";\n\tprint \"YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\\n\";\n\tprint \"MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\\n\";\n\tprint \"TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\\n\";\n\tprint \"NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\\n\";\n\tprint \"MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\\n\";\n\tprint \"IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\\n\";\n\tprint \"YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\\n\";\n\tprint \"YOU GET $G GUESSES TO GET MY NUMBER.\\n\";\n\t}\n\nwhile (1) {\n\tmy $Flag= 0;\n\tmy $X=int($N*rand(1))+1;\n\tfor (my $Q=1; $Q<=$G; $Q++) {\n\t\tprint \"\\n\";\n\t\tprint \"GUESS #$Q \";\n\t\tprint \"? \"; chomp(my $Pair= uc(<STDIN>));\n\t\tmy ($A, $B)= split(\",\", $Pair);\n\t\tif ($A eq $B && $X eq $A) { $Flag=1; last; }\n\n\t\tif ($A>$B) { ($A,$B)= ($B,$A); }\n\t\tif ($X>$B) {\n\t\t\tprint \"MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\\n\";\n\t\t\tnext;\n\t\t\t}\n\t\tif ($X<$A) {\n\t\t\tprint \"MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\\n\";\n\t\t\tnext;\n\t\t\t}\n\t\tprint \"YOU HAVE TRAPPED MY NUMBER.\\n\";\n\t\t}\n\n\tif ($Flag==0) {\n\t\tprint \"SORRY, THAT'S $G GUESSES. THE NUMBER WAS $X\\n\";\n\t\t} else {\n\t\tprint \"YOU GOT IT!!!\\n\";\n\t\t}\n\n\tprint \"\\n\";\n\tprint \"TRY AGAIN.\\n\";\n\tprint \"\\n\";\n\t}\n\nexit;\n"
  },
  {
    "path": "92_Trap/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "92_Trap/python/trap.py",
    "content": "#!/usr/bin/env python3\n# TRAP\n#\n# STEVE ULLMAN, 8-1-72\n# Converted from BASIC to Python by Trevor Hobson\n\nimport random\n\nnumber_max = 100\nguess_max = 6\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n\n    number_computer = random.randint(1, number_max)\n    turn = 0\n    while True:\n        turn += 1\n        user_guess = [-1, -1]\n        while user_guess == [-1, -1]:\n            try:\n                user_input = [\n                    int(item)\n                    for item in input(\"\\nGuess # \" + str(turn) + \" ? \").split(\",\")\n                ]\n                if len(user_input) != 2:\n                    raise ValueError\n                if sum(1 < x < number_max for x in user_input) == 2:\n                    user_guess = user_input\n                else:\n                    raise ValueError\n            except (ValueError, IndexError):\n                print(\"Please enter a valid guess.\")\n        if user_guess[0] > user_guess[1]:\n            user_guess[0], user_guess[1] = user_guess[1], user_guess[0]\n        if user_guess[0] == user_guess[1] == number_computer:\n            print(\"You got it!!!\")\n            break\n        elif user_guess[0] <= number_computer <= user_guess[1]:\n            print(\"You have trapped my number.\")\n        elif number_computer < user_guess[0]:\n            print(\"My number is smaller than your trap numbers.\")\n        else:\n            print(\"My number is larger than your trap numbers.\")\n        if turn == guess_max:\n            print(\"That's\", turn, \"guesses. The number was\", number_computer)\n            break\n\n\ndef main() -> None:\n    print(\" \" * 34 + \"TRAP\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n    if input(\"Instructions \").lower().startswith(\"y\"):\n        print(\"\\nI am thinking of a number between 1 and\", number_max)\n        print(\"try to guess my number. On each guess,\")\n        print(\"you are to enter 2 numbers, trying to trap\")\n        print(\"my number between the two numbers. I will\")\n        print(\"tell you if you have trapped my number, if my\")\n        print(\"number is larger than your two numbers, or if\")\n        print(\"my number is smaller than your two numbers.\")\n        print(\"If you want to guess one single number, type\")\n        print(\"your guess for both your trap numbers.\")\n        print(\"You get\", guess_max, \"guesses to get my number.\")\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nTry again. \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "92_Trap/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "92_Trap/ruby/trap.rb",
    "content": "#!/usr/bin/env ruby\n\n# Trap\n# Steve Ullman, 1972-08-01\n# Ruby version Glenn Vanderburg, 2022-03-04\n\n# Change these values to make the game easier or harder.\nGUESSES_PER_GAME = 6\nNUMBER_UPPER_BOUND = 100\n\n# Put everything in methods for order of presentation; we\n# want to be able to refer to methods before declaring them,\n# so the code reads nicely from top to bottom.\ndef main\n  print_banner_and_instructions\n\n  loop do\n    play_a_game\n    break unless yes?(\"Try again?\")\n  end\nend\n\ndef yes?(prompt)\n  print \"\\n#{prompt} \"\n  answer = gets\n  return answer.downcase.start_with?(\"y\")\nend\n\ndef print_banner_and_instructions\n  banner = \"Creative Computing -- Morristown, New Jersey\"\n\n  puts \"Trap!\".center(banner.size)\n  puts banner\n  2.times { puts }\n\n  return unless yes?(\"Instructions?\")\n\n  puts <<~\"END\"\n    I am thinking of a number between 1 and #{NUMBER_UPPER_BOUND}.\n    Try to guess my number. On each guess,\n    you are to enter 2 numbers, trying to trap\n    my number between the two numbers. I will\n    tell you if you have trapped my number, if my\n    number is larger than your two numbers, or if\n    my number is smaller than your two numbers.\n    If you want to guess one single number, type\n    your guess for both your trap numbers.\n    You get #{GUESSES_PER_GAME} guesses to get my number.\n  END\nend\n\ndef play_a_game\n  n = choose_number\n\n  GUESSES_PER_GAME.times do |i|\n    lower, upper = get_guesses(\"Guess ##{i+1}?\")\n\n    case\n    when n < lower\n      puts \"My number is smaller than your trap numbers.\"\n    when n > upper\n      puts \"My number is larger than your trap numbers.\"\n    when lower != upper\n      puts \"You have trapped my number.\"\n    else\n      puts \"You got it!!!\"\n      return\n    end\n  end\n\n  puts \"Sorry, that's #{GUESSES_PER_GAME} guesses. Number was #{n}\"\nend\n\ndef choose_number\n  rand(NUMBER_UPPER_BOUND) + 1\nend\n\ndef get_guesses(prompt)\n  loop do\n    print \"\\n#{prompt} \"\n\n    # This is forgiving of input format; it ignores spaces and\n    # punctuation, returning only the strings of consecutive\n    # digits in the input line.\n    guesses = gets.scan(/\\d+/)\n\n    if guesses.size != 2\n      puts \"Please enter two numbers for each guess.\"\n    else\n      # convert the strings of digits to integers:\n      numbers = guesses.map(&:to_i)\n      # and return them, lowest number first:\n      return numbers.sort\n    end\n  end\nend\n\nmain\n"
  },
  {
    "path": "92_Trap/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand=\"0.8.5\"\n"
  },
  {
    "path": "92_Trap/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Uğur Küpeli [ugurkupeli](https://github.com/ugurkupeli)"
  },
  {
    "path": "92_Trap/rust/src/main.rs",
    "content": "use std::io::stdin;\n\nuse rand::Rng;\n\nfn main() {\n    println!(\"\\n\\t\\tTRAP\");\n    println!(\"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\\n\");\n\n    let max_guess = 6;\n    let max_number = 100;\n\n    prompt_instructions();\n\n    loop {\n        let number = rand::thread_rng().gen_range(1..(max_number + 1));\n        let mut guesses = 1u8;\n\n        loop {\n            let (min, max) = prompt_numbers(guesses);\n\n            if min == number && max == number {\n                println!(\"\\nYou got it!!!\");\n                break;\n            } else if (min..=max).contains(&number) {\n                println!(\"You have trapped my number.\");\n            } else if number < min {\n                println!(\"My number is smaller than your trap numbers.\");\n            } else if number > max {\n                println!(\"My number is bigger than your trap numbers.\");\n            }\n\n            guesses += 1;\n            if guesses > max_guess {\n                println!(\"\\nSorry, that was {max_guess} guesses. Number was {number}\");\n                break;\n            }\n        }\n\n        println!(\"\\nTry again.\");\n    }\n}\n\nfn prompt_instructions() {\n    println!(\"Instructions?\\t\");\n\n    let mut input = String::new();\n    if let Ok(_) = stdin().read_line(&mut input) {\n        match input.to_uppercase().trim() {\n            \"YES\" | \"Y\" => {\n                println!(\"\\nI am thinking of a number between 1 and 100\");\n                println!(\"Try to guess my number. On each guess,\");\n                println!(\"you are to enter 2 numbers, trying to trap\");\n                println!(\"my number between the two numbers. I will\");\n                println!(\"tell you if you have trapped my number, if my\");\n                println!(\"number is larger than your two numbers, or if\");\n                println!(\"my number is smaller than your two numbers.\");\n                println!(\"If you want to guess one single number, type\");\n                println!(\"your guess for both your trap numbers.\");\n                println!(\"You get 6 guesses to get my number.\");\n            }\n            _ => (),\n        }\n    }\n}\n\nfn prompt_numbers(guess: u8) -> (u8, u8) {\n    loop {\n        let mut nums: Vec<u8> = Vec::new();\n        println!(\"\\nGuess # {guess} ?\");\n\n        let mut input = String::new();\n        if let Ok(_) = stdin().read_line(&mut input) {\n            let input: Vec<&str> = input.trim().split(\",\").collect();\n\n            for string in input {\n                if let Ok(number) = string.parse::<u8>() {\n                    nums.push(number);\n                } else {\n                    break;\n                }\n            }\n\n            if nums.len() == 2 {\n                if nums[0] <= nums[1] {\n                    return (nums[0], nums[1]);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "92_Trap/trap.bas",
    "content": "1 PRINT TAB(34);\"TRAP\"\n2 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n3 PRINT:PRINT:PRINT\n10 G=6\n20 N=100\n30 REM-TRAP\n40 REM-STEVE ULLMAN, 8-1-72\n50 PRINT \"INSTRUCTIONS\";\n60 INPUT Z$\n70 IF LEFT$(Z$,1)<>\"Y\" THEN 180\n80 PRINT \"I AM THINKING OF A NUMBER BETWEEN 1 AND\";N\n90 PRINT \"TRY TO GUESS MY NUMBER. ON EACH GUESS,\"\n100 PRINT \"YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\"\n110 PRINT \"MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\"\n120 PRINT \"TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\"\n130 PRINT \"NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\"\n140 PRINT \"MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\"\n150 PRINT \"IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\"\n160 PRINT \"YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\"\n170 PRINT \"YOU GET\";G;\"GUESSES TO GET MY NUMBER.\"\n180 X=INT(N*RND(1))+1\n190 FOR Q=1 TO G\n200 PRINT\n210 PRINT \"GUESS #\";Q;\n220 INPUT A,B\n230 IF A=B AND X=A THEN 400\n240 IF A <= B THEN 260\n250 GOSUB 360\n260 IF A <= X AND X <= B THEN 320\n270 IF X<A THEN 300\n280 PRINT \"MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\"\n290 GOTO 330\n300 PRINT \"MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\"\n310 GOTO 330\n320 PRINT \"YOU HAVE TRAPPED MY NUMBER.\"\n330 NEXT Q\n340 PRINT \"SORRY, THAT'S\";G;\"GUESSES. THE NUMBER WAS\";X\n345 PRINT\n350 GOTO 410\n360 R=A\n370 A=B\n380 B=R\n390 RETURN\n400 PRINT \"YOU GOT IT!!!\"\n410 PRINT\n420 PRINT \"TRY AGAIN.\"\n430 PRINT\n440 GOTO 180\n450 END\n"
  },
  {
    "path": "92_Trap/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "92_Trap/vbnet/Trap.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Trap\", \"Trap.vbproj\", \"{BAA7B27D-D52D-4C34-972B-2F357F60B8AB}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BAA7B27D-D52D-4C34-972B-2F357F60B8AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BAA7B27D-D52D-4C34-972B-2F357F60B8AB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BAA7B27D-D52D-4C34-972B-2F357F60B8AB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BAA7B27D-D52D-4C34-972B-2F357F60B8AB}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "92_Trap/vbnet/Trap.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Trap</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "93_23_Matches/23matches.bas",
    "content": "20 PRINT TAB(31);\"23 MATCHES\"\n30 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n40 PRINT:PRINT:PRINT\n80 PRINT \" THIS IS A GAME CALLED '23 MATCHES'.\"\n90 PRINT\n100 PRINT \"WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\"\n110 PRINT \"MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\"\n120 PRINT \"THE LAST MATCH.\"\n130 PRINT\n140 PRINT \"LET'S FLIP A COIN TO SEE WHO GOES FIRST.\"\n150 PRINT \"IF IT COMES UP HEADS, I WILL WIN THE TOSS.\"\n155 PRINT\n160 REM\n165 N = 23\n170 Q = INT(2*RND(5))\n180 IF Q = 1 THEN 210\n190 PRINT \"TAILS! YOU GO FIRST. \"\n195 PRINT\n200 GOTO 300\n210 PRINT \"HEADS! I WIN! HA! HA!\"\n220 PRINT \"PREPARE TO LOSE, MEATBALL-NOSE!!\"\n230 PRINT\n250 PRINT \"I TAKE 2 MATCHES\"\n260 N = N -2\n270 PRINT \"THE NUMBER OF MATCHES IS NOW\" N\n280 PRINT\n290 PRINT \"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\"\n300 PRINT \"HOW MANY DO YOU WISH TO REMOVE\",\n310 INPUT K\n320 IF K > 3 THEN 430\n330 IF K <= 0 THEN 430\n340 N = N - K\n350 PRINT \"THERE ARE NOW\";N;\"MATCHES REMAINING.\"\n351 IF N = 4 THEN 381\n352 IF N = 3 THEN 383\n353 IF N = 2 THEN 385\n360 IF N <= 1 THEN  530\n370 Z = 4 - K\n372 GOTO 390\n380 PRINT\n381 Z = 3\n382 GOTO 390\n383 Z = 2\n384 GOTO 390\n385 Z = 1\n390 PRINT \"MY TURN ! I REMOVE\" Z \"MATCHES\"\n400 N = N - Z\n410 IF N <= 1 THEN 470\n420 GOTO 270\n430 PRINT \"VERY FUNNY! DUMMY!\"\n440 PRINT \"DO YOU WANT TO PLAY OR GOOF AROUND?\"\n450 PRINT \"NOW, HOW MANY MATCHES DO YOU WANT\",\n460 GOTO 310\n470 PRINT\n480 PRINT\"YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\"\n490 PRINT \"HA ! HA ! I BEAT YOU !!!\"\n500 PRINT\n510 PRINT \"GOOD BYE LOSER!\"\n520 GOTO 560\n530 PRINT \"YOU WON, FLOPPY EARS !\"\n540 PRINT \"THINK YOU'RE PRETTY SMART !\"\n550 PRINT \"LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\"\n560 STOP\n570 END\n"
  },
  {
    "path": "93_23_Matches/README.md",
    "content": "### 23 Matches\n\nIn the game of twenty-three matches, you start with 23 matches lying on a table. On each turn, you may take 1, 2, or 3 matches. You alternate moves with the computer and the one who has to take the last match loses.\n\nThe easiest way to devise a winning strategy is to start at the end of the game. Since your wish to leave the last match to your opponent, you would like to have either 4, 3, or 2 on your last turn you so can take away 3, 2, or 1 and leave 1. Consequently, you would like to leave your opponent with 5 on his next to last turn so, no matter what his move, you are left with 4, 3, or 2. Work this backwards to the beginning and you’ll find the game can effectively be won on the first move. Fortunately, the computer gives you the first move, so if you play wisely, you can win.\n\nAfter you’ve mastered 23 Matches, move on to BATNUM and then to NUM.\n\nThis version of 23 Matches was originally written by Bob Albrecht of People’s Computer Company.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=177)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=192)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\nThere is an oddity (you can call it a bug, but it is no big deal) in the original code. If there are only two or three matches left at the player's turn and the player picks all of them (or more), the game would still register that as a win for the player.\n"
  },
  {
    "path": "93_23_Matches/csharp/23Matches.cs",
    "content": "﻿using System;\n\nnamespace Program\n{\n  class Program\n  {\n\n    // Initialize 3 public variables so that they can be ascessed anywhere in the code\n    public static int numberOfMatches;\n    public static int numberOfMatchesRemovedByPlayer;\n    public static bool playerGoesFirst = false; // a flag to show if the player won the coin toss\n    static void Main(string[] args)\n    {\n      // Print introduction text\n\n      // Prints the title with 31 spaces placed in front of the text using the PadLeft() string function\n      Console.WriteLine(\"23 MATCHES\".PadLeft(31));\n      Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".PadLeft(15));\n      \n      // Print 3 blank lines with \\n escape sequence\n      Console.Write(\"\\n\\n\\n\");\n      Console.WriteLine(\" THIS IS A GAME CALLED '23 MATCHES'.\");\n      Console.Write(\"\\n\");\n\n      Console.WriteLine(\"WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\");\n      Console.WriteLine(\"MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\");\n      Console.WriteLine(\"THE LAST MATCH.\");\n      Console.Write(\"\\n\");\n      Console.WriteLine(\"LET'S FLIP A COIN TO SEE WHO GOES FIRST.\");\n      Console.WriteLine(\"IF IT COMES UP HEADS, I WILL WIN THE TOSS.\");\n      Console.Write(\"\\n\");\n\n      // Set the number of matches to 23\n      numberOfMatches = 23;\n\n      // Create a random class object to generate the coin toss\n      Random random = new Random();\n      // Generates a random number between 0.0 and 1.0\n      // Multiplies that number by 2 and then\n      // Converts it into an integer giving either a 0 or a 1\n      int coinTossResult = (int)(2 * random.NextDouble()); \n\n      if (coinTossResult == 1)\n      {\n        Console.WriteLine(\"TAILS! YOU GO FIRST. \");\n        // Sets the player coin toss flag to true\n        playerGoesFirst = true;\n        PlayerTurn();\n      }\n      else\n      {\n        Console.WriteLine(\"HEADS! I WIN! HA! HA!\");\n        Console.WriteLine(\"PREPARE TO LOSE, MEATBALL-NOSE!!\");\n        Console.Write(\"\\n\");\n        Console.WriteLine(\"I TAKE 2 MATCHES\");\n        numberOfMatches = numberOfMatches - 2;\n      }\n\n      // loops the code until there is 1 or fewer matches\n      do\n      {\n        // Checks if the player has already gone \n        // because they won the coin toss\n        // if they have not then the player can go\n        if (playerGoesFirst == false)\n        {\n          Console.Write(\"THE NUMBER OF MATCHES IS NOW \" + numberOfMatches);\n          PlayerTurn();\n        }\n        // sets the coint toss flag to false since\n        // this is only needed on the first loop of the code\n        playerGoesFirst = false;\n        ComputerTurn();        \n      } while (numberOfMatches > 1);\n\n    }\n\n    static void PlayerTurn()\n    {\n      Console.WriteLine(\"\\n\");\n      Console.WriteLine(\"YOUR TURN -- YOU MAY TAKE 1, 2, OR 3 MATCHES.\");\n      Console.Write(\"HOW MANY DO YOU WISH TO REMOVE ?? \");\n      // Get player input\n      numberOfMatchesRemovedByPlayer = ReadPlayerInput();\n      // If the input is invalid (not 1, 2, or 3)\n      // then ask the player to input again\n      while (numberOfMatchesRemovedByPlayer > 3 || numberOfMatchesRemovedByPlayer <= 0)\n      {\n        Console.WriteLine(\"VERY FUNNY! DUMMY!\");\n        Console.WriteLine(\"DO YOU WANT TO PLAY OR GOOF AROUND?\");\n        Console.Write(\"NOW, HOW MANY MATCHES DO YOU WANT                 ?? \");\n        numberOfMatchesRemovedByPlayer = ReadPlayerInput();\n      }\n\n      // Remove the player specified number of matches\n      numberOfMatches = numberOfMatches - numberOfMatchesRemovedByPlayer;\n\n      Console.WriteLine(\"THE ARE NOW \" + numberOfMatches + \" MATCHES REMAINING\");      \n    }\n    static void ComputerTurn()\n    {\n      // Initialize the numberOfMatchesRemovedByComputer\n      int numberOfMatchesRemovedByComputer = 0;\n      switch (numberOfMatches)\n      {\n        case 4:\n          numberOfMatchesRemovedByComputer = 3;\n          break;\n        case 3:\n          numberOfMatchesRemovedByComputer = 2;\n          break;\n        case 2:\n          numberOfMatchesRemovedByComputer = 1;\n          break;\n        case 1: case 0: // If the computer losses call this case\n          Console.WriteLine(\"YOU WON, FLOPPY EARS !\");\n          Console.WriteLine(\"THING YOU'RE PRETTY SMART !\");\n          Console.WriteLine(\"LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\");\n          break;\n        default: // If there are > than 4 matches call this case\n          numberOfMatchesRemovedByComputer = 4 - numberOfMatchesRemovedByPlayer;\n          break;\n      }\n      // If the numberOfMatchesRemovedByComputer has been updated run this code,\n      // if not them the computer has lost\n      if (numberOfMatchesRemovedByComputer != 0)\n      {\n        Console.WriteLine(\"MY TURN ! I REMOVE \" + numberOfMatchesRemovedByComputer + \" MATCHES\");\n        numberOfMatches = numberOfMatches - numberOfMatchesRemovedByComputer;\n        // If there are less than or equal to 1 matches\n        // then the player has lost        \n        if (numberOfMatches <= 1)\n        {\n          Console.Write(\"\\n\");\n          Console.WriteLine(\"YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\");\n          Console.WriteLine(\"HA ! HA ! I BEAT YOU !!!\");\n          Console.Write(\"\\n\");\n          Console.WriteLine(\"GOOD BYE LOSER!\");\n        }\n      }\n    }\n\n\n    // This method handles the player input \n    // and will handle inncorrect input\n    static int ReadPlayerInput()\n    {\n      // Read user input and convert to integer\n      int playerInput = 0;\n      // Try to read player input\n      try\n      {\n        playerInput = Convert.ToInt32(Console.ReadLine());\n      }\n      // If there is an error in the player input\n      catch (System.Exception)\n      {\n        Console.WriteLine(\"?REENTER\");\n        Console.Write(\"?? \");\n        // Ask the player to reenter their input\n        playerInput = ReadPlayerInput();\n      }\n      return playerInput;      \n    }\n\n  }\n}"
  },
  {
    "path": "93_23_Matches/csharp/csharp.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "93_23_Matches/java/CoinSide.java",
    "content": "public enum CoinSide {\n    HEADS,\n    TAILS\n}\n"
  },
  {
    "path": "93_23_Matches/java/Messages.java",
    "content": "public class Messages {\n\n    // This is a utility class and contains only static members.\n    // Utility classes are not meant to be instantiated.\n    private Messages() {\n        throw new IllegalStateException(\"Utility class\");\n    }\n\n    public static final String INTRO = \"\"\"\n                                          23 MATCHES\n                          CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n             THIS IS A GAME CALLED '23 MATCHES'.\n\n            WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\n            MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\n            THE LAST MATCH.\n\n            LET'S FLIP A COIN TO SEE WHO GOES FIRST.\n            IF IT COMES UP HEADS, I WILL WIN THE TOSS.\n            \"\"\";\n\n    public static final String HEADS = \"\"\"\n            HEADS! I WIN! HA! HA!\n            PREPARE TO LOSE, MEATBALL-NOSE!!\n\n            I TAKE 2 MATCHES\n            \"\"\";\n\n    public static final String TAILS = \"\"\"\n            TAILS! YOU GO FIRST.\n            \"\"\";\n\n    public static final String MATCHES_LEFT = \"\"\"\n            THE NUMBER OF MATCHES IS NOW %d\n\n            YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\n            \"\"\";\n\n    public static final String REMOVE_MATCHES_QUESTION = \"HOW MANY DO YOU WISH TO REMOVE? \";\n\n    public static final String REMAINING_MATCHES = \"\"\"\n            THERE ARE NOW %d MATCHES REMAINING.\n            \"\"\";\n\n    public static final String INVALID = \"\"\"\n            VERY FUNNY! DUMMY!\n            DO YOU WANT TO PLAY OR GOOF AROUND?\n            NOW, HOW MANY MATCHES DO YOU WANT?\n            \"\"\";\n\n    public static final String WIN = \"\"\"\n            YOU WON, FLOPPY EARS !\n            THINK YOU'RE PRETTY SMART !\n            LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\n            \"\"\";\n\n    public static final String CPU_TURN = \"\"\"\n            MY TURN ! I REMOVE %d MATCHES.\n            \"\"\";\n\n    public static final String LOSE = \"\"\"\n            YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\n            HA ! HA ! I BEAT YOU !!!\n\n            GOOD BYE LOSER!\n            \"\"\";\n}\n"
  },
  {
    "path": "93_23_Matches/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "93_23_Matches/java/TwentyThreeMatches.java",
    "content": "import java.util.Random;\nimport java.util.Scanner;\n\npublic class TwentyThreeMatches {\n\n    private static final int MATCH_COUNT_START = 23;\n    private static final Random RAND = new Random();\n    private final Scanner scan = new Scanner(System.in);\n\n    public void startGame() {\n        //Initialize values\n        int cpuRemoves = 0;\n        int matchesLeft = MATCH_COUNT_START;\n        int playerRemoves = 0;\n\n        //Flip coin and decide who goes first.\n        CoinSide coinSide = flipCoin();\n        if (coinSide == CoinSide.HEADS) {\n            System.out.println(Messages.HEADS);\n            matchesLeft -= 2;\n        } else {\n            System.out.println(Messages.TAILS);\n        }\n\n        // Game loop\n        while (true) {\n            //Show matches left if CPU went first or Player already removed matches\n            if (coinSide == CoinSide.HEADS) {\n                System.out.format(Messages.MATCHES_LEFT, matchesLeft);\n            }\n            coinSide = CoinSide.HEADS;\n\n            // Player removes matches\n            System.out.println(Messages.REMOVE_MATCHES_QUESTION);\n            playerRemoves = turnOfPlayer();\n            matchesLeft -= playerRemoves;\n            System.out.format(Messages.REMAINING_MATCHES, matchesLeft);\n\n            // If 1 match is left, the CPU has to take it. You win!\n            if (matchesLeft <= 1) {\n                System.out.println(Messages.WIN);\n                return;\n            }\n\n            // CPU removes matches\n            // At least two matches are left, because win condition above was not triggered.\n            if (matchesLeft <= 4) {\n                cpuRemoves = matchesLeft - 1;\n            } else {\n                cpuRemoves = 4 - playerRemoves;\n            }\n            System.out.format(Messages.CPU_TURN, cpuRemoves);\n            matchesLeft -= cpuRemoves;\n\n            // If 1 match is left, the Player has to take it. You lose!\n            if (matchesLeft <= 1) {\n                System.out.println(Messages.LOSE);\n                return;\n            }\n        }\n    }\n\n    private CoinSide flipCoin() {\n        return RAND.nextBoolean() ? CoinSide.HEADS : CoinSide.TAILS;\n    }\n\n    private int turnOfPlayer() {\n        while (true) {\n            int playerRemoves = scan.nextInt();\n            // Handle invalid entries\n            if ((playerRemoves > 3) || (playerRemoves <= 0)) {\n                System.out.println(Messages.INVALID);\n                continue;\n            }\n            return playerRemoves;\n        }\n    }\n\n}\n"
  },
  {
    "path": "93_23_Matches/java/TwentyThreeMatchesGame.java",
    "content": "/**\n * Game of 23 Matches\n * <p>\n * Based on the BASIC game of 23 Matches here\n * https://github.com/coding-horror/basic-computer-games/blob/main/93%2023%20Matches/23matches.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n * <p>\n * Converted from BASIC to Java by Darren Cardenas.\n */\npublic class TwentyThreeMatchesGame {\n\n    public static void main(String[] args) {\n        showIntro();\n        TwentyThreeMatches game = new TwentyThreeMatches();\n        game.startGame();\n    }\n\n    private static void showIntro() {\n        System.out.println(Messages.INTRO);\n    }\n\n}\n"
  },
  {
    "path": "93_23_Matches/javascript/23matches.html",
    "content": "<html>\n<head>\n<title>23 MATCHES</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"23matches.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "93_23_Matches/javascript/23matches.js",
    "content": "// 23 MATCHES\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str)\n{\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction input()\n{\n    var input_element;\n    var input_str;\n\n    return new Promise(function (resolve) {\n                       input_element = document.createElement(\"INPUT\");\n\n                       print(\"? \");\n                       input_element.setAttribute(\"type\", \"text\");\n                       input_element.setAttribute(\"length\", \"50\");\n                       document.getElementById(\"output\").appendChild(input_element);\n                       input_element.focus();\n                       input_str = undefined;\n                       input_element.addEventListener(\"keydown\", function (event) {\n                                                      if (event.keyCode == 13) {\n                                                      input_str = input_element.value;\n                                                      document.getElementById(\"output\").removeChild(input_element);\n                                                      print(input_str);\n                                                      print(\"\\n\");\n                                                      resolve(input_str);\n                                                      }\n                                                      });\n                       });\n}\n\nfunction tab(space)\n{\n    var str = \"\";\n    while (space-- > 0)\n        str += \" \";\n    return str;\n}\n\n// Main control section\nasync function main()\n{\n    print(tab(31) + \"23 MATCHES\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\" THIS IS A GAME CALLED '23 MATCHES'.\\n\");\n    print(\"\\n\");\n    print(\"WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\\n\");\n    print(\"MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\\n\");\n    print(\"THE LAST MATCH.\\n\");\n    print(\"\\n\");\n    print(\"LET'S FLIP A COIN TO SEE WHO GOES FIRST.\\n\");\n    print(\"IF IT COMES UP HEADS, I WILL WIN THE TOSS.\\n\");\n    print(\"\\n\");\n    n = 23;\n    q = Math.floor(2 * Math.random());\n    if (q != 1) {\n        print(\"TAILS! YOU GO FIRST. \\n\");\n        print(\"\\n\");\n    } else {\n        print(\"HEADS! I WIN! HA! HA!\\n\");\n        print(\"PREPARE TO LOSE, MEATBALL-NOSE!!\\n\");\n        print(\"\\n\");\n        print(\"I TAKE 2 MATCHES\\n\");\n        n -= 2;\n    }\n    while (1) {\n        if (q == 1) {\n            print(\"THE NUMBER OF MATCHES IS NOW \" + n + \"\\n\");\n            print(\"\\n\");\n            print(\"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\\n\");\n        }\n        print(\"HOW MANY DO YOU WISH TO REMOVE \");\n        while (1) {\n            k = parseInt(await input());\n            if (k <= 0 || k > 3) {\n                print(\"VERY FUNNY! DUMMY!\\n\");\n                print(\"DO YOU WANT TO PLAY OR GOOF AROUND?\\n\");\n                print(\"NOW, HOW MANY MATCHES DO YOU WANT \");\n            } else {\n                break;\n            }\n        }\n        n -= k;\n        print(\"THERE ARE NOW \" + n + \" MATCHES REMAINING.\\n\");\n        if (n == 4) {\n            z = 3;\n        } else if (n == 3) {\n            z = 2;\n        } else if (n == 2) {\n            z = 1;\n        } else if (n > 1) {\n            z = 4 - k;\n        } else {\n            print(\"YOU WON, FLOPPY EARS !\\n\");\n            print(\"THINK YOU'RE PRETTY SMART !\\n\");\n            print(\"LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\\n\");\n            break;\n        }\n        print(\"MY TURN ! I REMOVE \" + z + \" MATCHES\\n\");\n        n -= z;\n        if (n <= 1) {\n            print(\"\\n\");\n            print(\"YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\\n\");\n            print(\"HA ! HA ! I BEAT YOU !!!\\n\");\n            print(\"\\n\");\n            print(\"GOOD BYE LOSER!\\n\");\n            break;\n        }\n        q = 1;\n    }\n\n}\n\nmain();\n"
  },
  {
    "path": "93_23_Matches/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "93_23_Matches/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "93_23_Matches/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "93_23_Matches/perl/23matches.pl",
    "content": "#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\nprint ' ' x 31 . \"23 MATCHES\\n\";\nprint ' ' x 15 . \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\";\nprint \"\\n\\n\\n\";\n\nprint \" THIS IS A GAME CALLED '23 MATCHES'.\\n\\n\";\n\nprint \"WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\\n\";\nprint \"MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\\n\";\nprint \"THE LAST MATCH.\\n\\n\";\n\nprint \"LET'S FLIP A COIN TO SEE WHO GOES FIRST.\\n\";\nprint \"IF IT COMES UP HEADS, I WILL WIN THE TOSS.\\n\\n\";\n\nmy $N = 23;\nmy $Q = int( 2 * rand(5) );\n\nif ( $Q == 1 ) {\n    print \"HEADS! I WIN! HA! HA!\\n\";\n    print \"PREPARE TO LOSE, MEATBALL-NOSE!!\\n\\n\";\n\n    print \"I TAKE 2 MATCHES\\n\";\n    $N -= 2;\n\n    print \"THE NUMBER OF MATCHES IS NOW $N\\n\\n\";\n\n    print \"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\\n\";\n}\nelse {\n    print \"TAILS! YOU GO FIRST.\\n\\n\";\n}\n\nprint \"HOW MANY DO YOU WISH TO REMOVE?\\n\";\n\nINPUT:\n{\n    chomp( my $K = <STDIN> );\n\n    if ( $K > 3 or $K <= 0 ) {\n        print \"VERY FUNNY! DUMMY!\\n\";\n        print \"DO YOU WANT TO PLAY OR GOOF AROUND?\\n\";\n        print \"NOW, HOW MANY MATCHES DO YOU WANT?\\n\";\n        redo INPUT;\n    }\n\n    $N -= $K;\n\n    print \"THERE ARE NOW $N MATCHES REMAINING.\\n\";\n\n    my $Z;\n\n    if ( $N <= 1 ) {\n        print \"YOU WON, FLOPPY EARS!\\n\";\n        print \"THINK YOU'RE PRETTY SMART!\\n\";\n        print \"LET'S PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF!!\\n\";\n        exit;\n    }\n    elsif ( $N > 4 ) {\n        $Z = 4 - $K;\n    }\n    else {\n        $Z = $N - 1;\n    }\n\n    print \"MY TURN! I REMOVE $Z MATCHES\\n\";\n\n    $N -= $Z;\n\n    if ( $N <= 1 ) {\n        print \"\\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\\n\";\n        print \"HA! HA! I BEAT YOU!!!\\n\\n\";\n\n        print \"GOOD BYE LOSER!\\n\";\n    }\n    else {\n        print \"THE NUMBER OF MATCHES IS NOW $N\\n\\n\";\n\n        print \"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\\n\";\n        print \"HOW MANY DO YOU WISH TO REMOVE?\\n\";\n        redo INPUT;\n    }\n}\n"
  },
  {
    "path": "93_23_Matches/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "93_23_Matches/python/23matches.py",
    "content": "#!/usr/bin/env python3\n# 23 Matches\n#\n# Converted from BASIC to Python by Trevor Hobson\n\nimport random\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n\n    matches = 23\n    humans_turn = random.randint(0, 1) == 1\n    if humans_turn:\n        print(\"Tails! You go first.\\n\")\n        prompt_human = \"How many do you wish to remove \"\n    else:\n        print(\"Heads! I win! Ha! Ha!\")\n        print(\"Prepare to lose, meatball-nose!!\")\n\n    choice_human = 2\n    while matches > 0:\n        if humans_turn:\n            choice_human = 0\n            if matches == 1:\n                choice_human = 1\n            while choice_human == 0:\n                try:\n                    choice_human = int(input(prompt_human))\n                    if choice_human not in [1, 2, 3] or choice_human > matches:\n                        choice_human = 0\n                        print(\"Very funny! Dummy!\")\n                        print(\"Do you want to play or goof around?\")\n                        prompt_human = \"Now, how many matches do you want \"\n                except ValueError:\n                    print(\"Please enter a number.\")\n                    prompt_human = \"How many do you wish to remove \"\n            matches -= choice_human\n            if matches == 0:\n                print(\"You poor boob! You took the last match! I gotcha!!\")\n                print(\"Ha ! Ha ! I beat you !!\\n\")\n                print(\"Good bye loser!\")\n            else:\n                print(\"There are now\", matches, \"matches remaining.\\n\")\n        else:\n            choice_computer = 4 - choice_human\n            if matches == 1:\n                choice_computer = 1\n            elif 1 < matches < 4:\n                choice_computer = matches - 1\n            matches -= choice_computer\n            if matches == 0:\n                print(\"You won, floppy ears !\")\n                print(\"Think you're pretty smart !\")\n                print(\"Let's play again and I'll blow your shoes off !!\")\n            else:\n                print(\"My turn ! I remove\", choice_computer, \"matches\")\n                print(\"The number of matches is now\", matches, \"\\n\")\n        humans_turn = not humans_turn\n        prompt_human = \"Your turn -- you may take 1, 2 or 3 matches.\\nHow many do you wish to remove \"\n\n\ndef main() -> None:\n    print(\" \" * 31 + \"23 MATCHHES\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n    print(\"This is a game called '23 Matches'.\\n\")\n    print(\"When it is your turn, you may take one, two, or three\")\n    print(\"matches. The object of the game is not to have to take\")\n    print(\"the last match.\\n\")\n    print(\"Let's flip a coin to see who goes first.\")\n    print(\"If it comes up heads, I will win the toss.\\n\")\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nPlay again? (yes or no) \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "93_23_Matches/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "93_23_Matches/ruby/23_matches.rb",
    "content": "class Matches\n    def initialize\n        puts \" \" * 31 + \"23 MATCHES\"\n        puts \"This is a game called '23 Matches'.\"\n        puts \"When it is your turn, you may take one, two, or three\"\n        puts \"matches. The object of the game is not to have to take\"\n        puts \"the last match.\"\n        puts \"Let's flip a coin to see who goes first.\"\n        puts \"If it comes up heads, I will win the toss.\"\n\n        while true\n            play_game\n            print \"Play again? (yes or no) \"\n            answer = gets.chomp!.upcase\n            break unless [\"Y\", \"YES\"].include? answer\n        end\n    end\n\n    private\n        def play_game\n            matches = 23\n            humans_turn = rand(0..1) == 1\n            if humans_turn\n                puts \"Tails! You go first.\"\n                prompt_human = \"How many do you wish to remove? \"\n            else\n                puts \"Heads! I win! Ha! Ha!\"\n                puts \"Prepare to lose, meatball-nose!!\"\n            end\n\n            choice_human = 2\n\n            while matches > 0\n                if humans_turn\n                    choice_human = 0\n                    if matches == 1\n                        choice_human = 1\n                    end\n\n                    while choice_human == 0\n                        print \"#{prompt_human}[1,2,3] \"\n                        choice_human = gets.chomp!\n\n                        if ![1, 2, 3].include?(choice_human.to_i) || choice_human.to_i > matches\n                            choice_human = 0\n                            puts \"Very funny! Dummy!\"\n                            puts \"Do you want to play or goof around?\"\n                            prompt_human = \"Now, how many matches do you want \"\n                        end\n                    end\n\n                    matches = matches - choice_human.to_i\n\n                    if matches == 0\n                        puts \"You poor boob! You took the last match! I gotcha!!\"\n                        puts \"Ha ! Ha ! I beat you !!\"\n                        puts \"Good bye loser!\"\n                    else\n                        puts \"There are now #{matches} matches remaining.\"\n                    end\n                else\n                    choice_computer = 4 - choice_human.to_i\n                    if matches == 1\n                        choice_computer = 1\n                    elsif (1 < matches) && (matches < 4)\n                        choice_computer = matches - 1\n                    end\n\n                    matches = matches - choice_computer\n                    if matches == 0\n                        puts \"You won, floppy ears !\"\n                        puts \"Think you're pretty smart !\"\n                        puts \"Let's play again and I'll blow your shoes off !!\"\n                    else\n                        puts \"My turn ! I remove #{choice_computer} matches\"\n                        puts \"The number of matches is now #{matches}\"\n                    end\n                end\n\n                humans_turn = !humans_turn\n                prompt_human = \"Your turn -- you may take 1, 2 or 3 matches.\\nHow many do you wish to remove \"\n            end\n        end\nend\n\nif __FILE__ == $0\n    Matches.new\nend"
  },
  {
    "path": "93_23_Matches/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "93_23_Matches/rust/Cargo.toml",
    "content": "[package]\nname = \"twenty-three-matches\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nfastrand = \"^2.0.0\"\n"
  },
  {
    "path": "93_23_Matches/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [rust](https://www.rust-lang.org/)\n"
  },
  {
    "path": "93_23_Matches/rust/src/main.rs",
    "content": "use std::io;\nuse std::io::{stdin, stdout, BufRead, Write};\n\nfn main() -> io::Result<()> {\n    intro();\n    let mut input = stdin().lock();\n    let mut buf = String::with_capacity(16);\n    // variable `N` in the original game\n    let mut matches: u8 = 23;\n    if fastrand::bool() {\n        println!(\"TAILS! YOU GO FIRST. \\n\");\n    } else {\n        println!(\"HEADS! I WIN! HA! HA!\\nPREPARE TO LOSE, MEATBALL-NOSE!!\\n\\nI TAKE 2 MATCHES\");\n        matches -= 2;\n        println!(\"THE NUMBER OF MATCHES IS NOW {matches}\\n\");\n        println!(\"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\");\n    }\n    loop {\n        // variable `K` in the original game\n        let human_picked = read_matches(&mut input, &mut buf)?;\n        matches = matches.saturating_sub(human_picked);\n        if matches == 0 {\n            // this can only happen if the player could win with the next turn but they take too\n            // many matches (e.g. if there are three matches left and the player takes three instead of\n            // two). In the original game, this would count as a win for the player.\n            println!(\"\\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\\nHA ! HA ! I BEAT YOU !!!\\n\\nGOOD BYE LOSER!\");\n            return Ok(());\n        }\n\n        println!(\"THERE ARE NOW {matches} MATCHES REMAINING.\");\n\n        if matches <= 1 {\n            println!(\"YOU WON, FLOPPY EARS !\\nTHINK YOU'RE PRETTY SMART !\\nLETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\");\n            return Ok(());\n        }\n\n        // variable `Z` in the original game\n        let ai_picked = ai_pick(matches, human_picked);\n        println!(\"MY TURN ! I REMOVE {ai_picked} MATCHES\");\n        matches = matches.saturating_sub(ai_picked);\n        // The AI will never pick the last match except for the case where only one match is left (which is handled above)\n        if matches == 1 {\n            println!(\"\\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\\nHA ! HA ! I BEAT YOU !!!\\n\\nGOOD BYE LOSER!\");\n            return Ok(());\n        }\n        println!(\"THE NUMBER OF MATCHES IS NOW {matches}\\n\");\n        println!(\"YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\");\n    }\n}\n\nfn intro() {\n    println!(\n        r\"                               23 MATCHES\n               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n THIS IS A GAME CALLED '23 MATCHES'.\n\nWHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\nMATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\nTHE LAST MATCH.\n\nLET'S FLIP A COIN TO SEE WHO GOES FIRST.\nIF IT COMES UP HEADS, I WILL WIN THE TOSS.\n\"\n    );\n}\n\nfn read_matches<R: BufRead>(mut input: R, buf: &mut String) -> io::Result<u8> {\n    print!(\"HOW MANY DO YOU WISH TO REMOVE ?? \");\n    stdout().flush()?;\n    loop {\n        let input = read_int(&mut input, buf)?;\n        if input <= 0 || input > 3 {\n            print!(\"VERY FUNNY! DUMMY!\\nDO YOU WANT TO PLAY OR GOOF AROUND?\\nNOW, HOW MANY MATCHES DO YOU WANT              ?? \");\n            stdout().flush()?;\n        } else {\n            return Ok(input as u8);\n        }\n    }\n}\n\nfn read_int<R: BufRead>(mut input: R, buf: &mut String) -> io::Result<i8> {\n    loop {\n        buf.clear();\n        input.read_line(buf)?;\n        let line = buf.trim();\n        // This is implicit behaviour in the original code: empty input is equal to 0\n        if line.is_empty() {\n            return Ok(0);\n        }\n        if let Ok(n) = line.parse::<i8>() {\n            return Ok(n);\n        } else {\n            print!(\"??REENTER\\n?? \");\n            stdout().flush()?;\n        }\n    }\n}\n\nfn ai_pick(matches: u8, human_picked: u8) -> u8 {\n    if matches < 4 {\n        matches - 1\n    } else {\n        4 - human_picked\n    }\n}\n"
  },
  {
    "path": "93_23_Matches/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "93_23_Matches/vbnet/TwentyThreeMatches.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"TwentyThreeMatches\", \"TwentyThreeMatches.vbproj\", \"{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "93_23_Matches/vbnet/TwentyThreeMatches.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>TwentyThreeMatches</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "94_War/README.md",
    "content": "### War\n\nThis program plays the card game of War. In War, the card deck is shuffled, then two cards are dealt, one to each player. Players compare cards and the higher card (numerically) wins. In case of a tie, no one wins. The game ends when you have gone through the whole deck (52 cards, 26 games) or when you decide to quit.\n\nThe computer gives cards by suit and number, for example, S-7 is the 7 of spades.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=178)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=193)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "94_War/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "94_War/csharp/War/Cards.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\n\n\nnamespace War\n{\n    // These enums define the card's suit and rank.\n    public enum Suit\n    {\n        clubs,\n        diamonds,\n        hearts,\n        spades\n    }\n\n    public enum Rank\n    {\n        // Skip 1 because ace is high.\n        two = 2,\n        three,\n        four,\n        five,\n        six,\n        seven,\n        eight,\n        nine,\n        ten,\n        jack,\n        queen,\n        king,\n        ace\n    }\n\n    // A class to represent a playing card.\n    public class Card\n    {\n        // A card is an immutable object (i.e. it can't be changed) so its suit\n        // and rank value are readonly; they can only be set in the constructor.\n        private readonly Suit suit;\n        private readonly Rank rank;\n\n        // These dictionaries are used to convert a suit or rank value into a string.\n        private readonly Dictionary<Suit, string> suitNames = new Dictionary<Suit, string>()\n        {\n            { Suit.clubs, \"C\"},\n            { Suit.diamonds, \"D\"},\n            { Suit.hearts, \"H\"},\n            { Suit.spades, \"S\"},\n        };\n\n        private readonly Dictionary<Rank, string> rankNames = new Dictionary<Rank, string>()\n        {\n            { Rank.two, \"2\"},\n            { Rank.three, \"3\"},\n            { Rank.four, \"4\"},\n            { Rank.five, \"5\"},\n            { Rank.six, \"6\"},\n            { Rank.seven, \"7\"},\n            { Rank.eight, \"8\"},\n            { Rank.nine, \"9\"},\n            { Rank.ten, \"10\"},\n            { Rank.jack, \"J\"},\n            { Rank.queen, \"Q\"},\n            { Rank.king, \"K\"},\n            { Rank.ace, \"A\"},\n        };\n\n        public Card(Suit suit, Rank rank)\n        {\n            this.suit = suit;\n            this.rank = rank;\n        }\n\n        // Relational Operator Overloading.\n        //\n        // You would normally expect the relational operators to consider both the suit and the\n        // rank of a card, but in this program suit doesn't matter so we define the operators to just\n        // compare rank.\n\n        // When adding relational operators we would normally include == and != but they are not\n        // relevant to this program so haven't been defined. Note that if they were defined we\n        // should also override the Equals() and GetHashCode() methods. See, for example:\n        // http://www.blackwasp.co.uk/CSharpRelationalOverload.aspx\n\n        // If the == and != operators were defined they would look like this:\n        //\n        //public static bool operator ==(Card lhs, Card rhs)\n        //{\n        //    return lhs.rank == rhs.rank;\n        //}\n        //\n        //public static bool operator !=(Card lhs, Card rhs)\n        //{\n        //    return !(lhs == rhs);\n        //}\n\n        public static bool operator <(Card lhs, Card rhs)\n        {\n            return lhs.rank < rhs.rank;\n        }\n\n        public static bool operator >(Card lhs, Card rhs)\n        {\n            return rhs < lhs;\n        }\n\n        public static bool operator <=(Card lhs, Card rhs)\n        {\n            return !(lhs > rhs);\n        }\n\n        public static bool operator >=(Card lhs, Card rhs)\n        {\n            return !(lhs < rhs);\n        }\n\n        public override string ToString()\n        {\n            // N.B. We are using string interpolation to create the card name.\n            return $\"{suitNames[suit]}-{rankNames[rank]}\";\n        }\n    }\n\n    // A class to represent a deck of cards.\n    public class Deck\n    {\n        public const int deckSize = 52;\n\n        private Card[] theDeck = new Card[deckSize];\n\n        public Deck()\n        {\n            // Populate theDeck with all the cards in order.\n            int i = 0;\n            for (Suit suit = Suit.clubs; suit <= Suit.spades; suit++)\n            {\n                for (Rank rank = Rank.two; rank <= Rank.ace; rank++)\n                {\n                    theDeck[i] = new Card(suit, rank);\n                    i++;\n                }\n            }\n        }\n\n        // Return the card at a particular position in the deck.\n        // N.B. As this is such a short method, we make it an\n        // expression-body method.\n        public Card GetCard(int i) => theDeck[i];\n\n        // Shuffle the cards, this uses the modern version of the\n        // Fisher-Yates shuffle, see:\n        // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm\n        public void Shuffle()\n        {\n            var rand = new Random();\n\n            // Iterate backwards through the deck.\n            for (int i = deckSize - 1; i >= 1; i--)\n            {\n                int j = rand.Next(0, i);\n\n                // Swap the cards at i and j\n                Card temp = theDeck[j];\n                theDeck[j] = theDeck[i];\n                theDeck[i] = temp;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "94_War/csharp/War/Program.cs",
    "content": "﻿namespace War\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            var ui = new UserInterface();\n            ui.WriteIntro();\n\n            var deck = new Deck();\n            deck.Shuffle();\n\n            int yourScore = 0;\n            int computersScore = 0;\n            bool usedAllCards = true;\n\n            for (int i = 0; i < Deck.deckSize; i += 2)\n            {\n                // Play the next hand.\n                var yourCard = deck.GetCard(i);\n                var computersCard = deck.GetCard(i + 1);\n\n                ui.WriteAResult(yourCard, computersCard, ref computersScore, ref yourScore);\n\n                if (!ui.AskAQuestion(\"DO YOU WANT TO CONTINUE? \"))\n                {\n                    usedAllCards = false;\n                    break;\n                }\n            }\n\n            ui.WriteClosingRemarks(usedAllCards, yourScore, computersScore);\n        }\n    }\n}\n"
  },
  {
    "path": "94_War/csharp/War/UserInterface.cs",
    "content": "﻿using System;\n\n\n\nnamespace War\n{\n    // This class displays all the text that the user sees when playing the game.\n    // It also handles asking the user a yes/no question and returning their answer.\n    public class UserInterface\n    {\n        public void WriteIntro()\n        {\n            Console.WriteLine(\"                                 WAR\");\n            Console.WriteLine(\"               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine();\n\n            Console.WriteLine(\"THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#\");\n            Console.Write(\"AS S-7 FOR SPADE 7.  \");\n\n            if (AskAQuestion(\"DO YOU WANT DIRECTIONS? \"))\n            {\n                Console.WriteLine(\"THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD\");\n                Console.WriteLine(\"(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO\");\n                Console.WriteLine(\"CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\");\n            }\n\n            Console.WriteLine();\n            Console.WriteLine();\n        }\n\n        public void WriteAResult(Card yourCard, Card computersCard, ref int computersScore, ref int yourScore)\n        {\n            Console.WriteLine($\"YOU: {yourCard}     COMPUTER: {computersCard}\");\n            if (yourCard < computersCard)\n            {\n                computersScore++;\n                Console.WriteLine($\"THE COMPUTER WINS!!! YOU HAVE {yourScore} AND THE COMPUTER HAS {computersScore}\");\n            }\n            else if (yourCard > computersCard)\n            {\n                yourScore++;\n                Console.WriteLine($\"YOU WIN. YOU HAVE {yourScore} AND THE COMPUTER HAS {computersScore}\");\n            }\n            else\n            {\n                Console.WriteLine(\"TIE.  NO SCORE CHANGE\");\n            }\n        }\n\n        public bool AskAQuestion(string question)\n        {\n            // Repeat asking the question until the user answers \"YES\" or \"NO\".\n            while (true)\n            {\n                Console.Write(question);\n                string result = Console.ReadLine();\n\n                if (result.ToLower() == \"yes\")\n                {\n                    Console.WriteLine();\n                    return true;\n                }\n                else if (result.ToLower() == \"no\")\n                {\n                    Console.WriteLine();\n                    return false;\n                }\n\n                Console.WriteLine(\"YES OR NO, PLEASE.\");\n            }\n        }\n\n        public void WriteClosingRemarks(bool usedAllCards, int yourScore, int computersScore)\n        {\n            if (usedAllCards)\n            {\n                Console.WriteLine(\"WE HAVE RUN OUT OF CARDS.\");\n            }\n            Console.WriteLine($\"FINAL SCORE:  YOU: {yourScore}  THE COMPUTER: {computersScore}\");\n            Console.WriteLine(\"THANKS FOR PLAYING.  IT WAS FUN.\");\n        }\n    }\n}\n"
  },
  {
    "path": "94_War/csharp/War/War.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "94_War/csharp/War.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31112.23\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"War\", \"War\\War.csproj\", \"{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"WarTester\", \"WarTester\\WarTester.csproj\", \"{B539F618-EE83-486C-9A6D-404E998BED2D}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{B539F618-EE83-486C-9A6D-404E998BED2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B539F618-EE83-486C-9A6D-404E998BED2D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B539F618-EE83-486C-9A6D-404E998BED2D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B539F618-EE83-486C-9A6D-404E998BED2D}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {3FA273C6-089E-4F3D-8DC0-F9143D1CDF3A}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "94_War/csharp/WarTester/Tests.cs",
    "content": "using Microsoft.VisualStudio.TestTools.UnitTesting;\nusing System.Text;\nusing War;\n\n\n\nnamespace WarTester\n{\n    [TestClass]\n    public class CardTest\n    {\n        private Card c1 = new Card(Suit.clubs, Rank.two);\n        private Card c2 = new Card(Suit.clubs, Rank.ten);\n        private Card c3 = new Card(Suit.diamonds, Rank.ten);\n        private Card c4 = new Card(Suit.diamonds, Rank.ten);\n\n        // Test the relational operators.\n\n        [TestMethod]\n        public void LessThanIsValid()\n        {\n            Assert.IsTrue(c1 < c2, \"c1 < c2\");  // Same suit, different rank.\n            Assert.IsFalse(c2 < c1, \"c2 < c1\"); // Same suit, different rank.\n\n            Assert.IsFalse(c3 < c4, \"c3 < c4\"); // Same suit, same rank.\n\n            Assert.IsTrue(c1 < c3, \"c1 < c3\");  // Different suit, different rank.\n            Assert.IsFalse(c3 < c1, \"c3 < c1\"); // Different suit, different rank.\n\n            Assert.IsFalse(c2 < c4, \"c2 < c4\"); // Different suit, same rank.\n            Assert.IsFalse(c4 < c2, \"c4 < c2\"); // Different suit, same rank.\n        }\n\n        [TestMethod]\n        public void GreaterThanIsValid()\n        {\n            Assert.IsFalse(c1 > c2, \"c1 > c2\"); // Same suit, different rank.\n            Assert.IsTrue(c2 > c1, \"c2 > c1\");  // Same suit, different rank.\n\n            Assert.IsFalse(c3 > c4, \"c3 > c4\"); // Same suit, same rank.\n\n            Assert.IsFalse(c1 > c3, \"c1 > c3\"); // Different suit, different rank.\n            Assert.IsTrue(c3 > c1, \"c3 > c1\");  // Different suit, different rank.\n\n            Assert.IsFalse(c2 > c4, \"c2 > c4\"); // Different suit, same rank.\n            Assert.IsFalse(c4 > c2, \"c4 > c2\"); // Different suit, same rank.\n        }\n\n        [TestMethod]\n        public void LessThanEqualsIsValid()\n        {\n            Assert.IsTrue(c1 <= c2, \"c1 <= c2\");  // Same suit, different rank.\n            Assert.IsFalse(c2 <= c1, \"c2 <= c1\"); // Same suit, different rank.\n\n            Assert.IsTrue(c3 <= c4, \"c3 <= c4\");  // Same suit, same rank.\n\n            Assert.IsTrue(c1 <= c3, \"c1 <= c3\");  // Different suit, different rank.\n            Assert.IsFalse(c3 <= c1, \"c3 <= c1\"); // Different suit, different rank.\n\n            Assert.IsTrue(c2 <= c4, \"c2 <= c4\");  // Different suit, same rank.\n            Assert.IsTrue(c4 <= c2, \"c4 <= c2\");  // Different suit, same rank.\n        }\n\n        [TestMethod]\n        public void GreaterThanEqualsIsValid()\n        {\n            Assert.IsFalse(c1 >= c2, \"c1 >= c2\"); // Same suit, different rank.\n            Assert.IsTrue(c2 >= c1, \"c2 >= c1\");  // Same suit, different rank.\n\n            Assert.IsTrue(c3 >= c4, \"c3 >= c4\");  // Same suit, same rank.\n\n            Assert.IsFalse(c1 >= c3, \"c1 >= c3\"); // Different suit, different rank.\n            Assert.IsTrue(c3 >= c1, \"c3 >= c1\");  // Different suit, different rank.\n\n            Assert.IsTrue(c2 >= c4, \"c2 >= c4\");  // Different suit, same rank.\n            Assert.IsTrue(c4 >= c2, \"c4 >= c2\");  // Different suit, same rank.\n        }\n\n        [TestMethod]\n        public void ToStringIsValid()\n        {\n            var s1 = c1.ToString();\n            var s2 = c3.ToString();\n            var s3 = new Card(Suit.hearts, Rank.queen).ToString();\n            var s4 = new Card(Suit.spades, Rank.ace).ToString();\n\n            Assert.IsTrue(s1 == \"C-2\", \"s1 invalid\");\n            Assert.IsTrue(s2 == \"D-10\", \"s2 invalid\");\n            Assert.IsTrue(s3 == \"H-Q\", \"s3 invalid\");\n            Assert.IsTrue(s4 == \"S-A\", \"s4 invalid\");\n        }\n    }\n\n    [TestClass]\n    public class DeckTest\n    {\n        private readonly string cardNamesInOrder = \"C-2C-3C-4C-5C-6C-7C-8C-9C-10C-JC-QC-KC-AD-2D-3D-4D-5D-6D-7D-8D-9D-10D-JD-QD-KD-AH-2H-3H-4H-5H-6H-7H-8H-9H-10H-JH-QH-KH-AS-2S-3S-4S-5S-6S-7S-8S-9S-10S-JS-QS-KS-A\";\n\n        //Helper method. Adds the names of all the cards together into a single string.\n        private string ConcatenateTheDeck(Deck d)\n        {\n            StringBuilder sb = new StringBuilder();\n\n            for (int i = 0; i < Deck.deckSize; i++)\n            {\n                sb.Append(d.GetCard(i));\n            }\n\n            return sb.ToString();\n        }\n\n        [TestMethod]\n        public void InitialDeckContainsCardsInOrder()\n        {\n            Deck d = new Deck();\n            string allTheCards = ConcatenateTheDeck(d);\n\n            Assert.IsTrue(allTheCards == cardNamesInOrder);\n        }\n\n        [TestMethod]\n        public void ShufflingChangesDeck()\n        {\n            // I'm not sure how to test that shuffling has worked other than to check that the cards aren't in the initial order.\n            Deck d = new Deck();\n            d.Shuffle();\n            string allTheCards = ConcatenateTheDeck(d);\n\n            Assert.IsTrue(allTheCards != cardNamesInOrder);\n        }\n    }\n}\n"
  },
  {
    "path": "94_War/csharp/WarTester/WarTester.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n\n    <Platforms>AnyCPU</Platforms>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <Optimize>true</Optimize>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"16.9.1\" />\n    <PackageReference Include=\"MSTest.TestAdapter\" Version=\"2.2.3\" />\n    <PackageReference Include=\"MSTest.TestFramework\" Version=\"2.2.3\" />\n    <PackageReference Include=\"coverlet.collector\" Version=\"3.0.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\War\\War.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "94_War/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "94_War/d/README.md",
    "content": "﻿Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -preview=dip1000 -run war.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n\n## Specialties explained\n\nThis game code contains some specialties that you might want to know more about. Here goes.\n\n### Suits\n\nMost modern consoles are capable of displaying more than just ASCII, and so I have chosen to display the actual ♠, ♥, ♦\nand ♣ instead of substituting them by letters like the BASIC original did. Only the Windows console needs a nudge in\nthe right direction with these instructions:\n```d\nSetConsoleOutputCP(CP_UTF8); // Set code page\nSetConsoleOutputCP(GetACP);  // Restore the default\n```\nInstead of cluttering the `main()` function with these lesser important details, we can move them into a\n[module constructor and module destructor](https://dlang.org/spec/module.html#staticorder), which run before and after\n`main()` respectively. And because order of declaration is irrelevant in a D module, we can push those all the way\ndown to the bottom of the file. This is of course only necessary on Windows (and won't even work anywhere else) so\nwe'll need to wrap this in a `version (Windows)` conditional code block:\n```d\nversion (Windows)\n{\n    import core.sys.windows.windows;\n\n    shared static this() @trusted\n    {\n        SetConsoleOutputCP(CP_UTF8);\n    }\n\n    shared static ~this() @trusted\n    {\n        SetConsoleOutputCP(GetACP);\n    }\n}\n```\nAlthough it doesn't matter much in this single-threaded program, the `shared` attribute makes that these\nconstructors/destructors are run once per program invocation; non-shared module constructors and module destructors are\nrun for every thread. The `@trusted` annotation is necessary because these are system API calls; The compiler cannot\ncheck these for memory-safety, and so we must indicate that we have reviewed the safety manually.\n\n### Uniform Function Call Syntax\n\nIn case you wonder why this line works:\n```d\nif (\"Do you want instructions?\".yes)\n    // ...\n```\nthen it is because this is equivalent to\n```d\nif (yes(\"Do you want instructions?\"))\n    // ...\n```\nwhere `yes()` is a Boolean function that is defined below `main()`. This is made possible by the language feature that\nis called [uniform function call syntax (UFCS)](https://dlang.org/spec/function.html#pseudo-member). UFCS works by\npassing what is in front of the dot as the first parameter to the function, and it was invented to make it possible to\ncall free functions on objects as if they were member functions. UFCS can also be used to obtain a more natural order\nof function calls, such as this line inside `yes()`:\n```d\nreturn trustedReadln.strip.toLower.startsWith(\"y\");\n```\nwhich reads easier than the equivalent\n```d\nreturn startsWith(toLower(strip(trustedReadln())), \"y\");\n```\n\n### Type a lot or not?\n\nIt would have been straight forward to define the `cards` array explicitly like so:\n```d\nconst cards = [\"2♠\", \"2♥\", \"2♦\", \"2♣\", \"3♠\", \"3♥\", \"3♦\", \"3♣\",\n               \"4♠\", \"4♥\", \"4♦\", \"4♣\", \"5♠\", \"5♥\", \"5♦\", \"5♣\",\n               \"6♠\", \"6♥\", \"6♦\", \"6♣\", \"7♠\", \"7♥\", \"7♦\", \"7♣\",\n               \"8♠\", \"8♥\", \"8♦\", \"8♣\", \"9♠\", \"9♥\", \"9♦\", \"9♣\",\n               \"10♠\", \"10♥\", \"10♦\", \"10♣\", \"J♥\", \"J♦\", \"J♣\", \"J♣\",\n               \"Q♠\", \"Q♥\", \"Q♦\", \"Q♣\", \"K♠\", \"K♥\", \"K♦\", \"K♣\",\n               \"A♠\", \"A♥\", \"A♦\", \"A♣\"];\n```\nbut that's tedious, difficult to spot errors in (*can you?*) and looks like something a computer can automate. Indeed\nit can:\n```d\nstatic const cards = cartesianProduct([\"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\"],\n                                      [\"♠\", \"♥\", \"♦\", \"♣\"]).map!(a => a.expand.only.join).array;\n```\nThe function [`cartesianProduct`](https://dlang.org/phobos/std_algorithm_setops.html#cartesianProduct) takes two\nranges, like the horizontal and vertical headers of a spreadsheet, and fills the table with the combinations that form\nthe coordinates of the cells. But the output of that function is in the form of an array of\n[`Tuple`](https://dlang.org/phobos/std_typecons.html#Tuple)s, which looks like `[Tuple!(string, string)(\"2\", \"♠\"),\nTuple!(string, string)(\"2\", \"♥\"), ... etc]`. [`map`](https://dlang.org/phobos/std_algorithm_iteration.html#map)\ncomes to the rescue, converting each Tuple to a string, by calling\n[`expand`](https://dlang.org/phobos/std_typecons.html#.Tuple.expand), then\n[`only`](https://dlang.org/phobos/std_range.html#only) and then [`join`](https://dlang.org/phobos/std_array.html#join)\non them. The result is a lazily evaluated range of strings. Finally,\n[`array`](https://dlang.org/phobos/std_array.html#array) turns the range into a random access array. The `static`\nattribute makes that all this is performed at compile-time, so the result is exactly the same as the manually entered\ndata, but without the typo's.\n\n### Shuffle the cards or not?\n\nThe original BASIC code works with a constant array of cards, ordered by increasing numerical value, and indexing it\nwith indices that have been shuffled. This is efficient because in comparing who wins, the indices can be compared\ndirectly, since a higher index correlates to a card with a higher numerical value (when divided by the number of suits,\n4). Some of the other reimplementations in other languages have been written in a lesser efficient way by shuffling the\narray of cards itself. This then requires the use of a lookup table or searching for equality in an auxiliary array\nwhen comparing cards.\n\nI find the original more elegant, so that's what you see here:\n```d\nconst indices = iota(0, cards.length).array.randomShuffle;\n```\n[`iota`](https://dlang.org/phobos/std_range.html#iota) produces a range of integers, in this case starting at 0 and\nincreasing up to the number of cards in the deck (exclusive). [`array`](https://dlang.org/phobos/std_array.html#array)\nturns the range into an array, so that [`randomShuffle`](https://dlang.org/phobos/std_random.html#randomShuffle) can\ndo its work.\n"
  },
  {
    "path": "94_War/d/war.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std;\n\nvoid main()\n{\n    enum width = 50;\n    writeln(center(\"War\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\", width));\n    writeln(wrap(\"This is the card game of war.  Each card is given by suit-# \" ~\n                 \"as 7♠ for seven of spades.  \", width));\n\n    if (\"Do you want instructions?\".yes)\n        writeln(\"\\n\", wrap(\"The computer gives you and it a 'card'.  The higher card \" ~\n                           \"(numerically) wins.  The game ends when you choose not to \" ~\n                           \"continue or when you have finished the pack.\\n\", width));\n\n    static const cards = cartesianProduct([\"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\"],\n                                          [\"♠\", \"♥\", \"♦\", \"♣\"]).map!(a => a.expand.only.join).array;\n    const indices = iota(0, cards.length).array.randomShuffle;\n    int yourScore = 0, compScore = 0, i = 0;\n    while (i < indices.length)\n    {\n        size_t your = indices[i++], comp = indices[i++];\n        writeln(\"\\nYou: \", cards[your].leftJustify(9), \"Computer: \", cards[comp]);\n        your /= 4; comp /= 4;\n        if (your == comp)\n            writeln(\"Tie. No score change.\");\n        else if (your < comp)\n            writeln(\"The computer wins!!! You have \", yourScore,\n                    \" and the computer has \", ++compScore, \".\");\n        else\n            writeln(\"You win. You have \", ++yourScore,\n                    \" and the computer has \", compScore, \".\");\n        if (i == indices.length)\n            writeln(\"\\nWe have run out of cards. Final score: You: \", yourScore,\n                    \", the computer: \", compScore, \".\");\n        else if (!\"Do you want to continue?\".yes)\n            break;\n    }\n    writeln(\"\\nThanks for playing. It was fun.\");\n}\n\n/// Returns whether question was answered positively.\nbool yes(string question)\n{\n    writef!\"%s \"(question);\n    try\n        return trustedReadln.strip.toLower.startsWith(\"y\");\n    catch (Exception)   // readln throws on I/O and Unicode errors, which we handle here.\n        return false;\n}\n\n/** An @trusted wrapper around readln.\n*\n* This is the only function that formally requires manual review for memory-safety.\n* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)\n* which would remove the need to have any @trusted code in this program.\n*/\nstring trustedReadln() @trusted\n{\n    return readln;\n}\n\nversion (Windows)\n{\n    // Make the Windows console do a better job at printing UTF-8 strings,\n    // and restore the default upon termination.\n\n    import core.sys.windows.windows;\n\n    shared static this() @trusted\n    {\n        SetConsoleOutputCP(CP_UTF8);\n    }\n\n    shared static ~this() @trusted\n    {\n        SetConsoleOutputCP(GetACP);\n    }\n}\n"
  },
  {
    "path": "94_War/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "94_War/java/War.java",
    "content": "import java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Scanner;\n\n/**\n * Converted FROM BASIC to Java by Nahid Mondol.\n *\n * Based on Trevor Hobsons approach.\n */\npublic class War {\n\n    private static final int CARD_DECK_SIZE = 52;\n    private static int playerTotalScore = 0;\n    private static int computerTotalScore = 0;\n    private static boolean invalidInput;\n    private static Scanner userInput = new Scanner(System.in);\n\n    // Simple approach for storing a deck of cards.\n    // Suit-Value, ex: 2 of Spades = S-2, King of Diamonds = D-K, etc...\n    private static ArrayList<String> deckOfCards = new ArrayList<String>(\n            Arrays.asList(\"S-2\", \"H-2\", \"C-2\", \"D-2\", \"S-3\", \"H-3\", \"C-3\", \"D-3\", \"S-4\", \"H-4\", \"C-4\", \"D-4\", \"S-5\",\n                    \"H-5\", \"C-5\", \"D-5\", \"S-6\", \"H-6\", \"C-6\", \"D-6\", \"S-7\", \"H-7\", \"C-7\", \"D-7\", \"S-8\", \"H-8\", \"C-8\",\n                    \"D-8\", \"S-9\", \"H-9\", \"C-9\", \"D-9\", \"S-10\", \"H-10\", \"C-10\", \"D-10\", \"S-J\", \"H-J\", \"C-J\", \"D-J\",\n                    \"S-Q\", \"H-Q\", \"C-Q\", \"D-Q\", \"S-K\", \"H-K\", \"C-K\", \"D-K\", \"S-A\", \"H-A\", \"C-A\", \"D-A\"));\n\n    public static void main(String[] args) {\n        introMessage();\n        showDirectionsBasedOnInput();\n        playGame();\n    }\n\n    private static void introMessage() {\n        System.out.println(\"\\t         WAR\");\n        System.out.println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n        System.out.println(\"THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#\");\n        System.out.print(\"AS S-7 FOR SPADE 7. DO YOU WANT DIRECTIONS? \");\n    }\n\n    private static void showDirectionsBasedOnInput() {\n        // Stay in loop until player chooses an option.\n        invalidInput = true;\n        while (invalidInput) {\n            switch (userInput.nextLine().toLowerCase()) {\n                case \"yes\":\n                    System.out.println(\"THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\");\n                    System.out.println(\"(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO \");\n                    System.out.println(\"CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\\n\");\n                    invalidInput = false;\n                    break;\n                case \"no\":\n                    System.out.println();\n                    invalidInput = false;\n                    break;\n                default:\n                    System.out.print(\"YES OR NO, PLEASE.   \");\n            }\n        }\n    }\n\n    private static void playGame() {\n\n        // Checks to see if the player ends the game early.\n        // Ending early will cause a different output to appear.\n        boolean gameEndedEarly = false;\n\n        // Shuffle the deck of cards.\n        Collections.shuffle(deckOfCards);\n\n        // Since the deck is already suffled, pull each card until the deck is empty or\n        // until the user quits.\n        outerloop:\n        for (int i = 1; i <= CARD_DECK_SIZE; i += 2) {\n            System.out.println(\"YOU: \" + deckOfCards.get(i - 1) + \"\\t \" + \"COMPUTER: \" + deckOfCards.get(i));\n            getWinner(deckOfCards.get(i - 1), deckOfCards.get(i));\n\n            invalidInput = true;\n            while (invalidInput) {\n                if (endedEarly()) {\n                    // Player ended game early.\n                    // Break out of game loop and show end game output.\n                    gameEndedEarly = true;\n                    break outerloop;\n                }\n            }\n        }\n\n        endGameOutput(gameEndedEarly);\n    }\n\n    /**\n     * Outputs the winner of the current round.\n     *\n     * @param playerCard   Players card.\n     * @param computerCard Computers card.\n     */\n    private static void getWinner(String playerCard, String computerCard) {\n\n        // Return the number value of the card pulled.\n        String playerCardScore = (playerCard.length() == 3) ? Character.toString(playerCard.charAt(2))\n                : playerCard.substring(2, 4);\n        String computerCardScore = (computerCard.length() == 3) ? Character.toString(computerCard.charAt(2))\n                : computerCard.substring(2, 4);\n\n        if (checkCourtCards(playerCardScore) > checkCourtCards(computerCardScore)) {\n            System.out.println(\"YOU WIN.   YOU HAVE \" + playerWonRound() + \"   COMPUTER HAS \" + getComputerScore());\n        } else if (checkCourtCards(playerCardScore) < checkCourtCards(computerCardScore)) {\n            System.out.println(\n                    \"COMPUTER WINS!!!   YOU HAVE \" + getPlayerScore() + \"   COMPUTER HAS \" + computerWonRound());\n        } else {\n            System.out.println(\"TIE.  NO SCORE CHANGE\");\n        }\n\n        System.out.print(\"DO YOU WANT TO CONTINUE? \");\n    }\n\n    /**\n     * @param cardScore Score of the card being pulled.\n     * @return an integer value of the current card's score.\n     */\n    private static int checkCourtCards(String cardScore) {\n        switch (cardScore) {\n            case \"J\":\n                return Integer.parseInt(\"11\");\n            case \"Q\":\n                return Integer.parseInt(\"12\");\n            case \"K\":\n                return Integer.parseInt(\"13\");\n            case \"A\":\n                return Integer.parseInt(\"14\");\n            default:\n                return Integer.parseInt(cardScore);\n        }\n    }\n\n    /**\n     * @return true if the player ended the game early. false otherwise.\n     */\n    private static boolean endedEarly() {\n        switch (userInput.nextLine().toLowerCase()) {\n            case \"yes\":\n                invalidInput = false;\n                return false;\n            case \"no\":\n                invalidInput = false;\n                return true;\n            default:\n                invalidInput = true;\n                System.out.print(\"YES OR NO, PLEASE.   \");\n                return false;\n        }\n    }\n\n    /**\n     * Show output based on if the game was ended early or not.\n     *\n     * @param endedEarly true if the game was ended early, false otherwise.\n     */\n    private static void endGameOutput(boolean endedEarly) {\n        if (endedEarly) {\n            System.out.println(\"YOU HAVE ENDED THE GAME. FINAL SCORE:  YOU: \" + getPlayerScore() + \" COMPUTER: \"\n                    + getComputerScore());\n            System.out.println(\"THANKS FOR PLAYING.  IT WAS FUN.\");\n        } else {\n            System.out.println(\"WE HAVE RUN OUT OF CARDS. FINAL SCORE:  YOU: \" + getPlayerScore() + \" COMPUTER: \"\n                    + getComputerScore());\n            System.out.println(\"THANKS FOR PLAYING.  IT WAS FUN.\");\n        }\n    }\n\n    /**\n     * Increment the player's total score if they have won the round.\n     */\n    private static int playerWonRound() {\n        return playerTotalScore += 1;\n    }\n\n    /**\n     * Get the player's total score.\n     */\n    private static int getPlayerScore() {\n        return playerTotalScore;\n    }\n\n    /**\n     * Increment the computer's total score if they have won the round.\n     */\n    private static int computerWonRound() {\n        return computerTotalScore += 1;\n    }\n\n    /**\n     * Get the computer's total score.\n     */\n    private static int getComputerScore() {\n        return computerTotalScore;\n    }\n}\n"
  },
  {
    "path": "94_War/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "94_War/javascript/war.html",
    "content": "<html>\n<head>\n<title>WAR</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"war.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "94_War/javascript/war.js",
    "content": "// WAR\n//\n// Original conversion from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\nfunction print(str) {\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\nfunction tab(space) {\n    let str = \"\";\n    while (space-- > 0) {\n        str += \" \";\n    }\n    return str;\n}\n\nfunction input() {\n    return new Promise(function (resolve) {\n        const input_element = document.createElement(\"INPUT\");\n\n        print(\"? \");\n        input_element.setAttribute(\"type\", \"text\");\n        input_element.setAttribute(\"length\", \"50\");\n        document.getElementById(\"output\").appendChild(input_element);\n        input_element.focus();\n        input_element.addEventListener(\"keydown\", function (event) {\n            if (event.keyCode == 13) {\n                const input_str = input_element.value;\n                document.getElementById(\"output\").removeChild(input_element);\n                print(input_str);\n                print(\"\\n\");\n                resolve(input_str);\n            }\n        });\n    });\n}\n\nasync function askYesOrNo(question) {\n    while (1) {\n        print(question);\n        const str = (await input()).toUpperCase();\n        if (str === \"YES\") {\n            return true;\n        }\n        else if (str === \"NO\") {\n            return false;\n        }\n        else {\n            print(\"YES OR NO, PLEASE.  \");\n        }\n    }\n}\n\nasync function askAboutInstructions() {\n    const playerWantsInstructions = await askYesOrNo(\"DO YOU WANT DIRECTIONS\");\n    if (playerWantsInstructions) {\n        print(\"THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD\\n\");\n        print(\"(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO\\n\");\n        print(\"CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\\n\");\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nfunction createGameDeck(cards, gameSize) {\n    const deck = [];\n    const deckSize = cards.length;\n    for (let j = 0; j < gameSize; j++) {\n        let card;\n\n        // Compute a new card index until we find one that isn't already in the new deck\n        do {\n            card = Math.floor(deckSize * Math.random());\n        } while (deck.includes(card));\n        deck.push(card);\n    }\n    return deck;\n}\n\nfunction computeCardValue(cardIndex) {\n    return Math.floor(cardIndex / 4);\n}\n\nfunction printGameOver(playerScore, computerScore) {\n    print(\"\\n\");\n    print(\"\\n\");\n    print(`WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: ${playerScore}  THE COMPUTER: ${computerScore}\\n`);\n    print(\"\\n\");\n}\n\nfunction printTitle() {\n    print(tab(33) + \"WAR\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#\\n\");\n    print(\"AS S-7 FOR SPADE 7.  \");\n}\n\nfunction printCards(playerCard, computerCard) {\n    print(\"\\n\");\n    print(`YOU: ${playerCard}\\tCOMPUTER: ${computerCard}\\n`);\n}\n\nconst cards = [\n    \"S-2\", \"H-2\", \"C-2\", \"D-2\",\n    \"S-3\", \"H-3\", \"C-3\", \"D-3\",\n    \"S-4\", \"H-4\", \"C-4\", \"D-4\",\n    \"S-5\", \"H-5\", \"C-5\", \"D-5\",\n    \"S-6\", \"H-6\", \"C-6\", \"D-6\",\n    \"S-7\", \"H-7\", \"C-7\", \"D-7\",\n    \"S-8\", \"H-8\", \"C-8\", \"D-8\",\n    \"S-9\", \"H-9\", \"C-9\", \"D-9\",\n    \"S-10\", \"H-10\", \"C-10\", \"D-10\",\n    \"S-J\", \"H-J\", \"C-J\", \"D-J\",\n    \"S-Q\", \"H-Q\", \"C-Q\", \"D-Q\",\n    \"S-K\", \"H-K\", \"C-K\", \"D-K\",\n    \"S-A\", \"H-A\", \"C-A\", \"D-A\"\n];\n\n// Main control section\nasync function main() {\n    printTitle();\n    await askAboutInstructions();\n\n    let computerScore = 0;\n    let playerScore = 0;\n\n    // Generate a random deck\n    const gameSize = cards.length;    // Number of cards to shuffle into the game deck.  Can be <= cards.length.\n    const deck = createGameDeck(cards, gameSize);\n    let shouldContinuePlaying = true;\n\n    while (deck.length > 0 && shouldContinuePlaying) {\n        const playerCard = deck.shift();    // Take a card\n        const computerCard = deck.shift();    // Take a card\n        printCards(cards[playerCard], cards[computerCard]);\n\n        const playerCardValue = computeCardValue(playerCard);\n        const computerCardValue = computeCardValue(computerCard);\n        if (playerCardValue < computerCardValue) {\n            computerScore++;\n            print(\"THE COMPUTER WINS!!! YOU HAVE \" + playerScore + \" AND THE COMPUTER HAS \" + computerScore + \"\\n\");\n        } else if (playerCardValue > computerCardValue) {\n            playerScore++;\n            print(\"YOU WIN. YOU HAVE \" + playerScore + \" AND THE COMPUTER HAS \" + computerScore + \"\\n\");\n        } else {\n            print(\"TIE.  NO SCORE CHANGE.\\n\");\n        }\n\n        if (deck.length === 0) {\n            printGameOver(playerScore, computerScore);\n        }\n        else {\n            shouldContinuePlaying = await askYesOrNo(\"DO YOU WANT TO CONTINUE\");\n        }\n    }\n    print(\"THANKS FOR PLAYING.  IT WAS FUN.\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "94_War/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "94_War/kotlin/War.kt",
    "content": "/**\n * Converted FROM BASIC to Kotlin by John Long, with hints from the Java by Nahid Mondol.\n *\n */\n\nval suits = listOf(\"S\", \"H\", \"C\", \"D\")\nval ranks = listOf(\"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\")\n\n// Create the deck programmatically\nval fullDeck = suits.flatMap { suit ->\n    ranks.map { rank ->\n        Card(suit, rank)\n    }\n}\n\nclass Card(private val suit: String, private val rank: String) {\n    // Allow comparison of cards to each other\n    operator fun compareTo(other: Card): Int = this.rankValue.compareTo(other.rankValue)\n    // We can figure relative rank by the order in the ranks value\n    private val rankValue: Int = ranks.indexOf(rank)\n    override fun toString(): String = \"$suit-$rank\"\n}\n\nfun main() {\n    introMessage()\n    showDirectionsBasedOnInput()\n    playGame()\n    println(\"THANKS FOR PLAYING.  IT WAS FUN.\")\n}\n\nprivate fun introMessage() {\n    println(\"\\t         WAR\")\n    println(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\")\n    println(\"THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#\")\n    print(\"AS S-7 FOR SPADE 7. DO YOU WANT DIRECTIONS? \")\n}\n\nprivate fun showDirectionsBasedOnInput() {\n    if (getYesOrNo()) {\n        println(\"THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\")\n        println(\"(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO \")\n        println(\"CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\\n\")\n    }\n}\n\n// Stay in loop until player chooses an option, then return \"true\" for yes or \"false\" for no\nprivate fun getYesOrNo() = generateSequence { readln() }.firstNotNullOf { it.asYesOrNo }\n\n// Since this returns null for an incorrect value, above firstNotNullOf will keep looping until\n// we get something valid\nprivate val String.asYesOrNo: Boolean?\n    get() =\n        when (this.lowercase()) {\n            \"yes\" -> true\n            \"no\" -> false\n            else -> {\n                println(\"YES OR NO, PLEASE.   \")\n                null\n            }\n        }\n\n\nprivate fun playGame() {\n    // Shuffle the deck than break it into 26 pairs\n    val pairs = fullDeck.shuffled().chunked(2)\n    val score = Score(0, 0)\n    val lastPlayerCard = pairs.last().first()\n    // We use \"destructuring\" to extract the pair of cards directly to a variable here\n    pairs.forEach { (playerCard, computerCard) ->\n        println(\"YOU: $playerCard\\tCOMPUTER: $computerCard\")\n        when {\n            playerCard > computerCard -> score.playerWins()\n            computerCard > playerCard -> score.computerWins()\n            else -> println(\"TIE.  NO SCORE CHANGE.\")\n        }\n        // Doesn't make sense to ask to continue if we have no more cards left to deal\n        if (playerCard != lastPlayerCard) {\n            println(\"DO YOU WANT TO CONTINUE\")\n            if (!getYesOrNo()) {\n                return\n            }\n        }\n    }\n    score.printFinalScore()\n    return\n}\n\n\nclass Score(private var player: Int, private var computer: Int) {\n    fun playerWins() {\n        player++\n        printScore(\"YOU WIN.\")\n    }\n\n    fun computerWins() {\n        computer++\n        printScore(\"THE COMPUTER WINS!!!\")\n    }\n\n    private fun printScore(text: String) {\n        println(\"$text YOU HAVE $player AND THE COMPUTER HAS $computer\")\n    }\n\n    // Only print if you go through the whole deck\n    fun printFinalScore() {\n        println(\"WE HAVE RUN OUT OF CARDS.  FINAL SCORE:   YOU: $player  THE COMPUTER:$computer\")\n    }\n}\n"
  },
  {
    "path": "94_War/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "94_War/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "94_War/perl/war.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse Getopt::Long 2.33 qw{ :config auto_version };\nuse List::Util qw{ shuffle };\nuse Pod::Usage;\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nmy %opt;\n\nGetOptions( \\%opt,\n    qw{ unicode! },\n    help => sub { pod2usage( { -verbose => 2 } ) },\n) or pod2usage( { -verbose => 0 } );\n\nmy @cards;\nmy $current_rank_value = 1;\nmy %rank_value;\nmy @suits = $opt{unicode} ?\n    ( map { chr } 0x2660 .. 0x2663 ) :\n    ( qw{ S H D C } );\nforeach my $rank ( ( 2 .. 10 ), qw{ J Q K A } ) {\n    $rank_value{$rank} = $current_rank_value++;\n    foreach my $suit ( @suits ) {\n        push @cards, \"$suit-$rank\";\n    }\n}\n\n$opt{unicode}\n    and binmode STDOUT, ':encoding(utf-8)';\n\n@cards = shuffle( @cards );\n\nprint <<'EOD';\n                                 WAR\n               Creative Computing  Morristown, New Jersey\n\n\n\nThis is the card game of War.  Each card is given by suit-#\nEOD\n\n# Create the readline object.\nstate $term = Term::ReadLine->new( 'word' );\n\nmy $resp = $term->readline(\n    \"as $suits[0]-7 for Spade 7.  Do you want directions? [y/N]: \" );\nexit unless defined $resp;\nif ( $resp =~ m/ \\A y /smxi ) {\n    print <<'EOD';\nThe computer gives you and it a 'card'.  The higher card\n(numerically) wins.  The game ends when you choose not to\ncontinue or when you have finished the pack.\n\nEOD\n}\n\nmy $your_score = my $computer_score = 0;\n\nwhile ( 1 ) {\n    my ( $you, $computer ) = splice @cards, 0, 2;\n    say '';\n    say \"You: $you; computer: $computer\";\n    my $result = $rank_value{ substr $you, 2 } <=>\n        $rank_value{ substr $computer, 2 };\n    if ( $result < 0 ) {\n        $computer_score++;\n        say \"The computer wins!!!  \",\n            \"You have $your_score and the computer has $computer_score\";\n    } elsif ( $result > 0 ) {\n        $your_score++;\n        say \"You win.  \",\n            \"You have $your_score and the computer has $computer_score\";\n    } else {\n        say 'Tie.  No score change.';\n    }\n\n    last unless @cards;\n\n    $resp = $term->readline( 'Do you want to continue? [Y/n]: ' );\n    last unless defined $resp;\n    last if $resp =~ m/ \\A n /smxi;\n}\n\nsay \"We have run out of cards.  \",\n    \"Final score:  you: $your_score;  the computer: $computer_score\"\n    unless @cards;\nsay '';\nsay 'Thanks for playing.  It was fun.';\n__END__\n\n=head1 TITLE\n\nwar.pl - Play the game 'War' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n war.pl\n war.pl --help\n war.pl --version\n\n=head1 OPTIONS\n\n=head2 --help\n\nThis option displays the documentation for this script. The script then\nexits.\n\n=head2 --unicode\n\nIf this Boolean option is asserted, the suits are designated by their\nUnicode glyphs rather than by ASCII letters. For these to display\nproperly your terminal must properly interpret Unicode.\n\nThe default is C<--no-unicode>.\n\n=head2 --version\n\nThis option displays the version of this script. The script then exits.\n\n=head1 DETAILS\n\nThis Perl script is a port of C<war>, which is the 94th entry in Basic\nComputer Games.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "94_War/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "94_War/python/cards.json",
    "content": "[\n    \"S-2\",\n    \"H-2\",\n    \"C-2\",\n    \"D-2\",\n    \"S-3\",\n    \"H-3\",\n    \"C-3\",\n    \"D-3\",\n    \"S-4\",\n    \"H-4\",\n    \"C-4\",\n    \"D-4\",\n    \"S-5\",\n    \"H-5\",\n    \"C-5\",\n    \"D-5\",\n    \"S-6\",\n    \"H-6\",\n    \"C-6\",\n    \"D-6\",\n    \"S-7\",\n    \"H-7\",\n    \"C-7\",\n    \"D-7\",\n    \"S-8\",\n    \"H-8\",\n    \"C-8\",\n    \"D-8\",\n    \"S-9\",\n    \"H-9\",\n    \"C-9\",\n    \"D-9\",\n    \"S-10\",\n    \"H-10\",\n    \"C-10\",\n    \"D-10\",\n    \"S-J\",\n    \"H-J\",\n    \"C-J\",\n    \"D-J\",\n    \"S-Q\",\n    \"H-Q\",\n    \"C-Q\",\n    \"D-Q\",\n    \"S-K\",\n    \"H-K\",\n    \"C-K\",\n    \"D-K\",\n    \"S-A\",\n    \"H-A\",\n    \"C-A\",\n    \"D-A\"\n]\n"
  },
  {
    "path": "94_War/python/war.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nWAR\n\nConverted from BASIC to Python by Trevor Hobson\n\"\"\"\n\nimport json\nimport random\nfrom pathlib import Path\nfrom typing import List\n\n\ndef card_value(input: str) -> int:\n    return [\"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\"].index(\n        input.split(\"-\")[1]\n    )\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n    with open(Path(__file__).parent / \"cards.json\") as f:\n        cards: List[str] = json.load(f)\n\n    random.shuffle(cards)\n    score_you = 0\n    score_computer = 0\n    cards_left = 52\n    for round in range(26):\n        print()\n        card_you = cards[round]\n        card_computer = cards[round * 2]\n        print(\"You:\", card_you, \" \" * (8 - len(card_you)) + \"Computer:\", card_computer)\n        value_you = card_value(card_you)\n        value_computer = card_value(card_computer)\n        if value_you > value_computer:\n            score_you += 1\n            print(\n                \"You win. You have\", score_you, \"and the computer has\", score_computer\n            )\n        elif value_computer > value_you:\n            score_computer += 1\n            print(\n                \"The computer wins!!! You have\",\n                score_you,\n                \"and the computer has\",\n                score_computer,\n            )\n        else:\n            print(\"Tie. No score change.\")\n        cards_left -= 2\n        if cards_left > 2 and input(\"Do you want to continue \").lower().startswith(\"n\"):\n            break\n    if cards_left == 0:\n        print(\n            \"\\nWe have run out of cards. Final score: You:\",\n            score_you,\n            \"the computer:\",\n            score_computer,\n        )\n    print(\"\\nThanks for playing. It was fun.\")\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"WAR\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n    print(\"This is the card game of war. Each card is given by suit-#\")\n    print(\"as S-7 for Spade 7.\")\n    if input(\"Do you want directions \").lower().startswith(\"y\"):\n        print(\"The computer gives you and it a 'card'. The higher card\")\n        print(\"(numerically) wins. The game ends when you choose not to\")\n        print(\"continue or when you have finished the pack.\")\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nPlay again? (yes or no) \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "94_War/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "94_War/ruby/war.rb",
    "content": "#!/usr/bin/env ruby\n# reinterpreted from BASIC by stephan.com\nclass War\n  class Card\n    class CardError < StandardError; end\n\n    SUITS = %i[spades hearts clubs diamonds].freeze\n    PIPS = %i[ace deuce trey four five six seven eight nine ten jack king queen].freeze\n    CARDS = SUITS.product(PIPS).freeze\n    VALUES = PIPS.zip(1..13).to_h.freeze\n\n    attr_reader :value\n\n    def initialize(suit, pip)\n      @suit = suit\n      @pip = pip\n      raise CardError, 'invalid suit' unless SUITS.include? @suit\n      raise CardError, 'invalid pip' unless PIPS.include? @pip\n\n      @value = VALUES[pip]\n    end\n\n    def <=>(other)\n      @value <=> other.value\n    end\n\n    def >(other)\n      @value > other.value\n    end\n\n    def <(other)\n      @value < other.value\n    end\n\n    def to_s\n      \"the #{@pip} of #{@suit}\"\n    end\n\n    def self.shuffle\n      CARDS.map { |suit, pip| new(suit, pip) }.shuffle\n    end\n  end\n\n  def initialize\n    @your_score = 0\n    @computer_score = 0\n    @your_deck = Card.shuffle\n    @computer_deck = Card.shuffle\n  end\n\n  def play\n    intro\n\n    loop do\n      puts \"\\nYou: #{@your_score} Computer: #{@computer_score}\"\n      round @your_deck.shift, @computer_deck.shift\n      break if empty?\n\n      puts 'Do you want to continue?'\n      break unless yesno\n    end\n\n    outro\n  end\n\n  private\n\n  def round(your_card, computer_card)\n    puts \"You: #{your_card} vs Computer: #{computer_card}\"\n    return puts 'Tie. No score change.' if your_card == computer_card\n\n    if computer_card > your_card\n      puts \"Computer wins with #{computer_card}\"\n      @computer_score += 1\n    else\n      puts \"You win with #{your_card}\"\n      @your_score += 1\n    end\n  end\n\n  def yesno\n    loop do\n      wants = gets.strip\n      return true if wants.downcase == 'yes'\n      return false if wants.downcase == 'no'\n\n      puts 'Yes or no, please.'\n    end\n  end\n\n  def intro\n    puts 'War'.center(80)\n    puts 'stephan.com'.center(80)\n    puts\n    puts 'This is the card game of war.'\n    puts 'Do you want directions'\n    directions if yesno\n  end\n\n  def directions\n    puts 'The computer gives you and it a \\'card\\'.  The higher card'\n    puts '(numerically) wins.  The game ends when you choose not to'\n    puts 'continue or when you have finished the pack.'\n    puts\n  end\n\n  def outro\n    puts \"We've run out of cards\" if empty?\n    puts \"Final score:\\nYou: #{@your_score}\\nComputer: #{@computer_score}\"\n    puts 'Thanks for playing!'\n  end\n\n  def empty?\n    @your_deck.empty? || @computer_deck.empty?\n  end\nend\n\nWar.new.play\n"
  },
  {
    "path": "94_War/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "94_War/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "94_War/rust/src/main.rs",
    "content": "use rand::prelude::{thread_rng, SliceRandom};\nuse std::io;\n\n//DATA\nstruct CARD {\n    suit: u8, //1-4     1=hearts    2=diamonds     3=clubs     4=spades\n    value: u8, //2-14   2,3,4,5,6,7,8,9,10,jack,queen,king,ace\n}\nimpl CARD {\n    /**\n     * creates a new card from the passed card name\n     */\n    fn new(suit:u8,value:u8) -> CARD {\n        return CARD { suit: suit, value: value };\n    }\n}\nimpl ToString for CARD {\n    /**\n     * returns string representation of the Card\n     */\n    fn to_string(&self) -> String {\n        let mut name: String;\n        //value\n        name = match self.value {\n            2..=10 => self.value.to_string() + \" of \",\n            11 => String::from(\"Jack of \"),\n            12 => String::from(\"Queen of \"),\n            13 => String::from(\"King of \"),\n            14 => String::from(\"Ace of \"),\n            _ => panic!(\"card has an invalid value\"),\n        };\n        //suit\n        name += match self.suit {\n            1=>\"Hearts\",\n            2=>\"Diamonds\",\n            3=>\"Clubs\",\n            4=>\"Spades\",\n            _ => panic!(\"card has an invalid suit\"),\n        };\n        return name;\n    }\n}\nstruct GAME {\n    deck: Vec<CARD>, //cards in the deck\n    player_score: usize, //human player score\n    computer_score:usize,//computer score\n}\nimpl GAME {\n    /**\n     * creates a new game, filling a deck with 52 cards, and setting scores to 0\n     */\n    fn new() -> GAME{\n        //DATA\n        let mut game = GAME{deck: Vec::new(), player_score: 0, computer_score: 0};\n        //fill deck\n        for suit in 1..=4 { //4 suits\n            for value in 2..=14 { //13 cards\n                game.deck.push( CARD::new(suit,value) );\n            }\n        }\n        //shuffle deck\n        game.deck.shuffle(&mut thread_rng());\n        //return game\n        return game;\n    }\n\n    /**\n     * fully play game\n     */\n    fn play_game(&mut self) {\n        //DATA\n        let mut human_card: CARD;\n        let mut computer_card: CARD;\n\n        //game loop\n        while self.deck.len() >=2 {\n            //draw cards\n            human_card = self.deck.pop().expect(\"DECK IS EMPTY!\");\n            computer_card = self.deck.pop().expect(\"DECK IS EMPTY!\");\n\n            //print cards\n            println!(\"\\nYou: {}\\t\\tComputer: {}\",human_card.to_string(), computer_card.to_string());\n\n            //determine winner\n            if human_card.value > computer_card.value { //human wins\n                self.player_score += 1;\n                println!(\"You win. You have {} and the computer has {}\", human_card.value, computer_card.value);\n            }\n            else if human_card.value < computer_card.value { //computer wins\n                self.computer_score += 1;\n                println!(\"The computer wins!!! You have {} and the computer has {}\", human_card.value, computer_card.value);\n            }\n            else { //tie\n                println!(\"Tie. No score change.\")\n            }\n            if !get_yes_no_from_user_input(\"Do you want to continue? y/n\") {break;}\n        }\n        if self.deck.is_empty() {\n            println!(\"WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: {} THE COMPUTER: {}\",self.player_score, self.computer_score);\n        }\n        println!(\"\\nThanks for playing. It was fun.\");\n    }\n}\n\nfn main() {\n    //print welcome message\n    welcome();\n\n    //game loop\n    let mut game = GAME::new();\n    loop {\n        game.play_game();\n        if !get_yes_no_from_user_input(\"\\nPlay again? (yes or no) \") {break;}\n        game = GAME::new();\n    }\n}\n\n/**\n * print welcome message\n */\nfn welcome() {\n    println!(\"\n                                War\\n\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\n    This is the card game of war. Each card is given by # of suit\n    ex: Ace of Spades\\n\n    \");\n    if get_yes_no_from_user_input(\"Do you want directions?\") {\n        println!(\"\n        The computer gives you and it a 'card'. The higher card\n        (numerically) wins. The game ends when you choose not to\n        continue or when you have finished the pack.\\n\n        \");\n    }\n}\n\n/**\n * returns true if user input starts with y or Y,\n * false otherwise\n */\nfn get_yes_no_from_user_input(prompt: &str) -> bool {\n    let mut raw_input = String::new(); // temporary variable for user input that can be parsed later\n\n    //print prompt\n    println!(\"{}\", prompt);\n    //read user input from standard input, and store it to raw_input\n    //raw_input.clear(); //clear input\n    io::stdin().read_line(&mut raw_input).expect( \"CANNOT READ INPUT!\");\n\n    //from input, try to read a valid character\n    if let Some(i) = raw_input.trim().chars().nth(0) {\n        if i == 'y' || i == 'Y' {\n            return true;\n        }\n    }\n    //default case\n    return false;\n}\n"
  },
  {
    "path": "94_War/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "94_War/vbnet/War.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"War\", \"War.vbproj\", \"{36D070A1-08CB-424E-AB8E-E782B0A6654B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "94_War/vbnet/War.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>War</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "94_War/war.bas",
    "content": "10 PRINT TAB(33);\"WAR\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT: PRINT: PRINT\n100 PRINT \"THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#\"\n110 PRINT \"AS S-7 FOR SPADE 7.  \";\n120 PRINT \"DO YOU WANT DIRECTIONS\";\n130 INPUT B$\n140 IF B$=\"NO\" THEN 210\n150 IF B$=\"YES\" THEN 180\n160 PRINT \"YES OR NO, PLEASE.  \";\n170 GOTO 120\n180 PRINT \"THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD\"\n190 PRINT \"(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO\"\n200 PRINT \"CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\"\n210 PRINT\n220 PRINT\n230 DIM A$(52),L(54)\n240 FOR I=1 TO 52\n250 READ A$(I)\n260 NEXT I\n270 REM\n280 FOR J=1 TO 52\n290 LET L(J)=INT(52*RND(1))+1\n295 IF J=1 THEN 350\n300 FOR K=1 TO J-1\n310 IF L(K)<>L(J) THEN 340\n320 REM\n330 GOTO 290\n340 NEXT K\n350 NEXT J\n360 P=P+1\n370 M1=L(P)\n380 P=P+1\n390 M2=L(P)\n400 PRINT\n420 PRINT \"YOU: \";A$(M1),\"COMPUTER: \";A$(M2)\n430 N1=INT((M1-.5)/4)\n440 N2=INT((M2-.5)/4)\n450 IF N1>=N2 THEN 490\n460 A1=A1+1\n470 PRINT \"THE COMPUTER WINS!!! YOU HAVE\";B1;\"AND THE COMPUTER HAS\";A1\n480 GOTO 540\n490 IF N1=N2 THEN 530\n500 B1=B1+1\n510 PRINT \"YOU WIN. YOU HAVE\";B1;\"AND THE COMPUTER HAS\";A1\n520 GOTO 540\n530 PRINT \"TIE.  NO SCORE CHANGE.\"\n540 IF L(P+1)=0 THEN 610\n550 PRINT \"DO YOU WANT TO CONTINUE\";\n560 INPUT V$\n570 IF V$=\"YES\" THEN 360\n580 IF V$=\"NO\" THEN 650\n590 PRINT \"YES OR NO, PLEASE.  \";\n600 GOTO 540\n610 PRINT\n620 PRINT\n630 PRINT \"WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: \";B1;\n640 PRINT \"  THE COMPUTER: \";A1:PRINT\n650 PRINT \"THANKS FOR PLAYING.  IT WAS FUN.\"\n655 PRINT\n660 DATA \"S-2\",\"H-2\",\"C-2\",\"D-2\",\"S-3\",\"H-3\",\"C-3\",\"D-3\"\n670 DATA \"S-4\",\"H-4\",\"C-4\",\"D-4\",\"S-5\",\"H-5\",\"C-5\",\"D-5\"\n680 DATA \"S-6\",\"H-6\",\"C-6\",\"D-6\",\"S-7\",\"H-7\",\"C-7\",\"D-7\"\n690 DATA \"S-8\",\"H-8\",\"C-8\",\"D-8\",\"S-9\",\"H-9\",\"C-9\",\"D-9\"\n700 DATA \"S-10\",\"H-10\",\"C-10\",\"D-10\",\"S-J\",\"H-J\",\"C-J\",\"D-J\"\n710 DATA \"S-Q\",\"H-Q\",\"C-Q\",\"D-Q\",\"S-K\",\"H-K\",\"C-K\",\"D-K\"\n720 DATA \"S-A\",\"H-A\",\"C-A\",\"D-A\"\n999 END\n"
  },
  {
    "path": "95_Weekday/README.md",
    "content": "### Weekday\n\nThis program gives facts about your date of birth (or some other day of interest). It is not prepared to give information on people born before the use of the current type of calendar, i.e. year 1582.\n\nYou merely enter today’s date in the form—month, day, year and your date of birth in the same form. The computer then tells you the day of the week of your birth date, your age, and how much time you have spent sleeping, eating, working, and relaxing.\n\nThis program was adapted from a GE timesharing program by Tom Kloos at the Oregon Museum of Science and Industry.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=179)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=194)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "95_Weekday/csharp/Program.cs",
    "content": "﻿using System.Text;\n\nnamespace Weekday\n{\n    class Weekday\n    {\n        private void DisplayIntro()\n        {\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"SYNONYM\".PadLeft(23));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n            Console.WriteLine(\"\");\n            Console.WriteLine(\"Weekday is a computer demonstration that\");\n            Console.WriteLine(\"gives facts about a date of interest to you.\");\n            Console.WriteLine(\"\");\n        }\n\n        private bool ValidateDate(string InputDate, out DateTime ReturnDate)\n        {\n            // The expectation is that the input is in the format D,M,Y\n            // but any valid date format (other than with commas) will work\n            string DateString = InputDate.Replace(\",\", \"/\");\n\n            return (DateTime.TryParse(DateString, out ReturnDate));\n        }\n\n        private DateTime PromptForADate(string Prompt)\n        {\n            bool Success = false;\n            string LineInput = String.Empty;\n            DateTime TodaysDate = DateTime.MinValue;\n\n            // Get the date for input and validate it\n            while (!Success)\n            {\n                Console.Write(Prompt);\n                LineInput = Console.ReadLine().Trim().ToLower();\n\n                Success = ValidateDate(LineInput, out TodaysDate);\n\n                if (!Success)\n                {\n                    Console.WriteLine(\"*** Invalid date.  Please try again.\");\n                    Console.WriteLine(\"\");\n                }\n            }\n\n            return TodaysDate;\n        }\n\n        private void CalculateDateDiff(DateTime TodaysDate, DateTime BirthDate, Double Factor, out int AgeInYears, out int AgeInMonths, out int AgeInDays)\n        {\n            // leveraged Stack Overflow answer: https://stackoverflow.com/a/3055445\n\n            // Convert to number of days since Birth Date, multiple by factor then store as new FactorDate\n            TimeSpan TimeDiff = TodaysDate.Subtract(BirthDate);\n            Double NumberOfDays = TimeDiff.Days * Factor;\n            DateTime FactorDate = BirthDate.AddDays(NumberOfDays);\n\n            // Compute difference between FactorDate (which is TodaysDate * Factor) and BirthDate\n            AgeInMonths = FactorDate.Month - BirthDate.Month;\n            AgeInYears = FactorDate.Year - BirthDate.Year;\n\n            if (FactorDate.Day < BirthDate.Day)\n            {\n                AgeInMonths--;\n            }\n\n            if (AgeInMonths < 0)\n            {\n                AgeInYears--;\n                AgeInMonths += 12;\n            }\n\n            AgeInDays = (FactorDate - BirthDate.AddMonths((AgeInYears * 12) + AgeInMonths)).Days;\n\n        }\n\n        private void WriteColumnOutput(string Message, int Years, int Months, int Days)\n        {\n\n            Console.WriteLine(\"{0,-25} {1,-10:N0} {2,-10:N0} {3,-10:N0}\", Message, Years, Months, Days);\n\n        }\n\n        private void DisplayOutput(DateTime TodaysDate, DateTime BirthDate)\n        {\n            Console.WriteLine(\"\");\n\n            // Not allowed to play if the current year is before 1582\n            if (TodaysDate.Year < 1582)\n            {\n                Console.WriteLine(\"Not prepared to give day of week prior to MDLXXXII.\");\n                return;\n            }\n\n            // Share which day of the week the BirthDate was on\n            Console.Write(\" {0} \", BirthDate.ToString(\"d\"));\n\n            string DateVerb = \"\";\n            if (BirthDate.CompareTo(TodaysDate) < 0)\n            {\n                DateVerb = \"was a \";\n            }\n            else if (BirthDate.CompareTo(TodaysDate) == 0)\n            {\n                DateVerb = \"is a \";\n            }\n            else\n            {\n                DateVerb = \"will be a \";\n            }\n            Console.Write(\"{0}\", DateVerb);\n\n            // Special warning if their birth date was on a Friday the 13th!\n            if (BirthDate.DayOfWeek.ToString().Equals(\"Friday\") && BirthDate.Day == 13)\n            {\n                Console.WriteLine(\"{0} the Thirteenth---BEWARE\", BirthDate.DayOfWeek.ToString());\n            }\n            else\n            {\n                Console.WriteLine(\"{0}\", BirthDate.DayOfWeek.ToString());\n            }\n\n            // If today's date is the same month & day as the birth date then wish them a happy birthday!\n            if (BirthDate.Month == TodaysDate.Month && BirthDate.Day == TodaysDate.Day)\n            {\n                Console.WriteLine(\"\");\n                Console.Write(\"***Happy Birthday***\");\n            }\n\n            Console.WriteLine(\"\");\n\n            // Only show the date calculations if BirthDate is before TodaysDate\n            if (DateVerb.Trim().Equals(\"was a\"))\n            {\n\n                Console.WriteLine(\"{0,-24} {1,-10} {2,-10} {3,-10}\", \" \", \"Years\", \"Months\", \"Days\");\n\n                int TheYears = 0, TheMonths = 0, TheDays = 0;\n                int FlexYears = 0, FlexMonths = 0, FlexDays = 0;\n\n                CalculateDateDiff(TodaysDate, BirthDate, 1, out TheYears, out TheMonths, out TheDays);\n                WriteColumnOutput(\"Your age if birthdate\", TheYears, TheMonths, TheDays);\n\n                FlexYears = TheYears;\n                FlexMonths = TheMonths;\n                FlexDays = TheDays;\n                CalculateDateDiff(TodaysDate, BirthDate, .35, out FlexYears, out FlexMonths, out FlexDays);\n                WriteColumnOutput(\"You have slept\", FlexYears, FlexMonths, FlexDays);\n\n                FlexYears = TheYears;\n                FlexMonths = TheMonths;\n                FlexDays = TheDays;\n                CalculateDateDiff(TodaysDate, BirthDate, .17, out FlexYears, out FlexMonths, out FlexDays);\n                WriteColumnOutput(\"You have eaten\", FlexYears, FlexMonths, FlexDays);\n\n                FlexYears = TheYears;\n                FlexMonths = TheMonths;\n                FlexDays = TheDays;\n                CalculateDateDiff(TodaysDate, BirthDate, .23, out FlexYears, out FlexMonths, out FlexDays);\n                string FlexPhrase = \"You have played\";\n                if (TheYears > 3)\n                    FlexPhrase = \"You have played/studied\";\n                if (TheYears > 9)\n                    FlexPhrase = \"You have worked/played\";\n                WriteColumnOutput(FlexPhrase, FlexYears, FlexMonths, FlexDays);\n\n                FlexYears = TheYears;\n                FlexMonths = TheMonths;\n                FlexDays = TheDays;\n                CalculateDateDiff(TodaysDate, BirthDate, .25, out FlexYears, out FlexMonths, out FlexDays);\n                WriteColumnOutput(\"You have relaxed\", FlexYears, FlexMonths, FlexDays);\n\n                Console.WriteLine(\"\");\n                Console.WriteLine(\"* You may retire in {0} *\".PadLeft(38), BirthDate.Year + 65);\n            }\n        }\n\n        public void PlayTheGame()\n        {\n            DateTime TodaysDate = DateTime.MinValue;\n            DateTime BirthDate = DateTime.MinValue;\n\n            DisplayIntro();\n\n            TodaysDate = PromptForADate(\"Enter today's date in the form: 3,24,1978  ? \");\n            BirthDate = PromptForADate(\"Enter day of birth (or other day of interest)? \");\n\n            DisplayOutput(TodaysDate, BirthDate);\n\n        }\n    }\n    class Program\n    {\n        static void Main(string[] args)\n        {\n\n            new Weekday().PlayTheGame();\n\n        }\n    }\n}\n"
  },
  {
    "path": "95_Weekday/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "95_Weekday/csharp/Weekday.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>10</LangVersion>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "95_Weekday/csharp/Weekday.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Weekday\", \"Weekday.csproj\", \"{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "95_Weekday/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "95_Weekday/java/Weekday.java",
    "content": "import java.util.Scanner;\n\n/**\n * WEEKDAY\n *\n * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)\n *\n */\npublic class Weekday {\n\n\t//TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS.\n\t//Dummy value added at index 0, so we can reference directly by the month number value\n\tprivate final static int[] t = new int[]{-1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};\n\n\tpublic static void main(String[] args) {\n\t\tprintIntro();\n\n\t\tScanner scanner = new Scanner(System.in);\n\t\tSystem.out.print(\"ENTER TODAY'S DATE IN THE FORM: 3,24,1979 \");\n\t\tDateStruct todaysDate = readDate(scanner);\n\n\t\tSystem.out.print(\"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) \");\n\t\tDateStruct dateOfInterest = readDate(scanner);\n\n\t\tint I1 = (dateOfInterest.year - 1500) / 100;\n\t\t//TEST FOR DATE BEFORE CURRENT CALENDAR.\n\t\tif ((dateOfInterest.year - 1582) >= 0) {\n\t\t\tint A = I1 * 5 + (I1 + 3) / 4;\n\t\t\tint I2 = (A - b(A) * 7);\n\t\t\tint Y2 = (dateOfInterest.year / 100);\n\t\t\tint Y3 = (dateOfInterest.year - Y2 * 100);\n\t\t\tA = Y3 / 4 + Y3 + dateOfInterest.day + t[dateOfInterest.month] + I2;\n\t\t\tcalculateAndPrintDayOfWeek(I1, A, todaysDate, dateOfInterest, Y3);\n\n\t\t\tif ((todaysDate.year * 12 + todaysDate.month) * 31 + todaysDate.day\n\t\t\t\t\t== (dateOfInterest.year * 12 + dateOfInterest.month) * 31 + dateOfInterest.day) {\n\t\t\t\treturn; //stop the program\n\t\t\t}\n\n\t\t\tint I5 = todaysDate.year - dateOfInterest.year;\n\t\t\tSystem.out.print(\"\\n\");\n\t\t\tint I6 = todaysDate.month - dateOfInterest.month;\n\t\t\tint I7 = todaysDate.day - dateOfInterest.day;\n\t\t\tif (I7 < 0) {\n\t\t\t\tI6 = I6 - 1;\n\t\t\t\tI7 = I7 + 30;\n\t\t\t}\n\t\t\tif (I6 < 0) {\n\t\t\t\tI5 = I5 - 1;\n\t\t\t\tI6 = I6 + 12;\n\t\t\t}\n\t\t\tif (I5 < 0) {\n\t\t\t\treturn; //do nothing. end the program\n\t\t\t} else {\n\t\t\t\tif (I7 != 0) {\n\t\t\t\t\tprintHeadersAndAge(I5, I6, I7);\n\t\t\t\t} else {\n\t\t\t\t\tif (I6 != 0) {\n\t\t\t\t\t\tprintHeadersAndAge(I5, I6, I7);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tSystem.out.println(\"***HAPPY BIRTHDAY***\");\n\t\t\t\t\t\tprintHeadersAndAge(I5, I6, I7);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint A8 = (I5 * 365) + (I6 * 30) + I7 + (I6 / 2);\n\t\t\tint K5 = I5;\n\t\t\tint K6 = I6;\n\t\t\tint K7 = I7;\n\t\t\t//CALCULATE RETIREMENT DATE.\n\t\t\tint E = dateOfInterest.year + 65;\n\t\t\t// CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS.\n\t\t\tfloat F = 0.35f;\n\t\t\tSystem.out.printf(\"%-28s\", \"YOU HAVE SLEPT\");\n\t\t\tDateStruct scratchDate = new DateStruct(K6, K7, K5); //K5 is a temp year, K6 is month, K7 is day\n\t\t\tprintStatisticRow(F, A8, scratchDate);\n\t\t\tK5 = scratchDate.year;\n\t\t\tK6 = scratchDate.month;\n\t\t\tK7 = scratchDate.day;\n\n\t\t\tF = 0.17f;\n\t\t\tSystem.out.printf(\"%-28s\", \"YOU HAVE EATEN\");\n\n\t\t\tscratchDate = new DateStruct(K6, K7, K5);\n\t\t\tprintStatisticRow(F, A8, scratchDate);\n\t\t\tK5 = scratchDate.year;\n\t\t\tK6 = scratchDate.month;\n\t\t\tK7 = scratchDate.day;\n\n\t\t\tF = 0.23f;\n\t\t\tif (K5 > 3) {\n\t\t\t\tif (K5 > 9) {\n\t\t\t\t\tSystem.out.printf(\"%-28s\", \"YOU HAVE WORKED/PLAYED\");\n\t\t\t\t} else {\n\t\t\t\t\tSystem.out.printf(\"%-28s\", \"YOU HAVE PLAYED/STUDIED\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tSystem.out.printf(\"%-28s\", \"YOU HAVE PLAYED\");\n\t\t\t}\n\n\t\t\tscratchDate = new DateStruct(K6, K7, K5);\n\t\t\tprintStatisticRow(F, A8, scratchDate);\n\t\t\tK5 = scratchDate.year;\n\t\t\tK6 = scratchDate.month;\n\t\t\tK7 = scratchDate.day;\n\n\t\t\tif (K6 == 12) {\n\t\t\t\tK5 = K5 + 1;\n\t\t\t\tK6 = 0;\n\t\t\t}\n\t\t\tSystem.out.printf(\"%-28s%14s%14s%14s%n\", \"YOU HAVE RELAXED\", K5, K6, K7);\n\t\t\tSystem.out.printf(\"%16s***  YOU MAY RETIRE IN %s ***%n\", \" \", E);\n\t\t\tSystem.out.printf(\"%n%n%n%n%n\");\n\t\t} else {\n\t\t\tSystem.out.println(\"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.\");\n\t\t}\n\t}\n\n\n\tprivate static void printStatisticRow(float F, int A8, DateStruct scratchDate) {\n\t\tint K1 = (int) (F * A8);\n\t\tint I5 = K1 / 365;\n\t\tK1 = K1 - (I5 * 365);\n\t\tint I6 = K1 / 30;\n\t\tint I7 = K1 - (I6 * 30);\n\t\tint K5 = scratchDate.year - I5;\n\t\tint K6 = scratchDate.month - I6;\n\t\tint K7 = scratchDate.day - I7;\n\t\tif (K7 < 0) {\n\t\t\tK7 = K7 + 30;\n\t\t\tK6 = K6 - 1;\n\t\t}\n\t\tif (K6 <= 0) {\n\t\t\tK6 = K6 + 12;\n\t\t\tK5 = K5 - 1;\n\t\t}\n\t\t//to return the updated values of K5, K6, K7 we send them through the scratchDate\n\t\tscratchDate.year = K5;\n\t\tscratchDate.month = K6;\n\t\tscratchDate.day = K7;\n\t\tSystem.out.printf(\"%14s%14s%14s%n\", I5, I6, I7);\n\t}\n\n\tprivate static void printHeadersAndAge(int I5, int I6, int I7) {\n\t\tSystem.out.printf(\"%14s%14s%14s%14s%14s%n\", \" \", \" \", \"YEARS\", \"MONTHS\", \"DAYS\");\n\t\tSystem.out.printf(\"%14s%14s%14s%14s%14s%n\", \" \", \" \", \"-----\", \"------\", \"----\");\n\t\tSystem.out.printf(\"%-28s%14s%14s%14s%n\", \"YOUR AGE (IF BIRTHDATE)\", I5, I6, I7);\n\t}\n\n\tprivate static void calculateAndPrintDayOfWeek(int i1, int a, DateStruct dateStruct, DateStruct dateOfInterest, int y3) {\n\t\tint b = (a - b(a) * 7) + 1;\n\t\tif (dateOfInterest.month > 2) {\n\t\t\tprintDayOfWeek(dateStruct, dateOfInterest, b);\n\t\t} else {\n\t\t\tif (y3 == 0) {\n\t\t\t\tint aa = i1 - 1;\n\t\t\t\tint t1 = aa - a(aa) * 4;\n\t\t\t\tif (t1 == 0) {\n\t\t\t\t\tif (b != 0) {\n\t\t\t\t\t\tb = b - 1;\n\t\t\t\t\t\tprintDayOfWeek(dateStruct, dateOfInterest, b);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tb = 6;\n\t\t\t\t\t\tb = b - 1;\n\t\t\t\t\t\tprintDayOfWeek(dateStruct, dateOfInterest, b);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * PRINT THE DAY OF THE WEEK THE DATE FALLS ON.\n\t */\n\tprivate static void printDayOfWeek(DateStruct dateStruct, DateStruct dateOfInterest, int b) {\n\t\tif (b == 0) {\n\t\t\tb = 7;\n\t\t}\n\t\tif ((dateStruct.year * 12 + dateStruct.month) * 31\n\t\t\t\t+ dateStruct.day\n\t\t\t\t<\n\t\t\t\t(dateOfInterest.year * 12\n\t\t\t\t\t\t+ dateOfInterest.month) * 31 + dateOfInterest.day) {\n\t\t\tSystem.out.printf(\"%s / %s / %s WILL BE A \", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);\n\t\t} else if ((dateStruct.year * 12 + dateStruct.month) * 31\n\t\t\t\t+ dateStruct.day == (dateOfInterest.year * 12 + dateOfInterest.month)\n\t\t\t\t* 31 + dateOfInterest.day) {\n\t\t\tSystem.out.printf(\"%s / %s / %s IS A \", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);\n\t\t} else {\n\t\t\tSystem.out.printf(\"%s / %s / %s WAS A \", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);\n\t\t}\n\t\tswitch (b) {\n\t\t\tcase 1:\n\t\t\t\tSystem.out.println(\"SUNDAY.\");\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tSystem.out.println(\"MONDAY.\");\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tSystem.out.println(\"TUESDAY.\");\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tSystem.out.println(\"WEDNESDAY.\");\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tSystem.out.println(\"THURSDAY.\");\n\t\t\t\tbreak;\n\t\t\tcase 6:\n\t\t\t\tif (dateOfInterest.day == 13) {\n\t\t\t\t\tSystem.out.println(\"FRIDAY THE THIRTEENTH---BEWARE!\");\n\t\t\t\t} else {\n\t\t\t\t\tSystem.out.println(\"FRIDAY.\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\t\tSystem.out.println(\"SATURDAY.\");\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate static int a(int a) {\n\t\treturn a / 4;\n\t}\n\n\tprivate static int b(int a) {\n\t\treturn a / 7;\n\t}\n\n\n\tprivate static void printIntro() {\n\t\tSystem.out.println(\"                                WEEKDAY\");\n\t\tSystem.out.println(\"              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n\t\tSystem.out.println(\"\\n\\n\\n\");\n\t\tSystem.out.println(\"WEEKDAY IS A COMPUTER DEMONSTRATION THAT\");\n\t\tSystem.out.println(\"GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\");\n\t\tSystem.out.println(\"\\n\");\n\t}\n\n\t/**\n\t * Read user input for a date, do some validation and return a simple date structure\n\t */\n\tprivate static DateStruct readDate(Scanner scanner) {\n\t\tboolean done = false;\n\t\tint mm = 0, dd = 0, yyyy = 0;\n\t\twhile (!done) {\n\t\t\tString input = scanner.next();\n\t\t\tString[] tokens = input.split(\",\");\n\t\t\tif (tokens.length < 3) {\n\t\t\t\tSystem.out.println(\"DATE EXPECTED IN FORM: 3,24,1979 - RETRY INPUT LINE\");\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tmm = Integer.parseInt(tokens[0]);\n\t\t\t\t\tdd = Integer.parseInt(tokens[1]);\n\t\t\t\t\tyyyy = Integer.parseInt(tokens[2]);\n\t\t\t\t\tdone = true;\n\t\t\t\t} catch (NumberFormatException nfe) {\n\t\t\t\t\tSystem.out.println(\"NUMBER EXPECTED - RETRY INPUT LINE\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new DateStruct(mm, dd, yyyy);\n\t}\n\n\t/**\n\t * Convenience date structure to hold user date input\n\t */\n\tprivate static class DateStruct {\n\t\tint month;\n\t\tint day;\n\t\tint year;\n\n\t\tpublic DateStruct(int month, int day, int year) {\n\t\t\tthis.month = month;\n\t\t\tthis.day = day;\n\t\t\tthis.year = year;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "95_Weekday/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "95_Weekday/javascript/weekday.html",
    "content": "<html>\n<head>\n<title>WEEKDAY</title>\n<link rel=\"stylesheet\" href=\"../../00_Utilities/javascript/style_terminal.css\" />\n</head>\n<body>\n<pre id=\"output\"></pre>\n<script src=\"weekday.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "95_Weekday/javascript/weekday.js",
    "content": "// WEEKDAY\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n//\n\n/**\n * Print given string to the end of the \"output\" element.\n * @param str\n */\nfunction print(str) {\n    document.getElementById(\"output\").appendChild(document.createTextNode(str));\n}\n\n/**\n * Obtain user input\n * @returns {Promise<String>}\n */\nfunction input() {\n    return new Promise(function (resolve) {\n        const input_element = document.createElement(\"INPUT\");\n\n        print(\"? \");\n        input_element.setAttribute(\"type\", \"text\");\n        input_element.setAttribute(\"length\", \"50\");\n        document.getElementById(\"output\").appendChild(input_element);\n        input_element.focus();\n        input_element.addEventListener(\"keydown\", function (event) {\n            if (event.keyCode === 13) {\n                const input_str = input_element.value;\n                document.getElementById(\"output\").removeChild(input_element);\n                print(input_str);\n                print(\"\\n\");\n                resolve(input_str);\n            }\n        });\n    });\n}\n\n/**\n * Create a string consisting of the given number of spaces\n * @param spaceCount\n * @returns {string}\n */\nfunction tab(spaceCount) {\n    let str = \"\";\n    while (spaceCount-- > 0)\n        str += \" \";\n    return str;\n}\n\nconst MONTHS_PER_YEAR = 12;\nconst DAYS_PER_COMMON_YEAR = 365;\nconst DAYS_PER_IDEALISED_MONTH = 30;\nconst MAXIMUM_DAYS_PER_MONTH = 31;\n// In a common (non-leap) year the day of the week for the first of each month moves by the following amounts.\nconst COMMON_YEAR_MONTH_OFFSET = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5];\n\n/**\n * Date representation.\n */\nclass DateStruct {\n    #year;\n    #month;\n    #day;\n\n    /**\n     * Build a DateStruct\n     * @param {number} year\n     * @param {number} month\n     * @param {number} day\n     */\n    constructor(year, month, day) {\n        this.#year = year;\n        this.#month = month;\n        this.#day = day;\n    }\n\n    get year() {\n        return this.#year;\n    }\n\n    get month() {\n        return this.#month;\n    }\n\n    get day() {\n        return this.#day;\n    }\n\n    /**\n     * Determine if the date could be a Gregorian date.\n     * Be aware the Gregorian calendar was not introduced in all places at once,\n     * see https://en.wikipedia.org/wiki/Gregorian_calendar\n     * @returns {boolean} true if date could be Gregorian; otherwise false.\n     */\n    isGregorianDate() {\n        let result = false;\n        if (this.#year > 1582) {\n            result = true;\n        } else if (this.#year === 1582) {\n            if (this.#month > 10) {\n                result = true;\n            } else if (this.#month === 10 && this.#day >= 15) {\n                result = true;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * The following performs a hash on the day parts which guarantees that\n     * 1. different days will return different numbers\n     * 2. the numbers returned are ordered.\n     * @returns {number}\n     */\n    getNormalisedDay() {\n        return (this.year * MONTHS_PER_YEAR + this.month) * MAXIMUM_DAYS_PER_MONTH + this.day;\n    }\n\n    /**\n     * Determine the day of the week.\n     * This calculation returns a number between 1 and 7 where Sunday=1, Monday=2, ..., Saturday=7.\n     * @returns {number} Value between 1 and 7 representing Sunday to Saturday.\n     */\n    getDayOfWeek() {\n        // Calculate an offset based on the century part of the year.\n        const centuriesSince1500 = Math.floor((this.year - 1500) / 100);\n        let centuryOffset = centuriesSince1500 * 5 + (centuriesSince1500 + 3) / 4;\n        centuryOffset = Math.floor(centuryOffset % 7);\n\n        // Calculate an offset based on the shortened two digit year.\n        // January 1st moves forward by approximately 1.25 days per year\n        const yearInCentury = this.year % 100;\n        const yearInCenturyOffsets = yearInCentury / 4 + yearInCentury;\n\n        // combine offsets with day and month\n        let dayOfWeek = centuryOffset + yearInCenturyOffsets + this.day + COMMON_YEAR_MONTH_OFFSET[this.month - 1];\n\n        dayOfWeek = Math.floor(dayOfWeek % 7) + 1;\n        if (this.month <= 2 && this.isLeapYear()) {\n            dayOfWeek--;\n        }\n        if (dayOfWeek === 0) {\n            dayOfWeek = 7;\n        }\n        return dayOfWeek;\n    }\n\n    /**\n     * Determine if the given year is a leap year.\n     * @returns {boolean}\n     */\n    isLeapYear() {\n        if ((this.year % 4) !== 0) {\n            return false;\n        } else if ((this.year % 100) !== 0) {\n            return true;\n        } else if ((this.year % 400) !== 0) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Returns a US formatted date, i.e. Month/Day/Year.\n     * @returns {string}\n     */\n    toString() {\n        return this.#month + \"/\" + this.#day + \"/\" + this.#year;\n    }\n}\n\n/**\n * Duration representation.\n * Note: this class only handles positive durations well\n */\nclass Duration {\n    #years;\n    #months;\n    #days;\n\n    /**\n     * Build a Duration\n     * @param {number} years\n     * @param {number} months\n     * @param {number} days\n     */\n    constructor(years, months, days) {\n        this.#years = years;\n        this.#months = months;\n        this.#days = days;\n        this.#fixRanges();\n    }\n\n    get years() {\n        return this.#years;\n    }\n\n    get months() {\n        return this.#months;\n    }\n\n    get days() {\n        return this.#days;\n    }\n\n    clone() {\n        return new Duration(this.#years, this.#months, this.#days);\n    }\n\n    /**\n     * Adjust Duration by removing years, months and days from supplied Duration.\n     * This is a naive calculation which assumes all months are 30 days.\n     * @param {Duration} timeToRemove\n     */\n    remove(timeToRemove) {\n        this.#years -= timeToRemove.years;\n        this.#months -= timeToRemove.months;\n        this.#days -= timeToRemove.days;\n        this.#fixRanges();\n    }\n\n    /**\n     * Move days and months into expected range.\n     */\n    #fixRanges() {\n        if (this.#days < 0) {\n            this.#days += DAYS_PER_IDEALISED_MONTH;\n            this.#months--;\n        }\n        if (this.#months < 0) {\n            this.#months += MONTHS_PER_YEAR;\n            this.#years--;\n        }\n    }\n\n    /**\n     * Computes an approximation of the days covered by the duration.\n     * The calculation assumes all years are 365 days, months are 30 days each,\n     * and adds on an extra bit the more months that have passed.\n     * @returns {number}\n     */\n    getApproximateDays() {\n        return (\n            (this.#years * DAYS_PER_COMMON_YEAR)\n            + (this.#months * DAYS_PER_IDEALISED_MONTH)\n            + this.#days\n            + Math.floor(this.#months / 2)\n        );\n    }\n\n    /**\n     * Returns a formatted duration with tab separated values, i.e. Years\\tMonths\\tDays.\n     * @returns {string}\n     */\n    toString() {\n        return this.#years + \"\\t\" + this.#months + \"\\t\" + this.#days;\n    }\n\n    /**\n     * Determine approximate Duration between two dates.\n     * This is a naive calculation which assumes all months are 30 days.\n     * @param {DateStruct} date1\n     * @param {DateStruct} date2\n     * @returns {Duration}\n     */\n    static between(date1, date2) {\n        let years = date1.year - date2.year;\n        let months = date1.month - date2.month;\n        let days = date1.day - date2.day;\n        return new Duration(years, months, days);\n    }\n\n    /**\n     * Calculate years, months and days as factor of days.\n     * This is a naive calculation which assumes all months are 30 days.\n     * @param dayCount Total day to convert to a duration\n     * @param factor   Factor to apply when calculating the duration\n     * @returns {Duration}\n     */\n    static fromDays(dayCount, factor) {\n        let totalDays = Math.floor(factor * dayCount);\n        const years = Math.floor(totalDays / DAYS_PER_COMMON_YEAR);\n        totalDays -= years * DAYS_PER_COMMON_YEAR;\n        const months = Math.floor(totalDays / DAYS_PER_IDEALISED_MONTH);\n        const days = totalDays - (months * DAYS_PER_IDEALISED_MONTH);\n        return new Duration(years, months, days);\n    }\n}\n\n// Main control section\nasync function main() {\n    /**\n     * Reads a date, and extracts the date information.\n     * This expects date parts to be comma separated, using US date ordering,\n     * i.e. Month,Day,Year.\n     * @returns {Promise<DateStruct>}\n     */\n    async function inputDate() {\n        let dateString = await input();\n        const month = parseInt(dateString);\n        const day = parseInt(dateString.substr(dateString.indexOf(\",\") + 1));\n        const year = parseInt(dateString.substr(dateString.lastIndexOf(\",\") + 1));\n        return new DateStruct(year, month, day);\n    }\n\n    /**\n     * Obtain text for the day of the week.\n     * @param {DateStruct} date\n     * @returns {string}\n     */\n    function getDayOfWeekText(date) {\n        const dayOfWeek = date.getDayOfWeek();\n        let dayOfWeekText = \"\";\n        switch (dayOfWeek) {\n            case 1:\n                dayOfWeekText = \"SUNDAY.\";\n                break;\n            case 2:\n                dayOfWeekText = \"MONDAY.\";\n                break;\n            case 3:\n                dayOfWeekText = \"TUESDAY.\";\n                break;\n            case 4:\n                dayOfWeekText = \"WEDNESDAY.\";\n                break;\n            case 5:\n                dayOfWeekText = \"THURSDAY.\";\n                break;\n            case 6:\n                if (date.day === 13) {\n                    dayOfWeekText = \"FRIDAY THE THIRTEENTH---BEWARE!\";\n                } else {\n                    dayOfWeekText = \"FRIDAY.\";\n                }\n                break;\n            case 7:\n                dayOfWeekText = \"SATURDAY.\";\n                break;\n        }\n        return dayOfWeekText;\n    }\n\n    print(tab(32) + \"WEEKDAY\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"WEEKDAY IS A COMPUTER DEMONSTRATION THAT\\n\");\n    print(\"GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\\n\");\n    print(\"\\n\");\n    print(\"ENTER TODAY'S DATE IN THE FORM: 3,24,1979  \");\n    const today = await inputDate();\n    // This program determines the day of the week\n    //  for a date after 1582\n    print(\"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)\");\n    const dateOfBirth = await inputDate();\n    print(\"\\n\");\n    // Test for date before current calendar.\n    if (!dateOfBirth.isGregorianDate()) {\n        print(\"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO X.XV.MDLXXXII.\\n\");\n    } else {\n        const normalisedToday = today.getNormalisedDay();\n        const normalisedDob = dateOfBirth.getNormalisedDay();\n\n        let dayOfWeekText = getDayOfWeekText(dateOfBirth);\n        if (normalisedToday < normalisedDob) {\n            print(dateOfBirth + \" WILL BE A \" + dayOfWeekText + \"\\n\");\n        } else if (normalisedToday === normalisedDob) {\n            print(dateOfBirth + \" IS A \" + dayOfWeekText + \"\\n\");\n        } else {\n            print(dateOfBirth + \" WAS A \" + dayOfWeekText + \"\\n\");\n        }\n\n        if (normalisedToday !== normalisedDob) {\n            print(\"\\n\");\n            let differenceBetweenDates = Duration.between(today, dateOfBirth);\n            if (differenceBetweenDates.years >= 0) {\n                if (differenceBetweenDates.days === 0 && differenceBetweenDates.months === 0) {\n                    print(\"***HAPPY BIRTHDAY***\\n\");\n                }\n                print(\"                        \\tYEARS\\tMONTHS\\tDAYS\\n\");\n                print(\"                        \\t-----\\t------\\t----\\n\");\n                print(\"YOUR AGE (IF BIRTHDATE) \\t\" + differenceBetweenDates + \"\\n\");\n\n                const approximateDaysBetween = differenceBetweenDates.getApproximateDays();\n                const unaccountedTime = differenceBetweenDates.clone();\n\n                // 35% sleeping\n                const sleepTimeSpent = Duration.fromDays(approximateDaysBetween, 0.35);\n                print(\"YOU HAVE SLEPT \\t\\t\\t\" + sleepTimeSpent + \"\\n\");\n                unaccountedTime.remove(sleepTimeSpent);\n\n                // 17% eating\n                const eatenTimeSpent = Duration.fromDays(approximateDaysBetween, 0.17);\n                print(\"YOU HAVE EATEN \\t\\t\\t\" + eatenTimeSpent + \"\\n\");\n                unaccountedTime.remove(eatenTimeSpent);\n\n                // 23% working, studying or playing\n                const workPlayTimeSpent = Duration.fromDays(approximateDaysBetween, 0.23);\n                if (unaccountedTime.years <= 3) {\n                    print(\"YOU HAVE PLAYED \\t\\t\" + workPlayTimeSpent + \"\\n\");\n                } else if (unaccountedTime.years <= 9) {\n                    print(\"YOU HAVE PLAYED/STUDIED \\t\" + workPlayTimeSpent + \"\\n\");\n                } else {\n                    print(\"YOU HAVE WORKED/PLAYED \\t\\t\" + workPlayTimeSpent + \"\\n\");\n                }\n                unaccountedTime.remove(workPlayTimeSpent);\n\n                // Remaining time spent relaxing\n                print(\"YOU HAVE RELAXED \\t\\t\" + unaccountedTime + \"\\n\");\n\n                const retirementYear = dateOfBirth.year + 65;\n                print(\"\\n\");\n                print(tab(16) + \"***  YOU MAY RETIRE IN \" + retirementYear + \" ***\\n\");\n                print(\"\\n\");\n            }\n        }\n    }\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n}\n\nmain();\n"
  },
  {
    "path": "95_Weekday/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "95_Weekday/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "95_Weekday/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n\nI have replaced the manual date logic with Perl built-ins to the extent\npossible. Unfortunately the kind of date math involved in the \"time\nspent doing ...\" functionality is not well-defined, so I have been\nforced to retain the original logic here. Sigh.\n\nYou can use any punctuation character you please in the date\ninput. So something like 2/29/2020 is perfectly acceptable.\n\nIt would also have been nice to produce a localized version that\nsupports day/month/year or year-month-day input, but that didn't happen.\n\nAlso nice would have been language-specific output -- especially if it\ncould have accommodated regional differences in which day of the week or\nmonth is unlucky.\n\nTom Wyant\n"
  },
  {
    "path": "95_Weekday/perl/weekday.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse Term::ReadLine;     # Prompt and return user input\nuse Time::Local qw{ timelocal };    # date-time to epoch\n# FIXME timelocal() is too smart for its own good in the interpretation\n# of years, and caused a bunch of Y2020 problems in Perl code that used\n# it. I believe that this script avoids these problems (which only occur\n# if the year is less than 1000), but it is probably safer in general to\n# use timelocal_modern() or timelocal_posix(). These are also exported\n# by Time::Local, but only by versions 1.28 and 1.30 respectively. This\n# means that they only come (by default) with Perl 5.30 and 5.34\n# respectively. Now, Time::Local is a dual-life module, meaning it can\n# be upgraded from the version packaged with older Perls. But I did not\n# want to assume that it HAD been upgraded. Caveat coder.\nuse Time::Piece;    # O-O epoch to date-time, plus formatting\n\nour $VERSION = '0.000_01';\n\nprint <<'EOD';\n\n                                WEEKDAY\n               Creative Computing  Morristown, New Jersey\n\n\n\nWEEKDAY is a computer demonstration that\ngives facts about a date of interest to you.\n\nEOD\n\nmy $now = localtime;\nmy $default_date = join ',', map { $now->$_() } qw{ mon mday year };\n\nmy $today = get_date(\n    \"Enter today's date in the form month,day,year (default: $default_date): \",\n    \"Please enter month,day,year or return for default\\n\",\n    $default_date,\n);\n\nmy $birthday = get_date(\n    'Ender day of birth (or other day of interest): ',\n    \"Please enter month,day,year\\n\",\n);\n\nsay '';\nprintf \"%d/%d/%d %s a %s\\n\", $birthday->mon, $birthday->mday,\n    $birthday->year, tense( $today, $birthday),\n    ( $birthday->mday == 13 && $birthday->wday == 6 ) ?\n        $birthday->fullday . ' the thirteenth --- Beware!' :\n        $birthday->fullday . '.';\n\nif ( $birthday->epoch <= $today->epoch ) {\n\n    say '*** Happy Birthday! ***'\n        if $birthday->mon == $today->mon &&\n            $birthday->mday == $today->mday;\n\n    print <<'EOD';\n                        Years   Months  Days\n                        -----   ------  ----\nEOD\n\n    my @delta = map { $today->$_() - $birthday->$_() } qw{ year mon mday };\n    if ( $delta[2] < 0 ) {\n        $delta[2] += 30;\n        $delta[1] -= 1;\n    }\n    if ( $delta[1] < 0 ) {\n        $delta[1] += 12;\n        $delta[0] -= 1;\n    }\n    my @residue = @delta;\n\n    my $delta_days = 365 * $delta[0] + 30 * $delta[1] + $delta[2];\n\n    display_ymd( 'Your age (if birthdate)', compute_ymd( $delta_days ) );\n    display_ymd( 'You have slept', compute_ymd( $delta_days, 0.35,\n            \\@residue ) );\n    display_ymd( 'You have eaten', compute_ymd( $delta_days, 0.17,\n            \\@residue ) );\n    display_ymd(\n        $residue[0] > 9 ? 'You have worked/played' :\n        $residue[0] > 3 ? 'You have played/studied' :\n            'You have played',\n        compute_ymd( $delta_days, 0.23,\n            \\@residue ) );\n    display_ymd( 'You have relaxed', \\@residue );\n\n    say '';\n    say \"\\t\\t*** You may retire in @{[ $birthday->year + 65 ]} ***\";\n}\n\nsay '';\n\nsub compute_ymd {\n    my ( $delta_days, $fract, $residue ) = @ARG;\n    my $days = defined $fract ? int ( $delta_days * $fract ) : $delta_days;\n    my $years = int( $days / 365 );\n    $days -= $years * 365;\n    my $months = int( $days / 30 );\n    $days -= $months * 30;\n\n    if ( $residue ) {\n        $residue->[2] -= $days;\n        if ( $residue->[2] < 0 ) {\n            $residue->[2] += 30;\n            $residue->[1] -= 1;\n        }\n        $residue->[1] -= $months;\n        if ( $residue->[1] < 0 ) {\n            $residue->[1] += 12;\n            $residue->[0] -= 1;\n        }\n        $residue->[0] -= $years;\n    }\n\n    return [ $years, $months, $days ];\n}\n\nsub display_ymd {\n    my ( $label, $ymd ) = @ARG;\n    printf \"%-24s%4d%6d%8d\\n\", $label, @{ $ymd };\n    return;\n}\n\nsub get_date {\n    my ( $prompt, $warning, $default ) = @ARG;\n    my ( $month, $day, $year ) = split qr< [[:punct:]] >smx, get_input(\n        $prompt,\n        sub {\n            return 0 unless m/ \\A (?: [0-9]+ [[:punct:]] ){2} ( [0-9]+ ) \\z /smx;\n            return 1 if $1 >= 1582;\n            warn \"Not prepared to give day of week prior to MDLXXXII.\\n\";\n            return 0;\n        },\n        $warning,\n        $default,\n    );\n    return localtime timelocal( 0, 0, 0, $day, $month - 1, $year );\n}\n\nsub tense {\n    my ( $today, $birthday ) = @ARG;\n    my $cmp = $birthday->epoch <=> $today->epoch\n        or return 'is';\n    return $cmp < 0 ? 'was' : 'will be';\n}\n\n# Get input from the user. The arguments are:\n# * The prompt\n# * A reference to validation code. This code receives the response in\n#   $ARG and returns true for a valid response.\n# * A warning to print if the response is not valid. This must end in a\n#   return.\n# * A default to return if the user simply presses <return>.\n# The first valid response is returned. An end-of-file terminates the\n# script.\nsub get_input {\n    my ( $prompt, $validate, $warning, $default ) = @ARG;\n\n    # If no validator is passed, default to one that always returns\n    # true.\n    $validate ||= sub { 1 };\n\n    # Create the readline object. The 'state' causes the variable to be\n    # initialized only once, no matter how many times this subroutine is\n    # called. The do { ... } is a compound statement used because we\n    # need to tweak the created object before we store it.\n    state $term = do {\n        my $obj = Term::ReadLine->new( 'reverse' );\n        $obj->ornaments( 0 );\n        $obj;\n    };\n\n    while ( 1 ) {   # Iterate indefinitely\n\n        # Read the input into the topic variable, localized to prevent\n        # Spooky Action at a Distance. We exit on undef, which signals\n        # end-of-file.\n        exit unless defined( local $ARG = $term->readline( $prompt ) );\n\n        # Return the default if it exists AND we got an empty line\n        return $default if defined( $default ) && $ARG eq '';\n\n        # Return the input if it is valid.\n        return $ARG if $validate->();\n\n        # Issue the warning, and go around the merry-go-round again.\n        warn $warning;\n    }\n}\n\n__END__\n\n=head1 TITLE\n\nweekday - Play the game 'Weekday' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n weekday.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of weekday.bas, which is the 95th entry in\nBasic Computer Games.\n\nI have replaced the manual date logic with Perl built-ins to the extent\npossible. Unfortunately the kind of date math involved in the \"time\nspent doing ...\" functionality is not well-defined, so I have been\nforced to retain the original logic here. Sigh.\n\nYou can use any punctuation character you please in the date\ninput. So something like 2/29/2020 is perfectly acceptable.\n\nIt would also have been nice to produce a localized version that\nsupports day/month/year or year-month-day input, but that didn't happen.\n\nAlso nice would have been language-specific output -- especially if it\ncould have accommodated regional differences in which day of the week or\nmonth is unlucky.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "95_Weekday/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "95_Weekday/python/weekday.py",
    "content": "\"\"\"\nWEEKDAY\n\nCalculates which weekday an entered date is.\n\nAlso estimates how long a person has done certain activities, if they\nentered their birthday.\n\nAlso calculates the year of retirement, assuming retiring at age 65.\n\nPorted by Dave LeCompte.\n\"\"\"\n\nimport datetime\nfrom typing import Tuple\n\nGET_TODAY_FROM_SYSTEM = True\n\n\ndef get_date_from_user(prompt: str) -> Tuple[int, int, int]:\n    while True:\n        print(prompt)\n        date_str = input()\n        try:\n            month_num, day_num, year_num = (int(x) for x in date_str.split(\",\"))\n            return month_num, day_num, year_num\n        except Exception:\n            print(\"I COULDN'T UNDERSTAND THAT. TRY AGAIN.\")\n\n\ndef get_date_from_system() -> Tuple[int, int, int]:\n    dt = datetime.datetime.now()\n    return dt.month, dt.day, dt.year\n\n\ndef get_day_of_week(weekday_index, day) -> str:\n    if weekday_index == 6 and day == 13:\n        return \"FRIDAY THE THIRTEENTH---BEWARE!\"\n    day_names = {\n        1: \"SUNDAY\",\n        2: \"MONDAY\",\n        3: \"TUESDAY\",\n        4: \"WEDNESDAY\",\n        5: \"THURSDAY\",\n        6: \"FRIDAY\",\n        7: \"SATURDAY\",\n    }\n\n    return day_names[weekday_index]\n\n\ndef previous_day(b) -> int:\n    if b == 0:\n        b = 6\n    return b - 1\n\n\ndef is_leap_year(year: int) -> bool:\n    if (year % 4) != 0:\n        return False\n    return True if (year % 100) != 0 else year % 400 == 0\n\n\ndef adjust_day_for_leap_year(b, year):\n    if is_leap_year(year):\n        b = previous_day(b)\n    return b\n\n\ndef adjust_weekday(b, month, year):\n    if month <= 2:\n        b = adjust_day_for_leap_year(b, year)\n    if b == 0:\n        b = 7\n    return b\n\n\ndef calc_day_value(year, month, day):\n    return (year * 12 + month) * 31 + day\n\n\ndef deduct_time(frac, days, years_remain, months_remain, days_remain):\n    # CALCULATE TIME IN YEARS, MONTHS, AND DAYS\n    days_available = int(frac * days)\n    years_used = days_available // 365\n    days_available -= years_used * 365\n    months_used = days_available // 30\n    days_used = days_available - (months_used * 30)\n    years_remain = years_remain - years_used\n    months_remain = months_remain - months_used\n    days_remain = days_remain - days_used\n\n    while days_remain < 0:\n        days_remain += 30\n        months_remain -= 1\n\n    while months_remain < 0 and years_remain > 0:\n        months_remain += 12\n        years_remain -= 1\n    return years_remain, months_remain, days_remain, years_used, months_used, days_used\n\n\ndef time_report(msg, years, months, days):\n    leading_spaces = 23 - len(msg)\n    print(\" \" * leading_spaces + f\"{msg}\\t{years}\\t{months}\\t{days}\")\n\n\ndef make_occupation_label(years):\n    if years <= 3:\n        return \"PLAYED\"\n    elif years <= 9:\n        return \"PLAYED/STUDIED\"\n    else:\n        return \"WORKED/PLAYED\"\n\n\ndef calculate_day_of_week(year, month, day):\n    # Initial values for months\n    month_table = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]\n\n    i1 = int((year - 1500) / 100)\n    a = i1 * 5 + (i1 + 3) / 4\n    i2 = int(a - int(a / 7) * 7)\n    y2 = int(year / 100)\n    y3 = int(year - y2 * 100)\n    a = y3 / 4 + y3 + day + month_table[month - 1] + i2\n    b = int(a - int(a / 7) * 7) + 1\n    b = adjust_weekday(b, month, year)\n\n    return b\n\n\ndef end() -> None:\n    for _ in range(5):\n        print()\n\n\ndef main() -> None:\n    print(\" \" * 32 + \"WEEKDAY\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\\n\\n\")\n    print(\"WEEKDAY IS A COMPUTER DEMONSTRATION THAT\")\n    print(\"GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\")\n    print()\n\n    if GET_TODAY_FROM_SYSTEM:\n        month_today, day_today, year_today = get_date_from_system()\n    else:\n        month_today, day_today, year_today = get_date_from_user(\n            \"ENTER TODAY'S DATE IN THE FORM: 3,24,1979\"\n        )\n\n    # This program determines the day of the week\n    # for a date after 1582\n\n    print()\n\n    month, day, year = get_date_from_user(\n        \"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) (like MM,DD,YYYY)\"\n    )\n\n    print()\n\n    # Test for date before current calendar\n    if year < 1582:\n        print(\"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.\")\n        end()\n        return\n\n    b = calculate_day_of_week(year, month, day)\n\n    today_day_value = calc_day_value(year_today, month_today, day_today)\n    target_day_value = calc_day_value(year, month, day)\n\n    is_today = False\n\n    if today_day_value < target_day_value:\n        label = \"WILL BE A\"\n    elif today_day_value == target_day_value:\n        label = \"IS A\"\n        is_today = True\n    else:\n        label = \"WAS A\"\n\n    day_name = get_day_of_week(b, day)\n\n    # print the day of the week the date falls on.\n    print(f\"{month}/{day}/{year} {label} {day_name}.\")\n\n    if is_today:\n        # nothing to report for today\n        end()\n        return\n\n    print()\n\n    el_years = year_today - year\n    el_months = month_today - month\n    el_days = day_today - day\n\n    if el_days < 0:\n        el_months = el_months - 1\n        el_days = el_days + 30\n    if el_months < 0:\n        el_years = el_years - 1\n        el_months = el_months + 12\n    if el_years < 0:\n        # target date is in the future\n        end()\n        return\n\n    if (el_months == 0) and (el_days == 0):\n        print(\"***HAPPY BIRTHDAY***\")\n\n    # print report\n    print(\" \" * 23 + \"\\tYEARS\\tMONTHS\\tDAYS\")\n    print(\" \" * 23 + \"\\t-----\\t------\\t----\")\n    print(f\"YOUR AGE (IF BIRTHDATE)\\t{el_years}\\t{el_months}\\t{el_days}\")\n\n    life_days = (el_years * 365) + (el_months * 30) + el_days + int(el_months / 2)\n    rem_years = el_years\n    rem_months = el_months\n    rem_days = el_days\n\n    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(\n        0.35, life_days, rem_years, rem_months, rem_days\n    )\n    time_report(\"YOU HAVE SLEPT\", used_years, used_months, used_days)\n    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(\n        0.17, life_days, rem_years, rem_months, rem_days\n    )\n    time_report(\"YOU HAVE EATEN\", used_years, used_months, used_days)\n\n    label = make_occupation_label(rem_years)\n    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(\n        0.23, life_days, rem_years, rem_months, rem_days\n    )\n    time_report(f\"YOU HAVE {label}\", used_years, used_months, used_days)\n    time_report(\"YOU HAVE RELAXED\", rem_years, rem_months, rem_days)\n\n    print()\n\n    # Calculate retirement date\n    e = year + 65\n    print(\" \" * 16 + f\"***  YOU MAY RETIRE IN {e} ***\")\n    end()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "95_Weekday/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "95_Weekday/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n"
  },
  {
    "path": "95_Weekday/rust/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)\n"
  },
  {
    "path": "95_Weekday/rust/src/main.rs",
    "content": "use std::io::{self, stdout, Write};\n\nstruct DATE {\n    month: u32,\n    day: u32,\n    year:u32,\n    day_of_week:u32,\n}\nimpl DATE {\n    /**\n     * create new date with given paramets\n     */\n    fn new(month:u32,day:u32,year:u32,day_of_week:u32) -> DATE {\n        return DATE { month: month, day: day, year: year, day_of_week: day_of_week };\n    }\n    /**\n     * create date from user input\n     */\n    fn new_from_input(prompt:&str) -> DATE {\n        //DATA\n        let mut raw_date: Vec<u32>;\n        //get date\n        //input loop\n        loop {\n            //get user input,\n            raw_date = get_str_from_user(prompt)\n            .split(',')//split it up by ',''s\n            .filter_map(|s| s.parse::<u32>().ok()).collect();//convert it to numbers, ignore things that fail\n            \n            //if they didn't give enough data\n            if raw_date.len() == 3 { //is it long enough? (3 elements)\n                //are each ones valid things?\n                if (1..=12).contains(&raw_date[0]) { //valid month\n                    if (1..=31).contains(&raw_date[1]) { //valid day\n                        break;\n                    }\n                }\n            }\n            //otherwise, print error message and go again\n            println!(\"Invalid date, try again!\");\n        }\n\n        //create date\n        let mut date =DATE::new(raw_date[0], raw_date[1], raw_date[2], 0);\n        date.update_day_of_week();\n        //return date\n        return date\n    }\n    /**\n     * create a new date from a number of days\n     */\n    fn new_from_days(days:u32) -> DATE{\n        let mut days_remaining = days;\n        let d;\n        let m;\n        let y;\n\n        //get the years\n        y=(days_remaining as f64 / 365.25) as u32;\n        //deduct\n        days_remaining = (days_remaining as f64 % 365.25) as u32;\n\n        //get months\n        m=(days_remaining as f64 / 30.437) as u32;\n        //deduct\n        days_remaining = (days_remaining as f64 % 30.437) as u32;\n\n        //get days\n        d = days_remaining;\n\n        //return new date\n        return DATE::new(m, d, y, 0);\n    }\n\n    /**\n     * caluclates the day of the week (1-7)\n     * uses the methodology found here: https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html\n     */\n    fn update_day_of_week(&mut self) {\n        //DATA\n        let day = self.day as isize;\n        let month = self.month as isize;\n        let year = self.year as isize;\n        let century = year/100;\n        let year_of_century = year - century*100;\n        let weekday; //as 0-6\n\n        //calculate weekday\n        if self.month <= 2 { //if jan or feb\n            weekday = (day + (2.6 * ((month+10) as f64)-0.2)as isize - 2*century + (year_of_century-1) + (year_of_century-1)/4 + century/4) % 7;\n        } else {\n            weekday = (day + (2.6 * ((month-2)  as f64)-0.2)as isize - 2*century + year_of_century     + year_of_century/4     + century/4) % 7;\n        }\n\n        //update weekday\n        self.day_of_week=(weekday+1) as u32; //weekday as 1-7\n    }\n\n    /**\n     * return the string for the weekday\n     */\n    fn day_of_week_as_string(&self) -> String {\n        match self.day_of_week {\n            1 => {return String::from(\"SUNDAY\")},\n            2 => {return String::from(\"MONDAY\")},\n            3 => {return String::from(\"TUESDAY\")},\n            4 => {return String::from(\"WEDNESDAY\")},\n            5 => {return String::from(\"THURSDAY\")},\n            6 => {\n                if self.day == 13 {return String::from(\"FRIDAY THE THIRTEENTH---BEWARE!\")}\n                else {return String::from(\"FRIDAY\")}\n            },\n            7 => {return String::from(\"SATURDAY\")}, \n            _ => {return String::from(\"\")},\n        }\n    }\n\n    /**\n     * is the year a leap_year\n     */\n    fn _is_leap_year(&self) -> bool{\n        if self.year % 4 != 0 {\n            return false;\n        } else if self.year %100 != 0 {\n            return true;\n        } else if self.year % 400 != 0 {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * calculates the day value, number of days the date represents\n     */\n    fn calc_days(&self) -> u32 {\n        return (self.year as f64 * 365.25)as u32 + self.month*30 + self.day + self.month/2;\n    }\n\n    /**\n     * calculates the time difference between self and the passed date,\n     */\n    fn time_since(&self, other: &DATE) -> Option<DATE> {\n        //DATA\n        // /*\n        let diff = self.calc_days()as i32 - other.calc_days()as i32;\n        if diff < 0 { \n            return None;\n        } else {\n            return Some(DATE::new_from_days(diff as u32));\n        }\n    }\n\n    /**\n     * formats the date in a different format, used for time table\n     */\n    fn format_ymd(&self, spacer:&str) -> String {\n        return format!(\n            \"{}{}{}{}{}\",\n            self.year, spacer,\n            self.month, spacer,\n            self.day,\n        );\n    }\n}\nimpl ToString for DATE {\n    fn to_string(&self) -> String {\n        return format!(\"{}/{}/{}\",self.month,self.day,self.year);\n    }\n}\n\nfn main() {\n    //DATA\n    let today_date: DATE;\n    let other_date:DATE;\n    let delta_date:DATE; //represents the difference between the two dates\n    let today_value;\n    let other_day_value;\n    let mut other_is_today = false;\n\n    //print welcome\n    welcome();\n    \n    //get todays date\n    today_date = DATE::new_from_input(\"ENTER TODAY'S DATE IN THE FORM: 3,24,1979  \");\n    //check todays date\n    if today_date.year < 1582 {\n        println!(\"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.\");\n        return;\n    }\n\n    println!();\n\n    //get other date\n    other_date = DATE::new_from_input(\"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) (like MM,DD,YYYY)\");\n    //check other date\n    if other_date.year < 1582 {\n        println!(\"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.\");\n        return;\n    }\n\n    //do some calculations\n    today_value = today_date.calc_days();\n    other_day_value = other_date.calc_days();\n\n    //print the other date in a nice format\n    println!(\n        \"{} {} A {}\",\n        other_date.to_string(),\n        { //use proper tense of To Be\n            if today_value < other_day_value {\"WILL BE\"}\n            else if today_value == other_day_value {other_is_today=true;\"IS\"}\n            else {\"WAS\"}\n        },\n        other_date.day_of_week_as_string(),\n    );\n\n    //end if both days are the same\n    if other_is_today {\n        return;\n    } \n\n    //create date representing the difference between the two dates\n    delta_date = today_date.time_since(&other_date).unwrap();\n\n    //print happy birthday message\n    if delta_date.month == 0 && delta_date.day == 0 {\n        println!(\"***HAPPY BIRTHDAY***\");\n    }\n\n    //print report\n    println!(\"\n                      \\tYEARS\\tMONTHS\\tDAYS\n                      \\t-----\\t------\\t----\"\n    );\n    println!(\"YOUR AGE (IF BIRTHDATE)\\t{}\", delta_date.format_ymd(\"\\t\"));\n    \n    //how much have they slept\n    println!(\n        \"YOU HAVE SLEPT\\t\\t{}\",\n        DATE::new_from_days( (0.35 * delta_date.calc_days() as f64) as u32).format_ymd(\"\\t\"), //35% of their life\n    );\n\n    //how much they have eaten\n    println!(\n        \"YOU HAVE EATEN\\t\\t{}\",\n        DATE::new_from_days( (0.17 * delta_date.calc_days() as f64) as u32).format_ymd(\"\\t\"), //17% of their life\n    );\n\n    //how much they have worked\n    println!(\n        \"YOU HAVE {}\\t{}\",\n        {\n            if delta_date.year <= 3 {\"PLAYED\"}\n            else if delta_date.year <= 9 {\"PLAYED/STUDIED\"}\n            else {\"WORKED/PLAYED\"}\n        },\n        DATE::new_from_days( (0.23 * delta_date.calc_days() as f64) as u32).format_ymd(\"\\t\"), //23% of their life\n    );\n    //how much they have relaxed\n    println!(\n        \"YOU HAVE RELAXED\\t{}\",\n        DATE::new_from_days( ( (1.0-0.35-0.17-0.23) * delta_date.calc_days() as f64) as u32).format_ymd(\"\\t\"), //remaining% of their life\n    );\n    //when they can retire\n    println!(\n        \"YOU MAY RETIRE IN\\t{}\",\n        DATE::new(other_date.month, other_date.day, other_date.year + 65, 0).time_since(&today_date).unwrap().format_ymd(\"\\t\")\n    );\n}\n\n\n/**\n * print welome message\n */\nfn welcome() {\n    println!(\"\n                               WEEKDAY\n              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n    \n    \n    \n    WEEKDAY IS A COMPUTER DEMONSTRATION THAT\n    GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\n    \");\n}\n\n/**\n * gets a string from user input\n */\nfn get_str_from_user(prompt:&str) -> String {\n    //DATA\n    let mut raw_input = String::new();\n\n    //print prompt\n    print!(\"{}\",prompt);\n    //flust std out //allows prompt to be on same line as input\n    stdout().flush().expect(\"failed to flush\");\n\n    //get input and trim whitespaces\n    io::stdin().read_line(&mut raw_input).expect(\"Failed to read input\");\n\n    //return raw input\n    return raw_input.trim().to_string();\n}\n"
  },
  {
    "path": "95_Weekday/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "95_Weekday/vbnet/Weekday.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.30114.105\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{F184B08F-C81C-45F6-A57F-5ABD9991F28F}\") = \"Weekday\", \"Weekday.vbproj\", \"{3BE031BE-D032-477A-A419-48FA7D3C2DD2}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "95_Weekday/vbnet/Weekday.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Weekday</RootNamespace>\n    <TargetFramework>net6.0</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "95_Weekday/weekday.bas",
    "content": "10 PRINT TAB(32);\"WEEKDAY\"\n20 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n30 PRINT:PRINT:PRINT\n100 PRINT \"WEEKDAY IS A COMPUTER DEMONSTRATION THAT\"\n110 PRINT\"GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\"\n120 PRINT\n130 PRINT \"ENTER TODAY'S DATE IN THE FORM: 3,24,1979  \";\n140 INPUT M1,D1,Y1\n150 REM THIS PROGRAM DETERMINES THE DAY OF THE WEEK\n160 REM  FOR A DATE AFTER 1582\n170 DEF FNA(A)=INT(A/4)\n180 DIM T(12)\n190 DEF FNB(A)=INT(A/7)\n200 REM SPACE OUTPUT AND READ IN INITIAL VALUES FOR MONTHS.\n210 FOR I= 1 TO 12\n220 READ T(I)\n230 NEXT I\n240 PRINT\"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)\";\n250 INPUT M,D,Y\n260 PRINT\n270 LET I1 = INT((Y-1500)/100)\n280 REM TEST FOR DATE BEFORE CURRENT CALENDAR.\n290 IF Y-1582 <0 THEN 1300\n300 LET A = I1*5+(I1+3)/4\n310 LET I2=INT(A-FNB(A)*7)\n320 LET Y2=INT(Y/100)\n330 LET Y3 =INT(Y-Y2*100)\n340 LET A =Y3/4+Y3+D+T(M)+I2\n350 LET B=INT(A-FNB(A)*7)+1\n360 IF M > 2 THEN 470\n370 IF Y3 = 0 THEN 440\n380 LET T1=INT(Y-FNA(Y)*4)\n390 IF T1 <> 0 THEN 470\n400 IF B<>0 THEN 420\n410 LET B=6\n420 LET B = B-1\n430 GOTO 470\n440 LET A = I1-1\n450 LET T1=INT(A-FNA(A)*4)\n460 IF T1 = 0 THEN 400\n470 IF B <>0 THEN 490\n480 LET B = 7\n490 IF (Y1*12+M1)*31+D1<(Y*12+M)*31+D THEN 550\n500 IF (Y1*12+M1)*31+D1=(Y*12+M)*31+D THEN 530\n510 PRINT M;\"/\";D;\"/\";Y;\" WAS A \";\n520 GOTO 570\n530 PRINT M;\"/\";D;\"/\";Y;\" IS A \";\n540 GOTO 570\n550 PRINT M;\"/\";D;\"/\";Y;\" WILL BE A \";\n560 REM PRINT THE DAY OF THE WEEK THE DATE FALLS ON.\n570 IF B <>1 THEN 590\n580 PRINT \"SUNDAY.\"\n590 IF B<>2 THEN 610\n600 PRINT \"MONDAY.\"\n610 IF B<>3 THEN 630\n620 PRINT \"TUESDAY.\"\n630 IF B<>4 THEN 650\n640 PRINT \"WEDNESDAY.\"\n650 IF B<>5 THEN 670\n660 PRINT \"THURSDAY.\"\n670 IF B<>6 THEN 690\n680 GOTO 1250\n690 IF B<>7 THEN 710\n700 PRINT \"SATURDAY.\"\n710 IF (Y1*12+M1)*31+D1=(Y*12+M)*31+D THEN 1120\n720 LET I5=Y1-Y\n730 PRINT\n740 LET I6=M1-M\n750 LET I7=D1-D\n760 IF I7>=0 THEN 790\n770 LET I6= I6-1\n780 LET I7=I7+30\n790 IF I6>=0 THEN 820\n800 LET I5=I5-1\n810 LET I6=I6+12\n820 IF I5<0 THEN 1310\n830 IF I7 <> 0 THEN 850\n835 IF I6 <> 0 THEN 850\n840 PRINT\"***HAPPY BIRTHDAY***\"\n850 PRINT \" \",\" \",\"YEARS\",\"MONTHS\",\"DAYS\"\n855 PRINT \" \",\" \",\"-----\",\"------\",\"----\"\n860 PRINT \"YOUR AGE (IF BIRTHDATE) \",I5,I6,I7\n870 LET A8 = (I5*365)+(I6*30)+I7+INT(I6/2)\n880 LET K5 = I5\n890 LET K6 = I6\n900 LET K7 = I7\n910 REM CALCULATE RETIREMENT DATE.\n920 LET E = Y+65\n930 REM CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS.\n940 LET F = .35\n950 PRINT \"YOU HAVE SLEPT \",\n960 GOSUB 1370\n970 LET F = .17\n980 PRINT \"YOU HAVE EATEN \",\n990 GOSUB 1370\n1000 LET F = .23\n1010 IF K5 > 3 THEN 1040\n1020 PRINT \"YOU HAVE PLAYED\",\n1030 GOTO 1080\n1040 IF K5 > 9 THEN 1070\n1050 PRINT \"YOU HAVE PLAYED/STUDIED\",\n1060 GOTO  1080\n1070 PRINT \"YOU HAVE WORKED/PLAYED\",\n1080 GOSUB 1370\n1085 GOTO 1530\n1090 PRINT \"YOU HAVE RELAXED \",K5,K6,K7\n1100 PRINT\n1110 PRINT TAB(16);\"***  YOU MAY RETIRE IN\";E;\" ***\"\n1120 PRINT\n1140 PRINT\n1200 PRINT\n1210 PRINT\n1220 PRINT\n1230 PRINT\n1240 END\n1250 IF D=13 THEN 1280\n1260 PRINT \"FRIDAY.\"\n1270 GOTO 710\n1280 PRINT \"FRIDAY THE THIRTEENTH---BEWARE!\"\n1290 GOTO 710\n1300 PRINT \"NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII. \"\n1310 GOTO 1140\n1320 REM TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS.\n1330 DATA 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5\n1340 REM THIS IS THE CURRENT DATE USED IN THE CALCULATIONS.\n1350 REM THIS IS THE DATE TO BE CALCULATED ON.\n1360 REM CALCULATE TIME IN YEARS, MONTHS, AND DAYS\n1370 LET K1=INT(F*A8)\n1380 LET I5 = INT(K1/365)\n1390 LET K1 = K1- (I5*365)\n1400 LET I6 = INT(K1/30)\n1410 LET I7 = K1 -(I6*30)\n1420 LET K5 = K5-I5\n1430 LET K6 =K6-I6\n1440 LET K7 = K7-I7\n1450 IF K7>=0 THEN 1480\n1460 LET K7=K7+30\n1470 LET K6=K6-1\n1480 IF K6>0 THEN 1510\n1490 LET K6=K6+12\n1500 LET K5=K5-1\n1510 PRINT I5,I6,I7\n1520 RETURN\n1530 IF K6=12 THEN 1550\n1540 GOTO 1090\n1550 LET K5=K5+1\n1560 LET K6=0\n1570 GOTO 1090\n1580 REM\n1590 END\n"
  },
  {
    "path": "96_Word/README.md",
    "content": "### Word\n\nWORD is a combination of HANGMAN and BAGELS. In this game, the player must guess a word with clues as to a letter position furnished by the computer. However, instead of guessing one letter at a time, in WORD you guess an entire word (or group of 5 letters, such as ABCDE). The computer will tell you if any letters that you have guessed are in the mystery word and if any of them are in the correct position. Armed with these clues, you go on guessing until you get the word or, if you can’t get it, input a “?” and the computer will tell you the mystery word.\n\nYou may change the words in Data Statements, but they must be 5-letter words.\n\nThe author of this program is Charles Reid of Lexington High School, Lexington, Massachusetts.\n\n---\n\nAs published in Basic Computer Games (1978):\n- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=181)\n- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=194)\n\nDownloaded from Vintage Basic at\nhttp://www.vintage-basic.net/games.html\n\n#### Porting Notes\n\n(please note any difficulties or challenges in porting here)\n"
  },
  {
    "path": "96_Word/csharp/Program.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Text;\n\nnamespace word\n{\n    class Word\n    {\n        // Here's the list of potential words that could be selected\n        // as the winning word.\n        private string[] words = { \"DINKY\", \"SMOKE\", \"WATER\", \"GRASS\", \"TRAIN\", \"MIGHT\", \"FIRST\",\n         \"CANDY\", \"CHAMP\", \"WOULD\", \"CLUMP\", \"DOPEY\" };\n\n        /// <summary>\n        /// Outputs the instructions of the game.\n        /// </summary>\n        private void intro()\n        {\n            Console.WriteLine(\"WORD\".PadLeft(37));\n            Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".PadLeft(59));\n\n            Console.WriteLine(\"I am thinking of a word -- you guess it. I will give you\");\n            Console.WriteLine(\"clues to help you get it. Good luck!!\");\n        }\n\n        /// <summary>\n        /// This allows the user to enter a guess - doing some basic validation\n        /// on those guesses.\n        /// </summary>\n        /// <returns>The guess entered by the user</returns>\n        private string get_guess()\n        {\n            string guess = \"\";\n\n            while (guess.Length == 0)\n            {\n                Console.WriteLine($\"{Environment.NewLine}Guess a five letter word. \");\n                guess = Console.ReadLine().ToUpper();\n\n                if ((guess.Length != 5) || (guess.Equals(\"?\")) || (!guess.All(char.IsLetter)))\n                {\n                    guess = \"\";\n                    Console.WriteLine(\"You must guess a five letter word. Start again.\");\n                }\n            }\n\n            return guess;\n        }\n\n        /// <summary>\n        /// This checks the user's guess against the target word - capturing\n        /// any letters that match up between the two as well as the specific\n        /// letters that are correct.\n        /// </summary>\n        /// <param name=\"guess\">The user's guess</param>\n        /// <param name=\"target\">The 'winning' word</param>\n        /// <param name=\"progress\">A string showing which specific letters have already been guessed</param>\n        /// <returns>The integer value showing the number of character matches between guess and target</returns>\n        private int check_guess(string guess, string target, StringBuilder progress)\n        {\n            // Go through each letter of the guess and see which\n            // letters match up to the target word.\n            // For each position that matches, update the progress\n            // to reflect the guess\n            int matches = 0;\n            string common_letters = \"\";\n\n            for (int ctr = 0; ctr < 5; ctr++)\n            {\n                // First see if this letter appears anywhere in the target\n                // and, if so, add it to the common_letters list.\n                if (target.Contains(guess[ctr]))\n                {\n                    common_letters.Append(guess[ctr]);\n                }\n                // Then see if this specific letter matches the\n                // same position in the target. And, if so, update\n                // the progress tracker\n                if (guess[ctr].Equals(target[ctr]))\n                {\n                    progress[ctr] = guess[ctr];\n                    matches++;\n                }\n            }\n\n            Console.WriteLine($\"There were {matches} matches and the common letters were... {common_letters}\");\n            Console.WriteLine($\"From the exact letter matches, you know......... {progress}\");\n            return matches;\n        }\n\n        /// <summary>\n        /// This plays one full game.\n        /// </summary>\n        private void play_game()\n        {\n            string guess_word, target_word;\n            StringBuilder guess_progress = new StringBuilder(\"-----\");\n            Random rand = new Random();\n            int count = 0;\n\n            Console.WriteLine(\"You are starting a new game...\");\n\n            // Randomly select a word from the list of words\n            target_word = words[rand.Next(words.Length)];\n\n            // Just run as an infinite loop until one of the\n            // endgame conditions are met.\n            while (true)\n            {\n                // Ask the user for their guess\n                guess_word = get_guess();\n                count++;\n\n                // If they enter a question mark, then tell them\n                // the answer and quit the game\n                if (guess_word.Equals(\"?\"))\n                {\n                    Console.WriteLine($\"The secret word is {target_word}\");\n                    return;\n                }\n\n                // Otherwise, check the guess against the target - noting progress\n                if (check_guess(guess_word, target_word, guess_progress) == 0)\n                {\n                    Console.WriteLine(\"If you give up, type '?' for your next guess.\");\n                }\n\n                // Once they've guess the word, end the game.\n                if (guess_progress.Equals(guess_word))\n                {\n                    Console.WriteLine($\"You have guessed the word.  It took {count} guesses!\");\n                    return;\n                }\n            }\n        }\n\n        /// <summary>\n        /// The main entry point for the class - just keeps\n        /// playing the game until the user decides to quit.\n        /// </summary>\n        public void play()\n        {\n            intro();\n\n            bool keep_playing = true;\n\n            while (keep_playing)\n            {\n                play_game();\n                Console.WriteLine($\"{Environment.NewLine}Want to play again? \");\n                keep_playing = Console.ReadLine().StartsWith(\"y\", StringComparison.CurrentCultureIgnoreCase);\n            }\n        }\n    }\n\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            new Word().play();\n        }\n    }\n}\n"
  },
  {
    "path": "96_Word/csharp/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)\n"
  },
  {
    "path": "96_Word/csharp/word.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "96_Word/csharp/word.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.32014.148\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Word\", \"Word.csproj\", \"{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {B4D37881-6972-406B-978F-C1B60BA42638}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "96_Word/d/.gitignore",
    "content": "*.exe\n*.obj\n"
  },
  {
    "path": "96_Word/d/README.md",
    "content": "Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConverted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).\n\nThe Basic original required words to be exactly five letters in length for the program to behave correctly.\nThis version does not replicate that limitation, and the test for that requirement is commented out.\n\n## Running the code\n\nAssuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:\n```shell\ndmd -dip1000 -run word.d\n```\n\n[Other compilers](https://dlang.org/download.html) also exist.\n"
  },
  {
    "path": "96_Word/d/word.d",
    "content": "@safe: // Make @safe the default for this file, enforcing memory-safety.\nimport std;\n\nvoid main()\n{\n    enum width = 80;\n    writeln(center(\"Word\", width));\n    writeln(center(\"(After Creative Computing  Morristown, New Jersey)\\n\\n\\n\", width));\n    writeln(wrap(\"I am thinking of a word -- you guess it.  I will give you \" ~\n                 \"clues to help you get it.  Good luck!!\\n\\n\", width));\n\n    string[] words = [\"dinky\", \"smoke\", \"water\", \"grass\", \"train\", \"might\", \"first\",\n                      \"candy\", \"champ\", \"would\", \"clump\", \"dopey\"];\n\n    playLoop: while (true)\n    {\n        writeln(\"\\n\\nYou are starting a new game...\");\n\n        string word = words[uniform(0, $-1)];  // $ is a short-hand for words.length.\n        int guesses = 0;\n        string knownLetters = '-'.repeat(word.length).array;\n\n        while (true)\n        {\n            writeln(\"Guess a \", word.length, \" letter word\");\n            string guess = readString.toLower;\n            if (guess == \"?\")\n            {\n                writeln(\"The secret word is \", word, \"\\n\");\n                continue playLoop;  // Start a new game.\n            }\n            /* Uncomment this for equivalence with Basic.\n            if (guess.length != 5)\n            {\n                writeln(\"You must guess a 5 letter word.  Start again.\");\n                continue;           // Ask for new guess.\n            }\n            */\n            guesses++;\n            if (guess == word)\n                break;  // Done guessing\n            string commonLetters;\n            foreach (i, wordLetter; word)\n                foreach (j, guessLetter; guess)\n                    if (guessLetter == wordLetter)\n                    {\n                        commonLetters ~= guessLetter;\n                        if (i == j)\n                            knownLetters.replaceInPlace(i, i + 1, [guessLetter]);\n                    }\n            writeln(\"There were \", commonLetters.length, \" matches and the common letters were... \", commonLetters);\n            writeln(\"From the exact letter matches, you know................ \", knownLetters);\n            if (knownLetters == word)\n                break;  // Done guessing\n            if (commonLetters.length < 2)\n                writeln(\"If you give up, type '?' for your next guess.\");\n            writeln;\n        }\n\n        writeln(\"You have guessed the word.  It took \", guesses, \" guesses!\");\n        write(\"\\n\\nWant to play again? \");\n        if (readString.toLower != \"yes\")\n            break;  // Terminate playLoop\n    }\n}\n\n/// Read a string from standard input, stripping newline and other enclosing whitespace.\nstring readString() nothrow\n{\n    try\n        return trustedReadln.strip;\n    catch (Exception)   // readln throws on I/O and Unicode errors, which we handle here.\n        return \"\";\n}\n\n/** An @trusted wrapper around readln.\n *\n * This is the only function that formally requires manual review for memory-safety.\n * [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)\n * which would remove the need to have any @trusted code in this program.\n */\nstring trustedReadln() @trusted\n{\n    return readln;\n}\n"
  },
  {
    "path": "96_Word/java/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Oracle Java](https://openjdk.java.net/)\n"
  },
  {
    "path": "96_Word/java/Word.java",
    "content": "import java.util.Arrays;\nimport java.util.Scanner;\n\n/**\n * Game of Word\n * <p>\n * Based on the BASIC game of Word here\n * https://github.com/coding-horror/basic-computer-games/blob/main/96%20Word/word.bas\n * <p>\n * Note:  The idea was to create a version of the 1970's BASIC game in Java, without introducing\n * new features - no additional text, error checking, etc has been added.\n *\n * Converted from BASIC to Java by Darren Cardenas.\n */\n\npublic class Word {\n\n  private final static String[] WORDS = {\n\n  \"DINKY\", \"SMOKE\", \"WATER\", \"GRASS\", \"TRAIN\", \"MIGHT\",\n  \"FIRST\", \"CANDY\", \"CHAMP\", \"WOULD\", \"CLUMP\", \"DOPEY\"\n\n  };\n\n  private final Scanner scan;  // For user input\n\n  private enum Step {\n    INITIALIZE, MAKE_GUESS, USER_WINS\n  }\n\n  public Word() {\n\n    scan = new Scanner(System.in);\n\n  }  // End of constructor Word\n\n  public void play() {\n\n    showIntro();\n    startGame();\n\n  }  // End of method play\n\n  private void showIntro() {\n\n    System.out.println(\" \".repeat(32) + \"WORD\");\n    System.out.println(\" \".repeat(14) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\");\n    System.out.println(\"\\n\\n\");\n\n    System.out.println(\"I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\");\n    System.out.println(\"CLUES TO HELP YOU GET IT.  GOOD LUCK!!\");\n    System.out.println(\"\\n\");\n\n  }  // End of method showIntro\n\n  private void startGame() {\n\n    char[] commonLetters = new char[8];\n    char[] exactLetters = new char[8];\n\n    int commonIndex = 0;\n    int ii = 0;  // Loop iterator\n    int jj = 0;  // Loop iterator\n    int numGuesses = 0;\n    int numMatches = 0;\n    int wordIndex = 0;\n\n    Step nextStep = Step.INITIALIZE;\n\n    String commonString = \"\";\n    String exactString = \"\";\n    String guessWord = \"\";\n    String secretWord = \"\";\n    String userResponse = \"\";\n\n    // Begin outer while loop\n    while (true) {\n\n      switch (nextStep) {\n\n        case INITIALIZE:\n\n          System.out.println(\"\\n\");\n          System.out.println(\"YOU ARE STARTING A NEW GAME...\");\n\n          // Select a secret word from the list\n          wordIndex = (int) (Math.random() * WORDS.length);\n          secretWord = WORDS[wordIndex];\n\n          numGuesses = 0;\n\n          Arrays.fill(exactLetters, 1, 6, '-');\n          Arrays.fill(commonLetters, 1, 6, '\\0');\n\n          nextStep = Step.MAKE_GUESS;\n          break;\n\n        case MAKE_GUESS:\n\n          System.out.print(\"GUESS A FIVE LETTER WORD? \");\n          guessWord = scan.nextLine().toUpperCase();\n\n          numGuesses++;\n\n          // Win condition\n          if (guessWord.equals(secretWord)) {\n            nextStep = Step.USER_WINS;\n            continue;\n          }\n\n          Arrays.fill(commonLetters, 1, 8, '\\0');\n\n          // Surrender condition\n          if (guessWord.equals(\"?\")) {\n            System.out.println(\"THE SECRET WORD IS \" + secretWord);\n            System.out.println(\"\");\n            nextStep = Step.INITIALIZE;  // Play again\n            continue;\n          }\n\n          // Check for valid input\n          if (guessWord.length() != 5) {\n            System.out.println(\"YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\");\n            numGuesses--;\n            nextStep = Step.MAKE_GUESS;  // Guess again\n            continue;\n          }\n\n          numMatches = 0;\n          commonIndex = 1;\n\n          for (ii = 1; ii <= 5; ii++) {\n\n            for (jj = 1; jj <= 5; jj++) {\n\n              if (secretWord.charAt(ii - 1) != guessWord.charAt(jj - 1)) {\n                continue;\n              }\n\n              // Avoid out of bounds errors\n              if (commonIndex <= 5) {\n                commonLetters[commonIndex] = guessWord.charAt(jj - 1);\n                commonIndex++;\n              }\n\n              if (ii == jj) {\n                exactLetters[jj] = guessWord.charAt(jj - 1);\n              }\n\n              // Avoid out of bounds errors\n              if (numMatches < 5) {\n                numMatches++;\n              }\n            }\n          }\n\n          exactString = \"\";\n          commonString = \"\";\n\n          // Build the exact letters string\n          for (ii = 1; ii <= 5; ii++) {\n            exactString += exactLetters[ii];\n          }\n\n          // Build the common letters string\n          for (ii = 1; ii <= numMatches; ii++) {\n            commonString += commonLetters[ii];\n          }\n\n          System.out.println(\"THERE WERE \" + numMatches + \" MATCHES AND THE COMMON LETTERS WERE...\"\n                             + commonString);\n\n          System.out.println(\"FROM THE EXACT LETTER MATCHES, YOU KNOW................\" + exactString);\n\n          // Win condition\n          if (exactString.equals(secretWord)) {\n            nextStep = Step.USER_WINS;\n            continue;\n          }\n\n          // No matches\n          if (numMatches <= 1) {\n            System.out.println(\"\");\n            System.out.println(\"IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\");\n          }\n\n          System.out.println(\"\");\n          nextStep = Step.MAKE_GUESS;\n          break;\n\n        case USER_WINS:\n\n          System.out.println(\"YOU HAVE GUESSED THE WORD.  IT TOOK \" + numGuesses + \" GUESSES!\");\n          System.out.println(\"\");\n\n          System.out.print(\"WANT TO PLAY AGAIN? \");\n          userResponse = scan.nextLine();\n\n          if (userResponse.toUpperCase().equals(\"YES\")) {\n            nextStep = Step.INITIALIZE;  // Play again\n          } else {\n            return;  // Quit game\n          }\n          break;\n\n        default:\n          System.out.println(\"INVALID STEP\");\n          break;\n\n      }\n\n    }  // End outer while loop\n\n  }  // End of method startGame\n\n  public static void main(String[] args) {\n\n    Word word = new Word();\n    word.play();\n\n  }  // End of method main\n\n}  // End of class Word\n"
  },
  {
    "path": "96_Word/javascript/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)\n"
  },
  {
    "path": "96_Word/javascript/word.mjs",
    "content": "#!/usr/bin/env node\n// WORD\n//\n// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)\n\nimport { print, tab, input } from '../../00_Common/javascript/common.mjs';\n\n// These are the words that the game knows about> If you want a bigger challenge you could add more words to the array\nconst WORDS = [\"DINKY\", \"SMOKE\", \"WATER\", \"GLASS\", \"TRAIN\",\n             \"MIGHT\", \"FIRST\", \"CANDY\", \"CHAMP\", \"WOULD\",\n             \"CLUMP\", \"DOPEY\"];\nconst WORD_COUNT = WORDS.length;\n\n// Main control section\nasync function main()\n{\n    print(tab(33) + \"WORD\\n\");\n    print(tab(15) + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    print(\"I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\\n\");\n    print(\"CLUES TO HELP YOU GET IT.  GOOD LUCK!!\\n\");\n    print(\"\\n\");\n    print(\"\\n\");\n    outer: while (1) {\n        print(\"\\n\");\n        print(\"\\n\");\n        print(\"YOU ARE STARTING A NEW GAME...\\n\");\n\n        const secretWord = WORDS[Math.floor(Math.random() * WORD_COUNT)];\n\n        let guessCount = 0;\n        // This array holds the letters which have been found in the correct position across all guesses\n        // For instance if the word is \"PLAIN\" and the guesses so far are\n        // \"SHALL\" (\"A\" correct) and \"CLIMB\" (\"L\" correct) then it will hold \"-LA--\"\n        const knownLetters = [];\n        for (let i = 0; i < 5; i++)\n            knownLetters[i] = \"-\";\n\n        let guess = undefined;\n        while (1) {\n            print(\"GUESS A FIVE LETTER WORD:\");\n            guess = (await input()).toUpperCase();\n            guessCount++;\n            if (secretWord === guess) {\n                // The player has guessed correctly\n                break;\n            }\n\n            if (guess.charAt(0) === \"?\") {\n                // Player has given up\n                print(\"THE SECRET WORD IS \" + secretWord + \"\\n\");\n                print(\"\\n\");\n                // Start a new game by going to the start of the outer while loop\n                continue outer;\n            }\n\n            if (guess.length !== 5) {\n                print(\"YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\\n\");\n                print(\"\\n\");\n                guessCount--;\n                continue;\n            }\n\n            // Two things happen in this double loop:\n            // 1. Letters which are in both the guessed and secret words are put in the lettersInCommon array\n            // 2. Letters which are in the correct position in the guessed word are added to the knownLetters array\n            let lettersInCommonCount = 0;\n            const lettersInCommon = [];\n            for (let i = 0; i < 5; i++) {// loop round characters in secret word\n                let secretWordCharacter = secretWord.charAt(i);\n                for (let j = 0; j < 5; j++) {// loop round characters in guessed word\n                    let guessedWordCharacter = guess.charAt(j);\n                    if (secretWordCharacter === guessedWordCharacter) {\n                        lettersInCommon[lettersInCommonCount] = guessedWordCharacter;\n                        if (i === j) {\n                            // Letter is in the exact position so add to the known letters array\n                            knownLetters[j] = guessedWordCharacter;\n                        }\n                        lettersInCommonCount++;\n                    }\n                }\n            }\n\n            const lettersInCommonText = lettersInCommon.join(\"\");\n            print(\"THERE WERE \" + lettersInCommonCount + \" MATCHES AND THE COMMON LETTERS WERE... \" + lettersInCommonText + \"\\n\");\n\n            const knownLettersText = knownLetters.join(\"\");\n            print(\"FROM THE EXACT LETTER MATCHES, YOU KNOW............ \" + knownLettersText + \"\\n\");\n\n            if (knownLettersText === secretWord) {\n                guess = knownLettersText;\n                break;\n            }\n\n            if (lettersInCommonCount <= 1) {\n                print(\"\\n\");\n                print(\"IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\\n\");\n                print(\"\\n\");\n            }\n        }\n\n        print(\"YOU HAVE GUESSED THE WORD.  IT TOOK \" + guessCount + \" GUESSES!\\n\");\n        print(\"\\n\");\n\n        print(\"WANT TO PLAY AGAIN\");\n        const playAgainResponse = (await input()).toUpperCase();\n        if (playAgainResponse !== \"YES\")\n            break;\n    }\n}\n\nmain();\n"
  },
  {
    "path": "96_Word/kotlin/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Kotlin](https://kotlinlang.org/)\n"
  },
  {
    "path": "96_Word/lua/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Lua](https://www.lua.org/)\n"
  },
  {
    "path": "96_Word/perl/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Perl](https://www.perl.org/)\n"
  },
  {
    "path": "96_Word/perl/word.pl",
    "content": "#!/usr/bin/env perl\n\nuse 5.010;      # To get 'state' and 'say'\n\nuse strict;     # Require explicit declaration of variables\nuse warnings;   # Enable optional compiler warnings\n\nuse English;    # Use more friendly names for Perl's magic variables\nuse Term::ReadLine;     # Prompt and return user input\n\nour $VERSION = '0.000_01';\n\nprint <<'EOD';\n                                 WORD\n               Creative Computing  Morristown, New Jersey\n\n\n\nI am thinking of a word -- you guess it.  I will give you\nclues to help you get it.  Good luck!!\n\n\nEOD\n\n# Read the content of __DATA__, remove the trailing newlines, and store\n# each line into @words. Stop at __END__, since Perl does not see this\n# as an end-of-file.\nmy @words;\nwhile ( <DATA> ) {\n    chomp;\n    last if $ARG eq '__END__';\n    push @words, lc $ARG;   # Normalize case to lower.\n}\n\n# This loop represents an actual game. We execute it until the player\n# does something that makes us explicitly break out.\nwhile ( 1 ) {\n    print <<'EOD';\n\n\nYou are starting a new game ...\nEOD\n\n    # Choose a random target word. The rand() function returns a number\n    # from 0 to its argument, and coerces its argument to a scalar. In\n    # scalar context, an array evaluates to the number of elements it\n    # contains.\n    my $target = $words[ rand @words ];\n\n    # We generalize the code by using the actual length of the target.\n    my $target_length = length $target;\n\n    my $count = 0;      # Number of guesses\n\n    # Make an array of the individual letters in the target. We will\n    # iterate over this to determine matching letters.\n    my @target_array = split qr<>, $target;\n\n    # Make a hash of those letters. We will use this to determine common\n    # letters. Any true value will do for the value of the hash. By\n    # making use of this hash we avoid the nested loops of the original\n    # BASIC program.\n    my %target_hash = map { $ARG => 1 } @target_array;\n\n    # We keep prompting the player until we get a response that causes\n    # us to break out of the loop.\n    while ( 1 ) {\n\n        # Create the readline object. The state keyword means the\n        # variable is only initialized once, no matter how many times\n        # execution passes this point.\n        state $term = Term::ReadLine->new( 'word' );\n\n        # Read the next guess. A return of undef means end-of-file.\n        my $guess = $term->readline( \"Guess a $target_length letter word: \" );\n        exit unless defined $guess;\n\n        last if $guess eq '?';  # A question mark means we give up\n        if ( length( $guess ) != $target_length ) {\n            # Wrong length. Ask again.\n            say \"You must guess a $target_length letter word.  Try again.\";\n            redo;       # Redo the innermost loop\n        }\n\n        $guess = lc $guess;     # Lower-case the guess\n        $count++;       # Count another guess\n\n        if ( $guess eq $target ) {\n            # We guessed the word.\n            say \"You have guessed the word. It took $count guesses!\";\n            my $answer = $term->readline( 'Want to play again? [y/N]: ');\n            exit unless defined $guess; # End of file\n            exit unless $guess =~ m/ \\A y /smxi;\n            last;       # Exit the innermost loop.\n        }\n\n        my @common_letters; # Letters common to guess and target\n        my $match = '-' x length $target;   # Assume no matches\n        my $inx = 0;    # Iterator\n        foreach my $letter ( split qr<>, $guess ) {\n            if ( $target_hash{$letter} ) {\n                # If the letter is in the hash, it occurs in the target\n                push @common_letters, $letter;\n                # If it is at the current position in the target, it is\n                # an actual match.\n                $target_array[$inx] eq $letter\n                    and substr $match, $inx, 1, $letter;\n            }\n            $inx++;\n        }\n\n        say 'There were ', scalar @common_letters,\n            ' matches and the common letters were... ', @common_letters;\n        say \"From the exact letter matches, you know................ $match\";\n        say '';\n        say q<If you give up, type '?' for your next guess.>;\n        redo;\n    }\n\n}\n__DATA__\ndinky\nsmoke\nwater\ngrass\ntrain\nmight\nfirst\ncandy\nchamp\nwould\nclump\ndopey\n__END__\n\n=head1 TITLE\n\nword.pl - Play the game 'word' from Basic Computer Games\n\n=head1 SYNOPSIS\n\n word.pl\n\n=head1 DETAILS\n\nThis Perl script is a port of C<word>, which is the 96th entry in Basic\nComputer Games.\n\n=head1 PORTED BY\n\nThomas R. Wyant, III F<wyant at cpan dot org>\n\n=head1 COPYRIGHT AND LICENSE\n\nCopyright (C) 2022 by Thomas R. Wyant, III\n\nThis program is free software; you can redistribute it and/or modify it\nunder the same terms as Perl 5.10.0. For more details, see the Artistic\nLicense 1.0 at\nL<https://www.perlfoundation.org/artistic-license-10.html>, and/or the\nGnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.\n\nThis program is distributed in the hope that it will be useful, but\nwithout any warranty; without even the implied warranty of\nmerchantability or fitness for a particular purpose.\n\n=cut\n\n# ex: set expandtab tabstop=4 textwidth=72 :\n"
  },
  {
    "path": "96_Word/python/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Python](https://www.python.org/about/)\n"
  },
  {
    "path": "96_Word/python/word.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nWORD\n\nConverted from BASIC to Python by Trevor Hobson\n\"\"\"\n\nimport random\n\nwords = [\n    \"DINKY\",\n    \"SMOKE\",\n    \"WATER\",\n    \"GRASS\",\n    \"TRAIN\",\n    \"MIGHT\",\n    \"FIRST\",\n    \"CANDY\",\n    \"CHAMP\",\n    \"WOULD\",\n    \"CLUMP\",\n    \"DOPEY\",\n]\n\n\ndef play_game() -> None:\n    \"\"\"Play one round of the game\"\"\"\n\n    random.shuffle(words)\n    target_word = words[0]\n    guess_count = 0\n    guess_progress = [\"-\"] * 5\n\n    print(\"You are starting a new game...\")\n    while True:\n        guess_word = \"\"\n        while not guess_word:\n            guess_word = input(\"\\nGuess a five letter word. \").upper()\n            if guess_word == \"?\":\n                break\n            elif not guess_word.isalpha() or len(guess_word) != 5:\n                guess_word = \"\"\n                print(\"You must guess a five letter word. Start again.\")\n        guess_count += 1\n        if guess_word == \"?\":\n            print(\"The secret word is\", target_word)\n            break\n        else:\n            common_letters = \"\"\n            matches = 0\n            for i in range(5):\n                for j in range(5):\n                    if guess_word[i] == target_word[j]:\n                        matches += 1\n                        common_letters = common_letters + guess_word[i]\n                        if i == j:\n                            guess_progress[j] = guess_word[i]\n            print(\n                f\"There were {matches}\",\n                f\"matches and the common letters were... {common_letters}\",\n            )\n            print(\n                \"From the exact letter matches, you know............ \"\n                + \"\".join(guess_progress)\n            )\n            if \"\".join(guess_progress) == guess_word:\n                print(f\"\\nYou have guessed the word. It took {guess_count} guesses!\")\n                break\n            elif matches == 0:\n                print(\"\\nIf you give up, type '?' for you next guess.\")\n\n\ndef main() -> None:\n    print(\" \" * 33 + \"WORD\")\n    print(\" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\")\n\n    print(\"I am thinking of a word -- you guess it. I will give you\")\n    print(\"clues to help you get it. Good luck!!\\n\")\n\n    keep_playing = True\n    while keep_playing:\n        play_game()\n        keep_playing = input(\"\\nWant to play again? \").lower().startswith(\"y\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "96_Word/ruby/README.md",
    "content": "Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Ruby](https://www.ruby-lang.org/en/)\n"
  },
  {
    "path": "96_Word/ruby/word.rb",
    "content": "#!/usr/bin/env ruby\n# WORD\n#\n# Converted from BASIC to Ruby\n\n\nWORDS = [\"DINKY\", \"SMOKE\", \"WATER\", \"GRASS\", \"TRAIN\", \"MIGHT\",\n         \"FIRST\",\"CANDY\", \"CHAMP\", \"WOULD\", \"CLUMP\", \"DOPEY\"]\n\ndef game_loop\n  target_word = WORDS.sample.downcase\n  guess_count = 0\n  guess_progress = [\"-\"] * 5\n\n  puts \"You are starting a new game...\"\n  while true\n    guess_word = \"\"\n    while guess_word == \"\"\n      puts \"Guess a five letter word. \"\n      guess_word = gets.chomp\n      if guess_word == \"?\"\n        break\n      elsif !guess_word.match(/^[[:alpha:]]+$/) || guess_word.length != 5\n        guess_word = \"\"\n        puts \"You must guess a five letter word. Start again.\"\n      end\n    end\n    guess_count += 1\n    if guess_word == \"?\"\n      puts \"The secret word is #{target_word}\"\n      break\n    else\n      common_letters = \"\"\n      matches = 0\n      5.times do |i|\n        5.times do |j|\n          if guess_word[i] == target_word[j]\n            matches += 1\n            common_letters = common_letters + guess_word[i]\n            guess_progress[j] = guess_word[i] if i == j\n          end\n        end\n      end\n      puts \"There were #{matches} matches and the common letters were... #{common_letters}\"\n      puts \"From the exact letter matches, you know............ #{guess_progress.join}\"\n      if guess_progress.join == guess_word\n        puts \"You have guessed the word. It took #{guess_count} guesses!\"\n        break\n      elsif matches < 2\n        puts \"If you give up, type '?' for you next guess.\"\n      end\n    end\n  end\nend\n\nputs \" \" * 33 + \"WORD\"\nputs \" \" * 15 + \"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\\n\"\nputs \"I am thinking of a word -- you guess it. I will give you\"\nputs \"clues to help you get it. Good luck!!\\n\"\n\nkeep_playing = true\nwhile keep_playing\n  game_loop\n  puts \"\\n Want to play again? \"\n  keep_playing = gets.chomp.downcase.index(\"y\") == 0\nend\n"
  },
  {
    "path": "96_Word/rust/Cargo.toml",
    "content": "[package]\nname = \"rust\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nrand = \"0.8.5\"\n"
  },
  {
    "path": "96_Word/rust/src/main.rs",
    "content": "use crate::word_game::WordGame;\nuse std::io;\nmod progress;\nmod word_game;\n\nfn main() {\n    println!(\"\\n\\n~~WORD~~\");\n    println!(\"Creative Computing Morristown, New Jersey\");\n\n    println!(\"\\nI am thinking of a word -- you guess it.\");\n    println!(\"I will give you clues to help you get it.\");\n    println!(\"Good luck!!\\n\");\n\n    let mut quit = false;\n\n    while quit == false {\n        let mut game = WordGame::new();\n        let mut game_over = false;\n\n        while game_over == false {\n            game_over = game.tick();\n        }\n\n        quit = !play_again();\n    }\n}\n\nfn play_again() -> bool {\n    let mut again = true;\n    let mut valid_response = false;\n\n    while valid_response == false {\n        println!(\"Want to play again? (Y/n)\");\n\n        let mut response = String::new();\n\n        io::stdin()\n            .read_line(&mut response)\n            .expect(\"Failed to read line.\");\n\n        match response.trim().to_uppercase().as_str() {\n            \"Y\" | \"YES\" => valid_response = true,\n            \"N\" | \"NO\" => {\n                again = false;\n                valid_response = true;\n            }\n            _ => (),\n        }\n    }\n\n    again\n}\n"
  },
  {
    "path": "96_Word/rust/src/progress.rs",
    "content": "pub struct Progress {\n    chars: [char; 5],\n}\n\nimpl Progress {\n    pub fn new() -> Self {\n        Progress { chars: ['-'; 5] }\n    }\n\n    pub fn set_char_at(&mut self, c: char, i: usize) {\n        self.chars[i] = c;\n    }\n\n    pub fn print(&self) {\n        for c in self.chars {\n            print!(\"{}\", c);\n        }\n    }\n\n    pub fn done(&self) -> bool {\n        for c in self.chars {\n            if c == '-' {\n                return false;\n            }\n        }\n\n        true\n    }\n}\n"
  },
  {
    "path": "96_Word/rust/src/word_game.rs",
    "content": "use crate::progress::Progress;\nuse rand::Rng;\nuse std::io;\n\npub struct WordGame<'a> {\n    word: &'a str,\n    progress: Progress,\n    guess: String,\n    guesses: usize,\n}\n\nimpl WordGame<'_> {\n    pub fn new() -> Self {\n        const WORDS: [&str; 12] = [\n            \"DINKY\", \"SMOKE\", \"WATER\", \"GRASS\", \"TRAIN\", \"MIGHT\", \"FIRST\", \"CANDY\", \"CHAMP\",\n            \"WOULD\", \"CLUMP\", \"DOPEY\",\n        ];\n\n        println!(\"\\nYou are starting a new game...\");\n\n        let random_index: usize = rand::thread_rng().gen_range(0..WORDS.len());\n\n        //println!(\"word is: {}\", WORDS[random_index]);\n\n        WordGame {\n            word: WORDS[random_index],\n            progress: Progress::new(),\n            guess: String::new(),\n            guesses: 0,\n        }\n    }\n\n    pub fn tick(&mut self) -> bool {\n        self.guesses += 1;\n\n        println!(\"\\n\\nGuess a five letter word?\");\n\n        let mut game_over = false;\n\n        if WordGame::<'_>::read_guess(self) {\n            game_over = WordGame::<'_>::process_guess(self);\n        }\n\n        game_over\n    }\n\n    fn read_guess(&mut self) -> bool {\n        let mut guess = String::new();\n\n        io::stdin()\n            .read_line(&mut guess)\n            .expect(\"Failed to read line.\");\n\n        let invalid_input = |message: &str| {\n            println!(\"\\n{} Guess again.\", message);\n            return false;\n        };\n\n        let guess = guess.trim();\n\n        for c in guess.chars() {\n            if c.is_numeric() {\n                return invalid_input(\"Your guess cannot include numbers.\");\n            }\n            if !c.is_ascii_alphabetic() {\n                return invalid_input(\"Your guess must only include ASCII characters.\");\n            }\n        }\n\n        if guess.len() != 5 {\n            return invalid_input(\"You must guess a 5 letter word.\");\n        }\n\n        self.guess = guess.to_string();\n\n        true\n    }\n\n    fn process_guess<'a>(&mut self) -> bool {\n        let guess = self.guess.to_uppercase();\n\n        let mut matches: Vec<char> = Vec::new();\n\n        for (i, c) in guess.chars().enumerate() {\n            if self.word.contains(c) {\n                matches.push(c);\n\n                if self.word.chars().nth(i).unwrap() == c {\n                    self.progress.set_char_at(c, i);\n                }\n            }\n        }\n\n        println!(\n            \"There were {} matches and the common letters were....{}\",\n            matches.len(),\n            matches.into_iter().collect::<String>()\n        );\n\n        print!(\"From the exact letter matches you know....\");\n        self.progress.print();\n\n        if self.progress.done() {\n            println!(\n                \"\\n\\nYou have guessed the word. It took {} guesses!\\n\",\n                self.guesses\n            );\n            return true;\n        }\n\n        false\n    }\n}\n"
  },
  {
    "path": "96_Word/vbnet/Program.vb",
    "content": "Imports System\nImports System.Text\nImports System.Text.RegularExpressions\n\nModule Word\n    ' Here's the list of potential words that could be selected\n    ' as the winning word.\n    Dim words As String() = {\"DINKY\", \"SMOKE\", \"WATER\", \"GRASS\", \"TRAIN\", \"MIGHT\", \"FIRST\",\n         \"CANDY\", \"CHAMP\", \"WOULD\", \"CLUMP\", \"DOPEY\"}\n\n    ' <summary>\n    ' Outputs the instructions of the game.\n    ' </summary>\n    Private Sub intro()\n        Console.WriteLine(\"WORD\".PadLeft(37))\n        Console.WriteLine(\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\".PadLeft(59))\n\n        Console.WriteLine(\"I am thinking of a word -- you guess it. I will give you\")\n        Console.WriteLine(\"clues to help you get it. Good luck!!\")\n    End Sub\n\n    ' <summary>\n    ' This allows the user to enter a guess - doing some basic validation\n    ' on those guesses.\n    ' </summary>\n    ' <returns>The guess entered by the user</returns>\n    Private Function get_guess() As String\n        Dim guess As String = \"\"\n\n        While (guess.Length = 0)\n            Console.WriteLine($\"{Environment.NewLine}Guess a five letter word. \")\n            guess = Console.ReadLine().ToUpper()\n\n            If ((guess.Length <> 5) Or guess.Equals(\"?\") Or Not Regex.IsMatch(guess, \"^[A-Z]+$\")) Then\n                guess = \"\"\n                Console.WriteLine(\"You must guess a give letter word. Start again.\")\n            End If\n        End While\n\n        Return guess\n    End Function\n\n    ' <summary>\n    ' This checks the user's guess against the target word - capturing\n    ' any letters that match up between the two as well as the specific\n    ' letters that are correct.\n    ' </summary>\n    ' <param name=\"guess\">The user's guess</param>\n    ' <param name=\"target\">The 'winning' word</param>\n    ' <param name=\"progress\">A string showing which specific letters have already been guessed</param>\n    ' <returns>The integer value showing the number of character matches between guess and target</returns>\n    Private Function check_guess(guess As String, target As String, progress As StringBuilder) As Integer\n        ' Go through each letter of the guess And see which\n        ' letters match up to the target word.\n        ' For each position that matches, update the progress\n        ' to reflect the guess\n        Dim matches As Integer = 0\n        Dim common_letters As String = \"\"\n\n        For ctr As Integer = 0 To 4\n\n            ' First see if this letter appears anywhere in the target\n            ' And, if so, add it to the common_letters list.\n            If (target.Contains(guess(ctr))) Then\n                common_letters.Append(guess(ctr))\n            End If\n            ' Then see if this specific letter matches the\n            ' same position in the target. And, if so, update\n            ' the progress tracker\n            If (guess(ctr).Equals(target(ctr))) Then\n                progress(ctr) = guess(ctr)\n                matches += 1\n            End If\n        Next\n\n        Console.WriteLine($\"There were {matches} matches and the common letters were... {common_letters}\")\n        Console.WriteLine($\"From the exact letter matches, you know......... {progress}\")\n        Return matches\n    End Function\n\n    ' <summary>\n    ' This plays one full game.\n    ' </summary>\n    Private Sub play_game()\n        Dim guess_word As String, target_word As String\n        Dim guess_progress As StringBuilder = New StringBuilder(\"-----\")\n        Dim rand As Random = New Random()\n        Dim count As Integer = 0\n\n        Console.WriteLine(\"You are starting a new game...\")\n\n        ' Randomly select a word from the list of words\n        target_word = words(rand.Next(words.Length))\n\n        ' Just run as an infinite loop until one of the\n        ' endgame conditions are met.\n        While (True)\n            ' Ask the user for their guess\n            guess_word = get_guess()\n            count += 1\n\n            ' If they enter a question mark, then tell them\n            ' the answer and quit the game\n            If (guess_word.Equals(\"?\")) Then\n                Console.WriteLine($\"The secret word is {target_word}\")\n                Return\n            End If\n\n            ' Otherwise, check the guess against the target - noting progress\n            If (check_guess(guess_word, target_word, guess_progress) = 0) Then\n                Console.WriteLine(\"If you give up, type '?' for your next guess.\")\n            End If\n\n            ' Once they've guess the word, end the game.\n            If (guess_progress.Equals(guess_word)) Then\n                Console.WriteLine($\"You have guessed the word.  It took {count} guesses!\")\n                Return\n            End If\n\n        End While\n    End Sub\n\n    ' <summary>\n    ' The main entry point for the class - just keeps\n    ' playing the game until the user decides to quit.\n    ' </summary>\n    Public Sub play()\n        intro()\n\n        Dim keep_playing As Boolean = True\n\n        While (keep_playing)\n            play_game()\n            Console.WriteLine($\"{Environment.NewLine}Want to play again? \")\n            keep_playing = Console.ReadLine().StartsWith(\"y\", StringComparison.CurrentCultureIgnoreCase)\n        End While\n\n    End Sub\nEnd Module\n\nModule Program\n    Sub Main(args As String())\n        Word.play()\n    End Sub\nEnd Module\n"
  },
  {
    "path": "96_Word/vbnet/README.md",
    "content": "Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)\n\nConversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)\n"
  },
  {
    "path": "96_Word/vbnet/word.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31321.278\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{778DAE3C-4631-46EA-AA77-85C1314464D9}\") = \"Word\", \"Word.vbproj\", \"{F0D2422C-983F-4DF3-9D17-D2480839DF07}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {179D39EB-C497-4336-B795-49CC799929BB}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "96_Word/vbnet/word.vbproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <RootNamespace>Word</RootNamespace>\n    <TargetFramework>netcoreapp3.1</TargetFramework>\n    <LangVersion>16.9</LangVersion>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "96_Word/word.bas",
    "content": "2 PRINT TAB(33);\"WORD\"\n3 PRINT TAB(15);\"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\"\n4 PRINT: PRINT: PRINT\n5 DIM S(7),A(7),L(7),D(7),P(7)\n10 PRINT \"I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\"\n15 PRINT \"CLUES TO HELP YOU GET IT.  GOOD LUCK!!\": PRINT: PRINT\n20 REM\n30 PRINT: PRINT: PRINT \"YOU ARE STARTING A NEW GAME...\"\n35 RESTORE\n40 READ N\n50 C=INT(RND(1)*N+1)\n60 FOR I=1 TO C\n70 READ S$\n80 NEXT I\n90 G=0\n95 S(0)=LEN(S$)\n100 FOR I=1 TO LEN(S$): S(I)=ASC(MID$(S$,I,1)): NEXT I\n110 FOR I=1 TO 5\n120 A(I)=45\n130 NEXT I\n140 FOR J=1 TO 5\n144 P(J)=0\n146 NEXT J\n150 PRINT \"GUESS A FIVE LETTER WORD\";\n160 INPUT L$\n170 G=G+1\n172 IF S$=L$ THEN 500\n173 FOR I=1 TO 7: P(I)=0: NEXT I\n175 L(0)=LEN(L$)\n180 FOR I=1 TO LEN(L$): L(I)=ASC(MID$(L$,I,1)): NEXT I\n190 IF L(1)=63 THEN 300\n200 IF L(0)<>5 THEN 400\n205 M=0: Q=1\n210 FOR I=1 TO 5\n220 FOR J=1 TO 5\n230 IF S(I)<>L(J) THEN 260\n231 P(Q)=L(J)\n232 Q=Q+1\n233 IF I<>J THEN 250\n240 A(J)=L(J)\n250 M=M+1\n260 NEXT J\n265 NEXT I\n270 A(0)=5\n272 P(0)=M\n275 A$=\"\": FOR I=1 TO A(0): A$=A$+CHR$(A(I)): NEXT I\n277 P$=\"\": FOR I=1 TO P(0): P$=P$+CHR$(P(I)): NEXT I\n280 PRINT \"THERE WERE\";M;\"MATCHES AND THE COMMON LETTERS WERE...\";P$\n285 PRINT \"FROM THE EXACT LETTER MATCHES, YOU KNOW................\";A$\n286 IF A$=S$ THEN 500\n287 IF M>1 THEN 289\n288 PRINT: PRINT \"IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\"\n289 PRINT\n290 GOTO 150\n300 S$=\"\": FOR I=1 TO 7: S$=S$+CHR$(S(I)): NEXT I\n310 PRINT \"THE SECRET WORD IS \";S$: PRINT\n320 GOTO 30\n400 PRINT \"YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\"\n410 PRINT: G=G-1: GOTO 150\n500 PRINT \"YOU HAVE GUESSED THE WORD.  IT TOOK\";G;\"GUESSES!\": PRINT\n510 INPUT \"WANT TO PLAY AGAIN\";Q$\n520 IF Q$=\"YES\" THEN 30\n530 DATA 12,\"DINKY\",\"SMOKE\",\"WATER\",\"GRASS\",\"TRAIN\",\"MIGHT\",\"FIRST\"\n540 DATA \"CANDY\",\"CHAMP\",\"WOULD\",\"CLUMP\",\"DOPEY\"\n999 END\n"
  },
  {
    "path": "HOW_TO_RUN_THE_GAMES.md",
    "content": "# How to run the games\n\nThe games in this repository have been translated into a number of different languages. How to run them depends on the target language.\n\n## csharp\n\n### dotnet command-line\n\nThe best cross-platform method for running the csharp examples is with the `dotnet` command-line tool. This can be downloaded for **MacOS**, **Windows** and **Linux** from [dotnet.microsoft.com](https://dotnet.microsoft.com/).\n\nFrom there, the program can be run by\n\n1. Opening a terminal window\n1. Navigating to the corresponding directory\n1. Starting with `dotnet run`\n\n### Visual Studio\n\nAlternatively, for non-dotnet compatible translations, you will need [Visual Studio](https://visualstudio.microsoft.com/vs/community/) which can be used to both open the project and run the example.\n\n1. Open the corresponding `.csproj` or `.sln` file\n1. Click `Run` from within the Visual Studio IDE\n\n## java\n\nThe Java translations can be run via the command line or from an IDE such as [Eclipse](https://www.eclipse.org/downloads/packages/release/kepler/sr1/eclipse-ide-java-developers) or [IntelJ][def]\n\nTo run from the command line, you will need a Java SDK (eg. [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) or [Open JDK](https://openjdk.java.net/)).\n\n1. Navigate to the corresponding directory.\n1. Compile the program with `javac`:\n   * eg. `**```python\n   javac\n   ```** AceyDuceyGame.java`\n1. Run the compiled program with `java`:\n   * eg. `java AceyDuceyGame`\n\nor if you are **using JDK11 or later** you can now execute a self contained java file that has a main method directly with `java <filename>.java`.\n\n## javascript\n\nThere are two ways of javascript implementations:\n\n### browser\n\nThe html examples can be run from within your web browser. Simply open the corresponding `.html` file from your web browser.\n\n### node.js\n\nSome games are implemented as a [node.js](https://nodejs.org/) script. In this case there is no `*.html` file in the folder.\n\n1. [install node.js](https://nodejs.org/en/download/) for your system.\n1. change directory to the root of this repository (e.g. `cd basic-computer-games`).\n1. from a terminal call the script you want to run (e.g. `node 78_Sine_Wave/javascript/sinewave.mjs`).\n\n_Hint: Normally javascript files have a `*.js` extension. We are using `*.mjs` to let node know , that we are using [ES modules](https://nodejs.org/docs/latest/api/esm.html#modules-ecmascript-modules) instead of [CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules)._\n\n## kotlin\n\nKotlin programs are compiled with the Kotlin compiler, and run with the java runtime, just like java programs.\nIn addition to the java runtime you will need the `kotlinc` compiler, which can be installed using [these instructions](https://kotlinlang.org/docs/command-line.html).\n\n1. Navigate to the corresponding directory.\n1. Compile the program with `kotlinc`:\n   * eg. `kotlinc AceyDuceyGame.kt -include-runtime -d AceyDuceyGame.jar`\n1. Run the compiled program with `java`:\n   * eg. `java -jar AceyDuceyGame.jar`\n\n## pascal\n\nThe pascal examples can be run using [Free Pascal](https://www.freepascal.org/). Additionally, `.lsi` project files can be opened with the [Lazarus Project IDE](https://www.lazarus-ide.org/).\n\nThe pascal examples include both ___simple_ (single-file) and_o**bject-oriented_ (in the `/object-pascal`directories) examples.\n\n1. You can compile the program from the command line with the `fpc` command.\n   * eg. `fpc amazing.pas`\n1. The output is an executable file that can be run directly.\n\n## perl\n\nThe perl translations can be run using a perl interpreter (a copy can be downloaded from [perl.org](https://www.perl.org/)) if not already installed.\n\n1. From the command-line, navigate to the corresponding directory.\n1. Invoke with the `perl` command.\n   * eg. `perl aceyducey.pl`\n\n## python\n\nThe python translations can be run from the command line by using the `py` interpreter. If not already installed, a copy can be downloaded from [python.org](https://www.python.org/downloads/) for **Windows**, **MacOS** and **Linux**.\n\n1. From the command-line, navigate to the corresponding directory.\n1. Invoke with the `py` or `python` interpreter (depending on your python version).\n   * eg. `py acey_ducey_oo.py`\n   * eg. `python aceyducey.py`\n\n**Note**\n{\n    \"MD013\": false\n}\nSome translations include multiple versions for python, such as `acey ducey` which features versions for Python 2 (`aceyducey.py`) and Python 3 (`acey_ducey.py`) as well as an extra object-oriented version (`acey_ducey_oo.py`).\n\nYou can manage and use different versions of python with [pip](https://pypi.org/project/pip/).\n\n## ruby\n\nIf you don't already have a ruby interpreter, you can download it from the [ruby project site](https://www.ruby-lang.org/en/).\n\n1. From the command-line, navigate to the corresponding directory.\n1. Invoke with the `ruby` tool.\n   * eg. `ruby aceyducey.rb`\n\n## vbnet\n\nFollow the same steps as for the [csharp](#csharp) translations. This can be run with `dotnet` or `Visual Studio`.\n\n## rust\n\nIf you don't already have Rust on your computer, you can follow the instruction on [Rust Book](https://doc.rust-lang.org/book/ch01-01-installation.html)\n\n1. From the command-line, navigate to the corresponding directory.\n2. Run the following command.\n   * `cargo run`\n\n[def]: https://www.jetbrains.com/idea/\n"
  },
  {
    "path": "LICENSE",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <https://unlicense.org>\n"
  },
  {
    "path": "README.md",
    "content": "### What are we doing?\n\nWe’re updating the first million selling computer book, [BASIC Computer Games](https://en.wikipedia.org/wiki/BASIC_Computer_Games), for 2022 and beyond!\n\n- [Read the original book](https://archive.org/details/basiccomputergam0000unse) (pdf)\n- [Play the original games in your browser](https://troypress.com/wp-content/uploads/user/js-basic/index.html)\n\n### Where can we discuss it?\n\nPlease see [the discussion here](https://discourse.codinghorror.com/t/-/7927) for a worklog and conversation around this project.\n\n### Project structure\n\nI have moved all [the original BASIC source code](http://www.vintage-basic.net/games.html) into a folder for each project in the original book (first volume). Note that Lyle Kopnicky has generously normalized all the code (thanks Lyle!) to run against [Vintage Basic](http://www.vintage-basic.net/download.html) circa 2009:\n\n> I’ve included all the games here for your tinkering pleasure. I’ve tested and tweaked each one of them to make sure they’ll run with Vintage BASIC, though you may see a few oddities. That’s part of the fun of playing with BASIC: it never works quite the same on two machines. The games will play better if you keep CAPS LOCK on, as they were designed to be used with capital-letter input.\n\nEach project has subfolders corresponding to the languages we’d like to see the games ported to. This is based on the [2022 TIOBE index of top languages](https://www.tiobe.com/tiobe-index/) that are _**memory safe**_ and _**general purpose scripting languages**_ per [this post](https://discourse.codinghorror.com/t/-/7927/34):\n\n1. C# \n2. Java\n3. JavaScript\n4. Kotlin\n5. Lua\n6. Perl\n7. Python\n8. Ruby\n9. Rust\n10. VB.NET\n\n> 📢 Note that in March 2022 we removed Pascal / Object Pascal and replaced it with Rust as we couldn’t determine if Pascal is effectively memory safe. We’ve also added Lua, as it made the top 20 in TIOBE (as of 2022) and it is both memory safe and a scripting language. The Pascal ports were moved to the alternate languages folder.\n\n> ⚠️ Please note that we have decided, as a project, that we **do not want any IDE-specific or build-specific files in the repository.** Please refrain from committing any files to the repository that only exist to work with a specific IDE or a specific build system.\n\n### Alternate Languages\n\nIf you wish to port one of the programs to a language not in our list – that is, a language which is either not memory safe, or not a general purpose scripting language, you can do so via the `00_Alternate_Languages` folder. Place your port in the appropriate game subfolder, in a subfolder named for the language. Please note that these ports are appreciated, but they will not count toward the donation total at the end of the project.\n\n### Project goals\n\nFeel free to begin converting these classic games into the above list of modern, memory safe languages. In fact, courtesy of @mojoaxel, you can even view the JavaScript versions in your web browser at\n\nhttps://coding-horror.github.io/basic-computer-games/\n\nBut first, a few guidelines:\n\n- **These are very old games**. They date from the mid-70s so they’re not exactly examples of what kids (or anyone, really?) would be playing these days. Consider them more like classic programming exercises to teach programming.  We’re paying it forward by converting them into modern languages, so the next generation can learn from the programs in this classic book – and compare implementations across common modern languages.\n\n- **Stay true to the original program**. These are mostly unsophisticated, simple command line / console games, so we should strive to replicate the command line / console output and behavior illustrated in the original book. See the README in the project folder for links to the original scanned source input and output. Try [running the game in your browser](https://troypress.com/wp-content/uploads/user/js-basic/index.html). Avoid the impulse to add features; keep it simple, _except_ for modern conventions, see next item 👇\n\n- **Please DO update for modern coding conventions**. Support uppercase and lowercase. Use structured programming. Use subroutines. Try to be an example of good, modern coding practices!\n\n- **Use lots of comments to explain what is going on**. Comment liberally! If there were clever tricks in the original code, decompose those tricks into simpler (even if more verbose) code, and use comments to explain what’s happening and why. If there is something particularly tricky about a program, edit the **Porting Notes** section of the `readme.md` to let everyone know. Those `GOTO`s can be very pesky..\n\n- **Please don’t get _too_ fancy**. Definitely use the most recent versions and features of the target language, but also try to keep the code samples simple and explainable – the goal is to teach programming in the target language, not necessarily demonstrate the cleverest one-line tricks, or big system \"enterprise\" coding techniques designed for thousands of lines of code.\n\n- **Please don't check in any build specific or IDE specific files**. We want the repository to be simple and clean, so we have ruled out including any IDE or build system specific files from the repository. Git related files are OK, as we are using Git and this is GitHub. 😉\n\n### Emulation and Bugfixes\n\nWe want the general behavior of the original programs to be preserved, _however_, we also want to update them, specifically:\n\n- allow both UPPERCASE and lowercase input and display\n- incorporate any bugfixes to the original programs; see the `readme.md` in the game folder\n- improved error handling for bad or erroneous input\n\nPlease note that on the back of the Basic Computer Games book it says **Microsoft 8K Basic, Rev 4.0 was the version David Ahl used to test**, so that is the level of compatibility we are looking for.  QBasic on the DOS emulation is a later version of Basic but one that retains downwards compatibility so far in our testing. To verify behavior, try [running the programs in your browser](https://troypress.com/wp-content/uploads/user/js-basic/index.html) with [JS BASIC, effectively Applesoft BASIC](https://github.com/inexorabletash/jsbasic/).\n\n### Have fun!\n\nThank you for taking part in this project to update a classic programming book – one of the most influential programming books in computing history – for 2022 and beyond!\n\nNOTE: per [the official blog post announcement](https://blog.codinghorror.com/updating-the-single-most-influential-book-of-the-basic-era/), I will be **donating $5 for each contributed program in the 10 agreed upon languages to [Girls Who Code](https://girlswhocode.com/)**.\n\n### Current Progress\n\n<details><summary>toggle for game by language table</summary>\n\n| Name                   | csharp | java | javascript | kotlin | lua | perl | python | ruby | rust | vbnet |\n| ---------------------- | ------ | ---- | ---------- | ------ | --- | ---- | ------ | ---- | ---- | ----- |\n| 01_Acey_Ducey          | x      | x    | x          | x      | x   | x    | x      | x    | x    | x     |\n| 02_Amazing             | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 03_Animal              | x      | x    | x          | x      | x   | x    | x      | x    | x    | x     |\n| 04_Awari               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 05_Bagels              | x      | x    | x          | x      | x   | x    | x      | x    | x    | x     |\n| 06_Banner              | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 07_Basketball          | x      | x    | x          |        |     | x    | x      | x    |      | x     |\n| 08_Batnum              | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 09_Battle              | x      | x    | x          |        |     |      | x      |      | x    | x     |\n| 10_Blackjack           | x      | x    | x          |        |     |      | x      | x    | x    | x     |\n| 11_Bombardment         | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 12_Bombs_Away          | x      | x    | x          |        | x   | x    | x      |      | x    | x     |\n| 13_Bounce              | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 14_Bowling             | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 15_Boxing              | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 16_Bug                 | x      | x    | x          |        |     |      | x      | x    |      | x     |\n| 17_Bullfight           | x      | x    | x          | x      |     |      | x      |      |      | x     |\n| 18_Bullseye            | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 19_Bunny               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 20_Buzzword            | x      | x    | x          |        | x   | x    | x      | x    | x    | x     |\n| 21_Calendar            | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 22_Change              | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 23_Checkers            | x      |      | x          |        |     | x    | x      | x    |      | x     |\n| 24_Chemist             | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 25_Chief               | x      | x    | x          |        | x   | x    | x      | x    | x    | x     |\n| 26_Chomp               | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 27_Civil_War           | x      | x    | x          |        |     |      | x      |      |      | x     |\n| 28_Combat              | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 29_Craps               | x      | x    | x          |        | x   | x    | x      | x    | x    | x     |\n| 30_Cube                | x      | x    | x          |        |     |      | x      | x    | x    | x     |\n| 31_Depth_Charge        | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 32_Diamond             | x      | x    | x          | x      |     | x    | x      | x    | x    | x     |\n| 33_Dice                | x      | x    | x          |        | x   | x    | x      | x    | x    | x     |\n| 34_Digits              | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 35_Even_Wins           | x      |      | x          |        |     | x    | x      |      | x    | x     |\n| 36_Flip_Flop           | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 37_Football            | x      |      | x          |        |     |      | x      |      |      | x     |\n| 38_Fur_Trader          | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 39_Golf                | x      |      | x          |        |     |      | x      |      |      | x     |\n| 40_Gomoko              | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 41_Guess               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 42_Gunner              | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 43_Hammurabi           | x      | x    | x          |        |     |      | x      |      | x    | x     |\n| 44_Hangman             | x      | x    | x          |        |     | x    | x      | x    |      | x     |\n| 45_Hello               | x      | x    | x          |        | x   | x    | x      | x    | x    | x     |\n| 46_Hexapawn            | x      |      |            |        |     |      | x      |      |      | x     |\n| 47_Hi-Lo               | x      |      | x          | x      | x   | x    | x      | x    | x    | x     |\n| 48_High_IQ             | x      | x    | x          |        |     |      | x      |      |      | x     |\n| 49_Hockey              | x      |      | x          |        |     |      | x      |      |      | x     |\n| 50_Horserace           | x      | x    | x          |        |     |      |        |      | x    | x     |\n| 51_Hurkle              | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 52_Kinema              | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 53_King                | x      |      | x          |        |     |      | x      |      | x    | x     |\n| 54_Letter              | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 55_Life                | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 56_Life_for_Two        | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 57_Literature_Quiz     | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 58_Love                | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 59_Lunar_LEM_Rocket    | x      |      | x          |        |     |      | x      |      | x    | x     |\n| 60_Mastermind          | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 61_Math_Dice           | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 62_Mugwump             | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 63_Name                | x      | x    | x          | x      |     | x    | x      | x    | x    | x     |\n| 64_Nicomachus          | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 65_Nim                 | x      |      | x          |        |     |      | x      | x    | x    | x     |\n| 66_Number              | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 67_One_Check           | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 68_Orbit               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 69_Pizza               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 70_Poetry              | x      | x    | x          |        |     | x    | x      | x    |      | x     |\n| 71_Poker               | x      | x    | x          |        |     |      |        |      |      | x     |\n| 72_Queen               | x      |      | x          |        |     | x    | x      |      | x    | x     |\n| 73_Reverse             | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 74_Rock_Scissors_Paper | x      | x    | x          | x      |     | x    | x      | x    | x    | x     |\n| 75_Roulette            | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 76_Russian_Roulette    | x      | x    | x          | x      |     | x    | x      | x    | x    | x     |\n| 77_Salvo               | x      |      | x          |        |     |      | x      |      | x    | x     |\n| 78_Sine_Wave           | x      | x    | x          | x      |     | x    | x      | x    | x    | x     |\n| 79_Slalom              | x      |      | x          |        |     |      | x      |      |      | x     |\n| 80_Slots               | x      | x    | x          |        |     | x    | x      | x    |      | x     |\n| 81_Splat               | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 82_Stars               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 83_Stock_Market        | x      | x    | x          |        |     |      | x      |      |      | x     |\n| 84_Super_Star_Trek     | x      | x    | x          |        |     |      | x      |      | x    | x     |\n| 85_Synonym             | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 86_Target              | x      | x    | x          |        |     | x    | x      |      |      | x     |\n| 87_3-D_Plot            | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 88_3-D_Tic-Tac-Toe     | x      |      | x          |        |     |      | x      |      |      | x     |\n| 89_Tic-Tac-Toe         | x      | x    | x          | x      |     | x    | x      |      | x    | x     |\n| 90_Tower               | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 91_Train               | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 92_Trap                | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 93_23_Matches          | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n| 94_War                 | x      | x    | x          | x      |     | x    | x      | x    | x    | x     |\n| 95_Weekday             | x      | x    | x          |        |     | x    | x      |      | x    | x     |\n| 96_Word                | x      | x    | x          |        |     | x    | x      | x    | x    | x     |\n\n</details>\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>BASIC Computer Games</title><link rel=\"stylesheet\" href=\"./00_Utilities/javascript/style_terminal.css\" /></head><body><article id=\"output\"><header><h1>BASIC Computer Games</h1></header><main><ul><li><a href=\"01_Acey_Ducey/javascript/aceyducey.html\">01 Acey_Ducey</a></li><li><a href=\"02_Amazing/javascript/amazing.html\">02 Amazing</a></li><li><a href=\"03_Animal/javascript/animal.html\">03 Animal</a></li><li><a href=\"04_Awari/javascript/awari.html\">04 Awari</a></li><li><a href=\"05_Bagels/javascript/bagels.html\">05 Bagels</a></li><li><a href=\"06_Banner/javascript/banner.html\">06 Banner</a></li><li><a href=\"07_Basketball/javascript/basketball.html\">07 Basketball</a></li><li><a href=\"08_Batnum/javascript/batnum.html\">08 Batnum</a></li><li><a href=\"09_Battle/javascript/battle.html\">09 Battle</a></li><li><a href=\"10_Blackjack/javascript/blackjack.html\">10 Blackjack</a></li><li><a href=\"11_Bombardment/javascript/bombardment.html\">11 Bombardment</a></li><li><a href=\"12_Bombs_Away/javascript/bombsaway.html\">12 Bombs_Away</a></li><li><a href=\"13_Bounce/javascript/bounce.html\">13 Bounce</a></li><li><a href=\"14_Bowling/javascript/bowling.html\">14 Bowling</a></li><li><a href=\"15_Boxing/javascript/boxing.html\">15 Boxing</a></li><li><a href=\"16_Bug/javascript/bug.html\">16 Bug</a></li><li><a href=\"17_Bullfight/javascript/bullfight.html\">17 Bullfight</a></li><li><a href=\"18_Bullseye/javascript/bullseye.html\">18 Bullseye</a></li><li><a href=\"19_Bunny/javascript/bunny.html\">19 Bunny</a></li><li><a href=\"20_Buzzword/javascript/buzzword.html\">20 Buzzword</a></li><li><a href=\"21_Calendar/javascript/calendar.html\">21 Calendar</a></li><li><a href=\"22_Change/javascript/change.html\">22 Change</a></li><li><a href=\"23_Checkers/javascript/checkers.html\">23 Checkers</a></li><li><a href=\"24_Chemist/javascript/chemist.html\">24 Chemist</a></li><li><a href=\"25_Chief/javascript/chief.html\">25 Chief</a></li><li><a href=\"26_Chomp/javascript/chomp.html\">26 Chomp</a></li><li><a href=\"27_Civil_War/javascript/civilwar.html\">27 Civil_War</a></li><li><a href=\"28_Combat/javascript/combat.html\">28 Combat</a></li><li><a href=\"29_Craps/javascript/craps.html\">29 Craps</a></li><li><a href=\"30_Cube/javascript/cube.html\">30 Cube</a></li><li><a href=\"31_Depth_Charge/javascript/depthcharge.html\">31 Depth_Charge</a></li><li><a href=\"32_Diamond/javascript/diamond.html\">32 Diamond</a></li><li><a href=\"33_Dice/javascript/dice.html\">33 Dice</a></li><li><a href=\"34_Digits/javascript/digits.html\">34 Digits</a></li><li><span>35 Even_Wins</span><ul><li><a href=\"35_Even_Wins/javascript/evenwins.html\">evenwins</a></li><li><a href=\"35_Even_Wins/javascript/gameofevenwins.html\">gameofevenwins</a></li></ul></li><li><a href=\"36_Flip_Flop/javascript/flipflop.html\">36 Flip_Flop</a></li><li><span>37 Football</span><ul><li><a href=\"37_Football/javascript/football.html\">football</a></li><li><a href=\"37_Football/javascript/ftball.html\">ftball</a></li></ul></li><li><a href=\"38_Fur_Trader/javascript/furtrader.html\">38 Fur_Trader</a></li><li><a href=\"39_Golf/javascript/golf.html\">39 Golf</a></li><li><a href=\"40_Gomoko/javascript/gomoko.html\">40 Gomoko</a></li><li><a href=\"41_Guess/javascript/guess.html\">41 Guess</a></li><li><a href=\"42_Gunner/javascript/gunner.html\">42 Gunner</a></li><li><a href=\"43_Hammurabi/javascript/hammurabi.html\">43 Hammurabi</a></li><li><a href=\"44_Hangman/javascript/hangman.html\">44 Hangman</a></li><li><a href=\"45_Hello/javascript/hello.html\">45 Hello</a></li><li><a href=\"46_Hexapawn/javascript/hexapawn.html\">46 Hexapawn</a></li><li><a href=\"47_Hi-Lo/javascript/hi-lo.html\">47 Hi-Lo</a></li><li><a href=\"48_High_IQ/javascript/highiq.html\">48 High_IQ</a></li><li><a href=\"49_Hockey/javascript/hockey.html\">49 Hockey</a></li><li><a href=\"50_Horserace/javascript/horserace.html\">50 Horserace</a></li><li><a href=\"51_Hurkle/javascript/hurkle.html\">51 Hurkle</a></li><li><a href=\"52_Kinema/javascript/kinema.html\">52 Kinema</a></li><li><a href=\"53_King/javascript/king.html\">53 King</a></li><li><a href=\"54_Letter/javascript/letter.html\">54 Letter</a></li><li><a href=\"55_Life/javascript/life.html\">55 Life</a></li><li><a href=\"56_Life_for_Two/javascript/lifefortwo.html\">56 Life_for_Two</a></li><li><span>57 Literature_Quiz</span><ul><li><a href=\"57_Literature_Quiz/javascript/litquiz.html\">litquiz</a></li><li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#57_Literature_Quiz/javascript/litquiz.mjs\">litquiz (node.js)</a></li></ul></li><li><a href=\"58_Love/javascript/love.html\">58 Love</a></li><li><span>59 Lunar_LEM_Rocket</span><ul><li><a href=\"59_Lunar_LEM_Rocket/javascript/lem.html\">lem</a></li><li><a href=\"59_Lunar_LEM_Rocket/javascript/lunar.html\">lunar</a></li></ul></li><li><a href=\"60_Mastermind/javascript/mastermind.html\">60 Mastermind</a></li><li><a href=\"61_Math_Dice/javascript/mathdice.html\">61 Math_Dice</a></li><li><a href=\"62_Mugwump/javascript/mugwump.html\">62 Mugwump</a></li><li><a href=\"63_Name/javascript/name.html\">63 Name</a></li><li><a href=\"64_Nicomachus/javascript/nicomachus.html\">64 Nicomachus</a></li><li><a href=\"65_Nim/javascript/nim.html\">65 Nim</a></li><li><a href=\"66_Number/javascript/number.html\">66 Number</a></li><li><a href=\"67_One_Check/javascript/onecheck.html\">67 One_Check</a></li><li><a href=\"68_Orbit/javascript/orbit.html\">68 Orbit</a></li><li><a href=\"69_Pizza/javascript/pizza.html\">69 Pizza</a></li><li><a href=\"70_Poetry/javascript/poetry.html\">70 Poetry</a></li><li><a href=\"71_Poker/javascript/poker.html\">71 Poker</a></li><li><a href=\"72_Queen/javascript/queen.html\">72 Queen</a></li><li><a href=\"73_Reverse/javascript/reverse.html\">73 Reverse</a></li><li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#74_Rock_Scissors_Paper/javascript/rockscissors.mjs\">74 Rock_Scissors_Paper (node.js)</a></li><li><a href=\"75_Roulette/javascript/roulette.html\">75 Roulette</a></li><li><a href=\"76_Russian_Roulette/javascript/russianroulette.html\">76 Russian_Roulette</a></li><li><a href=\"77_Salvo/javascript/salvo.html\">77 Salvo</a></li><li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#78_Sine_Wave/javascript/sinewave.mjs\">78 Sine_Wave (node.js)</a></li><li><a href=\"79_Slalom/javascript/slalom.html\">79 Slalom</a></li><li><a href=\"80_Slots/javascript/slots.html\">80 Slots</a></li><li><a href=\"81_Splat/javascript/splat.html\">81 Splat</a></li><li><a href=\"82_Stars/javascript/stars.html\">82 Stars</a></li><li><a href=\"83_Stock_Market/javascript/stockmarket.html\">83 Stock_Market</a></li><li><a href=\"84_Super_Star_Trek/javascript/index.html\">84 Super_Star_Trek</a></li><li><a href=\"85_Synonym/javascript/synonym.html\">85 Synonym</a></li><li><a href=\"86_Target/javascript/target.html\">86 Target</a></li><li><a href=\"87_3-D_Plot/javascript/3dplot.html\">87 3-D_Plot</a></li><li><a href=\"88_3-D_Tic-Tac-Toe/javascript/qubit.html\">88 3-D_Tic-Tac-Toe</a></li><li><span>89 Tic-Tac-Toe</span><ul><li><a href=\"89_Tic-Tac-Toe/javascript/tictactoe1.html\">tictactoe1</a></li><li><a href=\"89_Tic-Tac-Toe/javascript/tictactoe2.html\">tictactoe2</a></li></ul></li><li><a href=\"90_Tower/javascript/tower.html\">90 Tower</a></li><li><a href=\"91_Train/javascript/train.html\">91 Train</a></li><li><a href=\"92_Trap/javascript/trap.html\">92 Trap</a></li><li><a href=\"93_23_Matches/javascript/23matches.html\">93 23_Matches</a></li><li><a href=\"94_War/javascript/war.html\">94 War</a></li><li><a href=\"95_Weekday/javascript/weekday.html\">95 Weekday</a></li><li><span>96 Word</span><ul><li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#96_Word/javascript/word.mjs\">word (node.js)</a></li><li><a href=\"./00_Common/javascript/WebTerminal/terminal.html#96_Word/javascript/word_full.mjs\">word_full (node.js)</a></li></ul></li></ul></main></article></body></html>"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.pytest.ini_options]\nmarkers = [\n    \"slow: marks tests as slow (deselect with '-m \\\"not slow\\\"')\",\n]\n"
  }
]